<commit_before>package spamme

import (
	"appengine"
	"appengine/datastore"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	deleteAfter = 24 * time.Hour
	limit = 100
	kind = "Mail"

	// TODO: Add a button to immediately delete a message.
	// TODO: Add a button to pin a message to keep it around another 2h.
	// TODO: Pagination and search?
	mailHTML = `

Mails to: {{.To}}

{{if .Mails}}

  {{range .Mails}}

      {{.Received}}

{{.Text}}

  {{end}}

{{else}}
  No mails have been sent to this address.
{{end}}
`

	explainHTML = `

What is this?

Send an email to anything@spam-me.appspotmail.com, then visit /inbox/anything to see the emails it has received.

This is useful for debugging sending email, and also for signing up for spammy services that require email account authentication.

This service is *public* and *not at all secure or reliable*. Please don't use this for anything serious, ever. I mean it.

`
)

func init() {
	http.HandleFunc("/_ah/mail/", inbound)
	http.HandleFunc("/reap", reapMail)
	http.HandleFunc("/inbox/", view)
	http.HandleFunc("/", explain)
}

var mailTmpl = template.Must(template.New("mails").Parse(mailHTML))

type Mail struct {
	To       string
	Text     []byte
	Received time.Time
	DeleteAfter time.Time
}

// inbound handles incoming email requests by persisting a new Mail and enqueing
// a task to delete it later.
func inbound(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		c.Errorf("reading mail: %v", err.Error())
		return
	}
	defer r.Body.Close()

	now := time.Now()
	m := Mail{
		To:       r.URL.Path[len("/_ah/mail/"):],
		Text:     b,
		Received: now,
		DeleteAfter: now.Add(deleteAfter),
	}
	if _, err = datastore.Put(c, datastore.NewIncompleteKey(c, kind, nil), &m); err != nil {
		c.Errorf("saving mail: %v", err.Error())
	}
}

// reapMail runs periodically and deletes old mail.
func reapMail(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	q := datastore.NewQuery(kind).
		Filter("DeleteAfter >=", time.Now()).
		KeysOnly()
	ks, err := q.GetAll(c, nil)
	c.Infof("deleting %d mails", len(ks))
	if err != nil {
		c.Errorf("getting keys: %v", err)
		return
	}
	err = datastore.DeleteMulti(c, ks)
	if err != nil {
		c.Errorf("deleting: %v", err)
	}
}

func explain(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, explainHTML)
}

// view lists the Mails sent to a particular address.
func view(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	to := r.URL.Path[len("/inbox/"):] + "@spam-me.appspotmail.com"
	q := datastore.NewQuery(kind).
		Filter("To =", to).
		Order("-Received").
		Limit(limit)
	cnt, err := q.Count(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	mails := make([]map[string]string, cnt)
	i := 0
	for t := q.Run(c); ; i++ {
		var m Mail
		_, err := t.Next(&m)
		if err == datastore.Done {
			break
		} else if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		mails[i] = map[string]string{
			"Text":     string(m.Text),
			"Received": m.Received.String(),
		}
	}
	mailTmpl.Execute(w, map[string]interface{}{
		"To":    to,
		"Mails": mails,
	})
}
<commit_msg>gofmt<commit_after>package spamme

import (
	"appengine"
	"appengine/datastore"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	deleteAfter = 24 * time.Hour
	limit       = 100
	kind        = "Mail"

	// TODO: Add a button to immediately delete a message.
	// TODO: Add a button to pin a message to keep it around another 2h.
	// TODO: Pagination and search?
	mailHTML = `

Mails to: {{.To}}

{{if .Mails}}

  {{range .Mails}}

      {{.Received}}

{{.Text}}

  {{end}}

{{else}}
  No mails have been sent to this address.
{{end}}
`

	explainHTML = `

What is this?

Send an email to anything@spam-me.appspotmail.com, then visit /inbox/anything to see the emails it has received.

This is useful for debugging sending email, and also for signing up for spammy services that require email account authentication.

This service is *public* and *not at all secure or reliable*. Please don't use this for anything serious, ever. I mean it.

`
)

func init() {
	http.HandleFunc("/_ah/mail/", inbound)
	http.HandleFunc("/reap", reapMail)
	http.HandleFunc("/inbox/", view)
	http.HandleFunc("/", explain)
}

var mailTmpl = template.Must(template.New("mails").Parse(mailHTML))

type Mail struct {
	To          string
	Text        []byte
	Received    time.Time
	DeleteAfter time.Time
}

// inbound handles incoming email requests by persisting a new Mail and enqueing
// a task to delete it later.
func inbound(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		c.Errorf("reading mail: %v", err.Error())
		return
	}
	defer r.Body.Close()

	now := time.Now()
	m := Mail{
		To:          r.URL.Path[len("/_ah/mail/"):],
		Text:        b,
		Received:    now,
		DeleteAfter: now.Add(deleteAfter),
	}
	if _, err = datastore.Put(c, datastore.NewIncompleteKey(c, kind, nil), &m); err != nil {
		c.Errorf("saving mail: %v", err.Error())
	}
}

// reapMail runs periodically and deletes old mail.
func reapMail(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	q := datastore.NewQuery(kind).
		Filter("DeleteAfter >=", time.Now()).
		KeysOnly()
	ks, err := q.GetAll(c, nil)
	c.Infof("deleting %d mails", len(ks))
	if err != nil {
		c.Errorf("getting keys: %v", err)
		return
	}
	err = datastore.DeleteMulti(c, ks)
	if err != nil {
		c.Errorf("deleting: %v", err)
	}
}

func explain(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, explainHTML)
}

// view lists the Mails sent to a particular address.
func view(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	to := r.URL.Path[len("/inbox/"):] + "@spam-me.appspotmail.com"
	q := datastore.NewQuery(kind).
		Filter("To =", to).
		Order("-Received").
		Limit(limit)
	cnt, err := q.Count(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	mails := make([]map[string]string, cnt)
	i := 0
	for t := q.Run(c); ; i++ {
		var m Mail
		_, err := t.Next(&m)
		if err == datastore.Done {
			break
		} else if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		mails[i] = map[string]string{
			"Text":     string(m.Text),
			"Received": m.Received.String(),
		}
	}
	mailTmpl.Execute(w, map[string]interface{}{
		"To":    to,
		"Mails": mails,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	arrow "github.com/bmuller/arrow/lib"
	gorelic "github.com/brandfolder/gin-gorelic"
	"github.com/carlescere/scheduler"
	"github.com/gin-gonic/contrib/ginrus"
	"github.com/gin-gonic/gin"
	"github.com/nlopes/slack"
	"gopkg.in/mgo.v2/bson"

	"github.com/dwarvesf/working-on/db"
)

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")
	dailyScrumTime := os.Getenv("DAILYSCRUM_TIME")
	gorelic.InitNewrelicAgent(os.Getenv("NEW_RELIC_LICENSE_KEY"), "working", false)

	digestConfig, err := parseConfig("digest.json")
	if err != nil {
		log.Fatalln(err)
	}

	// Setup schedule digest jobs
	for _, i := range digestConfig.Items {
		digestJob := postDigest(i.Channel, os.Getenv(i.Token), i.Tags)
		_, err := scheduler.Every().Day().At(digestTime).Run(digestJob)
		if err != nil {
			log.Infoln(err)
		}
	}

	// Setup schedule for daily scrum reminer
	scheduler.Every().Day().At(dailyScrumTime).Run(remindDailyScrum)

	settingConfig, err := parseConfig("setting.json")
	if err != nil {
		log.Fatalln(err)
	}

	// 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", on(*settingConfig))
	router.POST("/til", til(*settingConfig))
	router.POST("/done", done(*settingConfig))

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

func done(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {

		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")

		addItem(text, userID, userName, config, ":cantboiroi: *%s* has *done*: %s")
	}
}

func til(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {
		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")

		addItem(text, userID, userName, config, "*%s* #til - Today I learned: %s :adore:")
	}
}

func on(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {
		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")

		addItem(text, userID, userName, config, "*%s* is *working* on: %s")
	}
}

// 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(text string, userID string, userName string, configuration Configuration, format string) {

	// Parse token and message
	var item Item

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

	ctx, err := db.NewContext()
	if err != nil {
		log.Fatal(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")
	}

	// <@U024BE7LH|bob>: format text to match Slack format
	userName = fmt.Sprintf("<@%s|%s>", userID, userName)
	title := fmt.Sprintf(format, userName, text)

	postItem(botToken, channel, title)

	// Post item to project group
	for _, config := range configuration.Items {
		for _, tag := range config.Tags {
			if strings.Contains(text, tag) {
				log.Infof("Hit %s", tag)
				log.Infof("Token: %s", config.Token)

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

func postItem(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 {
	Items []ConfigurationItem `json:"items"`
}

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

func parseConfig(path string) (*Configuration, error) {
	var configuration Configuration

	// Parse configuration
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, errors.New("Cannot read setting file")
	}

	err = json.Unmarshal(bytes, &configuration)
	if err != nil {
		return nil, errors.New("Cannot parse setting")
	}

	return &configuration, nil
}

// Remind daily scrum by posting message to Slack
func remindDailyScrum() {

	botToken := os.Getenv("BOT_TOKEN")
	url := os.Getenv("DAILYSCRUM_URL")

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

	s := slack.New(botToken)

	params := slack.PostMessageParameters{}
	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"

	text := "Đến giờ daily scrum rồi mấy bé <!here|here> " + url + " :4head:"
	channel := "#random"

	s.PostMessage(channel, text, params)
}

// Post summary to Slack channel.
// Only post to specific channel when tags are met.
func postDigest(channel, botToken string, tags []string) func() {
	return func() {
		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 {
			log.Fatal(err)
		}

		defer ctx.Close()

		log.Info("Preparing data")
		// If count > 0, it means there is data to show
		count := 0
		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)

		title := fmt.Sprintf(" :rocket: >> Team daily digest for *%s* :rocket: <!channel>", arrow.Yesterday().CFormat("%Y-%m-%d"))

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

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

			// log.Infof("Process user: %s - %s", 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_name": user.Name},
						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 {
				log.Infof("User: %s, item: %s, tags: %+v", user.Name, item.Text, tags)

				// delete items which text does not contain tags
				if tags != nil {
					// check if item contains any tags
					var containTag bool
					for _, tag := range tags {
						if !strings.Contains(item.Text, tag) {
							continue
						}
						containTag = true
						break
					}

					// if item.Text doesn't contains any tags then don't
					// add it to the digest message (values)
					if !containTag {
						continue
					}
				}

				// construct text format
				values = append(values, fmt.Sprintf("+ %s", item.Text))
			}

			// <@U024BE7LH|bob>
			if len(values) > 0 {
				count++
				field := slack.AttachmentField{
					// Title: fmt.Sprintf("<@%s|%s>", user.ID, user.Name),
					Title: fmt.Sprintf("%s", user.Name),
					Value: strings.Join(values, "\n"),
				}

				fields = append(fields, field)
			}
		}

		params.Attachments = []slack.Attachment{
			slack.Attachment{
				Color:      "#7CD197",
				Fields:     fields,
				Footer:     "Oshin Bot",
				FooterIcon: "http://i.imgur.com/fLcxkel.png",
			},
		}

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

		if count > 0 {
			s.PostMessage(channel, title, params)
		}
	}
}
<commit_msg>No need to post remind msg on weekend<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	arrow "github.com/bmuller/arrow/lib"
	gorelic "github.com/brandfolder/gin-gorelic"
	"github.com/carlescere/scheduler"
	"github.com/gin-gonic/contrib/ginrus"
	"github.com/gin-gonic/gin"
	"github.com/nlopes/slack"
	"gopkg.in/mgo.v2/bson"

	"github.com/dwarvesf/working-on/db"
)

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")
	dailyScrumTime := os.Getenv("DAILYSCRUM_TIME")
	gorelic.InitNewrelicAgent(os.Getenv("NEW_RELIC_LICENSE_KEY"), "working", false)

	digestConfig, err := parseConfig("digest.json")
	if err != nil {
		log.Fatalln(err)
	}

	// Setup schedule digest jobs
	for _, i := range digestConfig.Items {
		digestJob := postDigest(i.Channel, os.Getenv(i.Token), i.Tags)
		_, err := scheduler.Every().Day().At(digestTime).Run(digestJob)
		if err != nil {
			log.Infoln(err)
		}
	}

	// Setup schedule for daily scrum reminer
	scheduler.Every().Day().At(dailyScrumTime).Run(remindDailyScrum)

	settingConfig, err := parseConfig("setting.json")
	if err != nil {
		log.Fatalln(err)
	}

	// 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", on(*settingConfig))
	router.POST("/til", til(*settingConfig))
	router.POST("/done", done(*settingConfig))

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

func done(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {

		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")

		addItem(text, userID, userName, config, ":cantboiroi: *%s* has *done*: %s")
	}
}

func til(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {
		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")

		addItem(text, userID, userName, config, "*%s* #til - Today I learned: %s :adore:")
	}
}

func on(config Configuration) func(c *gin.Context) {
	return func(c *gin.Context) {
		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")

		addItem(text, userID, userName, config, "*%s* is *working* on: %s")
	}
}

// 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(text string, userID string, userName string, configuration Configuration, format string) {

	// Parse token and message
	var item Item

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

	ctx, err := db.NewContext()
	if err != nil {
		log.Fatal(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")
	}

	// <@U024BE7LH|bob>: format text to match Slack format
	userName = fmt.Sprintf("<@%s|%s>", userID, userName)
	title := fmt.Sprintf(format, userName, text)

	postItem(botToken, channel, title)

	// Post item to project group
	for _, config := range configuration.Items {
		for _, tag := range config.Tags {
			if strings.Contains(text, tag) {
				log.Infof("Hit %s", tag)
				log.Infof("Token: %s", config.Token)

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

func postItem(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 {
	Items []ConfigurationItem `json:"items"`
}

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

func parseConfig(path string) (*Configuration, error) {
	var configuration Configuration

	// Parse configuration
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, errors.New("Cannot read setting file")
	}

	err = json.Unmarshal(bytes, &configuration)
	if err != nil {
		return nil, errors.New("Cannot parse setting")
	}

	return &configuration, nil
}

// Remind daily scrum by posting message to Slack
func remindDailyScrum() {

	today := arrow.Now().Weekday()
	if today == time.Sunday || today == time.Saturday {
		log.Infoln("It's weekend and people goes party!")
		return
	}

	botToken := os.Getenv("BOT_TOKEN")
	url := os.Getenv("DAILYSCRUM_URL")

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

	s := slack.New(botToken)

	params := slack.PostMessageParameters{}
	params.IconURL = "http://i.imgur.com/fLcxkel.png"
	params.Username = "oshin"

	text := "Đến giờ daily scrum rồi mấy bé <!here|here> " + url + " :4head:"
	channel := "#random"

	s.PostMessage(channel, text, params)
}

// Post summary to Slack channel.
// Only post to specific channel when tags are met.
func postDigest(channel, botToken string, tags []string) func() {
	return func() {
		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 {
			log.Fatal(err)
		}

		defer ctx.Close()

		log.Info("Preparing data")
		// If count > 0, it means there is data to show
		count := 0
		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)

		title := fmt.Sprintf(" :rocket: >> Team daily digest for *%s* :rocket: <!channel>", arrow.Yesterday().CFormat("%Y-%m-%d"))

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

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

			// log.Infof("Process user: %s - %s", 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_name": user.Name},
						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 {
				log.Infof("User: %s, item: %s, tags: %+v", user.Name, item.Text, tags)

				// delete items which text does not contain tags
				if tags != nil {
					// check if item contains any tags
					var containTag bool
					for _, tag := range tags {
						if !strings.Contains(item.Text, tag) {
							continue
						}
						containTag = true
						break
					}

					// if item.Text doesn't contains any tags then don't
					// add it to the digest message (values)
					if !containTag {
						continue
					}
				}

				// construct text format
				values = append(values, fmt.Sprintf("+ %s", item.Text))
			}

			// <@U024BE7LH|bob>
			if len(values) > 0 {
				count++
				field := slack.AttachmentField{
					// Title: fmt.Sprintf("<@%s|%s>", user.ID, user.Name),
					Title: fmt.Sprintf("%s", user.Name),
					Value: strings.Join(values, "\n"),
				}

				fields = append(fields, field)
			}
		}

		params.Attachments = []slack.Attachment{
			slack.Attachment{
				Color:      "#7CD197",
				Fields:     fields,
				Footer:     "Oshin Bot",
				FooterIcon: "http://i.imgur.com/fLcxkel.png",
			},
		}

		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 (
	"bytes"
	"errors"
	"fmt"
	"github.com/kylelemons/go-gypsy/yaml"
	"io/ioutil"
	"os"
	"strings"
)

type Template struct {
	FuncName   string
	Parameters string
	Imports    map[string]bool
	Escape     string
	Body       bytes.Buffer
}

func (t *Template) Parse(templateBytes []byte) (err error) {
	regions := bytes.SplitN(templateBytes, []byte("\n---\n"), 2)

	if len(regions) != 2 {
		return errors.New("Did not find divider between header and body.")
	}

	err = t.parseHeader(regions[0])
	if err != nil {
		return err
	}

	err = t.parseBody(regions[1])
	if err != nil {
		return err
	}

	return nil
}

func (t *Template) parseHeader(header []byte) (err error) {
	yf := new(yaml.File)
	yf.Root, err = yaml.Parse(bytes.NewReader(header))
	if err != nil {
		return fmt.Errorf("Unable to parse YAML header: %v", err)
	}

	t.FuncName, err = yf.Get("func")
	if err != nil {
		return errors.New(`Missing "func"`)
	}

	t.Escape, _ = yf.Get("escape")

	t.Parameters = "writer io.Writer"
	var extraParameters string
	extraParameters, _ = yf.Get("parameters")
	if len(extraParameters) > 0 {
		t.Parameters = t.Parameters + ", " + extraParameters
	}

	t.Imports = map[string]bool{"io": true}

	var extraImports string
	extraImports, _ = yf.Get("imports")
	if len(extraImports) > 0 {
		for _, pkg := range strings.Split(extraImports, " ") {
			t.Imports[strings.Trim(pkg, " ")] = true
		}
	}

	return nil
}

func (t *Template) parseBody(body []byte) (err error) {
	unparsed := body

	for len(unparsed) > 0 {
		next := bytes.Index(unparsed, []byte("<%"))
		switch {
		case next > 0:
			segment := unparsed[:next]
			t.writeStringSegment(segment)
			unparsed = unparsed[next:]
		case next == 0:
			unparsed = unparsed[2:]
			endGo := bytes.Index(unparsed, []byte("%>"))

			if endGo > -1 {
				segment := unparsed[:endGo]

				if segment[0] == '=' {
					t.writeInterpolationSegment(segment[1:])
				} else {
					t.writeGoSegment(segment)
				}

				unparsed = unparsed[endGo+2:]
			} else {
				return errors.New("Unable to parse")
			}
		default:
			segment := unparsed
			t.writeStringSegment(segment)
			unparsed = nil
			break
		}
	}

	return nil
}

func (t *Template) writeStringSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, `")
	t.Body.Write(segment)
	t.Body.WriteString("`)\n")
	return nil
}

func (t *Template) writeInterpolationSegment(segment []byte) (err error) {
	switch {
	case segment[0] == 'i':
		t.Imports["strconv"] = true
		segment = segment[1:]
		t.writeIntegerInterpolationSegment(segment)
	default:
		t.writeStringInterpolationSegment(segment)
	}

	return nil
}

func (t *Template) writeIntegerInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, strconv.FormatInt(int64(")
	t.Body.Write(segment)
	t.Body.WriteString("), 10))\n")
	return nil
}

func (t *Template) writeStringInterpolationSegment(segment []byte) (err error) {
	switch t.Escape {
	case "":
		return t.writeRawStringInterpolationSegment(segment)
	case "html":
		t.Imports["html"] = true
		return t.writeHTMLEscapedStringInterpolationSegment(segment)
	default:
		return errors.New("Unknown escape type")
	}
}

func (t *Template) writeRawStringInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, ")
	t.Body.Write(segment)
	t.Body.WriteString(")\n")
	return nil
}

func (t *Template) writeHTMLEscapedStringInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, html.EscapeString(")
	t.Body.Write(segment)
	t.Body.WriteString("))\n")
	return nil
}

func (t *Template) writeGoSegment(segment []byte) (err error) {
	t.Body.Write(segment)
	t.Body.WriteString("\n")
	return nil
}

func main() {

	templates := make([]*Template, 0, len(os.Args[1:]))

	for _, path := range os.Args[1:] {
		fileBytes, err := ioutil.ReadFile(path)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		var t Template
		err = t.Parse(fileBytes)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Invalid template format: %v", err)
			os.Exit(1)
		}
		templates = append(templates, &t)
	}

	imports := make(map[string]bool)
	for _, t := range templates {
		for pkg, _ := range t.Imports {
			imports[pkg] = true
		}
	}

	fmt.Printf("package main\n")
	fmt.Printf("import (\n")
	for pkg, _ := range imports {
		fmt.Printf("\"%s\"\n", pkg)
	}
	fmt.Printf(")\n")

	for _, t := range templates {

		fmt.Printf("func %s(%s) (err error) {\n%s\nreturn\n}\n", t.FuncName, t.Parameters, t.Body.String())
	}
}
<commit_msg>Remove YAML dependency<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

type Template struct {
	FuncName   string
	Parameters string
	Imports    map[string]bool
	Escape     string
	Body       bytes.Buffer
}

func (t *Template) Parse(templateBytes []byte) (err error) {
	regions := bytes.SplitN(templateBytes, []byte("\n---\n"), 2)

	if len(regions) != 2 {
		return errors.New("Did not find divider between header and body.")
	}

	err = t.parseHeader(regions[0])
	if err != nil {
		return err
	}

	err = t.parseBody(regions[1])
	if err != nil {
		return err
	}

	return nil
}

func (t *Template) parseHeader(header []byte) (err error) {
	lines := bytes.Split(header, []byte("\n"))
	options := make(map[string]string, len(lines))
	for i, l := range lines {
		pair := bytes.SplitN(l, []byte(":"), 2)
		if len(pair) != 2 {
			return fmt.Errorf("Bad header line: %d", i)
		}
		options[string(pair[0])] = string(bytes.Trim(pair[1], " "))
	}

	t.FuncName = options["func"]
	if t.FuncName == "" {
		return errors.New(`Missing "func"`)
	}

	t.Escape = options["escape"]

	t.Parameters = "writer io.Writer"
	var extraParameters string
	extraParameters = options["parameters"]
	if len(extraParameters) > 0 {
		t.Parameters = t.Parameters + ", " + extraParameters
	}

	t.Imports = map[string]bool{"io": true}

	var extraImports string
	extraImports = options["imports"]
	if len(extraImports) > 0 {
		for _, pkg := range strings.Split(extraImports, " ") {
			t.Imports[strings.Trim(pkg, " ")] = true
		}
	}

	return nil
}

func (t *Template) parseBody(body []byte) (err error) {
	unparsed := body

	for len(unparsed) > 0 {
		next := bytes.Index(unparsed, []byte("<%"))
		switch {
		case next > 0:
			segment := unparsed[:next]
			t.writeStringSegment(segment)
			unparsed = unparsed[next:]
		case next == 0:
			unparsed = unparsed[2:]
			endGo := bytes.Index(unparsed, []byte("%>"))

			if endGo > -1 {
				segment := unparsed[:endGo]

				if segment[0] == '=' {
					t.writeInterpolationSegment(segment[1:])
				} else {
					t.writeGoSegment(segment)
				}

				unparsed = unparsed[endGo+2:]
			} else {
				return errors.New("Unable to parse")
			}
		default:
			segment := unparsed
			t.writeStringSegment(segment)
			unparsed = nil
			break
		}
	}

	return nil
}

func (t *Template) writeStringSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, `")
	t.Body.Write(segment)
	t.Body.WriteString("`)\n")
	return nil
}

func (t *Template) writeInterpolationSegment(segment []byte) (err error) {
	switch {
	case segment[0] == 'i':
		t.Imports["strconv"] = true
		segment = segment[1:]
		t.writeIntegerInterpolationSegment(segment)
	default:
		t.writeStringInterpolationSegment(segment)
	}

	return nil
}

func (t *Template) writeIntegerInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, strconv.FormatInt(int64(")
	t.Body.Write(segment)
	t.Body.WriteString("), 10))\n")
	return nil
}

func (t *Template) writeStringInterpolationSegment(segment []byte) (err error) {
	switch t.Escape {
	case "":
		return t.writeRawStringInterpolationSegment(segment)
	case "html":
		t.Imports["html"] = true
		return t.writeHTMLEscapedStringInterpolationSegment(segment)
	default:
		return errors.New("Unknown escape type")
	}
}

func (t *Template) writeRawStringInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, ")
	t.Body.Write(segment)
	t.Body.WriteString(")\n")
	return nil
}

func (t *Template) writeHTMLEscapedStringInterpolationSegment(segment []byte) (err error) {
	t.Body.WriteString("io.WriteString(writer, html.EscapeString(")
	t.Body.Write(segment)
	t.Body.WriteString("))\n")
	return nil
}

func (t *Template) writeGoSegment(segment []byte) (err error) {
	t.Body.Write(segment)
	t.Body.WriteString("\n")
	return nil
}

func main() {

	templates := make([]*Template, 0, len(os.Args[1:]))

	for _, path := range os.Args[1:] {
		fileBytes, err := ioutil.ReadFile(path)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		var t Template
		err = t.Parse(fileBytes)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Invalid template format: %v", err)
			os.Exit(1)
		}
		templates = append(templates, &t)
	}

	imports := make(map[string]bool)
	for _, t := range templates {
		for pkg, _ := range t.Imports {
			imports[pkg] = true
		}
	}

	fmt.Printf("package main\n")
	fmt.Printf("import (\n")
	for pkg, _ := range imports {
		fmt.Printf("\"%s\"\n", pkg)
	}
	fmt.Printf(")\n")

	for _, t := range templates {

		fmt.Printf("func %s(%s) (err error) {\n%s\nreturn\n}\n", t.FuncName, t.Parameters, t.Body.String())
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	fmt.Println("Hello World!")
}
<commit_msg>add japanese greeting<commit_after>package main

import "fmt"

func main() {
	fmt.Println("Hello World! Konichiwa!")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/inconshreveable/mousetrap"

	flag "github.com/jessevdk/go-flags"
)

//Default global variables
var (
	elog *log.Logger //The logger for errors
	done chan bool
)

func init() {
	if mousetrap.StartedByExplorer() {
		fmt.Println("Don't double-click ponydownloader")
		fmt.Println("You need to open cmd.exe and run it from the command line!")
		time.Sleep(5 * time.Second)
		os.Exit(1)
	}
	done = make(chan bool)
}

func main() {
	fmt.Println("Derpiboo.ru Downloader version 0.5.0")

	err := flag.IniParse("config.ini", &opts)
	if err != nil {
		switch err.(type) {
		default:
			panic(err)
		case *os.PathError:
			fmt.Println("config.ini not found, using defaults")
		}
	}
	var iniopts = opts

	args, err := flag.Parse(&opts)
	if err != nil {
		flagError := err.(*flag.Error)

		switch flagError.Type {
		case flag.ErrHelp:
		case flag.ErrUnknownFlag:
			fmt.Println("Use --help to view all available options")
		default:
			fmt.Printf("Error parsing flags: %s\n", err)
		}
		return
	}

	elog = SetLog() //Setting up logging of errors

	WriteConfig(iniopts)

	if len(args) != 0 {
		elog.Println("Too many arguments, skipping following:", args)

	}

	if len(opts.Args.IDs) == 0 && opts.Tag == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.

		log.SetPrefix("Done at ")                //We can not do this with elog!
		log.Println("Nothing to download, bye!") //Need to reshuffle flow: now it could end before it starts.
		os.Exit(0)
	}

	//Creating directory for downloads if it does not yet exist
	err = os.MkdirAll(opts.ImageDir, 0755)

	if err != nil { //Execute bit means different thing for directories that for files. And I was stupid.
		elog.Fatalln(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(ImageCh, opts.QDepth) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal perfomance on my system

	if opts.Tag == "" { //Because we can put imgid with flags. Why not?

		log.Println("Processing image No", opts.Args.IDs)
		go imgdat.ParseImg() // Sending imgid to parser. Here validity is our problem

	} else {

		//	and here we send tags to getter/parser. Validity is server problem, mostly

		log.Println("Processing tags", opts.Tag)
		go imgdat.ParseTag()
	}

	log.Println("Starting worker") //It would be funny if worker goroutine does not start

	filtimgdat := FilterChannel(imgdat) //see to move it into filter.Filter(inchan, outchan) where all filtration is done

	go filtimgdat.DlImg()

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finished")
	//And we are done here! Hooray!
	return
}
<commit_msg>Forgot to make use of new filter method<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/inconshreveable/mousetrap"

	flag "github.com/jessevdk/go-flags"
)

//Default global variables
var (
	elog *log.Logger //The logger for errors
	done chan bool
)

func init() {
	if mousetrap.StartedByExplorer() {
		fmt.Println("Don't double-click ponydownloader")
		fmt.Println("You need to open cmd.exe and run it from the command line!")
		time.Sleep(5 * time.Second)
		os.Exit(1)
	}
	done = make(chan bool)
}

func main() {
	fmt.Println("Derpiboo.ru Downloader version 0.5.0")

	err := flag.IniParse("config.ini", &opts)
	if err != nil {
		switch err.(type) {
		default:
			panic(err)
		case *os.PathError:
			fmt.Println("config.ini not found, using defaults")
		}
	}
	var iniopts = opts

	args, err := flag.Parse(&opts)
	if err != nil {
		flagError := err.(*flag.Error)

		switch flagError.Type {
		case flag.ErrHelp:
		case flag.ErrUnknownFlag:
			fmt.Println("Use --help to view all available options")
		default:
			fmt.Printf("Error parsing flags: %s\n", err)
		}
		return
	}

	elog = SetLog() //Setting up logging of errors

	WriteConfig(iniopts)

	if len(args) != 0 {
		elog.Println("Too many arguments, skipping following:", args)

	}

	if len(opts.Args.IDs) == 0 && opts.Tag == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.

		log.SetPrefix("Done at ")                //We can not do this with elog!
		log.Println("Nothing to download, bye!") //Need to reshuffle flow: now it could end before it starts.
		os.Exit(0)
	}

	//Creating directory for downloads if it does not yet exist
	err = os.MkdirAll(opts.ImageDir, 0755)

	if err != nil { //Execute bit means different thing for directories that for files. And I was stupid.
		elog.Fatalln(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(ImageCh, opts.QDepth) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal perfomance on my system

	if opts.Tag == "" { //Because we can put imgid with flags. Why not?

		log.Println("Processing image No", opts.Args.IDs)
		go imgdat.ParseImg() // Sending imgid to parser. Here validity is our problem

	} else {

		//	and here we send tags to getter/parser. Validity is server problem, mostly

		log.Println("Processing tags", opts.Tag)
		go imgdat.ParseTag()
	}

	log.Println("Starting worker") //It would be funny if worker goroutine does not start

	filterInit(opts)
	filtimgdat := FilterChannel(imgdat) //see to move it into filter.Filter(inchan, outchan) where all filtration is done

	go filtimgdat.DlImg()

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finished")
	//And we are done here! Hooray!
	return
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"io"
	"golang.org/x/net/websocket"
)

func main() {
	http.Handle("/echo", websocket.Handler(EchoHandler))
	err := http.ListenAndServe(":12345", nil)
	if err != nil {
		panic("ListenAndServe: " + err.Error())}
}

func EchoHandler(ws *websocket.Conn) {
	io.Copy(ws, ws)
}
<commit_msg>modify measurement program<commit_after>package main

import (
	"encoding/json"
	"bytes"
	"flag"
	"log"
	"time"
	"os"
	"os/signal"
	"net/url"

	"github.com/gorilla/websocket"
	"github.com/shirou/gopsutil/mem"
	// "github.com/shirou/gopsutil/cpu"
	// "github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/host"
)

type ServerStat struct {
	// Host
	HostName             string `json:"hostname"`
	HostID               string `json:"hostid"`
	VirtualizationSystem string `json:"virtualizationSystem"`
  // mem.VirtualMemoryStat
	Total        uint64 `json:"total"`
	Available    uint64 `json:"available"`
	Used         uint64 `json:"used"`
	UsedPercent  float64 `json:"usedPercent"`
	Free         uint64 `json:"free"`
	Active       uint64 `json:"active"`
	Inactive     uint64 `json:"inactive"`
	Wired        uint64 `json:"wired"`
	Buffers      uint64 `json:"buffers"`
	Cached       uint64 `json:"cached"`
	Writeback    uint64 `json:"writeback"`
	Dirty        uint64 `json:"dirty"`
	WritebackTmp uint64 `json:"writebacktmp"`
	// Cpu
	// DiskIO
	ReadCount        uint64 `json:"readCount"`
	MergedReadCount  uint64 `json:"mergedReadCount"`
	WriteCount       uint64 `json:"writeCount"`
	MergedWriteCount uint64 `json:"mergedWriteCount"`
	ReadBytes        uint64 `json:"readBytes"`
	WriteBytes       uint64 `json:"writeBytes"`
	ReadTime         uint64 `json:"readTime"`
	WriteTime        uint64 `json:"writeTime"`
	IopsInProgress   uint64 `json:"iopsInProgress"`
	IoTime           uint64 `json:"ioTime"`
	WeightedIO       uint64 `json:"weightedIO"`
	Name             string `json:"name"`
	SerialNumber     string `json:"serialNumber"`

	// Memory *mem.VirtualMemoryStat  `json:"-"`
	// Cpu    []cpu.TimesStat         `json:"-"`
	// DiskIO map[string]disk.IOCountersStat    `json:"-"`
	// Host   host.InfoStat  `json:"-"`
}

var addr = flag.String("addr", "localhost:8080", "monitoring address")

func main() {
	var buf bytes.Buffer
	flag.Parse()
	log.SetFlags(0)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
	log.Printf("connecting to %s", u.String())

	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	done := make(chan struct{})

	go func() {
		defer c.Close()
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)
		}
	}()

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			d := GetServerStat()
			j, _ :=json.Marshal(d)
			buf.Write(j)
			err := c.WriteMessage(websocket.TextMessage, j)
			if err != nil {
				log.Println("write:", err)
				return
			}
		case <-interrupt:
			log.Println("interrupt")
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			c.Close()
			return
		}
	}
}

func GetServerStat() (ServerStat) {
	var d ServerStat

	d = d.GetHostStat()
  d = d.GetMemoryStat()
	// d.GetDiskIOStat()

	return d
}

func (s ServerStat) GetHostStat() (ServerStat) {
	h, _ := host.Info()
	s.HostName = h.Hostname
	return s
}

func (s ServerStat) GetMemoryStat() (ServerStat){
	m, _ := mem.VirtualMemory()
	s.Total = m.Total
	return s
}

// func (s ServerStat) GetDiskIOStat() {
// 	i, _ := disk.IOCounters()
// 	s.ReadCount = i.ReadCount
// }
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"sync"
)

func main() {
	// Call realMain so that defers work properly, since os.Exit won't
	// call defers.
	os.Exit(realMain())
}

func realMain() int {
	var buildToolchain bool
	var ldflags string
	var outputTpl string
	var parallel int
	var platformFlag PlatformFlag
	var tags string
	var verbose bool
	var flagGcflags string
	var flagCgo, flagRebuild, flagListOSArch bool
	flags := flag.NewFlagSet("gox", flag.ExitOnError)
	flags.Usage = func() { printUsage() }
	flags.Var(platformFlag.ArchFlagValue(), "arch", "arch to build for or skip")
	flags.Var(platformFlag.OSArchFlagValue(), "osarch", "os/arch pairs to build for or skip")
	flags.Var(platformFlag.OSFlagValue(), "os", "os to build for or skip")
	flags.StringVar(&ldflags, "ldflags", "", "linker flags")
	flags.StringVar(&tags, "tags", "", "go build tags")
	flags.StringVar(&outputTpl, "output", "{{.Dir}}_{{.OS}}_{{.Arch}}", "output path")
	flags.IntVar(&parallel, "parallel", -1, "parallelization factor")
	flags.BoolVar(&buildToolchain, "build-toolchain", false, "build toolchain")
	flags.BoolVar(&verbose, "verbose", false, "verbose")
	flags.BoolVar(&flagCgo, "cgo", false, "")
	flags.BoolVar(&flagRebuild, "rebuild", false, "")
	flags.BoolVar(&flagListOSArch, "osarch-list", false, "")
	flags.StringVar(&flagGcflags, "gcflags", "", "")
	if err := flags.Parse(os.Args[1:]); err != nil {
		flags.Usage()
		return 1
	}

	// Determine what amount of parallelism we want Default to the current
	// number of CPUs-1 is <= 0 is specified.
	if parallel <= 0 {
		cpus := runtime.NumCPU()
		if cpus < 2 {
			parallel = 1
		} else {
			parallel = cpus - 1
		}
	}

	if buildToolchain {
		return mainBuildToolchain(parallel, platformFlag, verbose)
	}

	if _, err := exec.LookPath("go"); err != nil {
		fmt.Fprintf(os.Stderr, "go executable must be on the PATH\n")
		return 1
	}

	version, err := GoVersion()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error reading Go version: %s", err)
		return 1
	}

	if flagListOSArch {
		return mainListOSArch(version)
	}

	// Determine the packages that we want to compile. Default to the
	// current directory if none are specified.
	packages := flags.Args()
	if len(packages) == 0 {
		packages = []string{"."}
	}

	// Get the packages that are in the given paths
	mainDirs, err := GoMainDirs(packages)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error reading packages: %s", err)
		return 1
	}

	// Determine the platforms we're building for
	platforms := platformFlag.Platforms(SupportedPlatforms(version))
	if len(platforms) == 0 {
		fmt.Println("No valid platforms to build for. If you specified a value")
		fmt.Println("for the 'os', 'arch', or 'osarch' flags, make sure you're")
		fmt.Println("using a valid value.")
		return 0
	}

	// Build in parallel!
	fmt.Printf("Number of parallel builds: %d\n\n", parallel)
	var errorLock sync.Mutex
	var wg sync.WaitGroup
	errors := make([]string, 0)
	semaphore := make(chan int, parallel)
	for _, platform := range platforms {
		for _, path := range mainDirs {
			// Start the goroutine that will do the actual build
			wg.Add(1)
			go func(path string, platform Platform) {
				defer wg.Done()
				semaphore <- 1
				fmt.Printf("--> %15s: %s\n", platform.String(), path)

				opts := &CompileOpts{
					PackagePath: path,
					Platform:    platform,
					OutputTpl:   outputTpl,
					Ldflags:     ldflags,
					Tags:        tags,
					Cgo:         flagCgo,
					Rebuild:     flagRebuild,
				}
				if err := GoCrossCompile(opts); err != nil {
					errorLock.Lock()
					defer errorLock.Unlock()
					errors = append(errors,
						fmt.Sprintf("%s error: %s", platform.String(), err))
				}
				<-semaphore
			}(path, platform)
		}
	}
	wg.Wait()

	if len(errors) > 0 {
		fmt.Fprintf(os.Stderr, "\n%d errors occurred:\n", len(errors))
		for _, err := range errors {
			fmt.Fprintf(os.Stderr, "--> %s\n", err)
		}
		return 1
	}

	return 0
}

func printUsage() {
	fmt.Fprintf(os.Stderr, helpText)
}

const helpText = `Usage: gox [options] [packages]

  Gox cross-compiles Go applications in parallel.

  If no specific operating systems or architectures are specified, Gox
  will build for all pairs supported by your version of Go.

Options:

  -arch=""            Space-separated list of architectures to build for
  -build-toolchain    Build cross-compilation toolchain
  -cgo                Sets CGO_ENABLED=1, requires proper C toolchain (advanced)
  -gcflags=""         Additional '-gcflags' value to pass to go build
  -ldflags=""         Additional '-ldflags' value to pass to go build
  -tags=""            Additional '-tags' value to pass to go build
  -os=""              Space-separated list of operating systems to build for
  -osarch=""          Space-separated list of os/arch pairs to build for
  -osarch-list        List supported os/arch pairs for your Go version
  -output="foo"       Output path template. See below for more info
  -parallel=-1        Amount of parallelism, defaults to number of CPUs
  -rebuild            Force rebuilding of package that were up to date
  -verbose            Verbose mode

Output path template:

  The output path for the compiled binaries is specified with the
  "-output" flag. The value is a string that is a Go text template.
  The default value is "{{.Dir}}_{{.OS}}_{{.Arch}}". The variables and
  their values should be self-explanatory.

Platforms (OS/Arch):

  The operating systems and architectures to cross-compile for may be
  specified with the "-arch" and "-os" flags. These are space separated lists
  of valid GOOS/GOARCH values to build for, respectively. You may prefix an
  OS or Arch with "!" to negate and not build for that platform. If the list
  is made up of only negations, then the negations will come from the default
  list.

  Additionally, the "-osarch" flag may be used to specify complete os/arch
  pairs that should be built or ignored. The syntax for this is what you would
  expect: "darwin/amd64" would be a valid osarch value. Multiple can be space
  separated. An os/arch pair can begin with "!" to not build for that platform.

  The "-osarch" flag has the highest precedent when determing whether to
  build for a platform. If it is included in the "-osarch" list, it will be
  built even if the specific os and arch is negated in "-os" and "-arch",
  respectively.

`
<commit_msg>Default parallelism on Solaris to 3<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"sync"
)

func main() {
	// Call realMain so that defers work properly, since os.Exit won't
	// call defers.
	os.Exit(realMain())
}

func realMain() int {
	var buildToolchain bool
	var ldflags string
	var outputTpl string
	var parallel int
	var platformFlag PlatformFlag
	var tags string
	var verbose bool
	var flagGcflags string
	var flagCgo, flagRebuild, flagListOSArch bool
	flags := flag.NewFlagSet("gox", flag.ExitOnError)
	flags.Usage = func() { printUsage() }
	flags.Var(platformFlag.ArchFlagValue(), "arch", "arch to build for or skip")
	flags.Var(platformFlag.OSArchFlagValue(), "osarch", "os/arch pairs to build for or skip")
	flags.Var(platformFlag.OSFlagValue(), "os", "os to build for or skip")
	flags.StringVar(&ldflags, "ldflags", "", "linker flags")
	flags.StringVar(&tags, "tags", "", "go build tags")
	flags.StringVar(&outputTpl, "output", "{{.Dir}}_{{.OS}}_{{.Arch}}", "output path")
	flags.IntVar(&parallel, "parallel", -1, "parallelization factor")
	flags.BoolVar(&buildToolchain, "build-toolchain", false, "build toolchain")
	flags.BoolVar(&verbose, "verbose", false, "verbose")
	flags.BoolVar(&flagCgo, "cgo", false, "")
	flags.BoolVar(&flagRebuild, "rebuild", false, "")
	flags.BoolVar(&flagListOSArch, "osarch-list", false, "")
	flags.StringVar(&flagGcflags, "gcflags", "", "")
	if err := flags.Parse(os.Args[1:]); err != nil {
		flags.Usage()
		return 1
	}

	// Determine what amount of parallelism we want Default to the current
	// number of CPUs-1 is <= 0 is specified.
	if parallel <= 0 {
		cpus := runtime.NumCPU()
		if cpus < 2 {
			parallel = 1
		} else {
			parallel = cpus - 1
		}

		// Joyent containers report 48 cores via runtime.NumCPU(), and a
		// default of 47 parallel builds causes a panic. Default to 3 on
		// Solaris-derived operating systems unless overridden with the
		// -parallel flag.
		if runtime.GOOS == "solaris" {
			parallel = 3
		}
	}

	if buildToolchain {
		return mainBuildToolchain(parallel, platformFlag, verbose)
	}

	if _, err := exec.LookPath("go"); err != nil {
		fmt.Fprintf(os.Stderr, "go executable must be on the PATH\n")
		return 1
	}

	version, err := GoVersion()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error reading Go version: %s", err)
		return 1
	}

	if flagListOSArch {
		return mainListOSArch(version)
	}

	// Determine the packages that we want to compile. Default to the
	// current directory if none are specified.
	packages := flags.Args()
	if len(packages) == 0 {
		packages = []string{"."}
	}

	// Get the packages that are in the given paths
	mainDirs, err := GoMainDirs(packages)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error reading packages: %s", err)
		return 1
	}

	// Determine the platforms we're building for
	platforms := platformFlag.Platforms(SupportedPlatforms(version))
	if len(platforms) == 0 {
		fmt.Println("No valid platforms to build for. If you specified a value")
		fmt.Println("for the 'os', 'arch', or 'osarch' flags, make sure you're")
		fmt.Println("using a valid value.")
		return 0
	}

	// Build in parallel!
	fmt.Printf("Number of parallel builds: %d\n\n", parallel)
	var errorLock sync.Mutex
	var wg sync.WaitGroup
	errors := make([]string, 0)
	semaphore := make(chan int, parallel)
	for _, platform := range platforms {
		for _, path := range mainDirs {
			// Start the goroutine that will do the actual build
			wg.Add(1)
			go func(path string, platform Platform) {
				defer wg.Done()
				semaphore <- 1
				fmt.Printf("--> %15s: %s\n", platform.String(), path)

				opts := &CompileOpts{
					PackagePath: path,
					Platform:    platform,
					OutputTpl:   outputTpl,
					Ldflags:     ldflags,
					Tags:        tags,
					Cgo:         flagCgo,
					Rebuild:     flagRebuild,
				}
				if err := GoCrossCompile(opts); err != nil {
					errorLock.Lock()
					defer errorLock.Unlock()
					errors = append(errors,
						fmt.Sprintf("%s error: %s", platform.String(), err))
				}
				<-semaphore
			}(path, platform)
		}
	}
	wg.Wait()

	if len(errors) > 0 {
		fmt.Fprintf(os.Stderr, "\n%d errors occurred:\n", len(errors))
		for _, err := range errors {
			fmt.Fprintf(os.Stderr, "--> %s\n", err)
		}
		return 1
	}

	return 0
}

func printUsage() {
	fmt.Fprintf(os.Stderr, helpText)
}

const helpText = `Usage: gox [options] [packages]

  Gox cross-compiles Go applications in parallel.

  If no specific operating systems or architectures are specified, Gox
  will build for all pairs supported by your version of Go.

Options:

  -arch=""            Space-separated list of architectures to build for
  -build-toolchain    Build cross-compilation toolchain
  -cgo                Sets CGO_ENABLED=1, requires proper C toolchain (advanced)
  -gcflags=""         Additional '-gcflags' value to pass to go build
  -ldflags=""         Additional '-ldflags' value to pass to go build
  -tags=""            Additional '-tags' value to pass to go build
  -os=""              Space-separated list of operating systems to build for
  -osarch=""          Space-separated list of os/arch pairs to build for
  -osarch-list        List supported os/arch pairs for your Go version
  -output="foo"       Output path template. See below for more info
  -parallel=-1        Amount of parallelism, defaults to number of CPUs
  -rebuild            Force rebuilding of package that were up to date
  -verbose            Verbose mode

Output path template:

  The output path for the compiled binaries is specified with the
  "-output" flag. The value is a string that is a Go text template.
  The default value is "{{.Dir}}_{{.OS}}_{{.Arch}}". The variables and
  their values should be self-explanatory.

Platforms (OS/Arch):

  The operating systems and architectures to cross-compile for may be
  specified with the "-arch" and "-os" flags. These are space separated lists
  of valid GOOS/GOARCH values to build for, respectively. You may prefix an
  OS or Arch with "!" to negate and not build for that platform. If the list
  is made up of only negations, then the negations will come from the default
  list.

  Additionally, the "-osarch" flag may be used to specify complete os/arch
  pairs that should be built or ignored. The syntax for this is what you would
  expect: "darwin/amd64" would be a valid osarch value. Multiple can be space
  separated. An os/arch pair can begin with "!" to not build for that platform.

  The "-osarch" flag has the highest precedent when determing whether to
  build for a platform. If it is included in the "-osarch" list, it will be
  built even if the specific os and arch is negated in "-os" and "-arch",
  respectively.

`
<|endoftext|>


<commit_before>package main

import (
    "os"
    "os/exec"

    "errors"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/loadavg.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(raw[:]), "\n")
        headers := strings.Fields(lines[0])

        var cpuLoads [][2]string

        // Last 3 headers are CPU loads, clean them up
        for _, load := range headers[len(headers)-3:] {
            // Remove trailing coma if there
            cleanLoad := strings.Split(string(load), ",")[0]

            loadFloat, err := strconv.ParseFloat(cleanLoad, 32)

            if err != nil {
                continue
            }

            loadPercentage := int(loadFloat * 100) / runtime.NumCPU()

            cpuLoads = append(cpuLoads, [2]string{
                cleanLoad,
                strconv.Itoa(loadPercentage),
            })
        }

        return json.Marshal(cpuLoads)
    })

    m.Get("/sh/ping.php", func () ([]byte, error) {
        HOSTS := [4]string{
            "wikipedia.org",
            "github.com",
            "google.com",
            "gnu.org",
        }

        var entries [][]string

        for _, host := range HOSTS {
            ping, err := pingHost(host, 2)

            if err != nil {
                continue
            }

            entries = append(entries, []string{
                host,
                ping,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/netstat.php", func () ([]byte, error) {
        raw, err := exec.Command("netstat", "-nt").Output()

        if err != nil {
            return nil, err
        }

        // Get entries as a table
        entries := parseCommandTable(raw, 2, 1)

        // Connections we care about
        var connections [][]string

        // Filter by protocol
        for _, entry := range entries {
            // Skip bad entries or non tcp
            if len(entry) != 6 || (entry[0] != "tcp" && entry[0] != "tcp4") {
                continue
            }

            connections = append(connections, entry)
        }

        // Count connections from a machine
        connectionCount := make(map[string]int)

        // Extract
        for _, conn := range connections {
            // Foreign Address
            remoteAddr := conn[4]

            // Increment counter
            connectionCount[remoteAddr]++
        }

        // Expected output by client
        var output [][2]string

        for remoteAddr, count := range connectionCount {
            // Compensate for difference between OSX and linux
            parts := strings.Split(strings.Replace(remoteAddr, ",", ".", 1), ".")
            ip := strings.Join(parts[:4], ".")
            // port := parts[4]

            output = append(output, [2]string{
                strconv.Itoa(count),
                ip,
            })
        }

        return json.Marshal(output)
    })

    m.Get("/sh/where.php", func () ([]byte, error) {
        SOFTWARE := []string{
            "php",
            "node",
            "mysql",
            "vim",
            "python",
            "ruby",
            "java",
            "apache2",
            "nginx",
            "openssl",
            "vsftpd",
            "make",
        }

        var entries [][2]string

        for _, bin := range SOFTWARE {
            path, err := exec.LookPath(bin)

            if err != nil {
                path = "Not Installed"
            }

            entries = append(entries, [2]string{
                bin,
                path,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/mem.php", func () ([]byte, error) {
        var entries []string

        raw, err := exec.Command("free", "-m").Output()

        if err != nil {
            // OS X fallback
            raw, err := exec.Command("vm_stat").Output()

            if err != nil {
                return nil, err
            }

            vmMap := parseCommandMap(raw)

            freePages := toMB(vmMap["Pages free"])
            activePages := toMB(vmMap["Pages active"])
            inactivePages := toMB(vmMap["Pages inactive"])
            speculativePages := toMB(vmMap["Pages speculative"])

            free := freePages + speculativePages
            used := activePages + inactivePages

            return json.Marshal([]string{
                "Mem:",

                // Total
                strconv.Itoa(free + used),

                // Used
                strconv.Itoa(used),

                // Free
                strconv.Itoa(free),
            })
        }

        // Linux
        entries = parseCommandTable(raw, 2, 1)[0][:4]

        return json.Marshal(entries)
    })

    m.Get("/sh/lastlog.php", func () ([]byte, error) {
        raw, err := exec.Command("last").Output()

        if err != nil {
            return nil, err
        }

        entries := parseCommandTable(raw, 0, 3)

        var data [][]string

        for _, entry := range entries {
            var row []string

            // Non user action
            if entry[1] == "~" {
                continue
            }

            if runtime.GOOS == "linux" {
                row = []string{
                    // Username
                    entry[0],
                    entry[2],
                    strings.Join(entry[3:6], " "),
                }
            } else if runtime.GOOS == "darwin" {
                row = []string{
                    // Username
                    entry[0],
                    // From
                    "",
                    strings.Join(entry[2:6], " "),
                }
            }

            data = append(data, row)
        }

        return json.Marshal(data)
    })

    m.Get("/sh/swap.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/proc/swaps")

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(data, 1, 0))
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}

func parseCommandMap(rawOutput []byte) map[string]string {
    data := make(map[string]string)

    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // Lines of output
    lines := strings.Split(output, "\n")

    for _, line := range lines {
        parts := strings.Split(line, ":")

        // Bad line, skip it
        if len(parts) != 2 {
            continue
        }

        key := strings.TrimSpace(parts[0])
        value := strings.TrimSpace(parts[1])

        // Remove trailing dot if exists
        if value[len(value) - 1] == '.' {
            value = value[:len(value) - 1]
        }

        data[key] = value
    }

    return data
}

// Get average pingTime to a host
func pingHost(hostname string, pingCount int) (string, error) {
    raw, err := exec.Command("ping", "-c", strconv.Itoa(pingCount), hostname).Output()

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

    lines := strings.Split(string(raw[:]), "\n")

    if len(lines) < 2 {
        return "", errors.New("Bad output for ping command")
    }

    // Get 2nd last line
    lastLine := lines[len(lines)-2]

    // Extract average ping time as a string
    pingTime := strings.Split(strings.Split(lastLine, "=")[1], "/")[1]

    return pingTime, nil
}

func toMB(x string) int {
    num, _ := strconv.ParseInt(x, 10, 32)

    // 256 = 4096 / (1024 * 1024)
    return int(num) / 256
}
<commit_msg>Add swap usage for OS X<commit_after>package main

import (
    "os"
    "os/exec"

    "errors"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/loadavg.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(raw[:]), "\n")
        headers := strings.Fields(lines[0])

        var cpuLoads [][2]string

        // Last 3 headers are CPU loads, clean them up
        for _, load := range headers[len(headers)-3:] {
            // Remove trailing coma if there
            cleanLoad := strings.Split(string(load), ",")[0]

            loadFloat, err := strconv.ParseFloat(cleanLoad, 32)

            if err != nil {
                continue
            }

            loadPercentage := int(loadFloat * 100) / runtime.NumCPU()

            cpuLoads = append(cpuLoads, [2]string{
                cleanLoad,
                strconv.Itoa(loadPercentage),
            })
        }

        return json.Marshal(cpuLoads)
    })

    m.Get("/sh/ping.php", func () ([]byte, error) {
        HOSTS := [4]string{
            "wikipedia.org",
            "github.com",
            "google.com",
            "gnu.org",
        }

        var entries [][]string

        for _, host := range HOSTS {
            ping, err := pingHost(host, 2)

            if err != nil {
                continue
            }

            entries = append(entries, []string{
                host,
                ping,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/netstat.php", func () ([]byte, error) {
        raw, err := exec.Command("netstat", "-nt").Output()

        if err != nil {
            return nil, err
        }

        // Get entries as a table
        entries := parseCommandTable(raw, 2, 1)

        // Connections we care about
        var connections [][]string

        // Filter by protocol
        for _, entry := range entries {
            // Skip bad entries or non tcp
            if len(entry) != 6 || (entry[0] != "tcp" && entry[0] != "tcp4") {
                continue
            }

            connections = append(connections, entry)
        }

        // Count connections from a machine
        connectionCount := make(map[string]int)

        // Extract
        for _, conn := range connections {
            // Foreign Address
            remoteAddr := conn[4]

            // Increment counter
            connectionCount[remoteAddr]++
        }

        // Expected output by client
        var output [][2]string

        for remoteAddr, count := range connectionCount {
            // Compensate for difference between OSX and linux
            parts := strings.Split(strings.Replace(remoteAddr, ",", ".", 1), ".")
            ip := strings.Join(parts[:4], ".")
            // port := parts[4]

            output = append(output, [2]string{
                strconv.Itoa(count),
                ip,
            })
        }

        return json.Marshal(output)
    })

    m.Get("/sh/where.php", func () ([]byte, error) {
        SOFTWARE := []string{
            "php",
            "node",
            "mysql",
            "vim",
            "python",
            "ruby",
            "java",
            "apache2",
            "nginx",
            "openssl",
            "vsftpd",
            "make",
        }

        var entries [][2]string

        for _, bin := range SOFTWARE {
            path, err := exec.LookPath(bin)

            if err != nil {
                path = "Not Installed"
            }

            entries = append(entries, [2]string{
                bin,
                path,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/mem.php", func () ([]byte, error) {
        var entries []string

        raw, err := exec.Command("free", "-m").Output()

        if err != nil {
            // OS X fallback
            raw, err := exec.Command("vm_stat").Output()

            if err != nil {
                return nil, err
            }

            vmMap := parseCommandMap(string(raw[:]))

            freePages := toMB(vmMap["Pages free"])
            activePages := toMB(vmMap["Pages active"])
            inactivePages := toMB(vmMap["Pages inactive"])
            speculativePages := toMB(vmMap["Pages speculative"])

            free := freePages + speculativePages
            used := activePages + inactivePages

            return json.Marshal([]string{
                "Mem:",

                // Total
                strconv.Itoa(free + used),

                // Used
                strconv.Itoa(used),

                // Free
                strconv.Itoa(free),
            })
        }

        // Linux
        entries = parseCommandTable(raw, 2, 1)[0][:4]

        return json.Marshal(entries)
    })

    m.Get("/sh/lastlog.php", func () ([]byte, error) {
        raw, err := exec.Command("last").Output()

        if err != nil {
            return nil, err
        }

        entries := parseCommandTable(raw, 0, 3)

        var data [][]string

        for _, entry := range entries {
            var row []string

            // Non user action
            if entry[1] == "~" {
                continue
            }

            if runtime.GOOS == "linux" {
                row = []string{
                    // Username
                    entry[0],
                    entry[2],
                    strings.Join(entry[3:6], " "),
                }
            } else if runtime.GOOS == "darwin" {
                row = []string{
                    // Username
                    entry[0],
                    // From
                    "",
                    strings.Join(entry[2:6], " "),
                }
            }

            data = append(data, row)
        }

        return json.Marshal(data)
    })

    m.Get("/sh/swap.php", func () ([]byte, error) {
        // Linux
        data, err := ioutil.ReadFile("/proc/swaps")

        if err != nil {
            // OS X fallback
            stats, err := topStats()

            // Failed everything
            if err != nil {
                return nil, err
            }

            fields := strings.Fields(stats["Swap"])

            used, _ := strconv.ParseInt(fields[0][:len(fields[0])-1], 10, 32)
            free, _ := strconv.ParseInt(fields[2][:len(fields[2])-1], 10, 32)

            usedB := mbToB(int(used))
            freeB := mbToB(int(free))

            return json.Marshal([][]string{
                {
                    "/var/vm/swapfile0",
                    "file",
                    readableSize(usedB + freeB),
                    readableSize(usedB),
                    "-1",
                },
            })
        }

        return json.Marshal(parseCommandTable(data, 1, 0))
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}

func parseCommandMap(output string) map[string]string {
    data := make(map[string]string)

    // Lines of output
    lines := strings.Split(output, "\n")

    for _, line := range lines {
        parts := strings.Split(line, ":")

        // Bad line, skip it
        if len(parts) != 2 {
            continue
        }

        key := strings.TrimSpace(parts[0])
        value := strings.TrimSpace(parts[1])

        // Remove trailing dot if exists
        if value[len(value) - 1] == '.' {
            value = value[:len(value) - 1]
        }

        data[key] = value
    }

    return data
}

// Get average pingTime to a host
func pingHost(hostname string, pingCount int) (string, error) {
    raw, err := exec.Command("ping", "-c", strconv.Itoa(pingCount), hostname).Output()

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

    lines := strings.Split(string(raw[:]), "\n")

    if len(lines) < 2 {
        return "", errors.New("Bad output for ping command")
    }

    // Get 2nd last line
    lastLine := lines[len(lines)-2]

    // Extract average ping time as a string
    pingTime := strings.Split(strings.Split(lastLine, "=")[1], "/")[1]

    return pingTime, nil
}

func toMB(x string) int {
    num, _ := strconv.ParseInt(x, 10, 32)

    // 256 = 4096 / (1024 * 1024)
    return int(num) / 256
}

func mbToB(x int) int {
    return x * 1024 * 1024
}

// output frstring "top" command on OS X
func topStats() (map[string]string, error) {
    raw, err := exec.Command("top", "-S", "-l", "1", "-n", "0").Output()

    if err != nil {
        return nil, err
    }

    return parseCommandMap(string(raw[:])), nil
}

func readableSize(x int) string {
    KB := 1024
    MB := KB * KB
    GB := KB * KB * KB

    // Bytes
    if x < KB {
        return strconv.Itoa(x) + "b"
    } else if x < MB {
        return strconv.Itoa(x/KB) + "kb"
    } else if x < GB {
        return strconv.Itoa(x/MB) + "mb"
    }
    // else
    return strconv.Itoa(x/GB) + "gb"
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"os"
	"runtime"
	"sync"

	"github.com/CasualSuperman/Diorite/multiverse"
)

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

	canSaveMultiverse := true
	multiverseLoaded := false

	err := os.MkdirAll(StorageDir, os.ModePerm|os.ModeDir)

	if err != nil {
		fmt.Errorf("Unable to create application storage directory. Multiverse will not be saved.")
		canSaveMultiverse = false
	}

	var m multiverse.Multiverse

	if canSaveMultiverse {
		multiverseFile, err := os.Open(MultiverseFileName)

		if err != nil {
			if os.IsNotExist(err) {
				fmt.Println("No local database available. A local copy will be downloaded.")
			} else {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			fmt.Println("Loading local multiverse.")
			m, err = multiverse.Read(multiverseFile)
			multiverseFile.Close()

			if err != nil {
				fmt.Errorf("Unable to load multiverse: %s", err)
			} else {
				fmt.Println("Multiverse loaded.")
				multiverseLoaded = true
			}
		}

	}

	fmt.Println("Checking for multiverse updates.")
	mostRecentUpdate, err := onlineModifiedAt()

	if err != nil {
		if multiverseLoaded == false {
			fmt.Errorf("No local multiverse available, and unable to download copy. Unable to continue.")
			os.Exit(1)
		}
		fmt.Errorf("Warning: Online database unavailable. Your card index may be out of date.")
	}

	var saved sync.WaitGroup

	if mostRecentUpdate.After(m.Modified) {
		fmt.Println("Multiverse update available! Downloading now.")
		newM, err := downloadMultiverse()
		if err != nil {
			if !multiverseLoaded {
				fmt.Errorf("Downloading multiverse failed and no local database available. Unable to continue.")
				os.Exit(1)
			}
			fmt.Println("Unable to download most recent multiverse. Continuing with an out-of-date version.")
		} else {
			m = newM
		}

		if canSaveMultiverse {
			file, err := os.Create(MultiverseFileName)

			if err != nil {
				fmt.Errorf("Unable to save update to multiverse. Continuing with up-to-date multiverse, but it will be redownloaded on next startup.")
				fmt.Errorf("(Reason for failure: %s)", err)
			} else {
				saved.Add(1)
				go func() {
					defer file.Close()
					defer saved.Done()
					fmt.Println("Saving downloaded multiverse.")
					err := m.Write(file)
					if err != nil {
						fmt.Println("Error saving multiverse:", err)
					}
				}()
			}
		}
	} else {
		fmt.Println("No updates available.")
	}

	cards := m.FuzzyNameSearch("aetherling", 15)

	names := make([]string, len(cards))
	for i, card := range cards {
		names[i] = card.Name
		fmt.Println(card.Name)

		if math.IsNaN(float64(card.Toughness.Val)) {
			if card.IsCreature() {
				fmt.Println(card.Toughness.Original)
			}
		} else {
			fmt.Println(card.Toughness.Val)
		}
	}
	fmt.Println(names)

	saved.Wait()
}

func dataDir(baseDir string) string {
	return baseDir + string(os.PathSeparator) + dataLocation
}

func homeDirExists(baseDir string) bool {
	dir, err := os.Stat(dataDir(baseDir))
	return err == nil && dir.IsDir()
}

func createHomeDir(baseDir string) error {
	return os.Mkdir(dataDir(baseDir), os.ModePerm|os.ModeDir)
}
<commit_msg>Removed extra methods.<commit_after>package main

import (
	"fmt"
	"math"
	"os"
	"runtime"
	"sync"

	"github.com/CasualSuperman/Diorite/multiverse"
)

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

	canSaveMultiverse := true
	multiverseLoaded := false

	err := os.MkdirAll(StorageDir, os.ModePerm|os.ModeDir)

	if err != nil {
		fmt.Errorf("Unable to create application storage directory. Multiverse will not be saved.")
		canSaveMultiverse = false
	}

	var m multiverse.Multiverse

	if canSaveMultiverse {
		multiverseFile, err := os.Open(MultiverseFileName)

		if err != nil {
			if os.IsNotExist(err) {
				fmt.Println("No local database available. A local copy will be downloaded.")
			} else {
				fmt.Println(err)
				os.Exit(1)
			}
		} else {
			fmt.Println("Loading local multiverse.")
			m, err = multiverse.Read(multiverseFile)
			multiverseFile.Close()

			if err != nil {
				fmt.Errorf("Unable to load multiverse: %s", err)
			} else {
				fmt.Println("Multiverse loaded.")
				multiverseLoaded = true
			}
		}

	}

	fmt.Println("Checking for multiverse updates.")
	mostRecentUpdate, err := onlineModifiedAt()

	if err != nil {
		if multiverseLoaded == false {
			fmt.Errorf("No local multiverse available, and unable to download copy. Unable to continue.")
			os.Exit(1)
		}
		fmt.Errorf("Warning: Online database unavailable. Your card index may be out of date.")
	}

	var saved sync.WaitGroup

	if mostRecentUpdate.After(m.Modified) {
		fmt.Println("Multiverse update available! Downloading now.")
		newM, err := downloadMultiverse()
		if err != nil {
			if !multiverseLoaded {
				fmt.Errorf("Downloading multiverse failed and no local database available. Unable to continue.")
				os.Exit(1)
			}
			fmt.Println("Unable to download most recent multiverse. Continuing with an out-of-date version.")
		} else {
			m = newM
		}

		if canSaveMultiverse {
			file, err := os.Create(MultiverseFileName)

			if err != nil {
				fmt.Errorf("Unable to save update to multiverse. Continuing with up-to-date multiverse, but it will be redownloaded on next startup.")
				fmt.Errorf("(Reason for failure: %s)", err)
			} else {
				saved.Add(1)
				go func() {
					defer file.Close()
					defer saved.Done()
					fmt.Println("Saving downloaded multiverse.")
					err := m.Write(file)
					if err != nil {
						fmt.Println("Error saving multiverse:", err)
					}
				}()
			}
		}
	} else {
		fmt.Println("No updates available.")
	}

	cards := m.FuzzyNameSearch("aetherling", 15)

	names := make([]string, len(cards))
	for i, card := range cards {
		names[i] = card.Name
		fmt.Println(card.Name)

		if math.IsNaN(float64(card.Toughness.Val)) {
			if card.IsCreature() {
				fmt.Println(card.Toughness.Original)
			}
		} else {
			fmt.Println(card.Toughness.Val)
		}
	}
	fmt.Println(names)

	saved.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/rcrowley/go-metrics"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
)

type Datasource struct {
	Name        string
	Create_date time.Time
	Params      string
}

type state struct {
	*sync.RWMutex // inherits locking methods
	Vals          []Datasource
}

const myLogFormat = log.Ldate | log.Ltime

// declare a globally scoped State variable, otherwise
// the request handlers can't get to it. If there is a better
// way to do this, plmk.
var State = &state{&sync.RWMutex{}, []Datasource{}}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := log.New(os.Stdout, "http	", myLogFormat)
		l.Printf("Request: %+v %+v", r.URL, r)
		m := metrics.GetOrRegisterTimer(fmt.Sprintf("%s%s", r.Method, r.URL.Path), metrics.DefaultRegistry)
		m.Time(func() {
			fn(w, r)
		})
	}
}

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	l := log.New(os.Stdout, "http	", myLogFormat)

	State.RLock() // grab a lock, but then don't forget to
	defer State.RUnlock() // unlock it again once we're done

	l.Printf("Request for %s\n", r.URL.Path)
	js, err := json.Marshal(State.Vals)

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

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

func statsHandler(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		metrics.WriteJSONOnce(metrics.DefaultRegistry, w)
}

func parseTime(s string) time.Time {
	// 24/08/2014 20:59:54
	var t, _ = time.Parse("02/01/2006 15:04:05", s)
	return t
}

func addItemToState(ds Datasource) {
	l := log.New(os.Stdout, "tail	", myLogFormat)
	m_ds := metrics.GetOrRegisterCounter("tail/datasources", metrics.DefaultRegistry)
	defer m_ds.Inc(1)

	// We're writing to shared datastructures, grab a Write-lock
	State.Lock()
	defer State.Unlock()

	State.Vals = append(State.Vals, ds)
	l.Printf("New datasource: %+v (total: %v)", ds.Name, len(State.Vals))
}

func tailLogfile(c chan string) {
	m_lines := metrics.GetOrRegisterCounter("tail/input_lines", metrics.DefaultRegistry)

	var dataPath = regexp.MustCompile(`.*out:(.*) :: \[creates\] creating database file .*/whisper/(.*)\.wsp (.*)`)
	t, err := tail.TailFile("./creates.log", tail.Config{Follow: true, ReOpen: true, MustExist: true})
	if err == nil {
		for line := range t.Lines {
			m_lines.Inc(1)
			match := dataPath.FindStringSubmatch(line.Text)
			if len(match) > 0 {
				ds := fmt.Sprintf("%s", strings.Replace(match[2], `/`, `.`, -1))
				tmp := Datasource{Name: ds, Create_date: parseTime(match[1]), Params: match[3]}
				addItemToState(tmp)
			}
		}
	}
	c <- fmt.Sprintf("%s", err)
}

func main() {
	error_channel := make(chan string)
	l := log.New(os.Stdout, "main	", myLogFormat)

	// Set up metrics registry
	go metrics.Log(
		metrics.DefaultRegistry,
		5e9, // Xe9 -> X seconds
		log.New(os.Stdout, "metrics	", myLogFormat))

	// Set up web handlers in goroutines

	http.HandleFunc("/json/", makeHandler(jsonHandler))
	http.HandleFunc("/stats/", makeHandler(statsHandler))
	go http.ListenAndServe(":2934", nil)
	go tailLogfile(error_channel)

	l.Println("Graphite News -- Showing which new metrics are available since 2014\n")
	l.Println("Graphite News -- Serving UI on: http://localhost:2934\n")

	// Wait for errors to appear then shut down
	l.Println(<-error_channel)
}
<commit_msg>commented out metrics logging, go fmt<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/rcrowley/go-metrics"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"sync"
	"time"
)

type Datasource struct {
	Name        string
	Create_date time.Time
	Params      string
}

type state struct {
	*sync.RWMutex // inherits locking methods
	Vals          []Datasource
}

const myLogFormat = log.Ldate | log.Ltime

// declare a globally scoped State variable, otherwise
// the request handlers can't get to it. If there is a better
// way to do this, plmk.
var State = &state{&sync.RWMutex{}, []Datasource{}}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := log.New(os.Stdout, "http	", myLogFormat)
		l.Printf("Request: %+v %+v", r.URL, r)
		m := metrics.GetOrRegisterTimer(fmt.Sprintf("%s%s", r.Method, r.URL.Path), metrics.DefaultRegistry)
		m.Time(func() {
			fn(w, r)
		})
	}
}

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	l := log.New(os.Stdout, "http	", myLogFormat)

	State.RLock()         // grab a lock, but then don't forget to
	defer State.RUnlock() // unlock it again once we're done

	l.Printf("Request for %s\n", r.URL.Path)
	js, err := json.Marshal(State.Vals)

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

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

func statsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	metrics.WriteJSONOnce(metrics.DefaultRegistry, w)
}

func parseTime(s string) time.Time {
	// 24/08/2014 20:59:54
	var t, _ = time.Parse("02/01/2006 15:04:05", s)
	return t
}

func addItemToState(ds Datasource) {
	l := log.New(os.Stdout, "tail	", myLogFormat)
	m_ds := metrics.GetOrRegisterCounter("tail/datasources", metrics.DefaultRegistry)
	defer m_ds.Inc(1)

	// We're writing to shared datastructures, grab a Write-lock
	State.Lock()
	defer State.Unlock()

	State.Vals = append(State.Vals, ds)
	l.Printf("New datasource: %+v (total: %v)", ds.Name, len(State.Vals))
}

func tailLogfile(c chan string) {
	m_lines := metrics.GetOrRegisterCounter("tail/input_lines", metrics.DefaultRegistry)

	var dataPath = regexp.MustCompile(`.*out:(.*) :: \[creates\] creating database file .*/whisper/(.*)\.wsp (.*)`)
	t, err := tail.TailFile("./creates.log", tail.Config{Follow: true, ReOpen: true, MustExist: true})
	if err == nil {
		for line := range t.Lines {
			m_lines.Inc(1)
			match := dataPath.FindStringSubmatch(line.Text)
			if len(match) > 0 {
				ds := fmt.Sprintf("%s", strings.Replace(match[2], `/`, `.`, -1))
				tmp := Datasource{Name: ds, Create_date: parseTime(match[1]), Params: match[3]}
				addItemToState(tmp)
			}
		}
	}
	c <- fmt.Sprintf("%s", err)
}

func main() {
	error_channel := make(chan string)
	l := log.New(os.Stdout, "main	", myLogFormat)

	// Set up metrics registry
	//	go metrics.Log(
	//		metrics.DefaultRegistry,
	//		5e9, // Xe9 -> X seconds
	//		log.New(os.Stdout, "metrics	", myLogFormat))

	// Set up web handlers in goroutines

	http.HandleFunc("/json/", makeHandler(jsonHandler))
	http.HandleFunc("/stats/", makeHandler(statsHandler))
	go http.ListenAndServe(":2934", nil)
	go tailLogfile(error_channel)

	l.Println("Graphite News -- Showing which new metrics are available since 2014\n")
	l.Println("Graphite News -- Serving UI on: http://localhost:2934\n")

	// Wait for errors to appear then shut down
	l.Println(<-error_channel)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mgutz/logxi/v1"
	"github.com/namsral/flag"
	"os"
	"os/exec"
	"time"
)

const VERSION = "0.0.1"

var logger log.Logger

var (
	DockerRoot    string
	ContainerName string
	Output        string
	GraphiteHost  string
	Parser        string
	Prefix        string
	Interval      string
	LogsterPath   string
)

func init() {

	logger = log.NewLogger(os.Stdout, "logster-docker-runner:"+VERSION)

	flag.StringVar(&DockerRoot, "docker_root", "/var/lib/docker", "docker root")
	flag.StringVar(&ContainerName, "container_name", "", "container name")
	flag.StringVar(&Output, "output", "stdout", "logster output")
	flag.StringVar(&GraphiteHost, "graphite_host", "", "graphite host")
	flag.StringVar(&Parser, "parser", "", "logster parser")
	flag.StringVar(&Prefix, "prefix", "", "metric prefix")
	flag.StringVar(&Interval, "interval", "1m", "logster running interval")
	flag.StringVar(&LogsterPath, "logster_path", "logster", "logster file path")

}

func main() {
	flag.Parse()

	duration, err := time.ParseDuration(Interval)
	if err != nil {
		logger.Error("interval", "err", err)
		os.Exit(1)
	}

	if ContainerName == "" {
		logger.Error("container name not found")
		os.Exit(1)
	}

	ticker := time.NewTicker(duration)

	logger.Info("start logster runner")

	for _ = range ticker.C {
		logFile := ContainerLogFilePath(ContainerName)
		if logFile == "" {
			logger.Error("logfile not found", "file", logFile)
			continue
		}

		logsterArgs := LogsterArgs(logFile)

		logger.Info("logster", "args", logsterArgs)

		cmd := exec.Command(LogsterPath, logsterArgs...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			logger.Error("logster", "err", err.Error())
		}

		logger.Info("logster", "output", string(out))
	}

	logger.Info("bye")
}
<commit_msg>Add ${HOSTNAME} in prefix<commit_after>package main

import (
	"github.com/mgutz/logxi/v1"
	"github.com/namsral/flag"
	"os"
	"os/exec"
	"strings"
	"time"
)

const VERSION = "0.0.1"

var logger log.Logger

var (
	DockerRoot    string
	ContainerName string
	Output        string
	GraphiteHost  string
	Parser        string
	Prefix        string
	Interval      string
	LogsterPath   string
)

func init() {

	logger = log.NewLogger(os.Stdout, "logster-docker-runner:"+VERSION)

	flag.StringVar(&DockerRoot, "docker_root", "/var/lib/docker", "docker root")
	flag.StringVar(&ContainerName, "container_name", "", "container name")
	flag.StringVar(&Output, "output", "stdout", "logster output")
	flag.StringVar(&GraphiteHost, "graphite_host", "", "graphite host")
	flag.StringVar(&Parser, "parser", "", "logster parser")
	flag.StringVar(&Prefix, "prefix", "", "metric prefix")
	flag.StringVar(&Interval, "interval", "1m", "logster running interval")
	flag.StringVar(&LogsterPath, "logster_path", "logster", "logster file path")

}

func main() {
	flag.Parse()

	if Prefix != "" {
		if strings.Contains(Prefix, "${HOSTNAME}") {
			hostname, _ := os.Hostname()
			Prefix = strings.Replace(Prefix, "${HOSTNAME}", hostname, 1)
		}
	}

	duration, err := time.ParseDuration(Interval)
	if err != nil {
		logger.Error("interval", "err", err)
		os.Exit(1)
	}

	if ContainerName == "" {
		logger.Error("container name not found")
		os.Exit(1)
	}

	ticker := time.NewTicker(duration)

	logger.Info("start logster runner")

	for _ = range ticker.C {
		logFile := ContainerLogFilePath(ContainerName)
		if logFile == "" {
			logger.Error("logfile not found", "file", logFile)
			continue
		}

		logsterArgs := LogsterArgs(logFile)

		logger.Info("logster", "args", logsterArgs)

		cmd := exec.Command(LogsterPath, logsterArgs...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			logger.Error("logster", "err", err.Error())
		}

		logger.Info("logster", "output", string(out))
	}

	logger.Info("bye")
}
<|endoftext|>