<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/mackerelio/mackerel-agent/command"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/logging"
	"github.com/mackerelio/mackerel-agent/version"
)

// allow options like -role=... -role=...
type roleFullnamesFlag []string

var roleFullnamePattern = regexp.MustCompile(`^[a-zA-Z0-9][-_a-zA-Z0-9]*:\s*[a-zA-Z0-9][-_a-zA-Z0-9]*$`)

func (r *roleFullnamesFlag) String() string {
	return fmt.Sprint(*r)
}

func (r *roleFullnamesFlag) Set(input string) error {
	inputRoles := strings.Split(input, ",")
	*r = append(*r, inputRoles...)
	return nil
}

type otherOptions struct {
	printVersion bool
	runOnce      bool
}

var logger = logging.GetLogger("main")

func main() {
	conf, otherOptions := resolveConfig()

	if otherOptions != nil && otherOptions.printVersion {
		fmt.Printf("mackerel-agent version %s (rev %s) [%s %s %s] \n",
			version.VERSION, version.GITCOMMIT, runtime.GOOS, runtime.GOARCH, runtime.Version())
		exitWithoutPidfileCleaning(0)
	}

	if conf.Verbose {
		logging.SetLogLevel(logging.DEBUG)
	}

	logger.Infof("Starting mackerel-agent version:%s, rev:%s, apibase:%s", version.VERSION, version.GITCOMMIT, conf.Apibase)

	if otherOptions != nil && otherOptions.runOnce {
		command.RunOnce(conf)
		exitWithoutPidfileCleaning(0)
	}

	if conf.Apikey == "" {
		logger.Criticalf("Apikey must be specified in the command-line flag or in the config file")
		exit(1, conf)
	}

	if err := start(conf); err != nil {
		exit(1, conf)
	}
}

// resolveConfig parses command line arguments and loads config file to
// return config.Config information.
// As a special case, if `-version` flag is given it stops processing
// and return true for the second return value.
func resolveConfig() (*config.Config, *otherOptions) {
	conf := &config.Config{}
	otherOptions := &otherOptions{}

	var (
		conffile     = flag.String("conf", config.DefaultConfig.Conffile, "Config file path (Configs in this file are over-written by command line options)")
		apibase      = flag.String("apibase", config.DefaultConfig.Apibase, "API base")
		pidfile      = flag.String("pidfile", config.DefaultConfig.Pidfile, "File containing PID")
		root         = flag.String("root", config.DefaultConfig.Root, "Directory containing variable state information")
		apikey       = flag.String("apikey", "", "API key from mackerel.io web site")
		diagnostic   = flag.Bool("diagnostic", false, "Enables diagnostic features")
		runOnce      = flag.Bool("once", false, "Show spec and metrics to stdout once")
		printVersion = flag.Bool("version", false, "Prints version and exit")
	)

	var verbose bool
	flag.BoolVar(&verbose, "verbose", config.DefaultConfig.Verbose, "Toggle verbosity")
	flag.BoolVar(&verbose, "v", config.DefaultConfig.Verbose, "Toggle verbosity (shorthand)")

	// The value of "role" option is internally "roll fullname",
	// but we call it "role" here for ease.
	var roleFullnames roleFullnamesFlag
	flag.Var(&roleFullnames, "role", "Set this host's roles (format: <service>:<role>)")

	flag.Parse()

	if *printVersion {
		otherOptions.printVersion = true
		return conf, otherOptions
	}

	if *runOnce {
		otherOptions.runOnce = true
		return conf, otherOptions
	}

	conf, confErr := config.LoadConfig(*conffile)
	if confErr != nil {
		logger.Criticalf("Failed to load the config file: %s", confErr)
		exitWithoutPidfileCleaning(1)
	}

	// overwrite config from file by config from args
	flag.Visit(func(f *flag.Flag) {
		switch f.Name {
		case "apibase":
			conf.Apibase = *apibase
		case "apikey":
			conf.Apikey = *apikey
		case "pidfile":
			conf.Pidfile = *pidfile
		case "root":
			conf.Root = *root
		case "diagnostic":
			conf.Diagnostic = *diagnostic
		case "verbose", "v":
			conf.Verbose = verbose
		case "role":
			conf.Roles = roleFullnames
		}
	})

	r := []string{}
	for _, roleFullName := range conf.Roles {
		if !roleFullnamePattern.MatchString(roleFullName) {
			logger.Errorf("Bad format for role fullname (expecting <service>:<role>. Alphabet, numbers, hyphens and underscores are acceptable, but the first character must not be a hyphen or an underscore.): '%s'", roleFullName)
		} else {
			r = append(r, roleFullName)
		}
	}
	conf.Roles = r
	return conf, nil
}

func createPidFile(pidfile string) error {
	if pidString, err := ioutil.ReadFile(pidfile); err == nil {
		if pid, err := strconv.Atoi(string(pidString)); err == nil {
			if existsPid(pid) {
				return fmt.Errorf("Pidfile found, try stopping another running mackerel-agent or delete %s", pidfile)
			}
			// Note mackerel-agent in windows can't remove pidfile during stoping the service
			logger.Warningf("Pidfile found, but there seems no another process of mackerel-agent. Ignoring %s", pidfile)
		} else {
			logger.Warningf("Malformed pidfile found. Ignoring %s", pidfile)
		}
	}

	file, err := os.Create(pidfile)
	if err != nil {
		logger.Criticalf("Failed to create a pidfile: %s", err)
		return err
	}
	defer file.Close()

	_, err = fmt.Fprintf(file, "%d", os.Getpid())
	return err
}

func removePidFile(pidfile string) {
	if err := os.Remove(pidfile); err != nil {
		logger.Errorf("Failed to remove the pidfile: %s: %s", pidfile, err)
	}
}

func exit(exitCode int, conf *config.Config) {
	removePidFile(conf.Pidfile)
	exitWithoutPidfileCleaning(exitCode)
}

func exitWithoutPidfileCleaning(exitCode int) {
	os.Exit(exitCode)
}

const maxTerminatingInterval = 30

func start(conf *config.Config) error {
	if err := createPidFile(conf.Pidfile); err != nil {
		return err
	}

	ctx, err := command.Prepare(conf)
	if err != nil {
		logger.Criticalf(err.Error())
		exit(1, conf)
	}

	termCh := make(chan struct{})
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
	go func() {
		received := false
		for sig := range c {
			if sig == syscall.SIGHUP {
				logger.Debugf("Received signal '%v'", sig)
				// TODO reload configuration file

				command.UpdateHostSpecs(ctx.Conf, ctx.API, ctx.Host)
			} else {
				if !received {
					received = true
					logger.Infof(
						"Received signal '%v', try graceful shutdown up to %d seconds. If you want force shutdown immediately, send a signal again.",
						sig,
						maxTerminatingInterval)
				} else {
					logger.Infof("Received signal '%v' again, force shutdown.", sig)
				}
				termCh <- struct{}{}
				go func() {
					time.Sleep(maxTerminatingInterval * time.Second)
					logger.Infof("Timed out. force shutdown.")
					termCh <- struct{}{}
				}()
			}
		}
	}()

	exitCode := command.Run(ctx, termCh)
	exit(exitCode, conf)

	return nil
}
<commit_msg>define main.signalHandler() for testability<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/mackerelio/mackerel-agent/command"
	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/logging"
	"github.com/mackerelio/mackerel-agent/version"
)

// allow options like -role=... -role=...
type roleFullnamesFlag []string

var roleFullnamePattern = regexp.MustCompile(`^[a-zA-Z0-9][-_a-zA-Z0-9]*:\s*[a-zA-Z0-9][-_a-zA-Z0-9]*$`)

func (r *roleFullnamesFlag) String() string {
	return fmt.Sprint(*r)
}

func (r *roleFullnamesFlag) Set(input string) error {
	inputRoles := strings.Split(input, ",")
	*r = append(*r, inputRoles...)
	return nil
}

type otherOptions struct {
	printVersion bool
	runOnce      bool
}

var logger = logging.GetLogger("main")

func main() {
	conf, otherOptions := resolveConfig()

	if otherOptions != nil && otherOptions.printVersion {
		fmt.Printf("mackerel-agent version %s (rev %s) [%s %s %s] \n",
			version.VERSION, version.GITCOMMIT, runtime.GOOS, runtime.GOARCH, runtime.Version())
		exitWithoutPidfileCleaning(0)
	}

	if conf.Verbose {
		logging.SetLogLevel(logging.DEBUG)
	}

	logger.Infof("Starting mackerel-agent version:%s, rev:%s, apibase:%s", version.VERSION, version.GITCOMMIT, conf.Apibase)

	if otherOptions != nil && otherOptions.runOnce {
		command.RunOnce(conf)
		exitWithoutPidfileCleaning(0)
	}

	if conf.Apikey == "" {
		logger.Criticalf("Apikey must be specified in the command-line flag or in the config file")
		exit(1, conf)
	}

	if err := start(conf); err != nil {
		exit(1, conf)
	}
}

// resolveConfig parses command line arguments and loads config file to
// return config.Config information.
// As a special case, if `-version` flag is given it stops processing
// and return true for the second return value.
func resolveConfig() (*config.Config, *otherOptions) {
	conf := &config.Config{}
	otherOptions := &otherOptions{}

	var (
		conffile     = flag.String("conf", config.DefaultConfig.Conffile, "Config file path (Configs in this file are over-written by command line options)")
		apibase      = flag.String("apibase", config.DefaultConfig.Apibase, "API base")
		pidfile      = flag.String("pidfile", config.DefaultConfig.Pidfile, "File containing PID")
		root         = flag.String("root", config.DefaultConfig.Root, "Directory containing variable state information")
		apikey       = flag.String("apikey", "", "API key from mackerel.io web site")
		diagnostic   = flag.Bool("diagnostic", false, "Enables diagnostic features")
		runOnce      = flag.Bool("once", false, "Show spec and metrics to stdout once")
		printVersion = flag.Bool("version", false, "Prints version and exit")
	)

	var verbose bool
	flag.BoolVar(&verbose, "verbose", config.DefaultConfig.Verbose, "Toggle verbosity")
	flag.BoolVar(&verbose, "v", config.DefaultConfig.Verbose, "Toggle verbosity (shorthand)")

	// The value of "role" option is internally "roll fullname",
	// but we call it "role" here for ease.
	var roleFullnames roleFullnamesFlag
	flag.Var(&roleFullnames, "role", "Set this host's roles (format: <service>:<role>)")

	flag.Parse()

	if *printVersion {
		otherOptions.printVersion = true
		return conf, otherOptions
	}

	if *runOnce {
		otherOptions.runOnce = true
		return conf, otherOptions
	}

	conf, confErr := config.LoadConfig(*conffile)
	if confErr != nil {
		logger.Criticalf("Failed to load the config file: %s", confErr)
		exitWithoutPidfileCleaning(1)
	}

	// overwrite config from file by config from args
	flag.Visit(func(f *flag.Flag) {
		switch f.Name {
		case "apibase":
			conf.Apibase = *apibase
		case "apikey":
			conf.Apikey = *apikey
		case "pidfile":
			conf.Pidfile = *pidfile
		case "root":
			conf.Root = *root
		case "diagnostic":
			conf.Diagnostic = *diagnostic
		case "verbose", "v":
			conf.Verbose = verbose
		case "role":
			conf.Roles = roleFullnames
		}
	})

	r := []string{}
	for _, roleFullName := range conf.Roles {
		if !roleFullnamePattern.MatchString(roleFullName) {
			logger.Errorf("Bad format for role fullname (expecting <service>:<role>. Alphabet, numbers, hyphens and underscores are acceptable, but the first character must not be a hyphen or an underscore.): '%s'", roleFullName)
		} else {
			r = append(r, roleFullName)
		}
	}
	conf.Roles = r
	return conf, nil
}

func createPidFile(pidfile string) error {
	if pidString, err := ioutil.ReadFile(pidfile); err == nil {
		if pid, err := strconv.Atoi(string(pidString)); err == nil {
			if existsPid(pid) {
				return fmt.Errorf("Pidfile found, try stopping another running mackerel-agent or delete %s", pidfile)
			}
			// Note mackerel-agent in windows can't remove pidfile during stoping the service
			logger.Warningf("Pidfile found, but there seems no another process of mackerel-agent. Ignoring %s", pidfile)
		} else {
			logger.Warningf("Malformed pidfile found. Ignoring %s", pidfile)
		}
	}

	file, err := os.Create(pidfile)
	if err != nil {
		logger.Criticalf("Failed to create a pidfile: %s", err)
		return err
	}
	defer file.Close()

	_, err = fmt.Fprintf(file, "%d", os.Getpid())
	return err
}

func removePidFile(pidfile string) {
	if err := os.Remove(pidfile); err != nil {
		logger.Errorf("Failed to remove the pidfile: %s: %s", pidfile, err)
	}
}

func exit(exitCode int, conf *config.Config) {
	removePidFile(conf.Pidfile)
	exitWithoutPidfileCleaning(exitCode)
}

func exitWithoutPidfileCleaning(exitCode int) {
	os.Exit(exitCode)
}

const maxTerminatingInterval = 30

func start(conf *config.Config) error {
	if err := createPidFile(conf.Pidfile); err != nil {
		return err
	}

	ctx, err := command.Prepare(conf)
	if err != nil {
		logger.Criticalf(err.Error())
		exit(1, conf)
	}

	termCh := make(chan struct{})
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
	go signalHandler(c, ctx, termCh)

	exitCode := command.Run(ctx, termCh)
	exit(exitCode, conf)

	return nil
}

func signalHandler(c chan os.Signal, ctx *command.Context, termCh chan struct{}) {
	received := false
	for sig := range c {
		if sig == syscall.SIGHUP {
			logger.Debugf("Received signal '%v'", sig)
			// TODO reload configuration file

			command.UpdateHostSpecs(ctx.Conf, ctx.API, ctx.Host)
		} else {
			if !received {
				received = true
				logger.Infof(
					"Received signal '%v', try graceful shutdown up to %d seconds. If you want force shutdown immediately, send a signal again.",
					sig,
					maxTerminatingInterval)
			} else {
				logger.Infof("Received signal '%v' again, force shutdown.", sig)
			}
			termCh <- struct{}{}
			go func() {
				time.Sleep(maxTerminatingInterval * time.Second)
				logger.Infof("Timed out. force shutdown.")
				termCh <- struct{}{}
			}()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"reflect"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"

	log "github.com/Sirupsen/logrus"
	"github.com/bmuller/arrow/lib"
	"github.com/brandfolder/gin-gorelic"
	"github.com/carlescere/scheduler"
	"github.com/dwarvesf/working-on/db"
	"github.com/gin-gonic/contrib/ginrus"
	"github.com/gin-gonic/gin"
	"github.com/nlopes/slack"
	"github.com/olebedev/config"
)

type Item struct {
	ID        bson.ObjectId `json:"id" bson:"_id"`
	UserID    string        `json:"user_id" bson:"user_id"`
	Name      string        `json:"user_name" bson:"user_name"`
	Text      string        `json:"text" bson:"text"`
	CreatedAt time.Time     `json:"created_at" bson:"created_at"`
}

func main() {

	// Read configuration from file and env
	port := os.Getenv("PORT")
	digestTime := os.Getenv("DIGEST_TIME")
	gorelic.InitNewrelicAgent(os.Getenv("NEW_RELIC_LICENSE_KEY"), "working", false)

	// Setup schedule jobs
	digestJob := postDigest
	scheduler.Every().Day().At(digestTime).Run(digestJob)

	// Prepare router
	router := gin.New()
	router.Use(gorelic.Handler)
	router.Use(ginrus.Ginrus(log.StandardLogger(), time.RFC3339, true))

	// router.LoadHTMLGlob("templates/*.tmpl.html")
	router.Static("/static", "static")
	router.POST("/on", addItem)

	// Start server
	router.Run(":" + port)
}

// Message will be passed to server with '-' prefix via various way
//	+ Direct message with the bots
//	+ Use slash command `/working <message>`
//	+ Use cli `working-on <message>`
//	+ Might use Chrome plugin
//	+ ...
// Token is secondary param to indicate the user
func addItem(c *gin.Context) {

	// Parse token and message
	var item Item

	text := c.PostForm("text")
	text = strings.TrimSpace(text)

	if text == "" {
		log.Fatalln("Message is nil")
		return
	}

	userID := c.PostForm("user_id")
	userName := c.PostForm("user_name")

	item.ID = bson.NewObjectId()
	item.CreatedAt = time.Now()
	item.Name = userName
	item.UserID = userID
	item.Text = text

	ctx, err := db.NewContext()
	if err != nil {
		panic(err)
	}

	defer ctx.Close()

	// Add Item to database
	err = ctx.C("items").Insert(item)
	if err != nil {
		log.Fatalln(err)
	}

	// Repost to the target channel
	channel := os.Getenv("WORKING_CHANNEL")
	botToken := os.Getenv("BOT_TOKEN")

	if botToken == "" {
		log.Fatal("No token provided")
		os.Exit(1)
	}

	// <@U024BE7LH|bob>
	title := "*" + userName + "* is working on: " + text

	postWorkingItem(botToken, channel, title)

	// Parse configuration
	cfg, err := config.ParseJsonFile("setting.json")
	m, err := cfg.Map("items")
	r, err := cfg.List("items")

	log.Info(reflect.TypeOf(m))
	log.Info(reflect.TypeOf(r))

	// Post item to project group
	for _, item := range r {

		log.Info(reflect.TypeOf(item))
		config, ok := item.(Configuration)
		if ok {
			for _, tag := range config.Tags {
				if strings.Contains(text, tag) {

					log.Info("Hit" + tag)

					// Post to target channel
					postWorkingItem(config.Token, config.Channel, title)
				}
			}
		} else {
			log.Error("Sth went wrong")
		}

	}
}

func postWorkingItem(token string, channel string, text string) {
	s := slack.New(token)
	params := slack.PostMessageParameters{}
	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"
	s.PostMessage(channel, text, params)
}

type Configuration struct {
	Channel string   `json:"channel"`
	Tags    []string `json:"tags"`
	Token   string   `json:"token"`
}

// Post summary to Slack channel
func postDigest() {

	channel := os.Getenv("DIGEST_CHANNEL")
	botToken := os.Getenv("BOT_TOKEN")

	if botToken == "" {
		log.Fatal("No token provided")
		os.Exit(1)
	}

	s := slack.New(botToken)
	users, err := s.GetUsers()

	if err != nil {
		log.Fatal("Cannot get users")
		os.Exit(1)
	}

	ctx, err := db.NewContext()
	if err != nil {
		panic(err)
	}

	defer ctx.Close()

	log.Info("Preparing data")
	// If count > 0, it means there is data to show
	count := 0
	title := " >> Yesterday I did: "
	params := slack.PostMessageParameters{}
	fields := []slack.AttachmentField{}

	yesterday := arrow.Yesterday().UTC()
	toDate := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, time.UTC)

	// Prepare attachment of done items
	for _, user := range users {

		if user.IsBot || user.Deleted {
			continue
		}

		// log.Info("Process user: " + user.Name + " - " + user.Id)

		// Query done items from Database
		var values string
		var items []Item

		err = ctx.C("items").Find(bson.M{"$and": []bson.M{
			bson.M{"user_id": user.Id},
			bson.M{"created_at": bson.M{"$gt": toDate}},
		},
		}).All(&items)

		if err != nil {
			log.Fatal("Cannot query done items.")
			os.Exit(1)
		}

		for _, item := range items {
			values = "\t" + values + " + " + item.Text + "\n"
		}

		// <@U024BE7LH|bob>
		if len(items) > 0 {

			count = count + 1
			field := slack.AttachmentField{
				Title: "@" + user.Name,
				Value: values,
			}

			fields = append(fields, field)
		}
	}

	params.Attachments = []slack.Attachment{
		slack.Attachment{
			Color:  "#7CD197",
			Fields: fields,
		},
	}

	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"

	if count > 0 {
		s.PostMessage(channel, title, params)
	}
}
<commit_msg>minor changes<commit_after>package main

import (
	"os"
	"reflect"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"

	log "github.com/Sirupsen/logrus"
	"github.com/bmuller/arrow/lib"
	"github.com/brandfolder/gin-gorelic"
	"github.com/carlescere/scheduler"
	"github.com/dwarvesf/working-on/db"
	"github.com/gin-gonic/contrib/ginrus"
	"github.com/gin-gonic/gin"
	"github.com/nlopes/slack"
	"github.com/olebedev/config"
)

type Item struct {
	ID        bson.ObjectId `json:"id" bson:"_id"`
	UserID    string        `json:"user_id" bson:"user_id"`
	Name      string        `json:"user_name" bson:"user_name"`
	Text      string        `json:"text" bson:"text"`
	CreatedAt time.Time     `json:"created_at" bson:"created_at"`
}

func main() {

	// Read configuration from file and env
	port := os.Getenv("PORT")
	digestTime := os.Getenv("DIGEST_TIME")
	gorelic.InitNewrelicAgent(os.Getenv("NEW_RELIC_LICENSE_KEY"), "working", false)

	// Setup schedule jobs
	digestJob := postDigest
	scheduler.Every().Day().At(digestTime).Run(digestJob)

	// Prepare router
	router := gin.New()
	router.Use(gorelic.Handler)
	router.Use(ginrus.Ginrus(log.StandardLogger(), time.RFC3339, true))

	// router.LoadHTMLGlob("templates/*.tmpl.html")
	router.Static("/static", "static")
	router.POST("/on", addItem)

	// Start server
	router.Run(":" + port)
}

// Message will be passed to server with '-' prefix via various way
//	+ Direct message with the bots
//	+ Use slash command `/working <message>`
//	+ Use cli `working-on <message>`
//	+ Might use Chrome plugin
//	+ ...
// Token is secondary param to indicate the user
func addItem(c *gin.Context) {

	// Parse token and message
	var item Item

	text := c.PostForm("text")
	text = strings.TrimSpace(text)

	if text == "" {
		log.Fatalln("Message is nil")
		return
	}

	userID := c.PostForm("user_id")
	userName := c.PostForm("user_name")

	item.ID = bson.NewObjectId()
	item.CreatedAt = time.Now()
	item.Name = userName
	item.UserID = userID
	item.Text = text

	ctx, err := db.NewContext()
	if err != nil {
		panic(err)
	}

	defer ctx.Close()

	// Add Item to database
	err = ctx.C("items").Insert(item)
	if err != nil {
		log.Fatalln(err)
	}

	// Repost to the target channel
	channel := os.Getenv("WORKING_CHANNEL")
	botToken := os.Getenv("BOT_TOKEN")

	if botToken == "" {
		log.Fatal("No token provided")
		os.Exit(1)
	}

	// <@U024BE7LH|bob>
	title := "*" + userName + "* is working on: " + text

	postWorkingItem(botToken, channel, title)

	// Parse configuration
	cfg, err := config.ParseJsonFile("setting.json")
	m, err := cfg.Map("items")
	r, err := cfg.List("items")

	log.Info(reflect.TypeOf(m))
	log.Info(reflect.TypeOf(r))

	// Post item to project group
	for _, item := range r {

		log.Info(item["channel"])

		log.Info(reflect.TypeOf(item))
		config, ok := item.(Configuration)
		if ok {
			for _, tag := range config.Tags {
				if strings.Contains(text, tag) {

					log.Info("Hit" + tag)

					// Post to target channel
					postWorkingItem(config.Token, config.Channel, title)
				}
			}
		}
	}
}

func postWorkingItem(token string, channel string, text string) {
	s := slack.New(token)
	params := slack.PostMessageParameters{}
	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"
	s.PostMessage(channel, text, params)
}

type Configuration struct {
	Channel string   `json:"channel"`
	Tags    []string `json:"tags"`
	Token   string   `json:"token"`
}

// Post summary to Slack channel
func postDigest() {

	channel := os.Getenv("DIGEST_CHANNEL")
	botToken := os.Getenv("BOT_TOKEN")

	if botToken == "" {
		log.Fatal("No token provided")
		os.Exit(1)
	}

	s := slack.New(botToken)
	users, err := s.GetUsers()

	if err != nil {
		log.Fatal("Cannot get users")
		os.Exit(1)
	}

	ctx, err := db.NewContext()
	if err != nil {
		panic(err)
	}

	defer ctx.Close()

	log.Info("Preparing data")
	// If count > 0, it means there is data to show
	count := 0
	title := " >> Yesterday I did: "
	params := slack.PostMessageParameters{}
	fields := []slack.AttachmentField{}

	yesterday := arrow.Yesterday().UTC()
	toDate := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, time.UTC)

	// Prepare attachment of done items
	for _, user := range users {

		if user.IsBot || user.Deleted {
			continue
		}

		// log.Info("Process user: " + user.Name + " - " + user.Id)

		// Query done items from Database
		var values string
		var items []Item

		err = ctx.C("items").Find(bson.M{"$and": []bson.M{
			bson.M{"user_id": user.Id},
			bson.M{"created_at": bson.M{"$gt": toDate}},
		},
		}).All(&items)

		if err != nil {
			log.Fatal("Cannot query done items.")
			os.Exit(1)
		}

		for _, item := range items {
			values = "\t" + values + " + " + item.Text + "\n"
		}

		// <@U024BE7LH|bob>
		if len(items) > 0 {

			count = count + 1
			field := slack.AttachmentField{
				Title: "@" + user.Name,
				Value: values,
			}

			fields = append(fields, field)
		}
	}

	params.Attachments = []slack.Attachment{
		slack.Attachment{
			Color:  "#7CD197",
			Fields: fields,
		},
	}

	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"

	if count > 0 {
		s.PostMessage(channel, title, params)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"time"
)

//custom type
type timeHandler struct {
	format string
}

// ServeHTTP for custom time which makes it a handler
func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(th.format)
	w.Write([]byte("The time is: " + tm))
}

//One off method handler
func timeHandlerOneOff(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(time.RFC1123)
	w.Write([]byte("The time is: " + tm))
}

//One off that we can pass things to!
func timeHandlerClosure(format string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is " + tm + " | CLOSURE!"))
	}
	return http.HandlerFunc(fn)
}

func main() {
	mux := http.NewServeMux()

	rh := http.RedirectHandler("http://example.org", 307)
	mux.Handle("/foo", rh)

	//time
	th1123 := &timeHandler{format: time.RFC1123}
	mux.Handle("/time/rfc1123", th1123)

	//reuse!
	th3339 := &timeHandler{format: time.RFC3339}
	mux.Handle("/time/rfc3339", th3339)

	//one off method
	thOneOff := http.HandlerFunc(timeHandlerOneOff)
	mux.Handle("/time/oneoff", thOneOff)

	//even simpler
	mux.HandleFunc("/time/simpler", timeHandlerOneOff)

	//passing through closure
	thClosure := timeHandlerClosure(time.RFC1123)
	mux.Handle("/time/closure", thClosure)

	log.Println("Listening...")
	http.ListenAndServe(":3000", mux)
}
<commit_msg>Added a different way to do a closure route<commit_after>package main

import (
	"log"
	"net/http"
	"time"
)

//custom type
type timeHandler struct {
	format string
}

// ServeHTTP for custom time which makes it a handler
func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(th.format)
	w.Write([]byte("The time is: " + tm))
}

//One off method handler
func timeHandlerOneOff(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(time.RFC1123)
	w.Write([]byte("The time is: " + tm))
}

//One off that we can pass things to!
func timeHandlerClosure(format string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is " + tm + " | CLOSURE!"))
	}
	return http.HandlerFunc(fn)
}

//different closure
func timeHandlerDifferentClosure(format string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is: " + tm))
	})
}

func main() {
	mux := http.NewServeMux()

	rh := http.RedirectHandler("http://example.org", 307)
	mux.Handle("/foo", rh)

	//time
	th1123 := &timeHandler{format: time.RFC1123}
	mux.Handle("/time/rfc1123", th1123)

	//reuse!
	th3339 := &timeHandler{format: time.RFC3339}
	mux.Handle("/time/rfc3339", th3339)

	//one off method
	thOneOff := http.HandlerFunc(timeHandlerOneOff)
	mux.Handle("/time/oneoff", thOneOff)

	//even simpler
	mux.HandleFunc("/time/simpler", timeHandlerOneOff)

	//passing through closure
	thClosure := timeHandlerClosure(time.RFC1123)
	mux.Handle("/time/closure", thClosure)

	thDifferent := timeHandlerDifferentClosure(time.RFC1123)
	mux.Handle("/time/different", thDifferent)

	log.Println("Listening...")
	http.ListenAndServe(":3000", mux)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	ListenAddr   = flag.String("addr", ":80", "The ADDRESS:PORT to listen on")
	DocumentRoot = flag.String("dir", "", "The directory to serve up")
	Logging      = flag.Bool("log", false, "Enable/disable logging")
	LogPrefix    = flag.String("log-prefix", "uhttpd", "Set the logging prefix")
	LogPath      = flag.String("log-path", "", "Log to file (leave blank for STDOUT)")
)

func main() {
	flag.Parse()
	log.SetPrefix(*LogPrefix + " ")
	if *DocumentRoot == "" {
		log.Fatalln("You must specify a directory to serve, with '-dir=\"...\"'")
	}

	handler := http.FileServer(http.Dir(*DocumentRoot))
	if *Logging {
		// Set the logger output.
		var output io.Writer
		if *LogPath == "" {
			output = os.Stdout
		} else {
			var err error
			flags := os.O_CREATE | os.O_APPEND | os.O_WRONLY
			output, err = os.OpenFile(*LogPath, flags, 0644)
			if err != nil {
				log.Fatal(err.Error())
			}
		}
		handler = LoggingHandler(output, http.FileServer(http.Dir(*DocumentRoot)))
		log.Printf("Serving %q", *DocumentRoot)
		log.Printf("Listening on %q", *ListenAddr)
	}
	if err := http.ListenAndServe(*ListenAddr, handler); err != nil {
		log.Fatalln(err)
	}

	return
}

func LoggingHandler(w io.Writer, h http.Handler) http.Handler {
	return loggingHandler{Writer: w, Handler: h}
}

type loggingHandler struct {
	Writer  io.Writer
	Handler http.Handler
}

func (h loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	t := time.Now()
	h.Handler.ServeHTTP(w, r)
	d := time.Since(t)
	log.Printf("%s %s %s (%dms.)", r.Proto, r.Method, r.URL.RequestURI(), d.Nanoseconds()/1e3)
}
<commit_msg>logging: logging handler now has its own logger<commit_after>package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	ListenAddr   = flag.String("addr", ":80", "The ADDRESS:PORT to listen on")
	DocumentRoot = flag.String("dir", "", "The directory to serve up")
	Logging      = flag.Bool("log", false, "Enable/disable logging")
	LogPrefix    = flag.String("log-prefix", "uhttpd", "Set the logging prefix")
	LogPath      = flag.String("log-path", "", "Log to file (leave blank for STDOUT)")
)

func main() {
	flag.Parse()
	log.SetPrefix(*LogPrefix + " ")
	if *DocumentRoot == "" {
		log.Fatalln("You must specify a directory to serve, with '-dir=\"...\"'")
	}

	handler := http.FileServer(http.Dir(*DocumentRoot))
	if *Logging {
		// Set the logger output.
		var output io.Writer
		if *LogPath == "" {
			output = os.Stdout
		} else {
			var err error
			flags := os.O_CREATE | os.O_APPEND | os.O_WRONLY
			output, err = os.OpenFile(*LogPath, flags, 0644)
			if err != nil {
				log.Fatal(err.Error())
			}
		}
		handler = LoggingHandler(output, http.FileServer(http.Dir(*DocumentRoot)))
		log.Printf("Serving %q", *DocumentRoot)
		log.Printf("Listening on %q", *ListenAddr)
	}
	if err := http.ListenAndServe(*ListenAddr, handler); err != nil {
		log.Fatalln(err)
	}

	return
}

func LoggingHandler(w io.Writer, h http.Handler) http.Handler {
	logger := log.New(w, *LogPrefix+" ", log.LstdFlags)
	return loggingHandler{Logger: logger, Handler: h}
}

type loggingHandler struct {
	Logger  *log.Logger
	Handler http.Handler
}

func (h loggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	t := time.Now()
	h.Handler.ServeHTTP(w, r)
	d := time.Since(t)
	h.Logger.Printf("%s %s %s (%dms.)",
		r.Proto, r.Method, r.URL.RequestURI(), d.Nanoseconds()/1e3)
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "log"
    "time"
    "os/signal"
    "periodic/drivers"
    sch "periodic/sched"
    "periodic/cmd"
    "github.com/codegangsta/cli"
)

func main() {
    app := cli.NewApp()
    app.Name = "periodic"
    app.Usage = "Periodic task system"
    app.Version = "0.0.1"
    app.Flags = []cli.Flag {
        cli.StringFlag{
            Name: "H",
            Value: "unix:///tmp/periodic.sock",
            Usage: "the server address eg: tcp://127.0.0.1:5000",
            EnvVar: "PERIODIC_PORT",
        },
        cli.StringFlag{
            Name: "redis",
            Value: "tcp://127.0.0.1:6379",
            Usage: "The redis server address, required driver redis",
        },
        cli.StringFlag{
            Name: "driver",
            Value: "leveldb",
            Usage: "The driver driver [leveldb, redis]",
        },
        cli.StringFlag{
            Name: "dbpath",
            Value: "leveldb",
            Usage: "The db path, required driver leveldb",
        },
        cli.BoolFlag{
            Name: "d",
            Usage: "Enable daemon mode",
        },
        cli.IntFlag{
            Name: "timeout",
            Value: 0,
            Usage: "The socket timeout",
        },
    }
    app.Commands = []cli.Command{
        {
            Name: "status",
            Usage: "Show status",
            Action: func(c *cli.Context) {
                cmd.ShowStatus(c.GlobalString("H"))
            },
        },
        {
            Name: "submit",
            Usage: "Submit job",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name",
                },
                cli.StringFlag{
                    Name: "n",
                    Value: "",
                    Usage: "job name",
                },
                cli.StringFlag{
                    Name: "args",
                    Value: "",
                    Usage: "job workload",
                },
                cli.IntFlag{
                    Name: "t",
                    Value: 0,
                    Usage: "job running timeout",
                },
                cli.IntFlag{
                    Name: "sched_later",
                    Value: 0,
                    Usage: "job sched_later",
                },
            },
            Action: func(c *cli.Context) {
                var job = sch.Job{
                    Name: c.String("n"),
                    Func: c.String("f"),
                    Args: c.String("args"),
                    Timeout: int64(c.Int("t")),
                }
                if len(job.Name) == 0 || len(job.Func) == 0 {
                    cli.ShowCommandHelp(c, "submit")
                    log.Fatal("Job name and func is require")
                }
                delay := c.Int("sched_later")
                var now = time.Now()
                job.SchedAt = int64(now.Unix()) + int64(delay)
                cmd.SubmitJob(c.GlobalString("H"), job)
            },
        },
        {
            Name: "drop",
            Usage: "Drop func",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name",
                },
            },
            Action: func(c *cli.Context) {
                Func := c.String("f")
                if len(Func) == 0 {
                    cli.ShowCommandHelp(c, "drop")
                    log.Fatal("function name is required")
                }
                cmd.DropFunc(c.GlobalString("H"), Func)
            },
        },
        {
            Name: "run",
            Usage: "Run func",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name required",
                },
                cli.StringFlag{
                    Name: "exec",
                    Value: "",
                    Usage: "command required",
                },
            },
            Action: func(c *cli.Context) {
                Func := c.String("f")
                exec := c.String("exec")
                if len(Func) == 0 {
                    cli.ShowCommandHelp(c, "run")
                    log.Fatal("function name is required")
                }
                if len(exec) == 0 {
                    cli.ShowCommandHelp(c, "run")
                    log.Fatal("command is required")
                }
                cmd.Run(c.GlobalString("H"), Func, exec)
            },
        },
    }
    app.Action = func(c *cli.Context) {
        if c.Bool("d") {
            var st sch.StoreDriver
            if c.String("driver") == "redis" {
                st = drivers.NewRedisDriver(c.String("redis"))
            } else {
                st = drivers.NewLevelDBDriver(c.String("dbpath"))
            }
            timeout := time.Duration(c.Int("timeout"))
            sched := sch.NewSched(c.String("H"), st, timeout)
            go sched.Serve()
            s := make(chan os.Signal, 1)
            signal.Notify(s, os.Interrupt, os.Kill)
            <-s
            if c.String("driver") == "leveldb" {
                err := st.Close()
                if err != nil {
                    log.Fatal(err)
                }
            }
        } else {
            cli.ShowAppHelp(c)
        }
    }

    app.Run(os.Args)
}
<commit_msg>update usage<commit_after>package main

import (
    "os"
    "log"
    "time"
    "os/signal"
    "periodic/drivers"
    sch "periodic/sched"
    "periodic/cmd"
    "github.com/codegangsta/cli"
)

func main() {
    app := cli.NewApp()
    app.Name = "periodic"
    app.Usage = "Periodic task system"
    app.Version = "0.0.1"
    app.Flags = []cli.Flag {
        cli.StringFlag{
            Name: "H",
            Value: "unix:///tmp/periodic.sock",
            Usage: "the server address eg: tcp://127.0.0.1:5000",
            EnvVar: "PERIODIC_PORT",
        },
        cli.StringFlag{
            Name: "redis",
            Value: "tcp://127.0.0.1:6379",
            Usage: "The redis server address, required for driver redis",
        },
        cli.StringFlag{
            Name: "driver",
            Value: "leveldb",
            Usage: "The driver [leveldb, redis]",
        },
        cli.StringFlag{
            Name: "dbpath",
            Value: "leveldb",
            Usage: "The db path, required for driver leveldb",
        },
        cli.BoolFlag{
            Name: "d",
            Usage: "Enable daemon mode",
        },
        cli.IntFlag{
            Name: "timeout",
            Value: 0,
            Usage: "The socket timeout",
        },
    }
    app.Commands = []cli.Command{
        {
            Name: "status",
            Usage: "Show status",
            Action: func(c *cli.Context) {
                cmd.ShowStatus(c.GlobalString("H"))
            },
        },
        {
            Name: "submit",
            Usage: "Submit job",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name",
                },
                cli.StringFlag{
                    Name: "n",
                    Value: "",
                    Usage: "job name",
                },
                cli.StringFlag{
                    Name: "args",
                    Value: "",
                    Usage: "job workload",
                },
                cli.IntFlag{
                    Name: "t",
                    Value: 0,
                    Usage: "job running timeout",
                },
                cli.IntFlag{
                    Name: "sched_later",
                    Value: 0,
                    Usage: "job sched_later",
                },
            },
            Action: func(c *cli.Context) {
                var job = sch.Job{
                    Name: c.String("n"),
                    Func: c.String("f"),
                    Args: c.String("args"),
                    Timeout: int64(c.Int("t")),
                }
                if len(job.Name) == 0 || len(job.Func) == 0 {
                    cli.ShowCommandHelp(c, "submit")
                    log.Fatal("Job name and func is require")
                }
                delay := c.Int("sched_later")
                var now = time.Now()
                job.SchedAt = int64(now.Unix()) + int64(delay)
                cmd.SubmitJob(c.GlobalString("H"), job)
            },
        },
        {
            Name: "drop",
            Usage: "Drop func",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name",
                },
            },
            Action: func(c *cli.Context) {
                Func := c.String("f")
                if len(Func) == 0 {
                    cli.ShowCommandHelp(c, "drop")
                    log.Fatal("function name is required")
                }
                cmd.DropFunc(c.GlobalString("H"), Func)
            },
        },
        {
            Name: "run",
            Usage: "Run func",
            Flags: []cli.Flag {
                cli.StringFlag{
                    Name: "f",
                    Value: "",
                    Usage: "function name required",
                },
                cli.StringFlag{
                    Name: "exec",
                    Value: "",
                    Usage: "command required",
                },
            },
            Action: func(c *cli.Context) {
                Func := c.String("f")
                exec := c.String("exec")
                if len(Func) == 0 {
                    cli.ShowCommandHelp(c, "run")
                    log.Fatal("function name is required")
                }
                if len(exec) == 0 {
                    cli.ShowCommandHelp(c, "run")
                    log.Fatal("command is required")
                }
                cmd.Run(c.GlobalString("H"), Func, exec)
            },
        },
    }
    app.Action = func(c *cli.Context) {
        if c.Bool("d") {
            var st sch.StoreDriver
            if c.String("driver") == "redis" {
                st = drivers.NewRedisDriver(c.String("redis"))
            } else {
                st = drivers.NewLevelDBDriver(c.String("dbpath"))
            }
            timeout := time.Duration(c.Int("timeout"))
            sched := sch.NewSched(c.String("H"), st, timeout)
            go sched.Serve()
            s := make(chan os.Signal, 1)
            signal.Notify(s, os.Interrupt, os.Kill)
            <-s
            if c.String("driver") == "leveldb" {
                err := st.Close()
                if err != nil {
                    log.Fatal(err)
                }
            }
        } else {
            cli.ShowAppHelp(c)
        }
    }

    app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/kovetskiy/godocs"
	"github.com/kovetskiy/lorg"
	"github.com/reconquest/hierr-go"
	"github.com/reconquest/ser-go"
)

const (
	version = `manul 1.5`
	usage   = version + `

manul is the tool for vendoring dependencies using git submodule technology.

Usage:
    manul [options] -I [<dependency>...]
    manul [options] -U [<dependency>...]
    manul [options] -R [<dependency>...]
    manul [options] -Q [-o]
    manul [options] -C
    manul -h
    manul --version

Options:
    -I --install    Detect all dependencies and add git submodule into vendor directory.
                     If you don't specify any dependency, manul will
                     install all detected dependencies.
                     You can specify commit-ish that will be used as target to
                     update: -U golang.org/x/net=34a235h1
    -U --update     Update specified already-vendored dependencies.
                     If you don't specify any vendored dependency, manul will
                     update all already-vendored dependencies.
                     You can specify commit-ish that will be used as target to
                     update: -U golang.org/x/net=34a235h1
    -R --remove     Stop vendoring of specified dependencies.
                     If you don't specify any dependency, manul will
                     remove all vendored dependencies.
    -Q --query      List all dependencies.
        -o          List only already-vendored dependencies.
    -C --clean      Detect all unused vendored dependencies and remove it.
    -t --testing    Include dependencies from tests.
    -r --recursive  Be recursive.
    -h --help       Show help message.
    -v --verbose    Be verbose.
    --version       Show version.
`
)

var (
	verbose bool
	testing bool
	workdir string
	logger  = lorg.NewLog()
)

func init() {
	var err error

	newArgs := make([]string, 0, len(os.Args))
	for _, arg := range os.Args {
		if arg == "--integration-test" {
			testing = true
		} else if arg == "--insecure-skip-verify" {
			http.DefaultClient.Transport = &http.Transport{
				TLSClientConfig: &tls.Config{
					InsecureSkipVerify: true,
				},
			}
		} else {
			newArgs = append(newArgs, arg)
		}
	}
	os.Args = newArgs

	workdir, err = os.Getwd()
	if err != nil {
		hierr.Fatalf(
			err,
			"unable to get current working directory",
		)
	}

	logger.SetIndentLines(true)
}

func main() {
	args := godocs.MustParse(usage, version)

	var (
		modeInstall = args["--install"].(bool)
		modeUpdate  = args["--update"].(bool)
		modeRemove  = args["--remove"].(bool)
		modeQuery   = args["--query"].(bool)
		modeClean   = args["--clean"].(bool)

		dependencies, _ = args["<dependency>"].([]string)

		recursive       = args["--recursive"].(bool)
		includeTestDeps = args["--testing"].(bool)

		verbose = args["--verbose"].(bool)
	)

	if verbose {
		logger.SetLevel(lorg.LevelDebug)
	}

	var err error
	switch {
	case modeInstall:
		err = handleInstall(recursive, includeTestDeps, dependencies)

	case modeUpdate:
		err = handleUpdate(recursive, includeTestDeps, dependencies)

	case modeQuery:
		onlyVendored := args["-o"].(bool)
		err = handleQuery(recursive, includeTestDeps, onlyVendored)

	case modeRemove:
		err = handleRemove(dependencies)

	case modeClean:
		err = handleClean(recursive, includeTestDeps)
	}

	if err != nil {
		logger.Fatal(err)
	}
}

func handleInstall(recursive bool, includeTestDeps bool,
	dependencies []string) error {
	imports, err := parseImports(recursive, includeTestDeps)
	if err != nil {
		return err
	}

	installAll := len(dependencies) == 0
	if installAll {
		dependencies = imports
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	added := 0
	for _, dependency := range dependencies {
		parts := strings.Split(dependency, "=")
		if len(parts) > 2 {
			return fmt.Errorf("too many `=` delimiters: %s", dependency)
		}

		var version string
		if len(parts) == 2 {
			dependency, version = parts[0], parts[1]
		}

		if !installAll {
			found := false
			for _, importpath := range imports {
				// there is HasPrefix for handling subpackages
				if strings.HasPrefix(importpath, dependency) {
					found = true
					break
				}
			}

			if !found {
				return fmt.Errorf("unknown dependency: %s", dependency)
			}
		}

		vendored := false
		for submodule := range submodules {
			if dependency == submodule {
				vendored = true
				break
			}
		}

		if vendored {
			logger.Debugf("skipping %s, already vendored", dependency)
			continue
		}

		logger.Infof("adding submodule for %s", dependency)

		errs := addVendorSubmodule(dependency, version)
		if errs != nil {
			top := fmt.Errorf("unable to add submodule for %s", dependency)
			for _, err := range errs {
				top = ser.Push(top, err)
			}
			return top
		}

		added++
	}

	if added > 0 {
		if added == 1 {
			logger.Infof("added 1 submodule")
		} else {
			logger.Infof("added %d submodules", added)
		}
	} else {
		logger.Infof("all dependencies already vendored\n")
	}

	return nil
}

func handleUpdate(
	recursive bool,
	includeTestDeps bool,
	dependencies []string,
) error {
	var err error
	if len(dependencies) == 0 {
		dependencies, err = parseImports(recursive, includeTestDeps)
		if err != nil {
			return err
		}
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	updated := 0
	for _, importpath := range dependencies {
		parts := strings.Split(importpath, "=")
		if len(parts) > 2 {
			return fmt.Errorf("too many `=` delimiters: %s", importpath)
		}

		var version string
		if len(parts) == 2 {
			importpath = parts[0]
			version = parts[1]
		}

		if _, ok := submodules[importpath]; !ok {
			return fmt.Errorf("unknown dependency %s", importpath)
		}

		if version != "" {
			logger.Infof("updating vendor submodule %s to %s", importpath, version)
		} else {
			logger.Infof("updating vendor submodule %s", importpath)
		}

		err := updateVendorSubmodule(importpath, version)
		if err != nil {
			return err
		}

		updated++
	}

	if updated > 0 {
		if updated == 1 {
			logger.Infof("updated 1 dependency submodule")
		} else {
			logger.Infof("updated %d dependencies submodules", updated)
		}
	} else {
		logger.Infof("nothing to update")
	}

	return nil
}

func handleRemove(dependencies []string) error {
	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	removeAll := len(dependencies) == 0
	if removeAll {
		dependencies = getKeys(submodules)
	}

	for _, dependency := range dependencies {
		if !removeAll {
			_, found := submodules[dependency]
			if !found {
				return fmt.Errorf("unknown dependency %s", dependency)
			}
		}

		logger.Infof("removing vendor %s", dependency)

		err := removeVendorSubmodule(dependency)
		if err != nil {
			return err
		}
	}

	return nil
}

func handleQuery(recursive, includeTestDeps, onlyVendored bool) error {
	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	if onlyVendored {
		maxlength := getMaxLength(getKeys(submodules))
		format := "%-" + strconv.Itoa(maxlength) + "s %s\n"

		for submodule, commit := range submodules {
			fmt.Printf(format, submodule, commit)
		}
	} else {
		imports, err := parseImports(recursive, includeTestDeps)
		if err != nil {
			return err
		}

		maxlength := 0
		if len(submodules) > 0 {
			maxlength = getMaxLength(
				append(getKeys(submodules), imports...),
			)
		}

		vendoredFormat := "%-" + strconv.Itoa(maxlength) + "s  %s\n"

		for _, importpath := range imports {
			commit, vendored := submodules[importpath]
			if vendored {
				fmt.Printf(vendoredFormat, importpath, commit)
			} else {
				fmt.Println(importpath)
			}
		}

	}

	return nil
}

func handleClean(recursive, includeTestDeps bool) error {
	imports, err := parseImports(recursive, includeTestDeps)
	if err != nil {
		return err
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	removed := 0
	for submodule := range submodules {
		found := false
		for _, importpath := range imports {
			if importpath == submodule {
				found = true
				break
			}
		}

		if found {
			continue
		}

		logger.Infof("removing unused vendor submodule %s", submodule)

		err := removeVendorSubmodule(submodule)
		if err != nil {
			return ser.Errorf(
				err, "unable to remove vendor submodule: %s", submodule,
			)
		}

		removed++
	}

	if removed > 0 {
		if removed == 1 {
			logger.Infof("removed 1 unused vendor submodule")
		} else {
			logger.Infof("removed %d unused vendor submodules", removed)
		}
	} else {
		logger.Infof("nothing to remove")
	}

	return nil
}
<commit_msg>Update main.go (#37)<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/kovetskiy/godocs"
	"github.com/kovetskiy/lorg"
	"github.com/reconquest/hierr-go"
	"github.com/reconquest/ser-go"
)

const (
	version = `manul 1.5`
	usage   = version + `

manul is the tool for vendoring dependencies using git submodule technology.

Usage:
    manul [options] -I [<dependency>...]
    manul [options] -U [<dependency>...]
    manul [options] -R [<dependency>...]
    manul [options] -Q [-o]
    manul [options] -C
    manul -h
    manul --version

Options:
    -I --install    Detect all dependencies and add git submodule into vendor directory.
                     If you don't specify any dependency, manul will
                     install all detected dependencies.
                     You can specify commit-ish that will be used as target to
                     instal: -I golang.org/x/net=34a235h1
    -U --update     Update specified already-vendored dependencies.
                     If you don't specify any vendored dependency, manul will
                     update all already-vendored dependencies.
                     You can specify commit-ish that will be used as target to
                     update: -U golang.org/x/net=34a235h1
    -R --remove     Stop vendoring of specified dependencies.
                     If you don't specify any dependency, manul will
                     remove all vendored dependencies.
    -Q --query      List all dependencies.
        -o          List only already-vendored dependencies.
    -C --clean      Detect all unused vendored dependencies and remove it.
    -t --testing    Include dependencies from tests.
    -r --recursive  Be recursive.
    -h --help       Show help message.
    -v --verbose    Be verbose.
    --version       Show version.
`
)

var (
	verbose bool
	testing bool
	workdir string
	logger  = lorg.NewLog()
)

func init() {
	var err error

	newArgs := make([]string, 0, len(os.Args))
	for _, arg := range os.Args {
		if arg == "--integration-test" {
			testing = true
		} else if arg == "--insecure-skip-verify" {
			http.DefaultClient.Transport = &http.Transport{
				TLSClientConfig: &tls.Config{
					InsecureSkipVerify: true,
				},
			}
		} else {
			newArgs = append(newArgs, arg)
		}
	}
	os.Args = newArgs

	workdir, err = os.Getwd()
	if err != nil {
		hierr.Fatalf(
			err,
			"unable to get current working directory",
		)
	}

	logger.SetIndentLines(true)
}

func main() {
	args := godocs.MustParse(usage, version)

	var (
		modeInstall = args["--install"].(bool)
		modeUpdate  = args["--update"].(bool)
		modeRemove  = args["--remove"].(bool)
		modeQuery   = args["--query"].(bool)
		modeClean   = args["--clean"].(bool)

		dependencies, _ = args["<dependency>"].([]string)

		recursive       = args["--recursive"].(bool)
		includeTestDeps = args["--testing"].(bool)

		verbose = args["--verbose"].(bool)
	)

	if verbose {
		logger.SetLevel(lorg.LevelDebug)
	}

	var err error
	switch {
	case modeInstall:
		err = handleInstall(recursive, includeTestDeps, dependencies)

	case modeUpdate:
		err = handleUpdate(recursive, includeTestDeps, dependencies)

	case modeQuery:
		onlyVendored := args["-o"].(bool)
		err = handleQuery(recursive, includeTestDeps, onlyVendored)

	case modeRemove:
		err = handleRemove(dependencies)

	case modeClean:
		err = handleClean(recursive, includeTestDeps)
	}

	if err != nil {
		logger.Fatal(err)
	}
}

func handleInstall(recursive bool, includeTestDeps bool,
	dependencies []string) error {
	imports, err := parseImports(recursive, includeTestDeps)
	if err != nil {
		return err
	}

	installAll := len(dependencies) == 0
	if installAll {
		dependencies = imports
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	added := 0
	for _, dependency := range dependencies {
		parts := strings.Split(dependency, "=")
		if len(parts) > 2 {
			return fmt.Errorf("too many `=` delimiters: %s", dependency)
		}

		var version string
		if len(parts) == 2 {
			dependency, version = parts[0], parts[1]
		}

		if !installAll {
			found := false
			for _, importpath := range imports {
				// there is HasPrefix for handling subpackages
				if strings.HasPrefix(importpath, dependency) {
					found = true
					break
				}
			}

			if !found {
				return fmt.Errorf("unknown dependency: %s", dependency)
			}
		}

		vendored := false
		for submodule := range submodules {
			if dependency == submodule {
				vendored = true
				break
			}
		}

		if vendored {
			logger.Debugf("skipping %s, already vendored", dependency)
			continue
		}

		logger.Infof("adding submodule for %s", dependency)

		errs := addVendorSubmodule(dependency, version)
		if errs != nil {
			top := fmt.Errorf("unable to add submodule for %s", dependency)
			for _, err := range errs {
				top = ser.Push(top, err)
			}
			return top
		}

		added++
	}

	if added > 0 {
		if added == 1 {
			logger.Infof("added 1 submodule")
		} else {
			logger.Infof("added %d submodules", added)
		}
	} else {
		logger.Infof("all dependencies already vendored\n")
	}

	return nil
}

func handleUpdate(
	recursive bool,
	includeTestDeps bool,
	dependencies []string,
) error {
	var err error
	if len(dependencies) == 0 {
		dependencies, err = parseImports(recursive, includeTestDeps)
		if err != nil {
			return err
		}
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	updated := 0
	for _, importpath := range dependencies {
		parts := strings.Split(importpath, "=")
		if len(parts) > 2 {
			return fmt.Errorf("too many `=` delimiters: %s", importpath)
		}

		var version string
		if len(parts) == 2 {
			importpath = parts[0]
			version = parts[1]
		}

		if _, ok := submodules[importpath]; !ok {
			return fmt.Errorf("unknown dependency %s", importpath)
		}

		if version != "" {
			logger.Infof("updating vendor submodule %s to %s", importpath, version)
		} else {
			logger.Infof("updating vendor submodule %s", importpath)
		}

		err := updateVendorSubmodule(importpath, version)
		if err != nil {
			return err
		}

		updated++
	}

	if updated > 0 {
		if updated == 1 {
			logger.Infof("updated 1 dependency submodule")
		} else {
			logger.Infof("updated %d dependencies submodules", updated)
		}
	} else {
		logger.Infof("nothing to update")
	}

	return nil
}

func handleRemove(dependencies []string) error {
	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	removeAll := len(dependencies) == 0
	if removeAll {
		dependencies = getKeys(submodules)
	}

	for _, dependency := range dependencies {
		if !removeAll {
			_, found := submodules[dependency]
			if !found {
				return fmt.Errorf("unknown dependency %s", dependency)
			}
		}

		logger.Infof("removing vendor %s", dependency)

		err := removeVendorSubmodule(dependency)
		if err != nil {
			return err
		}
	}

	return nil
}

func handleQuery(recursive, includeTestDeps, onlyVendored bool) error {
	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	if onlyVendored {
		maxlength := getMaxLength(getKeys(submodules))
		format := "%-" + strconv.Itoa(maxlength) + "s %s\n"

		for submodule, commit := range submodules {
			fmt.Printf(format, submodule, commit)
		}
	} else {
		imports, err := parseImports(recursive, includeTestDeps)
		if err != nil {
			return err
		}

		maxlength := 0
		if len(submodules) > 0 {
			maxlength = getMaxLength(
				append(getKeys(submodules), imports...),
			)
		}

		vendoredFormat := "%-" + strconv.Itoa(maxlength) + "s  %s\n"

		for _, importpath := range imports {
			commit, vendored := submodules[importpath]
			if vendored {
				fmt.Printf(vendoredFormat, importpath, commit)
			} else {
				fmt.Println(importpath)
			}
		}

	}

	return nil
}

func handleClean(recursive, includeTestDeps bool) error {
	imports, err := parseImports(recursive, includeTestDeps)
	if err != nil {
		return err
	}

	submodules, err := getVendorSubmodules()
	if err != nil {
		return err
	}

	removed := 0
	for submodule := range submodules {
		found := false
		for _, importpath := range imports {
			if importpath == submodule {
				found = true
				break
			}
		}

		if found {
			continue
		}

		logger.Infof("removing unused vendor submodule %s", submodule)

		err := removeVendorSubmodule(submodule)
		if err != nil {
			return ser.Errorf(
				err, "unable to remove vendor submodule: %s", submodule,
			)
		}

		removed++
	}

	if removed > 0 {
		if removed == 1 {
			logger.Infof("removed 1 unused vendor submodule")
		} else {
			logger.Infof("removed %d unused vendor submodules", removed)
		}
	} else {
		logger.Infof("nothing to remove")
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/json"
    "fmt"
    "os"
    "math/rand"
    //"strconv"
    "time"
)

type Config struct {
    User    string
    Level   string
    Num     int
}

func save_result(score int, config Config) (){
    path := "./results/"+config.User

    // If no score for given user
    if _, err := os.Stat(path); os.IsNotExist(err) {
        fmt.Println("Creating score file for user", config.User)
        f, err := os.Create(path)
        if err != nil {
            panic(err)
        }
        f.Close()
    }
    // File exists, just open it
    f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0600)
    if err != nil {
        panic(err)
    }

    defer f.Close()

    data_str := time.Now().Format("2006-01-02 15:04:05")
    level := config.Level[0:1]
    text := fmt.Sprintf("%s %d %s\n", data_str, score, level)
    if _, err = f.WriteString(text); err != nil {
        panic(err)
    }
}

func get_random_values(level string) (float32, float32){
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    var r1, r2 float32
    switch level {
    case "Easy":
        r1 = float32(randgen.Intn(20))/2
        r2 = float32(randgen.Intn(20))/2
    case "Normal":
        r1 = float32(randgen.Intn(100)-50)/2
        r2 = float32(randgen.Intn(100)-50)/2
    case "Hard":
        r1 = float32(randgen.Intn(200)-100)/8
        r2 = float32(randgen.Intn(200)-100)/8
    default:
        panic("DEFINE YOURSELF!")
    }
    return r1, r2
}

func get_random_operator() (string){
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    op := "+-/*"[randgen.Intn(4)]
    return string(op)
}

func evaluate_expression(op string, r1 float32, r2 float32) (float32) {
    switch op {
    case "+":
        return r1 + r2
    case "-":
        return r1 - r2
    case "*":
        return r1 * r2
    case "/":
        return r1 / zeroDivide(r2)
    default:
        panic("UNSUPPORTED OPERATION")
    }
}

func zeroDivide(r2 float32) (float32) {
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    if r2 != 0 {
        return r2
    }
    return zeroDivide(float32(randgen.Intn(200)-100)/8)
}

func main() {
    file, _ := os.Open("config.json")
    decoder := json.NewDecoder(file)
    config := Config{}

    err := decoder.Decode(&config)
    if err != nil {
        fmt.Println("Error while decoding config", err)
    }

    fmt.Printf("Hello, %s. Let's do this!\n", config.User)
    fmt.Printf("Selected difficulty: %s\n", config.Level)

    var r1, r2 float32
    var op string

    // Variables
    var answer, expected float32
    score := 0
    good_responses := []string{"Awesome.", "Obviously.", "Yep.",
        "10 points for "+config.User+"dor.",
        "Whoever thinks otherwise is stupid."}

    for i:=0; i<config.Num; i++ {
        fmt.Printf("%d. ", i)

        // TODO: Why only two variables?
        r1, r2 = get_random_values(config.Level)

        // TODO: Making more sensible operations
        // e.g. rounding when using "/"
        op = get_random_operator()
        expected = evaluate_expression(op, r1, r2)

        fmt.Printf("%g %s %g = ", r1, op, r2)
        _, err := fmt.Scanf("%g", &answer)
        if err != nil {
            fmt.Println("Cannot read answer:", err)
        }

        if answer==expected {
            response_idx := rand.Intn(len(good_responses))
            fmt.Println(good_responses[response_idx])
            score += 1
        } else {
            fmt.Println("Nope. Excpected:", expected)
        }
    }
    fmt.Printf("Final score: %d/%d\n", score, config.Num)

    // Saving
    save_result(score, config)

}
<commit_msg>Differentiate operators by level Add a function to differentiate operator set by level.<commit_after>package main

import (
    "encoding/json"
    "fmt"
    "os"
    "math/rand"
    //"strconv"
    "time"
)

type Config struct {
    User    string
    Level   string
    Num     int
}

func save_result(score int, config Config) (){
    path := "./results/"+config.User

    // If no score for given user
    if _, err := os.Stat(path); os.IsNotExist(err) {
        fmt.Println("Creating score file for user", config.User)
        f, err := os.Create(path)
        if err != nil {
            panic(err)
        }
        f.Close()
    }
    // File exists, just open it
    f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0600)
    if err != nil {
        panic(err)
    }

    defer f.Close()

    data_str := time.Now().Format("2006-01-02 15:04:05")
    level := config.Level[0:1]
    text := fmt.Sprintf("%s %d %s\n", data_str, score, level)
    if _, err = f.WriteString(text); err != nil {
        panic(err)
    }
}

func get_random_values(level string) (float32, float32){
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    var r1, r2 float32
    switch level {
    case "Easy":
        r1 = float32(randgen.Intn(20))/2
        r2 = float32(randgen.Intn(20))/2
    case "Normal":
        r1 = float32(randgen.Intn(100)-50)/2
        r2 = float32(randgen.Intn(100)-50)/2
    case "Hard":
        r1 = float32(randgen.Intn(200)-100)/8
        r2 = float32(randgen.Intn(200)-100)/8
    default:
        panic("DEFINE YOURSELF!")
    }
    return r1, r2
}

func get_random_operator(level string) (string){
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    var operatorSet string
    switch level {
    case "Easy":
        operatorSet = "+-"
    case "Normal":
        operatorSet = "+-*"
    case "Hard":
        operatorSet = "+-*/"
    default:
        operatorSet = "+"
    }
    op := operatorSet[randgen.Intn(len(operatorSet))]
    return string(op)
}

func evaluate_expression(op string, r1 float32, r2 float32) (float32) {
    switch op {
    case "+":
        return r1 + r2
    case "-":
        return r1 - r2
    case "*":
        return r1 * r2
    case "/":
        return r1 / zeroDivide(r2)
    default:
        panic("UNSUPPORTED OPERATION")
    }
}

func zeroDivide(r2 float32) (float32) {
    seed := rand.NewSource(time.Now().UnixNano())
    randgen := rand.New(seed)
    if r2 != 0 {
        return r2
    }
    return zeroDivide(float32(randgen.Intn(200)-100)/8)
}

func main() {
    file, _ := os.Open("config.json")
    decoder := json.NewDecoder(file)
    config := Config{}

    err := decoder.Decode(&config)
    if err != nil {
        fmt.Println("Error while decoding config", err)
    }

    fmt.Printf("Hello, %s. Let's do this!\n", config.User)
    fmt.Printf("Selected difficulty: %s\n", config.Level)

    var r1, r2 float32
    var op string

    // Variables
    var answer, expected float32
    score := 0
    good_responses := []string{"Awesome.", "Obviously.", "Yep.",
        "10 points for "+config.User+"dor.",
        "Whoever thinks otherwise is stupid."}

    for i:=0; i<config.Num; i++ {
        fmt.Printf("%d. ", i)

        // TODO: Why only two variables?
        r1, r2 = get_random_values(config.Level)

        // TODO: Making more sensible operations
        // e.g. rounding when using "/"
        op = get_random_operator(config.Level)
        expected = evaluate_expression(op, r1, r2)

        fmt.Printf("%g %s %g = ", r1, op, r2)
        _, err := fmt.Scanf("%g", &answer)
        if err != nil {
            fmt.Println("Cannot read answer:", err)
        }

        if answer==expected {
            response_idx := rand.Intn(len(good_responses))
            fmt.Println(good_responses[response_idx])
            score += 1
        } else {
            fmt.Println("Nope. Excpected:", expected)
        }
    }
    fmt.Printf("Final score: %d/%d\n", score, config.Num)

    // Saving
    save_result(score, config)

}
<|endoftext|>


<commit_before>// See LICENSE.txt for licensing information.

package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"
)

const (
	VERSION = `0.9`
	timeFmt = `2006-01-02 15:04:05`
	fileFmt = `2006-01-02_150405`
)

var build = `UNKNOWN` // injected in Makefile

var (
	flagConfig  string
	flagVerbose bool
	cfg         *Config
	idRange     = regexp.MustCompile(`(\d+)-(\d+)`)
	spinner     = Spinner{}
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `Usage: %s (options...) <command>
saver v%s by Piotr S. Staszewski, see LICENSE.txt
binary build by %s

Options:
`, os.Args[0], VERSION, build)
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, `
Commands:
  [list]                       - list games
  <name> [add] <path>          - add new game
  <name> [b]ackup (note)       - backup current save
  <name> [l]ist                - list saves
  <name> [r]estore <id|ref>    - restore given save
  <name> [del]ete <id|from-to> - delete given save(s)
  <name> [kill]                - delete game and all saves
  [migrate]                    - migrate config, if needed

Where:
  name     - arbitrary name used to identify a game/character/world etc.
  path     - absolute path to save file/directory
  note     - optional quoted note, e.g. "haven't died yet"
  id       - particular save id
  from-to  - inclusive range of save ids
  ref      - non-positive offset from the latest save, e.g. -1 is the save before the latest`)
	}
	flag.StringVar(&flagConfig, "c", "saver.json", "path to config file")
	flag.BoolVar(&flagVerbose, "v", false, "be very verbose")
}

func main() {
	flag.Parse()
	checkArgs(false, 1)

	if flagConfig == "" {
		fmt.Fprintln(os.Stderr, "Config file path can't be empty")
		os.Exit(2)
	}
	flagConfig, err := filepath.Abs(flagConfig)
	dieOnErr("Can't resolve config path", err)

	save := false
	if _, err := os.Stat(flagConfig); err != nil {
		r, err := os.Getwd()
		dieOnErr("Can't get current path", err)
		cfg = &Config{
			Root:  r,
			Games: make([]*Game, 0),
		}
		fmt.Println("Will save fresh config to", flagConfig)
		save = true
	} else {
		c, err := loadConfig(flagConfig)
		dieOnErr("Config load error", err)
		cfg = c
	}

	switch flag.Arg(0) {
	case "list":
		// list games
		cfg.PrintWhole()
	case "migrate":
		// migrate config to latest version
		err := cfg.Migrate()
		dieOnErr("ERROR", err)
		save = true
	default:
		// per-game commands
		checkArgs(false, 2)
		game := flag.Arg(0)
		if flag.Arg(1) == "add" {
			// add a new game
			checkArgs(true, 3)
			if g := cfg.GetGame(game); g != nil {
				fmt.Fprintf(os.Stderr, "Game \"%s\" already exist\n", game)
				os.Exit(1)
			}
			p, err := filepath.Abs(flag.Arg(2))
			dieOnErr("Can't resolve path", err)
			gm, err := cfg.AddGame(game, p)
			dieOnErr("ERROR", err)
			gm.PrintHeader()
			gm.Print()
			save = true
		} else {
			g := cfg.GetGame(game)
			if g == nil {
				fmt.Fprintf(os.Stderr, "Game \"%s\" not found\n", game)
				os.Exit(1)
			}
			switch flag.Arg(1) {
			case "l", "list":
				// list game saves
				g.PrintWhole()
			case "kill":
				// remove game and all saves
				err := cfg.DelGame(game)
				dieOnErr("ERROR", err)
				fmt.Printf("Deleted game \"%s\" and all backed up saves\n", game)
				save = true
			case "b", "backup":
				// backup current save
				sv, err := g.Backup()
				dieOnErr("ERROR", err)
				g.Stamp = time.Now()
				if flag.NArg() > 2 {
					sv.Note = flag.Arg(2)
				}
				fmt.Printf("%3d ", len(g.Saves))
				sv.Print()
				save = true
			case "r", "restore":
				// restore selected save
				checkArgs(true, 3)
				if len(g.Saves) < 1 {
					fmt.Fprintf(os.Stderr, "Game \"%s\" has no saves backed up\n", g.Name)
					os.Exit(1)
				}
				i, err := strconv.Atoi(flag.Arg(2))
				dieOnErr(fmt.Sprintf("Malformed index \"%s\"", flag.Arg(2)), err)
				sv, err := g.Restore(i)
				dieOnErr("ERROR", err)
				g.Stamp = time.Now()
				fmt.Println("Restored save from", sv.Stamp.Format(timeFmt))
				if sv.Note != "" {
					fmt.Println("Save note:", sv.Note)
				}
				save = true
			case "del", "delete":
				// delete save(s)
				checkArgs(true, 3)
				if len(g.Saves) < 1 {
					fmt.Fprintf(os.Stderr, "Game \"%s\" has no saves backed up\n", g.Name)
					os.Exit(1)
				}
				var err error
				var f, t int
				f, err = strconv.Atoi(flag.Arg(2))
				t = f
				if err != nil {
					m := idRange.FindStringSubmatch(flag.Arg(2))
					f, err = strconv.Atoi(m[1])
					dieOnErr(fmt.Sprintf("Malformed index/range \"%s\"", flag.Arg(2)), err)
					t, err = strconv.Atoi(m[2])
					dieOnErr(fmt.Sprintf("Malformed index/range \"%s\"", flag.Arg(2)), err)
				}
				n, err := g.Delete(f, t)
				if err != nil {
					fmt.Fprintln(os.Stderr, "ERROR:", err)
				}
				fmt.Printf("Deleted %d save(s)\n", n)
				save = true
			default:
				flag.Usage()
				os.Exit(1)
			}
		}
	}

	if save {
		err := cfg.Save(flagConfig)
		dieOnErr("Can't save config", err)
	}
}

func dieOnErr(msg string, err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, msg+":", err)
		os.Exit(3)
	}
}

func checkArgs(exact bool, num int) {
	if (exact && flag.NArg() != num) ||
		(!exact && flag.NArg() < num) {
		flag.Usage()
		os.Exit(1)
	}
}
<commit_msg>Bump version to 0.9.1<commit_after>// See LICENSE.txt for licensing information.

package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"
)

const (
	VERSION = `0.9.1`
	timeFmt = `2006-01-02 15:04:05`
	fileFmt = `2006-01-02_150405`
)

var build = `UNKNOWN` // injected in Makefile

var (
	flagConfig  string
	flagVerbose bool
	cfg         *Config
	idRange     = regexp.MustCompile(`(\d+)-(\d+)`)
	spinner     = Spinner{}
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `Usage: %s (options...) <command>
saver v%s by Piotr S. Staszewski, see LICENSE.txt
binary build by %s

Options:
`, os.Args[0], VERSION, build)
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, `
Commands:
  [list]                       - list games
  <name> [add] <path>          - add new game
  <name> [b]ackup (note)       - backup current save
  <name> [l]ist                - list saves
  <name> [r]estore <id|ref>    - restore given save
  <name> [del]ete <id|from-to> - delete given save(s)
  <name> [kill]                - delete game and all saves
  [migrate]                    - migrate config, if needed

Where:
  name     - arbitrary name used to identify a game/character/world etc.
  path     - absolute path to save file/directory
  note     - optional quoted note, e.g. "haven't died yet"
  id       - particular save id
  from-to  - inclusive range of save ids
  ref      - non-positive offset from the latest save, e.g. -1 is the save before the latest`)
	}
	flag.StringVar(&flagConfig, "c", "saver.json", "path to config file")
	flag.BoolVar(&flagVerbose, "v", false, "be very verbose")
}

func main() {
	flag.Parse()
	checkArgs(false, 1)

	if flagConfig == "" {
		fmt.Fprintln(os.Stderr, "Config file path can't be empty")
		os.Exit(2)
	}
	flagConfig, err := filepath.Abs(flagConfig)
	dieOnErr("Can't resolve config path", err)

	save := false
	if _, err := os.Stat(flagConfig); err != nil {
		r, err := os.Getwd()
		dieOnErr("Can't get current path", err)
		cfg = &Config{
			Root:  r,
			Games: make([]*Game, 0),
		}
		fmt.Println("Will save fresh config to", flagConfig)
		save = true
	} else {
		c, err := loadConfig(flagConfig)
		dieOnErr("Config load error", err)
		cfg = c
	}

	switch flag.Arg(0) {
	case "list":
		// list games
		cfg.PrintWhole()
	case "migrate":
		// migrate config to latest version
		err := cfg.Migrate()
		dieOnErr("ERROR", err)
		save = true
	default:
		// per-game commands
		checkArgs(false, 2)
		game := flag.Arg(0)
		if flag.Arg(1) == "add" {
			// add a new game
			checkArgs(true, 3)
			if g := cfg.GetGame(game); g != nil {
				fmt.Fprintf(os.Stderr, "Game \"%s\" already exist\n", game)
				os.Exit(1)
			}
			p, err := filepath.Abs(flag.Arg(2))
			dieOnErr("Can't resolve path", err)
			gm, err := cfg.AddGame(game, p)
			dieOnErr("ERROR", err)
			gm.PrintHeader()
			gm.Print()
			save = true
		} else {
			g := cfg.GetGame(game)
			if g == nil {
				fmt.Fprintf(os.Stderr, "Game \"%s\" not found\n", game)
				os.Exit(1)
			}
			switch flag.Arg(1) {
			case "l", "list":
				// list game saves
				g.PrintWhole()
			case "kill":
				// remove game and all saves
				err := cfg.DelGame(game)
				dieOnErr("ERROR", err)
				fmt.Printf("Deleted game \"%s\" and all backed up saves\n", game)
				save = true
			case "b", "backup":
				// backup current save
				sv, err := g.Backup()
				dieOnErr("ERROR", err)
				g.Stamp = time.Now()
				if flag.NArg() > 2 {
					sv.Note = flag.Arg(2)
				}
				fmt.Printf("%3d ", len(g.Saves))
				sv.Print()
				save = true
			case "r", "restore":
				// restore selected save
				checkArgs(true, 3)
				if len(g.Saves) < 1 {
					fmt.Fprintf(os.Stderr, "Game \"%s\" has no saves backed up\n", g.Name)
					os.Exit(1)
				}
				i, err := strconv.Atoi(flag.Arg(2))
				dieOnErr(fmt.Sprintf("Malformed index \"%s\"", flag.Arg(2)), err)
				sv, err := g.Restore(i)
				dieOnErr("ERROR", err)
				g.Stamp = time.Now()
				fmt.Println("Restored save from", sv.Stamp.Format(timeFmt))
				if sv.Note != "" {
					fmt.Println("Save note:", sv.Note)
				}
				save = true
			case "del", "delete":
				// delete save(s)
				checkArgs(true, 3)
				if len(g.Saves) < 1 {
					fmt.Fprintf(os.Stderr, "Game \"%s\" has no saves backed up\n", g.Name)
					os.Exit(1)
				}
				var err error
				var f, t int
				f, err = strconv.Atoi(flag.Arg(2))
				t = f
				if err != nil {
					m := idRange.FindStringSubmatch(flag.Arg(2))
					f, err = strconv.Atoi(m[1])
					dieOnErr(fmt.Sprintf("Malformed index/range \"%s\"", flag.Arg(2)), err)
					t, err = strconv.Atoi(m[2])
					dieOnErr(fmt.Sprintf("Malformed index/range \"%s\"", flag.Arg(2)), err)
				}
				n, err := g.Delete(f, t)
				if err != nil {
					fmt.Fprintln(os.Stderr, "ERROR:", err)
				}
				fmt.Printf("Deleted %d save(s)\n", n)
				save = true
			default:
				flag.Usage()
				os.Exit(1)
			}
		}
	}

	if save {
		err := cfg.Save(flagConfig)
		dieOnErr("Can't save config", err)
	}
}

func dieOnErr(msg string, err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, msg+":", err)
		os.Exit(3)
	}
}

func checkArgs(exact bool, num int) {
	if (exact && flag.NArg() != num) ||
		(!exact && flag.NArg() < num) {
		flag.Usage()
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2018 SpiralScout
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"github.com/sirupsen/logrus"
	rr "github.com/spiral/roadrunner/cmd/rr/cmd"

	// services (plugins)
	"github.com/spiral/roadrunner/service/env"
	"github.com/spiral/roadrunner/service/http"
	"github.com/spiral/roadrunner/service/rpc"
	"github.com/spiral/roadrunner/service/static"

        "github.com/spiral/jobs"
	"github.com/spiral/jobs/broker/beanstalk"
	"github.com/spiral/jobs/broker/local"
	"github.com/spiral/jobs/broker/sqs"

	// additional commands and debug handlers
	_ "github.com/spiral/roadrunner/cmd/rr/http"
	_ "github.com/spiral/jobs/cmd"
)

func main() {
	rr.Container.Register(env.ID, &env.Service{})
	rr.Container.Register(rpc.ID, &rpc.Service{})
	rr.Container.Register(http.ID, &http.Service{})
	rr.Container.Register(static.ID, &static.Service{})

       rr.Container.Register(jobs.ID, &jobs.Service{
		Brokers: map[string]jobs.Broker{
			"local":     &local.Broker{},
			"beanstalk": &beanstalk.Broker{},
			"sqs":       &sqs.Broker{},
		},
	})

	rr.Logger.Formatter = &logrus.TextFormatter{ForceColors: true}

	// you can register additional commands using cmd.CLI
	rr.Execute()
}
<commit_msg>more stuff into gofile<commit_after>// MIT License
//
// Copyright (c) 2018 SpiralScout
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"github.com/sirupsen/logrus"
	rr "github.com/spiral/roadrunner/cmd/rr/cmd"

	// services (plugins)
	"github.com/spiral/grpc"

	"github.com/spiral/roadrunner/service/env"
	"github.com/spiral/roadrunner/service/http"
	"github.com/spiral/roadrunner/service/rpc"
	"github.com/spiral/roadrunner/service/static"

	"github.com/spiral/jobs"
	"github.com/spiral/jobs/broker/beanstalk"
	"github.com/spiral/jobs/broker/local"
	"github.com/spiral/jobs/broker/sqs"

	// additional commands and debug handlers
	_ "github.com/spiral/grpc/cmd/rgrpc/grpc"
	_ "github.com/spiral/jobs/cmd/rjobs/jobs"
	_ "github.com/spiral/roadrunner/cmd/rr/http"
)

func main() {
	rr.Container.Register(env.ID, &env.Service{})
	rr.Container.Register(rpc.ID, &rpc.Service{})
	rr.Container.Register(http.ID, &http.Service{})
	rr.Container.Register(grpc.ID, &grpc.Service{})
	rr.Container.Register(static.ID, &static.Service{})

	rr.Container.Register(jobs.ID, &jobs.Service{
		Brokers: map[string]jobs.Broker{
			"local":     &local.Broker{},
			"beanstalk": &beanstalk.Broker{},
			"sqs":       &sqs.Broker{},
		},
	})

	rr.Logger.Formatter = &logrus.TextFormatter{ForceColors: true}

	// you can register additional commands using cmd.CLI
	rr.Execute()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
)

type proxyPattern struct {
	matches  []string
	proxyURL *url.URL
}

type config struct {
	ProxyPatterns []proxyPattern
	proxyURL      *url.URL // PROXY_URL
	basicAuthUser string   // BASIC_AUTH_USER
	basicAuthPass string   // BASIC_AUTH_PASS
	port          string   // APP_PORT
	accessLog     bool     // ACCESS_LOG
	sslCert       string   // SSL_CERT_PATH
	sslKey        string   // SSL_KEY_PATH
}

var (
	version string
	date    string
	c       *config
)

func main() {
	c = configFromEnvironmentVariables()

	// Proxy!!
	dummy, _ := url.Parse("https://www.docker.com/")
	proxy := httputil.NewSingleHostReverseProxy(dummy)
	proxy.Director = func(r *http.Request) {
		found := false
		for _, patterns := range c.ProxyPatterns {
			if match(patterns.matches[0], r.URL.Scheme, false) &&
				match(patterns.matches[1], r.Host, false) &&
				match(patterns.matches[3], r.URL.Path, true) {
				r.Host = patterns.proxyURL.Host
				r.URL.Host = r.Host
				r.URL.Scheme = patterns.proxyURL.Scheme
				found = true
				break
			}
		}
		if !found {
			r.Host = c.proxyURL.Host
			r.URL.Host = r.Host
			r.URL.Scheme = c.proxyURL.Scheme
		}
	}
	http.Handle("/", wrapper(proxy))

	http.HandleFunc("/--version", func(w http.ResponseWriter, r *http.Request) {
		if len(version) > 0 && len(date) > 0 {
			fmt.Fprintf(w, "version: %s (built at %s)", version, date)
		} else {
			w.WriteHeader(http.StatusOK)
		}
	})

	// Listen & Serve
	log.Printf("[service] listening on port %s", c.port)
	if (len(c.sslCert) > 0) && (len(c.sslKey) > 0) {
		log.Fatal(http.ListenAndServeTLS(":"+c.port, c.sslCert, c.sslKey, nil))
	} else {
		log.Fatal(http.ListenAndServe(":"+c.port, nil))
	}
}

func match(pattern, target string, isPath bool) bool {
	if pattern == "" {
		return true
	}
	pattern = strings.Replace(pattern, "*", ".*", -1)
	if isPath && !strings.HasSuffix(pattern, "/") {
		pattern += "$"
	}
	match, _ := regexp.MatchString(pattern, target)
	return match
}

func configFromEnvironmentVariables() *config {
	candidateProxyURL := strings.Trim(os.Getenv("PROXY_URL"), "\"")
	candidateProxyPatterns := strings.Trim(os.Getenv("PROXY_PATTERNS"), "\"")
	if len(candidateProxyURL) == 0 && len(candidateProxyPatterns) == 0 {
		log.Fatal("Missing required environment variable: PROXY_URL or PROXY_PATTERNS")
	}
	var proxyURL *url.URL
	var err error
	if len(candidateProxyURL) > 0 {
		proxyURL, err = url.Parse(candidateProxyURL)
		if err != nil {
			log.Fatalf("Could not parse proxy URL: %s", candidateProxyURL)
		}
	}
	ProxyPatterns := []proxyPattern{}
	if len(candidateProxyPatterns) > 0 {
		regex := regexp.MustCompile(`(https?://)?([^:^/]*)(:\\d*)?(.*)?`)
		for _, pattern := range strings.Split(candidateProxyPatterns, ",") {
			splited := strings.Split(pattern, "=")
			if url, err := url.Parse(splited[1]); err == nil {
				pattern := proxyPattern{
					matches:  regex.FindStringSubmatch(splited[0])[1:],
					proxyURL: url,
				}
				ProxyPatterns = append(ProxyPatterns, pattern)
			}
		}
	}
	port := os.Getenv("APP_PORT")
	if len(port) == 0 {
		port = "80"
	}
	accessLog := false
	if b, err := strconv.ParseBool(os.Getenv("ACCESS_LOG")); err == nil {
		accessLog = b
	}
	conf := &config{
		ProxyPatterns: ProxyPatterns,
		proxyURL:      proxyURL,
		basicAuthUser: os.Getenv("BASIC_AUTH_USER"),
		basicAuthPass: os.Getenv("BASIC_AUTH_PASS"),
		port:          port,
		accessLog:     accessLog,
		sslCert:       os.Getenv("SSL_CERT_PATH"),
		sslKey:        os.Getenv("SSL_KEY_PATH"),
	}
	// TLS pem files
	if (len(conf.sslCert) > 0) && (len(conf.sslKey) > 0) {
		log.Print("[config] TLS enabled.")
	}
	// Basic authentication
	if (len(conf.basicAuthUser) > 0) && (len(conf.basicAuthPass) > 0) {
		log.Printf("[config] Basic authentication: %s", conf.basicAuthUser)
	}
	return conf
}

func wrapper(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if (len(c.basicAuthUser) > 0) && (len(c.basicAuthPass) > 0) && !auth(r, c.basicAuthUser, c.basicAuthPass) {
			w.Header().Set("WWW-Authenticate", `Basic realm="REALM"`)
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		h.ServeHTTP(w, r)
		if c.accessLog {
			log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		}
	})
}

func auth(r *http.Request, user, pass string) bool {
	if username, password, ok := r.BasicAuth(); ok {
		return username == user && password == pass
	}
	return false
}
<commit_msg>set host & x-forwarded-for headers<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
)

type proxyPattern struct {
	matches  []string
	proxyURL *url.URL
}

type config struct {
	ProxyPatterns []proxyPattern
	proxyURL      *url.URL // PROXY_URL
	basicAuthUser string   // BASIC_AUTH_USER
	basicAuthPass string   // BASIC_AUTH_PASS
	port          string   // APP_PORT
	accessLog     bool     // ACCESS_LOG
	sslCert       string   // SSL_CERT_PATH
	sslKey        string   // SSL_KEY_PATH
}

var (
	version string
	date    string
	c       *config
)

func main() {
	c = configFromEnvironmentVariables()

	// Proxy!!
	dummy, _ := url.Parse("https://www.docker.com/")
	proxy := httputil.NewSingleHostReverseProxy(dummy)
	proxy.Director = func(r *http.Request) {
		r.Header.Set("Host", r.Host)

		found := false
		for _, patterns := range c.ProxyPatterns {
			if match(patterns.matches[0], r.URL.Scheme, false) &&
				match(patterns.matches[1], r.Host, false) &&
				match(patterns.matches[3], r.URL.Path, true) {
				r.Host = patterns.proxyURL.Host
				r.URL.Host = r.Host
				r.URL.Scheme = patterns.proxyURL.Scheme
				found = true
				break
			}
		}
		if !found {
			r.Host = c.proxyURL.Host
			r.URL.Host = r.Host
			r.URL.Scheme = c.proxyURL.Scheme
		}
		if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
			if prior, ok := r.Header["X-Forwarded-For"]; ok {
				ip = strings.Join(prior, ", ") + ", " + ip
			}
			r.Header.Set("X-Forwarded-For", ip)
		}
	}
	http.Handle("/", wrapper(proxy))

	http.HandleFunc("/--version", func(w http.ResponseWriter, r *http.Request) {
		if len(version) > 0 && len(date) > 0 {
			fmt.Fprintf(w, "version: %s (built at %s)", version, date)
		} else {
			w.WriteHeader(http.StatusOK)
		}
	})

	// Listen & Serve
	log.Printf("[service] listening on port %s", c.port)
	if (len(c.sslCert) > 0) && (len(c.sslKey) > 0) {
		log.Fatal(http.ListenAndServeTLS(":"+c.port, c.sslCert, c.sslKey, nil))
	} else {
		log.Fatal(http.ListenAndServe(":"+c.port, nil))
	}
}

func match(pattern, target string, isPath bool) bool {
	if pattern == "" {
		return true
	}
	pattern = strings.Replace(pattern, "*", ".*", -1)
	if isPath && !strings.HasSuffix(pattern, "/") {
		pattern += "$"
	}
	match, _ := regexp.MatchString(pattern, target)
	return match
}

func configFromEnvironmentVariables() *config {
	candidateProxyURL := strings.Trim(os.Getenv("PROXY_URL"), "\"")
	candidateProxyPatterns := strings.Trim(os.Getenv("PROXY_PATTERNS"), "\"")
	if len(candidateProxyURL) == 0 && len(candidateProxyPatterns) == 0 {
		log.Fatal("Missing required environment variable: PROXY_URL or PROXY_PATTERNS")
	}
	var proxyURL *url.URL
	var err error
	if len(candidateProxyURL) > 0 {
		proxyURL, err = url.Parse(candidateProxyURL)
		if err != nil {
			log.Fatalf("Could not parse proxy URL: %s", candidateProxyURL)
		}
	}
	ProxyPatterns := []proxyPattern{}
	if len(candidateProxyPatterns) > 0 {
		regex := regexp.MustCompile(`(https?://)?([^:^/]*)(:\\d*)?(.*)?`)
		for _, pattern := range strings.Split(candidateProxyPatterns, ",") {
			splited := strings.Split(pattern, "=")
			if url, err := url.Parse(splited[1]); err == nil {
				pattern := proxyPattern{
					matches:  regex.FindStringSubmatch(splited[0])[1:],
					proxyURL: url,
				}
				ProxyPatterns = append(ProxyPatterns, pattern)
			}
		}
	}
	port := os.Getenv("APP_PORT")
	if len(port) == 0 {
		port = "80"
	}
	accessLog := false
	if b, err := strconv.ParseBool(os.Getenv("ACCESS_LOG")); err == nil {
		accessLog = b
	}
	conf := &config{
		ProxyPatterns: ProxyPatterns,
		proxyURL:      proxyURL,
		basicAuthUser: os.Getenv("BASIC_AUTH_USER"),
		basicAuthPass: os.Getenv("BASIC_AUTH_PASS"),
		port:          port,
		accessLog:     accessLog,
		sslCert:       os.Getenv("SSL_CERT_PATH"),
		sslKey:        os.Getenv("SSL_KEY_PATH"),
	}
	// TLS pem files
	if (len(conf.sslCert) > 0) && (len(conf.sslKey) > 0) {
		log.Print("[config] TLS enabled.")
	}
	// Basic authentication
	if (len(conf.basicAuthUser) > 0) && (len(conf.basicAuthPass) > 0) {
		log.Printf("[config] Basic authentication: %s", conf.basicAuthUser)
	}
	return conf
}

func wrapper(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if (len(c.basicAuthUser) > 0) && (len(c.basicAuthPass) > 0) && !auth(r, c.basicAuthUser, c.basicAuthPass) {
			w.Header().Set("WWW-Authenticate", `Basic realm="REALM"`)
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
			return
		}
		h.ServeHTTP(w, r)
		if c.accessLog {
			log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
		}
	})
}

func auth(r *http.Request, user, pass string) bool {
	if username, password, ok := r.BasicAuth(); ok {
		return username == user && password == pass
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nbari/violetear"
	"log"
	"net/http"
)

var version = "0.0.2"

func main() {
	router := violetear.New()
	router.LogRequests = true

	router.HandleFunc("/*", mainHandler)
	router.HandleFunc("/_healthcheck_", healthCheck)

	log.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>	modified:   main.go<commit_after>package main

import (
	"github.com/nbari/violetear"
	"log"
	"net/http"
)

var version = "0.0.1"

func main() {
	router := violetear.New()
	router.LogRequests = true

	router.HandleFunc("/*", mainHandler)
	router.HandleFunc("/_healthcheck_", healthCheck)

	log.Fatal(http.ListenAndServe(":8080", router))
}
<|endoftext|>