<commit_before>package main //import "github.com/tutumcloud/events"

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"github.com/getsentry/raven-go"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Event struct {
	Node       string `json:"node",omitempty`
	Status     string `json:"status"`
	ID         string `json:"id"`
	From       string `json:"from"`
	Time       int64  `json:"time"`
	HandleTime int64  `json:"handletime"`
	ExitCode   string `json:"exitcode"`
}

func init() {
	runtime.GOMAXPROCS(4)
}

const (
	VERSION     = "0.1"
	DockerPath  = "/usr/bin/docker"
	ApiEndpoint = "api/agent/container/event/"
)

var (
	AutorestartEvents = make([]Event, 0)
	UserAgent         = "tutum-events/" + VERSION
	ReportInterval    int
	TutumAuth         string
	TutumUrl          string
	sentryClient      *raven.Client = nil
	DSN               string
	NodeUUID          string
)

func main() {
	TutumAuth = os.Getenv("TUTUM_AUTH")
	TutumUrl = os.Getenv("TUTUM_URL")
	if TutumAuth == "**None**" {
		log.Fatal("TUTUM_AUTH must be specified")
	}
	if TutumUrl == "**None**" {
		TutumHost := os.Getenv("TUTUM_HOST")
		NodeUUID = os.Getenv("NODE_UUID")
		if strings.HasSuffix(TutumHost, "/") {
			TutumUrl = TutumHost + ApiEndpoint
		} else {
			TutumUrl = TutumHost + "/" + ApiEndpoint
		}
		if TutumUrl == "" {
			log.Fatal("TUTUM_URL must be specified")
		}
	}

	DSN = os.Getenv("SENTRY_DSN")

	if !fileExist(DockerPath) {
		log.Fatal("docker client is not mounted to", DockerPath)
	}

	intervalStr := os.Getenv("REPORT_INTERVAL")

	interval, err := strconv.Atoi(intervalStr)
	if err != nil {
		ReportInterval = 30
	} else {
		ReportInterval = interval
	}

	log.Println("POST docker event to:", TutumUrl)

	cmd := exec.Command(DockerPath, "version")
	if err := cmd.Start(); err != nil {
		sendError(err, "Fatal: Failed to run docker version", nil)
		log.Println(err)
		return
	}
	cmd.Wait()

	monitorEvents()
}

func monitorEvents() {
	ticker := time.NewTicker(time.Second * time.Duration(ReportInterval))
	go func() {
		for {
			select {
			case <-ticker.C:
				events := AutorestartEvents
				AutorestartEvents = make([]Event, 0)
				if len(events) > 0 {
					go sendContainerAutoRestartEvents(events)
				}
			}
		}
	}()

	for {
		log.Println("docker events starts")
		cmd := exec.Command(DockerPath, "events")
		cmdReader, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal("Error creating StdoutPipe for Cmd", err)
		}

		scanner := bufio.NewScanner(cmdReader)
		go func() {
			for scanner.Scan() {
				eventStr := scanner.Text()
				if eventStr != "" {
					re := regexp.MustCompile("(.*) (.{64}): \\(from (.*)\\) (.*)")
					terms := re.FindStringSubmatch(eventStr)
					if len(terms) == 5 {
						var event Event
						if NodeUUID != "" {
							event.Node = NodeUUID
						}
						eventTime, err := time.Parse(time.RFC3339Nano, terms[1])
						if err == nil {
							event.Time = eventTime.Unix()
						} else {
							event.Time = time.Now().Unix()
						}
						event.ID = terms[2]
						event.From = terms[3]
						event.Status = terms[4]
						event.HandleTime = time.Now().UnixNano()
						go eventHandler(event)
					}
				}
			}
		}()

		err = cmd.Start()
		if err != nil {
			log.Print("Error starting docker evets", err)
			break
		}

		err = cmd.Wait()
		if err != nil {
			log.Print("Error waiting for docker events", err)
			break
		}
		log.Println("docker events stops")
	}
}

func eventHandler(event Event) {
	event.ExitCode = "0"
	isRestart := false
	if strings.ToLower(event.Status) == "start" ||
		strings.ToLower(event.Status) == "die" {

		result, err := exec.Command(DockerPath, "inspect", "-f",
			"{{index .HostConfig.RestartPolicy.Name}} {{index .State.ExitCode}}",
			event.ID).Output()

		if err == nil && len(result) > 0 {
			terms := strings.Split(string(result), " ")
			if len(terms) == 2 {
				if strings.HasPrefix(strings.ToLower(terms[0]), "on-failure") ||
					strings.HasPrefix(strings.ToLower(terms[0]), "always") {
					isRestart = true
				}
				event.ExitCode = strings.Trim(terms[1], "\n")
			}
		}
		if isRestart {
			AutorestartEvents = append(AutorestartEvents, event)
		} else {
			sendContainerEvent(event)
		}
	}
}

func sendContainerAutoRestartEvents(events []Event) {
	data, err := json.Marshal(events)
	if err != nil {
		log.Printf("Cannot marshal the posting data: %s\n", events)
	}
	sendData(data)
}

func sendContainerEvent(event Event) {
	data, err := json.Marshal(event)
	if err != nil {
		log.Printf("Cannot marshal the posting data: %s\n", event)
	}
	sendData(data)
}

func sendData(data []byte) {
	counter := 1
	for {
		log.Println("sending event: ", string(data))
		err := send(TutumUrl, data)
		if err == nil {
			break
		} else {
			if counter > 100 {
				log.Println("Too many reties, give up")
				break
			} else {
				counter *= 2
				log.Printf("%s: Retry in %d seconds", err, counter)
				time.Sleep(time.Duration(counter) * time.Second)
			}
		}
	}
}

func send(url string, data []byte) error {
	client := &http.Client{}
	req, err := http.NewRequest("POST", url, bytes.NewReader(data))
	if err != nil {
		sendError(err, "Failed to create http.NewRequest", nil)
		return err
	}
	req.Header.Add("Authorization", TutumAuth)
	req.Header.Add("User-Agent", UserAgent)
	resp, err := client.Do(req)
	if err != nil {
		extra := map[string]interface{}{"data": string(data)}
		sendError(err, "Failed to POST the http request", extra)
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		log.Printf("Send event failed: %s - %s", resp.Status, string(data))
		extra := map[string]interface{}{"data": string(data)}
		sendError(errors.New(resp.Status), "http error", extra)
		if resp.StatusCode >= 500 {
			return errors.New(resp.Status)
		}
	}
	return nil
}

func fileExist(file string) bool {
	if _, err := os.Stat(file); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func getSentryClient() *raven.Client {
	if sentryClient == nil && DSN != "" {
		client, _ := raven.NewClient(DSN, nil)
		sentryClient = client
	}
	return sentryClient
}

func sendError(err error, msg string, extra map[string]interface{}) {
	go func() {
		client := getSentryClient()
		if sentryClient != nil {
			packet := &raven.Packet{Message: msg, Interfaces: []raven.Interface{raven.NewException(err, raven.NewStacktrace(0, 5, nil))}}
			if extra != nil {
				packet.Extra = extra
			}
			_, ch := client.Capture(packet, nil)
			<-ch
		}
	}()
}
<commit_msg>remove the outer for loop, and fail the program on scanner error<commit_after>package main //import "github.com/tutumcloud/events"

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"github.com/getsentry/raven-go"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Event struct {
	Node       string `json:"node",omitempty`
	Status     string `json:"status"`
	ID         string `json:"id"`
	From       string `json:"from"`
	Time       int64  `json:"time"`
	HandleTime int64  `json:"handletime"`
	ExitCode   string `json:"exitcode"`
}

func init() {
	runtime.GOMAXPROCS(4)
}

const (
	VERSION     = "0.1"
	DockerPath  = "/usr/bin/docker"
	ApiEndpoint = "api/agent/container/event/"
)

var (
	AutorestartEvents = make([]Event, 0)
	UserAgent         = "tutum-events/" + VERSION
	ReportInterval    int
	TutumAuth         string
	TutumUrl          string
	sentryClient      *raven.Client = nil
	DSN               string
	NodeUUID          string
)

func main() {
	TutumAuth = os.Getenv("TUTUM_AUTH")
	TutumUrl = os.Getenv("TUTUM_URL")
	if TutumAuth == "**None**" {
		log.Fatal("TUTUM_AUTH must be specified")
	}
	if TutumUrl == "**None**" {
		TutumHost := os.Getenv("TUTUM_HOST")
		NodeUUID = os.Getenv("NODE_UUID")
		if strings.HasSuffix(TutumHost, "/") {
			TutumUrl = TutumHost + ApiEndpoint
		} else {
			TutumUrl = TutumHost + "/" + ApiEndpoint
		}
		if TutumUrl == "" {
			log.Fatal("TUTUM_URL must be specified")
		}
	}

	DSN = os.Getenv("SENTRY_DSN")

	if !fileExist(DockerPath) {
		log.Fatal("docker client is not mounted to", DockerPath)
	}

	intervalStr := os.Getenv("REPORT_INTERVAL")

	interval, err := strconv.Atoi(intervalStr)
	if err != nil {
		ReportInterval = 30
	} else {
		ReportInterval = interval
	}

	log.Println("POST docker event to:", TutumUrl)

	cmd := exec.Command(DockerPath, "version")
	if err := cmd.Start(); err != nil {
		sendError(err, "Fatal: Failed to run docker version", nil)
		log.Println(err)
		return
	}
	cmd.Wait()

	monitorEvents()
}

func monitorEvents() {
	ticker := time.NewTicker(time.Second * time.Duration(ReportInterval))
	go func() {
		for {
			select {
			case <-ticker.C:
				events := AutorestartEvents
				AutorestartEvents = make([]Event, 0)
				if len(events) > 0 {
					go sendContainerAutoRestartEvents(events)
				}
			}
		}
	}()

	log.Println("docker events starts")
	cmd := exec.Command(DockerPath, "events")
	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal("Error creating StdoutPipe for Cmd", err)
	}

	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			eventStr := scanner.Text()
			if eventStr != "" {
				re := regexp.MustCompile("(.*) (.{64}): \\(from (.*)\\) (.*)")
				terms := re.FindStringSubmatch(eventStr)
				if len(terms) == 5 {
					var event Event
					if NodeUUID != "" {
						event.Node = NodeUUID
					}
					eventTime, err := time.Parse(time.RFC3339Nano, terms[1])
					if err == nil {
						event.Time = eventTime.Unix()
					} else {
						event.Time = time.Now().Unix()
					}
					event.ID = terms[2]
					event.From = terms[3]
					event.Status = terms[4]
					event.HandleTime = time.Now().UnixNano()
					go eventHandler(event)
				}
			}
		}
		if scanner.Err() == nil {
			log.Fatal("The scanner returns an error:", "EOF")
		} else {
			log.Fatal("The scanner returns an error:", scanner.Err())
		}
	}()

	err = cmd.Start()
	if err != nil {
		log.Fatal("Error starting docker evets", err)
	}

	err = cmd.Wait()
	if err != nil {
		log.Fatal("Error waiting for docker events", err)
	}
	log.Println("docker events stops")
}

func eventHandler(event Event) {
	event.ExitCode = "0"
	isRestart := false
	if strings.ToLower(event.Status) == "start" ||
		strings.ToLower(event.Status) == "die" {

		result, err := exec.Command(DockerPath, "inspect", "-f",
			"{{index .HostConfig.RestartPolicy.Name}} {{index .State.ExitCode}}",
			event.ID).Output()

		if err == nil && len(result) > 0 {
			terms := strings.Split(string(result), " ")
			if len(terms) == 2 {
				if strings.HasPrefix(strings.ToLower(terms[0]), "on-failure") ||
					strings.HasPrefix(strings.ToLower(terms[0]), "always") {
					isRestart = true
				}
				event.ExitCode = strings.Trim(terms[1], "\n")
			}
		}
		if isRestart {
			AutorestartEvents = append(AutorestartEvents, event)
		} else {
			sendContainerEvent(event)
		}
	}
}

func sendContainerAutoRestartEvents(events []Event) {
	data, err := json.Marshal(events)
	if err != nil {
		log.Printf("Cannot marshal the posting data: %s\n", events)
	}
	sendData(data)
}

func sendContainerEvent(event Event) {
	data, err := json.Marshal(event)
	if err != nil {
		log.Printf("Cannot marshal the posting data: %s\n", event)
	}
	sendData(data)
}

func sendData(data []byte) {
	counter := 1
	for {
		log.Println("sending event: ", string(data))
		err := send(TutumUrl, data)
		if err == nil {
			break
		} else {
			if counter > 100 {
				log.Println("Too many reties, give up")
				break
			} else {
				counter *= 2
				log.Printf("%s: Retry in %d seconds", err, counter)
				time.Sleep(time.Duration(counter) * time.Second)
			}
		}
	}
}

func send(url string, data []byte) error {
	client := &http.Client{}
	req, err := http.NewRequest("POST", url, bytes.NewReader(data))
	if err != nil {
		sendError(err, "Failed to create http.NewRequest", nil)
		return err
	}
	req.Header.Add("Authorization", TutumAuth)
	req.Header.Add("User-Agent", UserAgent)
	resp, err := client.Do(req)
	if err != nil {
		extra := map[string]interface{}{"data": string(data)}
		sendError(err, "Failed to POST the http request", extra)
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		log.Printf("Send event failed: %s - %s", resp.Status, string(data))
		extra := map[string]interface{}{"data": string(data)}
		sendError(errors.New(resp.Status), "http error", extra)
		if resp.StatusCode >= 500 {
			return errors.New(resp.Status)
		}
	}
	return nil
}

func fileExist(file string) bool {
	if _, err := os.Stat(file); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func getSentryClient() *raven.Client {
	if sentryClient == nil && DSN != "" {
		client, _ := raven.NewClient(DSN, nil)
		sentryClient = client
	}
	return sentryClient
}

func sendError(err error, msg string, extra map[string]interface{}) {
	go func() {
		client := getSentryClient()
		if sentryClient != nil {
			packet := &raven.Packet{Message: msg, Interfaces: []raven.Interface{raven.NewException(err, raven.NewStacktrace(0, 5, nil))}}
			if extra != nil {
				packet.Extra = extra
			}
			_, ch := client.Capture(packet, nil)
			<-ch
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "github.com/gorilla/feeds"
  "github.com/PuerkitoBio/goquery"
  "net/http"
  "strings"
)

func handleFeed(w http.ResponseWriter, feed *feeds.Feed) {
  atom, err := feed.ToAtom()
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    return
  }
  w.Header().Set("Content-Type", "application/atom+xml")
  fmt.Fprintln(w, atom)
}

func getPurolandNews() (*feeds.Feed, error) {
  doc, err := goquery.NewDocument("http://www.puroland.jp/")
  if err != nil {
    return nil, err
  }

  feed := &feeds.Feed{
    Title: "最新情報 | サンリオピューロランド",
    Link: &feeds.Link{Href: "http://www.puroland.jp/"},
  }

  var items []*feeds.Item
  doc.Find("#newsArea ul li a").Each(func(_ int, s *goquery.Selection) {
    title := strings.TrimSpace(s.Text())
    link, ok := s.Attr("href")
    if ok {
      items = append(items, &feeds.Item{
        Title: title,
        Link: &feeds.Link{Href: link},
        Id: link,
      })
    }
  })
  feed.Items = items

  return feed, nil
}

func handlePurolandNews(w http.ResponseWriter, r *http.Request) {
  feed, err := getPurolandNews()
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    return
  }
  handleFeed(w, feed)
}

func getPurolandInfo() (*feeds.Feed, error) {
  doc, err := goquery.NewDocument("http://www.puroland.jp/")
  if err != nil {
    return nil, err
  }

  feed := &feeds.Feed{
    Title: "お知らせ | サンリオピューロランド",
    Link: &feeds.Link{Href: "http://www.puroland.jp/"},
  }

  var items []*feeds.Item
  doc.Find("#infoSectionArea ul li a").Each(func(_ int, s *goquery.Selection) {
    title := strings.TrimSpace(s.Text())
    link, ok := s.Attr("href")
    if ok {
      items = append(items, &feeds.Item{
        Title: title,
        Link: &feeds.Link{Href: link},
        Id: link,
      })
    }
  })
  feed.Items = items

  return feed, nil
}

func handlePurolandInfo(w http.ResponseWriter, r *http.Request) {
  feed, err := getPurolandInfo()
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    return
  }
  handleFeed(w, feed)
}

func main() {
  http.HandleFunc("/puroland-info", handlePurolandInfo)
  http.HandleFunc("/puroland-news", handlePurolandNews)
  http.ListenAndServe(":13000", nil)
}
<commit_msg>Return 503 when puroland.jp in unavailable<commit_after>package main

import (
  "fmt"
  "github.com/gorilla/feeds"
  "github.com/PuerkitoBio/goquery"
  "net/http"
  "strings"
)

func handleFeed(w http.ResponseWriter, feed *feeds.Feed) {
  atom, err := feed.ToAtom()
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    return
  }
  w.Header().Set("Content-Type", "application/atom+xml")
  fmt.Fprintln(w, atom)
}

func getPurolandNews() (*feeds.Feed, error) {
  doc, err := goquery.NewDocument("http://www.puroland.jp/")
  if err != nil {
    return nil, err
  }

  feed := &feeds.Feed{
    Title: "最新情報 | サンリオピューロランド",
    Link: &feeds.Link{Href: "http://www.puroland.jp/"},
  }

  var items []*feeds.Item
  doc.Find("#newsArea ul li a").Each(func(_ int, s *goquery.Selection) {
    title := strings.TrimSpace(s.Text())
    link, ok := s.Attr("href")
    if ok {
      items = append(items, &feeds.Item{
        Title: title,
        Link: &feeds.Link{Href: link},
        Id: link,
      })
    }
  })
  feed.Items = items

  return feed, nil
}

func handlePurolandNews(w http.ResponseWriter, r *http.Request) {
  feed, err := getPurolandNews()
  if err != nil {
    w.WriteHeader(http.StatusServiceUnavailable)
    return
  }
  handleFeed(w, feed)
}

func getPurolandInfo() (*feeds.Feed, error) {
  doc, err := goquery.NewDocument("http://www.puroland.jp/")
  if err != nil {
    return nil, err
  }

  feed := &feeds.Feed{
    Title: "お知らせ | サンリオピューロランド",
    Link: &feeds.Link{Href: "http://www.puroland.jp/"},
  }

  var items []*feeds.Item
  doc.Find("#infoSectionArea ul li a").Each(func(_ int, s *goquery.Selection) {
    title := strings.TrimSpace(s.Text())
    link, ok := s.Attr("href")
    if ok {
      items = append(items, &feeds.Item{
        Title: title,
        Link: &feeds.Link{Href: link},
        Id: link,
      })
    }
  })
  feed.Items = items

  return feed, nil
}

func handlePurolandInfo(w http.ResponseWriter, r *http.Request) {
  feed, err := getPurolandInfo()
  if err != nil {
    w.WriteHeader(http.StatusServiceUnavailable)
    return
  }
  handleFeed(w, feed)
}

func main() {
  http.HandleFunc("/puroland-info", handlePurolandInfo)
  http.HandleFunc("/puroland-news", handlePurolandNews)
  http.ListenAndServe(":13000", nil)
}
<|endoftext|>


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

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements primitive functions.

package golisp

import (
	"fmt"
	"strings"
)

type PrimitiveFunction struct {
	Name         string
	Special      bool
	NumberOfArgs string
	Body         func(d *Data, env *SymbolTableFrame) (*Data, error)
	IsRestricted bool
}

func MakePrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedPrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func (self *PrimitiveFunction) String() string {
	return fmt.Sprintf("<prim: %s, %v>", self.Name, self.Body)
}

func (self *PrimitiveFunction) checkArgumentCount(argCount int) bool {
	if self.NumberOfArgs == "*" {
		return true
	}

	for _, term := range strings.Split(self.NumberOfArgs, "|") {
		var intTerm int
		n, _ := fmt.Sscanf(term, "%d", &intTerm)
		if n == 1 && argCount == intTerm {
			return true
		}
		n, _ = fmt.Sscanf(term, ">=%d", &intTerm)
		if n == 1 && argCount >= intTerm {
			return true
		}
		var lo int
		var hi int
		n, _ = fmt.Sscanf(term, "(%d,%d)", &lo, &hi)
		if n == 2 && lo <= argCount && argCount <= hi {
			return true
		}
	}
	return false
}

func (self *PrimitiveFunction) Apply(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.IsRestricted && env.IsRestricted {
		err = fmt.Errorf("The %s primitive is restricted from execution in this environment\n", self.Name)
		return
	}

	if !self.checkArgumentCount(Length(args)) {
		err = fmt.Errorf("Wrong number of args to %s. Expected %s but got %d.\n", self.Name, self.NumberOfArgs, Length(args))
		return
	}

	argArray := make([]*Data, 0)
	var argValue *Data
	for a := args; NotNilP(a); a = Cdr(a) {
		if self.Special {
			argValue = Car(a)
		} else {
			argValue, err = Eval(Car(a), env)
			if err != nil {
				return
			}
		}

		argArray = append(argArray, argValue)
	}

	localGuid := ProfileGUID
	ProfileGUID++
	ProfileEnter("prim", self.Name, localGuid)

	result, err = (self.Body)(ArrayToList(argArray), env)

	ProfileExit("prim", self.Name, localGuid)

	return
}

func (self *PrimitiveFunction) ApplyWithoutEval(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.Special {
		return self.Apply(args, env)
	} else {
		return self.Apply(QuoteAll(args), env)
	}
}
<commit_msg>Report special forms separately from primitives.<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements primitive functions.

package golisp

import (
	"fmt"
	"strings"
)

type PrimitiveFunction struct {
	Name         string
	Special      bool
	NumberOfArgs string
	Body         func(d *Data, env *SymbolTableFrame) (*Data, error)
	IsRestricted bool
}

func MakePrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedPrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func (self *PrimitiveFunction) String() string {
	return fmt.Sprintf("<prim: %s, %v>", self.Name, self.Body)
}

func (self *PrimitiveFunction) checkArgumentCount(argCount int) bool {
	if self.NumberOfArgs == "*" {
		return true
	}

	for _, term := range strings.Split(self.NumberOfArgs, "|") {
		var intTerm int
		n, _ := fmt.Sscanf(term, "%d", &intTerm)
		if n == 1 && argCount == intTerm {
			return true
		}
		n, _ = fmt.Sscanf(term, ">=%d", &intTerm)
		if n == 1 && argCount >= intTerm {
			return true
		}
		var lo int
		var hi int
		n, _ = fmt.Sscanf(term, "(%d,%d)", &lo, &hi)
		if n == 2 && lo <= argCount && argCount <= hi {
			return true
		}
	}
	return false
}

func (self *PrimitiveFunction) Apply(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.IsRestricted && env.IsRestricted {
		err = fmt.Errorf("The %s primitive is restricted from execution in this environment\n", self.Name)
		return
	}

	if !self.checkArgumentCount(Length(args)) {
		err = fmt.Errorf("Wrong number of args to %s. Expected %s but got %d.\n", self.Name, self.NumberOfArgs, Length(args))
		return
	}

	argArray := make([]*Data, 0)
	var argValue *Data
	for a := args; NotNilP(a); a = Cdr(a) {
		if self.Special {
			argValue = Car(a)
		} else {
			argValue, err = Eval(Car(a), env)
			if err != nil {
				return
			}
		}

		argArray = append(argArray, argValue)
	}

	localGuid := ProfileGUID
	ProfileGUID++
	fType := "prim"
	if self.Special {
		fType = "form"
	}

	ProfileEnter(fType, self.Name, localGuid)

	result, err = (self.Body)(ArrayToList(argArray), env)

	ProfileExit(fType, self.Name, localGuid)

	return
}

func (self *PrimitiveFunction) ApplyWithoutEval(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.Special {
		return self.Apply(args, env)
	} else {
		return self.Apply(QuoteAll(args), env)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/goreleaser/goreleaser/pipeline/archive"
	"github.com/goreleaser/goreleaser/pipeline/brew"
	"github.com/goreleaser/goreleaser/pipeline/build"
	"github.com/goreleaser/goreleaser/pipeline/defaults"
	"github.com/goreleaser/goreleaser/pipeline/env"
	"github.com/goreleaser/goreleaser/pipeline/fpm"
	"github.com/goreleaser/goreleaser/pipeline/git"
	"github.com/goreleaser/goreleaser/pipeline/release"
	"github.com/goreleaser/goreleaser/pipeline/repos"
	"github.com/goreleaser/goreleaser/pipeline/source"
	"github.com/urfave/cli"
)

var version = "master"

var pipes = []pipeline.Pipe{
	// load data, set defaults, etc...
	defaults.Pipe{},
	env.Pipe{},
	git.Pipe{},
	repos.Pipe{},

	source.Pipe{},

	// real work
	build.Pipe{},
	archive.Pipe{},
	fpm.Pipe{},
	release.Pipe{},
	brew.Pipe{},
}

func main() {
	var app = cli.NewApp()
	app.Name = "goreleaser"
	app.Version = version
	app.Usage = "Deliver Go binaries as fast and easily as possible"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
			Value: "goreleaser.yml",
		},
	}
	app.Action = func(c *cli.Context) (err error) {
		var file = c.String("config")
		cfg, err := config.Load(file)
		// Allow failing to load the config file if file is not explicitly specified
		if err != nil && c.IsSet("config") {
			return cli.NewExitError(err.Error(), 1)
		}
		ctx := context.New(cfg)
		log.SetFlags(0)
		for _, pipe := range pipes {
			log.Println(pipe.Description())
			log.SetPrefix(" -> ")
			if err := pipe.Run(ctx); err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			log.SetPrefix("")
		}
		log.Println("Done!")
		return
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>allow skipping release processes<commit_after>package main

import (
	"log"
	"os"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/goreleaser/goreleaser/pipeline/archive"
	"github.com/goreleaser/goreleaser/pipeline/brew"
	"github.com/goreleaser/goreleaser/pipeline/build"
	"github.com/goreleaser/goreleaser/pipeline/defaults"
	"github.com/goreleaser/goreleaser/pipeline/env"
	"github.com/goreleaser/goreleaser/pipeline/fpm"
	"github.com/goreleaser/goreleaser/pipeline/git"
	"github.com/goreleaser/goreleaser/pipeline/release"
	"github.com/goreleaser/goreleaser/pipeline/repos"
	"github.com/goreleaser/goreleaser/pipeline/source"
	"github.com/urfave/cli"
)

var version = "master"

func main() {
	var app = cli.NewApp()
	app.Name = "goreleaser"
	app.Version = version
	app.Usage = "Deliver Go binaries as fast and easily as possible"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
			Value: "goreleaser.yml",
		},
		cli.BoolFlag{
			Name:  "build-only, skip-release, no-release, nr",
			Usage: "Skip all the release processes and run only the build and packaging steps",
		},
	}
	app.Action = func(c *cli.Context) (err error) {
		var file = c.String("config")
		cfg, err := config.Load(file)
		// Allow failing to load the config file if file is not explicitly specified
		if err != nil && c.IsSet("config") {
			return cli.NewExitError(err.Error(), 1)
		}
		ctx := context.New(cfg)
		log.SetFlags(0)
		for _, pipe := range pipes(c.Bool("build-only")) {
			log.Println(pipe.Description())
			log.SetPrefix(" -> ")
			if err := pipe.Run(ctx); err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			log.SetPrefix("")
		}
		log.Println("Done!")
		return
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatalln(err)
	}
}

func pipes(buildOnly bool) []pipeline.Pipe {
	var pipes = []pipeline.Pipe{
		defaults.Pipe{}, // load default configs
		git.Pipe{},      // get current tag info
		repos.Pipe{},    // split repos into owner/name pairs
	}
	if !buildOnly {
		pipes = append(
			pipes,
			env.Pipe{},    // load and validate environment variables
			source.Pipe{}, // validate current git state
		)
	}
	pipes = append(
		pipes,
		build.Pipe{},   // build
		archive.Pipe{}, // archive (tar.gz, zip, etc)
		fpm.Pipe{},     // archive via fpm (deb, rpm, etc)
	)
	if !buildOnly {
		pipes = append(
			pipes,
			release.Pipe{}, // release to github
			brew.Pipe{},    // push to brew tap
		)
	}
	return pipes
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
)

type config struct {
	msg           string
	timeout       time.Duration
	retryInterval time.Duration
	sendInterval  time.Duration
}

func main() {
	log.SetOutput(os.Stderr)
	var (
		laddr string
		c     config
	)
	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}
	flag.StringVar(&laddr, "l", "", "listening address")
	flag.StringVar(&c.msg, "m", hostname, "message to send")
	flag.DurationVar(&c.timeout, "t", 5*time.Second, "connect/send/recv timeout")
	flag.DurationVar(&c.retryInterval, "r", 1*time.Second, "connection retry interval")
	flag.DurationVar(&c.sendInterval, "i", 1*time.Second, "message sending interval")
	flag.Parse()
	addrs := flag.Args()

	if laddr != "" {
		log.Infof("listening on %s", laddr)
		ln, err := net.Listen("tcp", laddr)
		if err != nil {
			log.Fatal(err)
		}
		go accept(ln, c)
	}

	for _, addr := range addrs {
		go send(addr, c)
	}

	select {}
}

func accept(ln net.Listener, c config) {
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Errorf("accept failed: %s", err)
			continue
		}
		log.Infof("accepted connection from %s", conn.RemoteAddr())
		go recv(conn, c)
	}
}

func recv(conn net.Conn, c config) {
	r := bufio.NewReader(conn)
	for {
		conn.SetDeadline(time.Now().Add(c.timeout))
		msg, err := r.ReadString('\n')
		if err != nil {
			log.Errorln(err)
			break
		}
		fmt.Print(msg)
		if _, err := conn.Write([]byte("\n")); err != nil {
			log.Errorln(err)
			break
		}
	}
	conn.Close()
}

func send(addr string, c config) {
	i := 1
	for {
		conn, err := net.DialTimeout("tcp", addr, c.timeout)
		if err != nil {
			log.Errorln(err)
			time.Sleep(c.retryInterval)
			continue
		}
		log.Infof("connected to %s", conn.RemoteAddr())
		r := bufio.NewReader(conn)
		for {
			conn.SetDeadline(time.Now().Add(c.timeout))
			if _, err := conn.Write([]byte(fmt.Sprintf("%s %d\n", c.msg, i))); err != nil {
				log.Errorln(err)
				break
			}
			_, err := r.ReadString('\n')
			if err != nil {
				log.Errorln(err)
				break
			}
			i++
			time.Sleep(c.sendInterval)
		}
		conn.Close()
	}
}
<commit_msg>remove trailing domain from default message<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
)

type config struct {
	msg           string
	timeout       time.Duration
	retryInterval time.Duration
	sendInterval  time.Duration
}

func main() {
	log.SetOutput(os.Stderr)
	var (
		laddr string
		c     config
	)

	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}
	parts := strings.Split(hostname, ".")

	flag.StringVar(&laddr, "l", "", "listening address")
	flag.StringVar(&c.msg, "m", parts[0], "message to send")
	flag.DurationVar(&c.timeout, "t", 5*time.Second, "connect/send/recv timeout")
	flag.DurationVar(&c.retryInterval, "r", 1*time.Second, "connection retry interval")
	flag.DurationVar(&c.sendInterval, "i", 1*time.Second, "message sending interval")
	flag.Parse()
	addrs := flag.Args()

	if laddr != "" {
		log.Infof("listening on %s", laddr)
		ln, err := net.Listen("tcp", laddr)
		if err != nil {
			log.Fatal(err)
		}
		go accept(ln, c)
	}

	for _, addr := range addrs {
		go send(addr, c)
	}

	select {}
}

func accept(ln net.Listener, c config) {
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Errorf("accept failed: %s", err)
			continue
		}
		log.Infof("accepted connection from %s", conn.RemoteAddr())
		go recv(conn, c)
	}
}

func recv(conn net.Conn, c config) {
	r := bufio.NewReader(conn)
	for {
		conn.SetDeadline(time.Now().Add(c.timeout))
		msg, err := r.ReadString('\n')
		if err != nil {
			log.Errorln(err)
			break
		}
		fmt.Print(msg)
		if _, err := conn.Write([]byte("\n")); err != nil {
			log.Errorln(err)
			break
		}
	}
	conn.Close()
}

func send(addr string, c config) {
	i := 1
	for {
		conn, err := net.DialTimeout("tcp", addr, c.timeout)
		if err != nil {
			log.Errorln(err)
			time.Sleep(c.retryInterval)
			continue
		}
		log.Infof("connected to %s", conn.RemoteAddr())
		r := bufio.NewReader(conn)
		for {
			conn.SetDeadline(time.Now().Add(c.timeout))
			if _, err := conn.Write([]byte(fmt.Sprintf("%s %d\n", c.msg, i))); err != nil {
				log.Errorln(err)
				break
			}
			_, err := r.ReadString('\n')
			if err != nil {
				log.Errorln(err)
				break
			}
			i++
			time.Sleep(c.sendInterval)
		}
		conn.Close()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/codegangsta/cli"
)

const version string = "0.1.0"

func main() {
	app := cli.NewApp()
	app.Name = "faw"
	app.Version = version
	app.Usage = "Font Awesome Workflow for Alfred"
	app.Author = "ruedap"
	app.Email = "ruedap@ruedap.com"
	app.Commands = commands
	app.Run(os.Args)
}
<commit_msg>Implement newApp function<commit_after>package main

import (
	"os"

	"github.com/codegangsta/cli"
)

const version string = "0.1.0"

func main() {
	newApp().Run(os.Args)
}

func newApp() *cli.App {
	app := cli.NewApp()
	app.Name = "faw"
	app.Version = version
	app.Usage = "Font Awesome Workflow for Alfred"
	app.Author = "ruedap"
	app.Email = "ruedap@ruedap.com"
	app.Commands = commands
	return app
}
<|endoftext|>


<commit_before>package timestamp

import "time"

type Timestamp float64

const nano = 1000000000.0

func New(t time.Time) Timestamp {
	return Timestamp(Timestamp(t.UnixNano()) / nano)
}

func (t Timestamp) Time() time.Time {
	sec := int64(t)
	nsec := int64((t - Timestamp(sec)) * nano)
	return time.Unix(sec, nsec)
}

func (t Timestamp) String() string {
	return t.Time().String()
}
<commit_msg>Add Now()<commit_after>package timestamp

import "time"

type Timestamp float64

const nano = 1000000000.0

func Now() Timestamp {
	return New(time.Now())
}

func New(t time.Time) Timestamp {
	return Timestamp(Timestamp(t.UnixNano()) / nano)
}

func (t Timestamp) Time() time.Time {
	sec := int64(t)
	nsec := int64((t - Timestamp(sec)) * nano)
	return time.Unix(sec, nsec)
}

func (t Timestamp) String() string {
	return t.Time().String()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	_ "github.com/go-sql-driver/mysql"

	"github.com/getlantern/systray"
	"github.com/sc7639/mysql-notifier/icon"
	"github.com/sc7639/mysql-notifier/status"
)

var settingsFolder string
var settingsPath string

func init() {
	var appData string
	if runtime.GOOS == "windows" {
		appData = os.Getenv("APPDATA")
		settingsFolder = appData + "/mysql-notifier"

	} else {
		appData = os.Getenv("HOME")
		settingsFolder = appData + "/.mysql-notifier"
	}

	if _, err := os.Stat(settingsFolder); os.IsNotExist(err) {
		os.Mkdir(settingsFolder, 0755)
	}

	settingsPath = settingsFolder + "/settings.yml"
}

type settings struct {
	Mysql    map[string]map[string]string `yml:"mysql"`
	Interval string                       `yml:"interval"`
}

var minSettings = settings{
	Mysql:    map[string]map[string]string{},
	Interval: "10s",
}

func main() {
	systray.Run(onReady)
}

func onReady() { // Set icon title and add menu items
	systray.SetTitle("MySQL Notifier")

	rdSettings := make(chan settings, 1)
	mI := make(chan map[string]map[string]string, 1)

	go addMenuItems(mI, rdSettings) // Add menu items

	go func() {
		defer close(rdSettings)
		defer close(mI)

		loaded, err := readSettings(rdSettings, mI)
		if loaded == false || err != nil {
			systray.SetIcon(icon.Red)
			systray.SetTooltip("Failed to load settings")

			// Try to open settings ever 30 seconds
			ticker := time.NewTicker(time.Second * 30)
			for _ = range ticker.C {
				loaded, err := readSettings(rdSettings, mI)
				if loaded == false || err != nil {
					go openSettings()
					continue
				} else {
					systray.SetIcon(icon.Green)
					systray.SetTooltip("All OK")
					break
				}
			}
		} else {
			systray.SetIcon(icon.Green)
			systray.SetTooltip("All OK")
		}
	}()
	// fmt.Printf("rdSettings: %v", <-rdSettings)
}

func addMenuItems(mysqlInstance chan map[string]map[string]string, rdSettings chan settings) {
	ldSettings := <-rdSettings

	dbStatuses := make([]chan bool, len(ldSettings.Mysql))
	var i = 0
	for instance, details := range <-mysqlInstance { // For each mysql instance create a new menu item
		instance = strings.Title(instance)
		item := systray.AddMenuItem(instance, instance)

		go func(title string, item *systray.MenuItem, details map[string]string) { // Handle on click of mysql instance menu item
			for {
				<-item.ClickedCh
				openMysqlCMD(details)
			}
		}(instance, item, details)

		// Create database connection
		var host string
		if _, ok := details["host"]; !ok {
			host = "127.0.0.1"
		} else {
			host = details["host"]
		}

		var port string
		if _, ok := details["port"]; !ok {
			port = "3306"
		} else {
			port = details["port"]
		}

		dbConn, err := sql.Open("mysql", details["username"]+":"+details["password"]+"@"+"tcp("+host+":"+port+")/"+details["database"])
		if err != nil {
			log.Fatalf("Failed to open %s database connection: %s", instance, err.Error())
		}

		// Parse interval
		var interval time.Duration
		if ok := strings.Contains(ldSettings.Interval, "s"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "s", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Second * time.Duration(pInt)
		} else if ok := strings.Contains(ldSettings.Interval, "ms"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "ms", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Millisecond * time.Duration(pInt)
		} else if ok := strings.Contains(ldSettings.Interval, "m"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "m", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Minute * time.Duration(pInt)
		}

		dbStatus := make(chan bool)
		updateItemCH := make(chan bool)
		updateIconCH := make(chan bool)
		dbStatuses[i] = updateIconCH

		// Check database conenction
		go status.Check(dbConn, interval, dbStatus)

		go func() { // On db status channel update, push update to update item and update icon channels
			for live := range dbStatus {
				updateItemCH <- live
				updateIconCH <- live
			}
		}()

		go updateItem(updateItemCH, instance, item)

		i++
	}

	go updateIcon(dbStatuses)

	mOpenSettings := systray.AddMenuItem("Open Settings", "Settings")

	go func() { // Handle on click menu item handlers
		for {
			select {
			case <-mOpenSettings.ClickedCh: // On open settings click
				go openSettings()
			}
		}
	}()

	mExit := systray.AddMenuItem("Exit", "Exit Notifier")
	go func() { // On exit menu item click chanel read, exit system tray and app
		<-mExit.ClickedCh
		systray.Quit()
		fmt.Println("Exited")
		os.Exit(0)
	}()
}
<commit_msg>Update read settings to sleep for 30 seconds instead of waiting 30 seconds at the end of loop. Instead of waiting on ticker sending on channel<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	_ "github.com/go-sql-driver/mysql"

	"github.com/getlantern/systray"
	"github.com/sc7639/mysql-notifier/icon"
	"github.com/sc7639/mysql-notifier/status"
)

var settingsFolder string
var settingsPath string

func init() {
	var appData string
	if runtime.GOOS == "windows" {
		appData = os.Getenv("APPDATA")
		settingsFolder = appData + "/mysql-notifier"

	} else {
		appData = os.Getenv("HOME")
		settingsFolder = appData + "/.mysql-notifier"
	}

	if _, err := os.Stat(settingsFolder); os.IsNotExist(err) {
		os.Mkdir(settingsFolder, 0755)
	}

	settingsPath = settingsFolder + "/settings.yml"
}

type settings struct {
	Mysql    map[string]map[string]string `yml:"mysql"`
	Interval string                       `yml:"interval"`
}

var minSettings = settings{
	Mysql:    map[string]map[string]string{},
	Interval: "10s",
}

func main() {
	systray.Run(onReady)
}

func onReady() { // Set icon title and add menu items
	systray.SetTitle("MySQL Notifier")

	rdSettings := make(chan settings, 1)
	mI := make(chan map[string]map[string]string, 1)

	go addMenuItems(mI, rdSettings) // Add menu items

	go func() {
		defer close(rdSettings)
		defer close(mI)

		loaded, err := readSettings(rdSettings, mI)
		if loaded == false || err != nil {
			systray.SetIcon(icon.Red)
			systray.SetTooltip("Failed to load settings")

			// Try to open settings ever 30 seconds
			for {
				loaded, err := readSettings(rdSettings, mI)
				if loaded == false || err != nil {
					go openSettings()
				} else {
					systray.SetIcon(icon.Green)
					systray.SetTooltip("All OK")
					break
				}

				time.Sleep(time.Second * 30) // Sleep for 30 seconds
			}
		} else {
			systray.SetIcon(icon.Green)
			systray.SetTooltip("All OK")
		}
	}()
	// fmt.Printf("rdSettings: %v", <-rdSettings)
}

func addMenuItems(mysqlInstance chan map[string]map[string]string, rdSettings chan settings) {
	ldSettings := <-rdSettings

	dbStatuses := make([]chan bool, len(ldSettings.Mysql))
	var i = 0
	for instance, details := range <-mysqlInstance { // For each mysql instance create a new menu item
		instance = strings.Title(instance)
		item := systray.AddMenuItem(instance, instance)

		go func(title string, item *systray.MenuItem, details map[string]string) { // Handle on click of mysql instance menu item
			for {
				<-item.ClickedCh
				openMysqlCMD(details)
			}
		}(instance, item, details)

		// Create database connection
		var host string
		if _, ok := details["host"]; !ok {
			host = "127.0.0.1"
		} else {
			host = details["host"]
		}

		var port string
		if _, ok := details["port"]; !ok {
			port = "3306"
		} else {
			port = details["port"]
		}

		dbConn, err := sql.Open("mysql", details["username"]+":"+details["password"]+"@"+"tcp("+host+":"+port+")/"+details["database"])
		if err != nil {
			log.Fatalf("Failed to open %s database connection: %s", instance, err.Error())
		}

		// Parse interval
		var interval time.Duration
		if ok := strings.Contains(ldSettings.Interval, "s"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "s", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Second * time.Duration(pInt)
		} else if ok := strings.Contains(ldSettings.Interval, "ms"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "ms", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Millisecond * time.Duration(pInt)
		} else if ok := strings.Contains(ldSettings.Interval, "m"); ok {
			pInt, err := strconv.Atoi(strings.Replace(ldSettings.Interval, "m", "", -1))
			if err != nil {
				log.Panicf("Failed to parse interval format: %s", err.Error())
			}

			interval = time.Minute * time.Duration(pInt)
		}

		dbStatus := make(chan bool)
		updateItemCH := make(chan bool)
		updateIconCH := make(chan bool)
		dbStatuses[i] = updateIconCH

		// Check database conenction
		go status.Check(dbConn, interval, dbStatus)

		go func() { // On db status channel update, push update to update item and update icon channels
			for live := range dbStatus {
				updateItemCH <- live
				updateIconCH <- live
			}
		}()

		go updateItem(updateItemCH, instance, item)

		i++
	}

	go updateIcon(dbStatuses)

	mOpenSettings := systray.AddMenuItem("Open Settings", "Settings")

	go func() { // Handle on click menu item handlers
		for {
			select {
			case <-mOpenSettings.ClickedCh: // On open settings click
				go openSettings()
			}
		}
	}()

	mExit := systray.AddMenuItem("Exit", "Exit Notifier")
	go func() { // On exit menu item click chanel read, exit system tray and app
		<-mExit.ClickedCh
		systray.Quit()
		fmt.Println("Exited")
		os.Exit(0)
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
)

var (
	dpasteUrl string = "https://dpaste.de/api/"
	lexer     string
	filename  string
)

func init() {
	flag.StringVar(&lexer, "lexer", "go", "lexer options are: python, go, c, mysql, ...")
}

func main() {
	flag.Parse()
	var bufInput bytes.Buffer

	var writers []io.Writer
	writers = append(writers, os.Stdout)
	writers = append(writers, &bufInput)
	mWriter := io.MultiWriter(writers...)

	if len(os.Args) == 1 {
		mReader := io.MultiReader(os.Stdin, os.Stderr)
		if _, err := io.Copy(mWriter, mReader); err != nil {
			log.Fatal("Error while copying from stdin to stdout", err)
		}
	} else {
		for _, filename = range os.Args[1:] {
			fh, err := os.Open(filename)
			if err != nil {
				log.Fatal("Error while opening:", filename, err)
			}
			_, err = io.Copy(mWriter, fh)
			if err != nil {
				log.Fatal("Error while copying:", filename, err)
			}
		}
	}

	u, err := url.ParseRequestURI(dpasteUrl)
	if err != nil {
		log.Fatal("Error while parsing dpasteUrl", err)
	}

	var b bytes.Buffer
	w := multipart.NewWriter(&b)
	// Add field content
	fw, err := w.CreateFormField("content")
	if err != nil {
		log.Fatal("Error while creating `content` field", err)
	}
	if _, err := fw.Write(bufInput.Bytes()); err != nil {
		log.Fatal("Error while writing to `content` field", err)
	}
	fw, err = w.CreateFormField("lexer")
	if err != nil {
		log.Fatal("Error while creating `lexer` field", err)
	}
	if _, err := fw.Write([]byte(lexer)); err != nil {
		log.Fatal("Error while writing to `lexer` field", err)
	}
	if filename != "" {
		fw, err = w.CreateFormField("filename")
		if err != nil {
			log.Fatal("Error while creating `filename` field", err)
		}
		if _, err := fw.Write([]byte(filename)); err != nil {
			log.Fatal("Error while writing to `filename` field", err)
		}
	}
	// Don't forget to close the multipart writer.
	// If you don't close it, your request will be missing the terminating boundary.
	w.Close()

	// Now that you have a form, you can submit it to your handler.
	req, err := http.NewRequest("POST", u.String(), &b)
	if err != nil {
		log.Fatalf("Error while building the request to dpaste:", err)
	}
	// Don't forget to set the content type, this will contain the boundary.
	req.Header.Set("Content-Type", w.FormDataContentType())

	// Submit the request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Error while posting to dpaste:", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Error while reading the response Body:", err)
	}
	fmt.Println("\n\ndpasted :", string(body)[1:len(string(body))-1])
}
<commit_msg>Void the lexer if we have a filename<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
)

var (
	dpasteUrl string = "https://dpaste.de/api/"
	lexer     string
	filename  string
)

func init() {
	flag.StringVar(&lexer, "lexer", "default", "lexer options are: python, go, c, mysql, ...")
}

func main() {
	flag.Parse()
	var bufInput bytes.Buffer

	var writers []io.Writer
	writers = append(writers, os.Stdout)
	writers = append(writers, &bufInput)
	mWriter := io.MultiWriter(writers...)

	if len(os.Args) == 1 {
		mReader := io.MultiReader(os.Stdin, os.Stderr)
		if _, err := io.Copy(mWriter, mReader); err != nil {
			log.Fatal("Error while copying from stdin to stdout", err)
		}
	} else {
		for _, filename = range os.Args[1:] {
			fh, err := os.Open(filename)
			if err != nil {
				log.Fatal("Error while opening:", filename, err)
			}
			_, err = io.Copy(mWriter, fh)
			if err != nil {
				log.Fatal("Error while copying:", filename, err)
			}
		}
	}

	if lexer == "default" && filename == "" {
		lexer = "GO"
	} else if lexer == "default" && filename != "" {
		lexer = ""
	}

	u, err := url.ParseRequestURI(dpasteUrl)
	if err != nil {
		log.Fatal("Error while parsing dpasteUrl", err)
	}

	var b bytes.Buffer
	w := multipart.NewWriter(&b)
	// Add field content
	fw, err := w.CreateFormField("content")
	if err != nil {
		log.Fatal("Error while creating `content` field", err)
	}
	if _, err := fw.Write(bufInput.Bytes()); err != nil {
		log.Fatal("Error while writing to `content` field", err)
	}
	fw, err = w.CreateFormField("lexer")
	if err != nil {
		log.Fatal("Error while creating `lexer` field", err)
	}
	if _, err := fw.Write([]byte(lexer)); err != nil {
		log.Fatal("Error while writing to `lexer` field", err)
	}
	if filename != "" {
		fw, err = w.CreateFormField("filename")
		if err != nil {
			log.Fatal("Error while creating `filename` field", err)
		}
		if _, err := fw.Write([]byte(filename)); err != nil {
			log.Fatal("Error while writing to `filename` field", err)
		}
	}
	// Don't forget to close the multipart writer.
	// If you don't close it, your request will be missing the terminating boundary.
	w.Close()

	// Now that you have a form, you can submit it to your handler.
	req, err := http.NewRequest("POST", u.String(), &b)
	if err != nil {
		log.Fatalf("Error while building the request to dpaste:", err)
	}
	// Don't forget to set the content type, this will contain the boundary.
	req.Header.Set("Content-Type", w.FormDataContentType())

	// Submit the request
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("Error while posting to dpaste:", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Error while reading the response Body:", err)
	}
	fmt.Println("\n\ndpasted :", string(body)[1:len(string(body))-1])
}
<|endoftext|>


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

package main

import (
	. "github.com/kahing/goofys/internal"

	"fmt"
	"os"
	"os/signal"
	"strings"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"

	"github.com/codegangsta/cli"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"

	"github.com/Sirupsen/logrus"

	daemon "github.com/sevlyar/go-daemon"
)

var log = GetLogger("main")

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			log.Println("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Error("Failed to unmount in response to SIGINT: %v", err)
			} else {
				log.Printf("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *FlagStorage) (mfs *fuse.MountedFileSystem, err error) {

	awsConfig := &aws.Config{
		Region: aws.String("us-west-2"),
		Logger: GetLogger("s3"),
		//LogLevel: aws.LogLevel(aws.LogDebug),
	}
	if len(flags.Endpoint) > 0 {
		awsConfig.Endpoint = &flags.Endpoint
	}
	if flags.UsePathRequest {
		awsConfig.S3ForcePathStyle = aws.Bool(true)
	}

	goofys := NewGoofys(bucketName, awsConfig, flags)
	if goofys == nil {
		err = fmt.Errorf("Mount: initialization failed")
		return
	}
	server := fuseutil.NewFileSystemServer(goofys)

	fuseLog := GetLogger("fuse")

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:                  bucketName,
		Options:                 flags.MountOptions,
		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
		DisableWritebackCaching: true,
	}

	if flags.DebugFuse {
		fuseLog.Level = logrus.DebugLevel
		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}

func massagePath() {
	for _, e := range os.Environ() {
		if strings.HasPrefix(e, "PATH=") {
			return
		}
	}

	// mount -a seems to run goofys without PATH
	// usually fusermount is in /bin
	os.Setenv("PATH", "/bin")
}

func main() {
	app := NewApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := PopulateFlags(c)

		if !flags.Foreground {
			ctx := new(daemon.Context)
			child, err := ctx.Reborn()

			if err != nil {
				panic(fmt.Sprintf("unable to daemonize: %v", err))
			}

			if child != nil {
				return
			} else {
				defer ctx.Release()

				massagePath()
			}

		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

	err := app.Run(MassageMountFlags(os.Args))
	if err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>workaround a go-daemon bug<commit_after>// Copyright 2015 Ka-Hing Cheung
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	. "github.com/kahing/goofys/internal"

	"fmt"
	"os"
	"os/signal"
	"strings"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"

	"github.com/codegangsta/cli"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"

	"github.com/kardianos/osext"

	"github.com/Sirupsen/logrus"

	daemon "github.com/sevlyar/go-daemon"
)

var log = GetLogger("main")

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			log.Println("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Error("Failed to unmount in response to SIGINT: %v", err)
			} else {
				log.Printf("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *FlagStorage) (mfs *fuse.MountedFileSystem, err error) {

	awsConfig := &aws.Config{
		Region: aws.String("us-west-2"),
		Logger: GetLogger("s3"),
		//LogLevel: aws.LogLevel(aws.LogDebug),
	}
	if len(flags.Endpoint) > 0 {
		awsConfig.Endpoint = &flags.Endpoint
	}
	if flags.UsePathRequest {
		awsConfig.S3ForcePathStyle = aws.Bool(true)
	}

	goofys := NewGoofys(bucketName, awsConfig, flags)
	if goofys == nil {
		err = fmt.Errorf("Mount: initialization failed")
		return
	}
	server := fuseutil.NewFileSystemServer(goofys)

	fuseLog := GetLogger("fuse")

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:                  bucketName,
		Options:                 flags.MountOptions,
		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
		DisableWritebackCaching: true,
	}

	if flags.DebugFuse {
		fuseLog.Level = logrus.DebugLevel
		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}

func massagePath() {
	for _, e := range os.Environ() {
		if strings.HasPrefix(e, "PATH=") {
			return
		}
	}

	// mount -a seems to run goofys without PATH
	// usually fusermount is in /bin
	os.Setenv("PATH", "/bin")
}

func massageArg0() {
	var err error
	os.Args[0], err = osext.Executable()
	if err != nil {
		panic(fmt.Sprintf("Unable to discover current executable: %v", err))
	}
}

func main() {
	app := NewApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := PopulateFlags(c)

		if !flags.Foreground {
			massageArg0()

			ctx := new(daemon.Context)
			child, err := ctx.Reborn()

			if err != nil {
				panic(fmt.Sprintf("unable to daemonize: %v", err))
			}

			if child != nil {
				return
			} else {
				defer ctx.Release()

				massagePath()
			}

		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

	err := app.Run(MassageMountFlags(os.Args))
	if err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s MOUNTPOINT\n", os.Args[0])
	flag.PrintDefaults()
}

func dbg(msg interface{}) {
	log.Println(msg)
}

func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	return false
}

func main() {
	flag.Usage = Usage
	flag.Parse()

	if flag.NArg() != 1 {
		Usage()
		os.Exit(2)
	}
	mountpoint := flag.Arg(0)

	c, err := fuse.Mount(mountpoint)
	if err != nil {
		log.Fatal(err)
	}

	you, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}

	if !exists(you.HomeDir + "/fstorage") {
		err := os.Mkdir(you.HomeDir + "/fstorage", 0700)
		if err != nil {
			log.Fatal(err)
		}
	}
	if !exists(you.HomeDir + "/fstorage/files") {
		err := os.Mkdir(you.HomeDir + "/fstorage/files", 0700)
		if err != nil {
			log.Fatal(err)
		}
	}

	myfs, err := newfs(you.HomeDir + "/fstorage")
	if err != nil {
		log.Fatal(err)
	}
	defer myfs.CloseBolt()

	err = myfs.SpawnAdminConsole()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("fs ready (admin console: nc localhost 2000)")

	server := fs.Server{
		FS: myfs,
//		Debug: dbg,
	}
	server.Serve(c)

	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}

<commit_msg>Add a little message about clean shutdown<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/user"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s MOUNTPOINT\n", os.Args[0])
	flag.PrintDefaults()
}

func dbg(msg interface{}) {
	log.Println(msg)
}

func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	return false
}

func main() {
	flag.Usage = Usage
	flag.Parse()

	if flag.NArg() != 1 {
		Usage()
		os.Exit(2)
	}
	mountpoint := flag.Arg(0)

	c, err := fuse.Mount(mountpoint)
	if err != nil {
		log.Fatal(err)
	}

	you, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}

	if !exists(you.HomeDir + "/fstorage") {
		err := os.Mkdir(you.HomeDir + "/fstorage", 0700)
		if err != nil {
			log.Fatal(err)
		}
	}
	if !exists(you.HomeDir + "/fstorage/files") {
		err := os.Mkdir(you.HomeDir + "/fstorage/files", 0700)
		if err != nil {
			log.Fatal(err)
		}
	}

	myfs, err := newfs(you.HomeDir + "/fstorage")
	if err != nil {
		log.Fatal(err)
	}
	defer myfs.CloseBolt()

	err = myfs.SpawnAdminConsole()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("fs ready (admin console: nc localhost 2000)")

	server := fs.Server{
		FS: myfs,
//		Debug: dbg,
	}
	server.Serve(c)

	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}

	log.Println("shut down nicely")
}

<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"sort"
	"strings"
	"time"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	prgnames := ""
	prgs := ResolveDependencies([]string{prgnames})
	for _, prg := range prgs {
		install(prg)
	}
}

type Prg struct {
	name       string
	extractVer Extractor
	extractUrl Extractor
	folder     string
	cache      CacheGetter
}

type Arch struct {
	win32 string
	win64 string
}

func (a *Arch) Arch() string {
	// http://stackoverflow.com/questions/601089/detect-whether-current-windows-version-is-32-bit-or-64-bit
	if isdir, err := exists("C:\\Program Files (x86)"); isdir && err == nil {
		return a.win64
	} else if err != nil {
		fmt.Printf("Error checking C:\\Program Files (x86): '%v'", err)
		return ""
	}
	return a.win32
}

type fextract func(str string) string

type Extractor interface {
	ExtractFrom(str string) string
	Extract() string
	Next() Extractor
}

type CacheGetter interface {
	Get(resource string, name string) string
	Folder(name string) string
	Next() CacheGetter
}

type Cache struct {
	root string
}

func (c *Cache) Get(resource string, name string) string {
	dir := c.root + name
	if isdir, err := exists(dir); !isdir && err == nil {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			fmt.Printf("Error creating cache folder for name '%v': '%v'\n", dir, err)
		}
		return ""
	} else if err != nil {
		fmt.Println("Error while testing dir existence '%v': '%v'\n", dir, err)
		return ""
	}
	filepath := dir + "/" + getLastModifiedFile(dir)
	if f, err := os.Open(filepath); err != nil {
		fmt.Println("Error while reading content of '%v': '%v'\n", filepath, err)
		return ""
	} else {
		defer f.Close()
		content := ""
		reader := bufio.NewReader(f)
		if contents, err := ioutil.ReadAll(reader); err != nil {
			fmt.Println("Error while reading content of '%v': '%v'\n", filepath, err)
			return ""
		} else {
			content = string(contents)
		}
		return content
	}
}

func (c *Cache) Next() CacheGetter {
	return nil
}
func (c *Cache) Folder(name string) string {
	return c.root + name + "/"
}

type Extractable struct {
	data  string
	name  string
	self  Extractor
	next  Extractor
	cache CacheGetter
	arch  *Arch
}

func (e *Extractable) Next() Extractor {
	return e.next
}

func (e *Extractable) Extract() string {
	res := e.self.ExtractFrom(e.data)
	if e.Next() != nil {
		res = e.Next().ExtractFrom(res)
	}
	return res
}

type ExtractorUrl struct {
	Extractable
}

func (eu *ExtractorUrl) ExtractFrom(url string) string {
	fmt.Println("ok! " + url)
	page := eu.cache.Get(url, eu.name)
	if page == "" {
		t := time.Now()
		filename := eu.cache.Folder(eu.name) + "_" + t.Format("20060102") + "_" + t.Format("150405")
		fmt.Println(filename)
		fmt.Println("empty page for " + url)
		response, err := http.Get(url)
		if err != nil {
			fmt.Println("Error while downloading", url, "-", err)
			return ""
		}
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Println("Error while reading downloaded", url, "-", err)
			return ""
		}
		err = ioutil.WriteFile(filename, body, 0666)
		if err != nil {
			fmt.Printf("Error while writing downloaded '%v': '%v'\n", url, err)
			return ""
		}
		defer response.Body.Close()
		page = string(body)
		fmt.Printf("downloaded '%v' to cache '%v'\n", url, filename)
	} else {
		fmt.Printf("Got '%v' from cache\n", url)
	}
	fmt.Println(len(page))
	return page
}

func NewExtractorUrl(uri string, cache CacheGetter, name string, arch *Arch) *ExtractorUrl {
	res := &ExtractorUrl{Extractable{data: uri, cache: cache, name: name, arch: arch}}
	res.self = res
	return res
}

type ExtractorMatch struct {
	Extractable
	regexp *regexp.Regexp
}

func (eu *ExtractorMatch) ExtractFrom(content string) string {
	rx := eu.Regexp()
	matches := rx.FindAllStringSubmatchIndex(content, -1)
	res := ""
	if len(matches) >= 1 && len(matches[0]) >= 4 {
		res = content[matches[0][2]:matches[0][3]]
		fmt.Printf("RES='%v'\n", res)
	}
	return res
}

func (em *ExtractorMatch) Regexp() *regexp.Regexp {
	if em.regexp == nil {
		rx := em.data
		if em.arch != nil {
			rx := strings.Replace(rx, "_$arch_", em.arch.Arch(), -1)
			var err error = nil
			if em.regexp, err = regexp.Compile(rx); err != nil {
				em.regexp = nil
				fmt.Printf("Error compiling Regexp for '%v': '%v' => err '%v'", em.name, rx, err)
			}
		}

	}
	return em.regexp
}

func ResolveDependencies(prgnames []string) []*Prg {
	cache := &Cache{root: "test/_cache/"}
	if isdir, err := exists("test/_cache/"); !isdir && err == nil {
		err := os.MkdirAll(cache.root, 0755)
		if err != nil {
			fmt.Printf("Error creating cache root folder: '%v'\n", err)
		}
	} else if err != nil {
		fmt.Printf("Error while checking existence of cache root folder: '%v'\n", err)
	}
	arch := &Arch{win32: "WINDOWS", win64: "WIN64"}
	dwnl := NewExtractorUrl("http://peazip.sourceforge.net/peazip-portable.html", cache, "peazip", arch)
	rx := &ExtractorMatch{Extractable{data: `/(peazip_portable-.*?\._$arch_).zip/download`, cache: cache, name: "peazip", arch: arch}, nil}
	dwnl.next = rx
	prgPeazip := &Prg{name: "peazip", extractVer: dwnl, cache: cache}
	prgGit := &Prg{name: "git"}
	prgInvalid := &Prg{name: "invalid"}
	return []*Prg{prgPeazip, prgGit, prgInvalid}
}

func install(prg *Prg) {
	folder := prg.GetFolder()
	if folder == "" {
		return
	}
	folder = "test/" + prg.name + "/" + folder
	if hasFolder, err := exists(folder); !hasFolder && err == nil {
		fmt.Printf("Need to install %v in '%v'\n", prg.name, folder)
		archive := prg.ArchiveName()
		fmt.Printf("Archive name: '%v'\n", archive)
	}
}

func (prg *Prg) ArchiveName() string {
	res := ""
	if prg.extractUrl != nil {
		res = prg.extractUrl.Extract()
	}
	return res
}

func (prg *Prg) GetFolder() string {
	if prg.folder == "" {
		if prg.extractVer != nil {
			prg.folder = prg.extractVer.Extract()
		}
	}
	return prg.folder
}

// exists returns whether the given file or directory exists or not
// http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// https://groups.google.com/forum/#!topic/golang-nuts/Q7hYQ9GdX9Q

type byDate []os.FileInfo

func (f byDate) Len() int {
	return len(f)
}
func (f byDate) Less(i, j int) bool {
	return f[i].ModTime().Unix() > f[j].ModTime().Unix()
}
func (f byDate) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func getLastModifiedFile(dir string) string {
	f, err := os.Open(dir)
	if err != nil {
		fmt.Printf("Error while opening dir '%v': '%v'\n", dir, err)
		return ""
	}
	list, err := f.Readdir(-1)
	if err != nil {
		fmt.Printf("Error while reading dir '%v': '%v'\n", dir, err)
		return ""
	}
	if len(list) == 0 {
		return ""
	}
	fmt.Printf("t: '%v' => '%v'\n", list, list[0])
	sort.Sort(byDate(list))
	fmt.Printf("t: '%v' => '%v'\n", list, list[0])
	return list[0].Name()
}
<commit_msg>ExtractorUrl.ExtractFrom() fix on filename.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"sort"
	"strings"
	"time"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	prgnames := ""
	prgs := ResolveDependencies([]string{prgnames})
	for _, prg := range prgs {
		install(prg)
	}
}

type Prg struct {
	name       string
	extractVer Extractor
	extractUrl Extractor
	folder     string
	cache      CacheGetter
}

type Arch struct {
	win32 string
	win64 string
}

func (a *Arch) Arch() string {
	// http://stackoverflow.com/questions/601089/detect-whether-current-windows-version-is-32-bit-or-64-bit
	if isdir, err := exists("C:\\Program Files (x86)"); isdir && err == nil {
		return a.win64
	} else if err != nil {
		fmt.Printf("Error checking C:\\Program Files (x86): '%v'", err)
		return ""
	}
	return a.win32
}

type fextract func(str string) string

type Extractor interface {
	ExtractFrom(str string) string
	Extract() string
	Next() Extractor
}

type CacheGetter interface {
	Get(resource string, name string) string
	Folder(name string) string
	Next() CacheGetter
}

type Cache struct {
	root string
}

func (c *Cache) Get(resource string, name string) string {
	dir := c.root + name
	if isdir, err := exists(dir); !isdir && err == nil {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			fmt.Printf("Error creating cache folder for name '%v': '%v'\n", dir, err)
		}
		return ""
	} else if err != nil {
		fmt.Println("Error while testing dir existence '%v': '%v'\n", dir, err)
		return ""
	}
	filepath := dir + "/" + getLastModifiedFile(dir)
	if f, err := os.Open(filepath); err != nil {
		fmt.Println("Error while reading content of '%v': '%v'\n", filepath, err)
		return ""
	} else {
		defer f.Close()
		content := ""
		reader := bufio.NewReader(f)
		if contents, err := ioutil.ReadAll(reader); err != nil {
			fmt.Println("Error while reading content of '%v': '%v'\n", filepath, err)
			return ""
		} else {
			content = string(contents)
		}
		return content
	}
}

func (c *Cache) Next() CacheGetter {
	return nil
}
func (c *Cache) Folder(name string) string {
	return c.root + name + "/"
}

type Extractable struct {
	data  string
	name  string
	self  Extractor
	next  Extractor
	cache CacheGetter
	arch  *Arch
}

func (e *Extractable) Next() Extractor {
	return e.next
}

func (e *Extractable) Extract() string {
	res := e.self.ExtractFrom(e.data)
	if e.Next() != nil {
		res = e.Next().ExtractFrom(res)
	}
	return res
}

type ExtractorUrl struct {
	Extractable
}

func (eu *ExtractorUrl) ExtractFrom(url string) string {
	fmt.Println("ok! " + url)
	page := eu.cache.Get(url, eu.name)
	if page == "" {
		t := time.Now()
		filename := eu.cache.Folder(eu.name) + eu.name + "_" + t.Format("20060102") + "_" + t.Format("150405")
		fmt.Println(filename)
		fmt.Println("empty page for " + url)
		response, err := http.Get(url)
		if err != nil {
			fmt.Println("Error while downloading", url, "-", err)
			return ""
		}
		body, err := ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Println("Error while reading downloaded", url, "-", err)
			return ""
		}
		err = ioutil.WriteFile(filename, body, 0666)
		if err != nil {
			fmt.Printf("Error while writing downloaded '%v': '%v'\n", url, err)
			return ""
		}
		defer response.Body.Close()
		page = string(body)
		fmt.Printf("downloaded '%v' to cache '%v'\n", url, filename)
	} else {
		fmt.Printf("Got '%v' from cache\n", url)
	}
	fmt.Println(len(page))
	return page
}

func NewExtractorUrl(uri string, cache CacheGetter, name string, arch *Arch) *ExtractorUrl {
	res := &ExtractorUrl{Extractable{data: uri, cache: cache, name: name, arch: arch}}
	res.self = res
	return res
}

type ExtractorMatch struct {
	Extractable
	regexp *regexp.Regexp
}

func (eu *ExtractorMatch) ExtractFrom(content string) string {
	rx := eu.Regexp()
	matches := rx.FindAllStringSubmatchIndex(content, -1)
	res := ""
	if len(matches) >= 1 && len(matches[0]) >= 4 {
		res = content[matches[0][2]:matches[0][3]]
		fmt.Printf("RES='%v'\n", res)
	}
	return res
}

func (em *ExtractorMatch) Regexp() *regexp.Regexp {
	if em.regexp == nil {
		rx := em.data
		if em.arch != nil {
			rx := strings.Replace(rx, "_$arch_", em.arch.Arch(), -1)
			var err error = nil
			if em.regexp, err = regexp.Compile(rx); err != nil {
				em.regexp = nil
				fmt.Printf("Error compiling Regexp for '%v': '%v' => err '%v'", em.name, rx, err)
			}
		}

	}
	return em.regexp
}

func ResolveDependencies(prgnames []string) []*Prg {
	cache := &Cache{root: "test/_cache/"}
	if isdir, err := exists("test/_cache/"); !isdir && err == nil {
		err := os.MkdirAll(cache.root, 0755)
		if err != nil {
			fmt.Printf("Error creating cache root folder: '%v'\n", err)
		}
	} else if err != nil {
		fmt.Printf("Error while checking existence of cache root folder: '%v'\n", err)
	}
	arch := &Arch{win32: "WINDOWS", win64: "WIN64"}
	dwnl := NewExtractorUrl("http://peazip.sourceforge.net/peazip-portable.html", cache, "peazip", arch)
	rx := &ExtractorMatch{Extractable{data: `/(peazip_portable-.*?\._$arch_).zip/download`, cache: cache, name: "peazip", arch: arch}, nil}
	dwnl.next = rx
	prgPeazip := &Prg{name: "peazip", extractVer: dwnl, cache: cache}
	prgGit := &Prg{name: "git"}
	prgInvalid := &Prg{name: "invalid"}
	return []*Prg{prgPeazip, prgGit, prgInvalid}
}

func install(prg *Prg) {
	folder := prg.GetFolder()
	if folder == "" {
		return
	}
	folder = "test/" + prg.name + "/" + folder
	if hasFolder, err := exists(folder); !hasFolder && err == nil {
		fmt.Printf("Need to install %v in '%v'\n", prg.name, folder)
		archive := prg.ArchiveName()
		fmt.Printf("Archive name: '%v'\n", archive)
	}
}

func (prg *Prg) ArchiveName() string {
	res := ""
	if prg.extractUrl != nil {
		res = prg.extractUrl.Extract()
	}
	return res
}

func (prg *Prg) GetFolder() string {
	if prg.folder == "" {
		if prg.extractVer != nil {
			prg.folder = prg.extractVer.Extract()
		}
	}
	return prg.folder
}

// exists returns whether the given file or directory exists or not
// http://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-denoted-by-a-path-exists-in-golang
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// https://groups.google.com/forum/#!topic/golang-nuts/Q7hYQ9GdX9Q

type byDate []os.FileInfo

func (f byDate) Len() int {
	return len(f)
}
func (f byDate) Less(i, j int) bool {
	return f[i].ModTime().Unix() > f[j].ModTime().Unix()
}
func (f byDate) Swap(i, j int) {
	f[i], f[j] = f[j], f[i]
}

func getLastModifiedFile(dir string) string {
	f, err := os.Open(dir)
	if err != nil {
		fmt.Printf("Error while opening dir '%v': '%v'\n", dir, err)
		return ""
	}
	list, err := f.Readdir(-1)
	if err != nil {
		fmt.Printf("Error while reading dir '%v': '%v'\n", dir, err)
		return ""
	}
	if len(list) == 0 {
		return ""
	}
	fmt.Printf("t: '%v' => '%v'\n", list, list[0])
	sort.Sort(byDate(list))
	fmt.Printf("t: '%v' => '%v'\n", list, list[0])
	return list[0].Name()
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"os/exec"
	"time"
)

func main() {
	if len(os.Args) == 0 {
		log.Fatal("Please put a command after this.")
	}
	cmd := exec.Command(os.Args[0], os.Args[1:]...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
}

func monitor(poke chan bool) {
	for {
		select {
		case <-poke:
			// a read from ch has occurred
		case <-time.Sleep(time.Minute):
			// the read from ch has timed out
		}
	}
}
<commit_msg>Fixed build error caused by me forgetting how to timeout chans<commit_after>package main

import (
	"log"
	"os"
	"os/exec"
	"time"
)

func main() {
	if len(os.Args) == 0 {
		log.Fatal("Please put a command after this.")
	}
	cmd := exec.Command(os.Args[0], os.Args[1:]...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
}

func monitor(poke chan bool) {
	for {
		select {
		case <-poke:
			// a read from ch has occurred
		case <-time.After(time.Minute):
			// the read from ch has timed out
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/prometheus/common/log"
	"github.com/soniah/gosnmp"
	"gopkg.in/yaml.v2"
)

var (
	configFile = flag.String(
		"config.file", "snmp.yml",
		"Path to configuration file.",
	)
	listenAddress = flag.String(
		"web.listen-address", ":9104",
		"Address to listen on for web interface and telemetry.",
	)
)

func LoadFile(filename string) (*Config, error) {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	cfg := &Config{}
	err = yaml.Unmarshal(content, cfg)
	if err != nil {
		return nil, err
	}
	return cfg, nil
}

type Config map[string]*Module

type Module struct {
	// A list of OIDs.
	Walk    []string  `yaml:"walk"`
	Metrics []*Metric `yaml:"metrics"`
	// TODO: Security

	// TODO: Use these.
	XXX map[string]interface{} `yaml:",inline"`
}

type Metric struct {
	Name    string    `yaml:"name"`
	Oid     string    `yaml:"oid"`
	Indexes []*Index  `yaml:"indexes,omitempty"`
	Lookups []*Lookup `yaml:"lookups,omitempty"`

	XXX map[string]interface{} `yaml:",inline"`
}

type Index struct {
	Labelname string `yaml:"labelname"`
	Type      string `yaml:"type"`

	XXX map[string]interface{} `yaml:",inline"`
}

type Lookup struct {
	Labels    []string `yaml:"labels"`
	Labelname string   `yaml:"labelname"`
	Oid       string   `yaml:"oid"`

	XXX map[string]interface{} `yaml:",inline"`
}

func OidToList(oid string) []int {
	result := []int{}
	for _, x := range strings.Split(oid, ".") {
		o, _ := strconv.Atoi(x)
		result = append(result, o)
	}
	return result
}

func ScrapeTarget(target string, config *Module) ([]gosnmp.SnmpPDU, error) {
	// Set the options.
	snmp := gosnmp.GoSNMP{}
	snmp.Retries = 3
	snmp.MaxRepetitions = 25

	snmp.Target = target
	snmp.Port = 161
	if host, port, err := net.SplitHostPort(target); err == nil {
		snmp.Target = host
		p, err := strconv.Atoi(port)
		if err != nil {
			return nil, fmt.Errorf("Error converting port number to int for target %s: %s", target, err)
		}
		snmp.Port = uint16(p)
	}

	snmp.Version = gosnmp.Version2c
	snmp.Community = "public"
	snmp.Timeout = time.Second * 60

	// Do the actual walk.
	err := snmp.Connect()
	if err != nil {
		return nil, fmt.Errorf("Error connecting to target %s: %s", target, err)
	}
	defer snmp.Conn.Close()

	result := []gosnmp.SnmpPDU{}
	for _, subtree := range config.Walk {
		var pdus []gosnmp.SnmpPDU
		if snmp.Version == gosnmp.Version1 {
			pdus, err = snmp.WalkAll(subtree)
		} else {
			pdus, err = snmp.BulkWalkAll(subtree)
		}
		if err != nil {
			return nil, fmt.Errorf("Error walking target %s: %s", snmp.Target, err)
		}
		result = append(result, pdus...)
	}
	return result, nil
}

type MetricNode struct {
	metric  *Metric
	oidList []int

	children map[int]*MetricNode
}

// Build a tree of metrics from the config, for fast lookup when there's lots of them.
func buildMetricTree(metrics []*Metric) *MetricNode {
	metricTree := &MetricNode{children: map[int]*MetricNode{}}
	for _, metric := range metrics {
		head := metricTree
		for _, o := range OidToList(metric.Oid) {
			_, ok := head.children[o]
			if !ok {
				head.children[o] = &MetricNode{children: map[int]*MetricNode{}}
			}
			head = head.children[o]
		}
		head.metric = metric
		head.oidList = OidToList(metric.Oid)
	}
	return metricTree
}

func main() {
	flag.Parse()

	cfg, err := LoadFile(*configFile)
	if err != nil {
		log.Errorf("Error parsing config file: %s", err)
		return
	}
	_ = cfg

	module := (*cfg)["default"]
	metricTree := buildMetricTree(module.Metrics)

	pdus, err := ScrapeTarget("192.168.1.2", module)
	oidToPdu := make(map[string]*gosnmp.SnmpPDU, len(pdus))
	for _, pdu := range pdus {
		oidToPdu[pdu.Name[1:]] = &pdu
	}

	// Look for metrics that match each pdu.
PduLoop:
	for oid, pdu := range oidToPdu {
		head := metricTree
		oidList := OidToList(oid)
		for _, o := range oidList {
			var ok bool
			head, ok = head.children[o]
			if !ok {
				continue PduLoop
			}
			if head.metric != nil {
				// Found a match.
				fmt.Printf("Metric: %s Value: %s Remaining Oid: %s\n", head.metric.Name, pdu.Value, oidList[len(head.oidList):])
				break
			}
		}
	}
}
<commit_msg>Add HTTP, more refactoring.<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/log"
	"github.com/soniah/gosnmp"
	"gopkg.in/yaml.v2"
)

var (
	configFile = flag.String(
		"config.file", "snmp.yml",
		"Path to configuration file.",
	)
	listenAddress = flag.String(
		"web.listen-address", ":9116",
		"Address to listen on for web interface and telemetry.",
	)
)

func LoadFile(filename string) (*Config, error) {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	cfg := &Config{}
	err = yaml.Unmarshal(content, cfg)
	if err != nil {
		return nil, err
	}
	return cfg, nil
}

type Config map[string]*Module

type Module struct {
	// A list of OIDs.
	Walk    []string  `yaml:"walk"`
	Metrics []*Metric `yaml:"metrics"`
	// TODO: Security

	// TODO: Use these.
	XXX map[string]interface{} `yaml:",inline"`
}

type Metric struct {
	Name    string    `yaml:"name"`
	Oid     string    `yaml:"oid"`
	Indexes []*Index  `yaml:"indexes,omitempty"`
	Lookups []*Lookup `yaml:"lookups,omitempty"`

	XXX map[string]interface{} `yaml:",inline"`
}

type Index struct {
	Labelname string `yaml:"labelname"`
	Type      string `yaml:"type"`

	XXX map[string]interface{} `yaml:",inline"`
}

type Lookup struct {
	Labels    []string `yaml:"labels"`
	Labelname string   `yaml:"labelname"`
	Oid       string   `yaml:"oid"`

	XXX map[string]interface{} `yaml:",inline"`
}

func OidToList(oid string) []int {
	result := []int{}
	for _, x := range strings.Split(oid, ".") {
		o, _ := strconv.Atoi(x)
		result = append(result, o)
	}
	return result
}

func ScrapeTarget(target string, config *Module) ([]gosnmp.SnmpPDU, error) {
	// Set the options.
	snmp := gosnmp.GoSNMP{}
	snmp.Retries = 3
	snmp.MaxRepetitions = 25

	snmp.Target = target
	snmp.Port = 161
	if host, port, err := net.SplitHostPort(target); err == nil {
		snmp.Target = host
		p, err := strconv.Atoi(port)
		if err != nil {
			return nil, fmt.Errorf("Error converting port number to int for target %s: %s", target, err)
		}
		snmp.Port = uint16(p)
	}

	snmp.Version = gosnmp.Version2c
	snmp.Community = "public"
	snmp.Timeout = time.Second * 60

	// Do the actual walk.
	err := snmp.Connect()
	if err != nil {
		return nil, fmt.Errorf("Error connecting to target %s: %s", target, err)
	}
	defer snmp.Conn.Close()

	result := []gosnmp.SnmpPDU{}
	for _, subtree := range config.Walk {
		var pdus []gosnmp.SnmpPDU
		if snmp.Version == gosnmp.Version1 {
			pdus, err = snmp.WalkAll(subtree)
		} else {
			pdus, err = snmp.BulkWalkAll(subtree)
		}
		if err != nil {
			return nil, fmt.Errorf("Error walking target %s: %s", snmp.Target, err)
		}
		result = append(result, pdus...)
	}
	return result, nil
}

type MetricNode struct {
	metric  *Metric
	oidList []int

	children map[int]*MetricNode
}

// Build a tree of metrics from the config, for fast lookup when there's lots of them.
func buildMetricTree(metrics []*Metric) *MetricNode {
	metricTree := &MetricNode{children: map[int]*MetricNode{}}
	for _, metric := range metrics {
		head := metricTree
		for _, o := range OidToList(metric.Oid) {
			_, ok := head.children[o]
			if !ok {
				head.children[o] = &MetricNode{children: map[int]*MetricNode{}}
			}
			head = head.children[o]
		}
		head.metric = metric
		head.oidList = OidToList(metric.Oid)
	}
	return metricTree
}

type collector struct {
	target string
	module *Module
}

// Describe implements Prometheus.Collector.
func (c collector) Describe(ch chan<- *prometheus.Desc) {
	ch <- prometheus.NewDesc("dummy", "dummy", nil, nil)
}

func PduToSample(metric *Metric, pdu *gosnmp.SnmpPDU) prometheus.Metric {
	return prometheus.MustNewConstMetric(prometheus.NewDesc(metric.Name, "", []string{"label"}, nil),
		prometheus.UntypedValue,
		float64(gosnmp.ToBigInt(pdu.Value).Int64()),
		pdu.Name,
	)
}

// Collect implements Prometheus.Collector.
func (c collector) Collect(ch chan<- prometheus.Metric) {
	start := time.Now()
	pdus, err := ScrapeTarget(c.target, c.module)
	if err != nil {
		log.Errorf("Error scraping target %s: %s", c.target, err)
		return
	}
	ch <- prometheus.MustNewConstMetric(
		prometheus.NewDesc("snmp_scrape_walk_duration_seconds", "Time SNMP walk/bulkwalk took.", nil, nil),
		prometheus.GaugeValue,
		float64(time.Since(start).Seconds()))
	ch <- prometheus.MustNewConstMetric(
		prometheus.NewDesc("snmp_scrape_pdus_returned", "PDUs returned from walk.", nil, nil),
		prometheus.GaugeValue,
		float64(len(pdus)))
	oidToPdu := make(map[string]gosnmp.SnmpPDU, len(pdus))
	for _, pdu := range pdus {
		oidToPdu[pdu.Name[1:]] = pdu
	}

	metricTree := buildMetricTree(c.module.Metrics)
	// Look for metrics that match each pdu.
PduLoop:
	for oid, pdu := range oidToPdu {
		head := metricTree
		oidList := OidToList(oid)
		for _, o := range oidList {
			var ok bool
			head, ok = head.children[o]
			if !ok {
				continue PduLoop
			}
			if head.metric != nil {
				// Found a match.
				ch <- PduToSample(head.metric, &pdu)
				break
			}
		}
	}
	ch <- prometheus.MustNewConstMetric(
		prometheus.NewDesc("snmp_scrape_duration_seconds", "Total SNMP time scrape took (walk and processing).", nil, nil),
		prometheus.GaugeValue,
		float64(time.Since(start).Seconds()))
}

func handler(w http.ResponseWriter, r *http.Request) {
	cfg, err := LoadFile(*configFile)
	if err != nil {
		msg := fmt.Sprintf("Error parsing config file: %s", err)
		http.Error(w, msg, 400)
		log.Errorf(msg)
		return
	}

	target := r.URL.Query().Get("target")
	if target == "" {
		http.Error(w, "'target' parameter must be specified", 400)
		return
	}
	moduleName := r.URL.Query().Get("module")
	if moduleName == "" {
		moduleName = "default"
	}
	module, ok := (*cfg)[moduleName]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown module '%s'", module), 400)
		return
	}

	registry := prometheus.NewRegistry()
	collector := collector{target: target, module: module}
	registry.MustRegister(collector)
	// Delegate http serving to Promethues client library, which will call collector.Collect.
	h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
	h.ServeHTTP(w, r)
}

func main() {
	flag.Parse()

	http.Handle("/metrics", promhttp.Handler()) // Normal metrics endpoint for SNMP exporter itself.
	http.HandleFunc("/snmp", handler)           // Endpoint to do SNMP scrapes.
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"
)

func main() {
	var (
		forceFlag    = flag.Bool("f", false, "Force running the command even after giving up")
		timeoutFlag  = flag.Duration("t", 1*time.Minute, "Timeout duration before giving up")
		verbose1Flag = flag.Bool("v", false, "Set verbose output mode")
		verbose2Flag = flag.Bool("vv", false, "Set more verbose output mode")
		quietFlag    = flag.Bool("q", false, "Set quiet mode")
	)
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: await [options...] <res>... [ -- <cmd>]")
		fmt.Fprintln(os.Stderr, "Await availability of resources.")
		fmt.Fprintln(os.Stderr)
		flag.PrintDefaults()
	}
	flag.Parse()

	var logLevel int
	switch {
	case *quietFlag:
		logLevel = silentLevel
	case *verbose1Flag:
		logLevel = infoLevel
	case *verbose2Flag:
		logLevel = debugLevel
	default:
		logLevel = errorLevel
	}

	logger := NewLogger(logLevel)
	resArgs, cmdArgs := splitArgs(flag.Args())

	ress, err := parseResources(resArgs)
	if err != nil {
		logger.Fatalln("Error: failed to parse resources: %v", err)
	}

	awaiter := &awaiter{
		logger:  logger,
		timeout: *timeoutFlag,
	}

	if err := awaiter.run(ress); err != nil {
		if e, ok := err.(*unavailabilityError); ok {
			logger.Infof("Resource unavailable: %v", e)
			logger.Infoln("Timeout exceeded")
		} else {
			logger.Fatalln("Error: %v", err)
		}
		if !*forceFlag {
			os.Exit(1)
		}
	} else {
		logger.Infoln("All resources available")
	}

	if len(cmdArgs) > 0 {
		logger.Infof("Runnning command: %v", cmdArgs)
		if err := execCmd(cmdArgs); err != nil {
			logger.Fatalf("Error: failed to execute command: %v", err)
		}
	}
}

func splitArgs(args []string) ([]string, []string) {
	if i := indexOf(args, "--"); i >= 0 {
		return args[0:i], args[i+1:]
	}

	// We haven't seen a resource|command separator ('--'). This can either be
	// because of Go's flag parser removing the separator if no args were given,
	// or because there actually was none given.
	// Fallback to the original (unparsed) flag argument list and see if a
	// separator was given there and if, assume all arguments given are part of
	// the command, i.e. no resources at all were provided.
	if i := indexOf(os.Args, "--"); i >= 0 {
		return []string{}, args
	}

	// We still haven't seen a resource|command separator ('--'). Now finally
	// assume because there actually was none given and use all arguments as
	// resources.
	return args, []string{}
}

func indexOf(l []string, s string) int {
	for i, e := range l {
		if e == "--" {
			return i
		}
	}
	return -1
}

func execCmd(cmdArgs []string) error {
	path, err := exec.LookPath(cmdArgs[0])
	if err != nil {
		return err
	}
	return syscall.Exec(path, cmdArgs, os.Environ())
}
<commit_msg>Bring back error message on timeout when not in quiet mode<commit_after>// Copyright (c) 2016 Betalo AB
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"syscall"
	"time"
)

func main() {
	var (
		forceFlag    = flag.Bool("f", false, "Force running the command even after giving up")
		timeoutFlag  = flag.Duration("t", 1*time.Minute, "Timeout duration before giving up")
		verbose1Flag = flag.Bool("v", false, "Set verbose output mode")
		verbose2Flag = flag.Bool("vv", false, "Set more verbose output mode")
		quietFlag    = flag.Bool("q", false, "Set quiet mode")
	)
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: await [options...] <res>... [ -- <cmd>]")
		fmt.Fprintln(os.Stderr, "Await availability of resources.")
		fmt.Fprintln(os.Stderr)
		flag.PrintDefaults()
	}
	flag.Parse()

	var logLevel int
	switch {
	case *quietFlag:
		logLevel = silentLevel
	case *verbose1Flag:
		logLevel = infoLevel
	case *verbose2Flag:
		logLevel = debugLevel
	default:
		logLevel = errorLevel
	}

	logger := NewLogger(logLevel)
	resArgs, cmdArgs := splitArgs(flag.Args())

	ress, err := parseResources(resArgs)
	if err != nil {
		logger.Fatalln("Error: failed to parse resources: %v", err)
	}

	awaiter := &awaiter{
		logger:  logger,
		timeout: *timeoutFlag,
	}

	if err := awaiter.run(ress); err != nil {
		if e, ok := err.(*unavailabilityError); ok {
			logger.Errorf("Resource unavailable: %v", e)
			logger.Errorln("Timeout exceeded")
		} else {
			logger.Fatalln("Error: %v", err)
		}
		if !*forceFlag {
			os.Exit(1)
		}
	} else {
		logger.Infoln("All resources available")
	}

	if len(cmdArgs) > 0 {
		logger.Infof("Runnning command: %v", cmdArgs)
		if err := execCmd(cmdArgs); err != nil {
			logger.Fatalf("Error: failed to execute command: %v", err)
		}
	}
}

func splitArgs(args []string) ([]string, []string) {
	if i := indexOf(args, "--"); i >= 0 {
		return args[0:i], args[i+1:]
	}

	// We haven't seen a resource|command separator ('--'). This can either be
	// because of Go's flag parser removing the separator if no args were given,
	// or because there actually was none given.
	// Fallback to the original (unparsed) flag argument list and see if a
	// separator was given there and if, assume all arguments given are part of
	// the command, i.e. no resources at all were provided.
	if i := indexOf(os.Args, "--"); i >= 0 {
		return []string{}, args
	}

	// We still haven't seen a resource|command separator ('--'). Now finally
	// assume because there actually was none given and use all arguments as
	// resources.
	return args, []string{}
}

func indexOf(l []string, s string) int {
	for i, e := range l {
		if e == "--" {
			return i
		}
	}
	return -1
}

func execCmd(cmdArgs []string) error {
	path, err := exec.LookPath(cmdArgs[0])
	if err != nil {
		return err
	}
	return syscall.Exec(path, cmdArgs, os.Environ())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

func usage() {
	os.Stderr.WriteString(`
Usage: circlecrossgame [OPTION]...
Play circle cross game on terminal.

Options:
	--help       show this help message
	--version    print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.1.1
`[1:])
}

func _main() error {
	isHelp := flag.Bool("help", false, "")
	isVersion := flag.Bool("version", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	g := NewGame()
	if err := g.Init(); err != nil {
		return err
	}
	return g.Main()
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "circlecrossgame:", err)
		os.Exit(1)
	}
}
<commit_msg>Use own flag.FlagSet<commit_after>package main

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

func usage() {
	os.Stderr.WriteString(`
Usage: circlecrossgame [OPTION]...
Play circle cross game on terminal.

Options:
	--help       show this help message
	--version    print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.1.1
`[1:])
}

func _main() error {
	f := flag.NewFlagSet("circlecrossgame:", flag.ContinueOnError)
	f.SetOutput(ioutil.Discard)

	isHelp := f.Bool("help", false, "")
	isVersion := f.Bool("version", false, "")
	if err := f.Parse(os.Args[1:]); err != nil {
		return err
	}
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	g := NewGame()
	if err := g.Init(); err != nil {
		return err
	}
	return g.Main()
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "circlecrossgame:", err)
		os.Exit(1)
	}
}
<|endoftext|>