<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/phayes/hookserve/hookserve"
	"io"
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
)

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

	InitConfig()
	InitDB()
	InitANSI2HTML()

	// Set up HTTP paths
	githubreceive := hookserve.NewServer()
	if Config.Github.Enabled {
		githubreceive.Secret = Config.Github.Secret
		http.Handle("/postreceive", githubreceive)
		fmt.Println("Github webhook URL: http://" + Config.Host + ":" + strconv.Itoa(Config.Port) + "/postreceive")
	}
	http.HandleFunc("/", handleUI)

	// Listen and serve HTTP
	go func() {
		fmt.Println("Listening on port " + strconv.Itoa(Config.Port))
		err := http.ListenAndServe(":"+strconv.Itoa(Config.Port), nil)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	// Launch workers for running jobs
	// We have a number of workers equal to the number of cores
	for i := 1; i <= runtime.NumCPU(); i++ {
		go func() {
			for {
				event, err := PopEvent()
				if err != nil {
					log.Println(err)
				} else if event != nil {
					err = event.Report()
					if err != nil {
						log.Println(err)
					} else {
						go func() {
							status, err := event.Run()
							err = event.Finalize(status, err)
							if err != nil {
								log.Println(err)
							}
						}()
					}
				}
				time.Sleep(50 * time.Millisecond)
			}
		}()
	}

	// Loop for adding new events to the queue
	for {
		select {
		case commit := <-githubreceive.Events:
			event := Event{
				Event:  commit,
				Domain: "github.com", // For now we only support github
				Status: StatusPending,
				Time:   time.Now(),
			}

			// First check to see if the event already exists, and if it is reque it if it's not running
			checkEvent, err := GetEvent(event.Domain, event.Owner, event.Repo, event.Branch, event.Commit)
			if err != nil {
				log.Println(err)
			}
			if checkEvent != nil {
				// It's an old event, requeue it if we can
				if checkEvent.Status != StatusRunning {
					checkEvent.Status = StatusPending
					err = checkEvent.Update()
					if err != nil {
						log.Println(err)
					}
					err = checkEvent.Report()
					if err != nil {
						log.Println(err)
					}
				}
			} else {
				// It's a new event, insert it anew
				err = event.Insert()
				if err != nil {
					log.Println(err)
				}
				err = event.Report()
				if err != nil {
					log.Println(err)
				}
			}
		default:
			time.Sleep(50 * time.Millisecond)
		}
	}
}

// Handle regular UI requests
func handleUI(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	path, err := parsePath(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	// If it's a POST we re-run it
	if r.Method == "POST" {
		handleReRun(path, w, r)
		return
	}

	// Check the method
	if r.Method != "GET" {
		http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	if len(path) == 5 { // It's a single item
		handleView(path, w, r)
	} else { // It's an index request
		handleIndex(path, w, r)
	}
}

func handleReRun(path []string, w http.ResponseWriter, r *http.Request) {
	if len(path) != 5 {
		http.NotFound(w, r)
		return
	}

	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		// For now we only support github
		if path[0] != "github.com" {
			http.Error(w, "Only github.com currently supported", http.StatusInternalServerError)
		}

		// Event doesn't exist, create it and mark pending to queue it
		event := Event{
			Event: hookserve.Event{
				Owner:  path[1],
				Repo:   path[2],
				Branch: path[3],
				Commit: path[4],
			},
			Domain: "github.com", // For now we only support github
			Status: StatusPending,
			Time:   time.Now(),
		}
		err := event.Insert()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/"+event.Path(), http.StatusSeeOther)
	} else {
		if event.Status == StatusRunning {
			http.Error(w, "Unable to re-run already running item", http.StatusInternalServerError)
			return
		}

		// We have the event, run it again
		// Save it back to the database marked as running
		event.Status = StatusRunning
		event.Log = []byte("Retrying...\n")
		err := event.Update()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}

		go func() {
			status, err := event.Run()
			err = event.Finalize(status, err)
			if err != nil {
				log.Println(err)
			}
		}()

		http.Redirect(w, r, "/"+event.Path(), 303)
	}
}

func handleView(path []string, w http.ResponseWriter, r *http.Request) {
	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		http.NotFound(w, r)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(event, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else { // Serve HTML
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		ansi2html, err := ANSI2HTML(event.String())
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Print output
		fmt.Fprintln(w, "")
		io.Copy(w, ansi2html)
		if event.Status == StatusSuccess || event.Status == StatusFailed || event.Status == StatusFailedBoot {
			fmt.Fprintln(w, "<form method='POST'><input type='submit' value='re-run'></form>")
		}
		fmt.Fprintln(w, "")
	}
}

func handleIndex(path []string, w http.ResponseWriter, r *http.Request) {
	// Handle main index -- list all events
	events, err := GetEvents(path...)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(events, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else {
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		fmt.Fprintln(w, "
")
		for _, event := range events {
			fmt.Fprintln(w, "
")
			fmt.Fprintln(w, ""+event.Time.String()+"	"+event.Status+"	"+event.Path()+"	")
			fmt.Fprintln(w, "
")
		}
		fmt.Fprintln(w, "
")
	}
}

func parsePath(path string) ([]string, error) {
	parts := strings.Split(path, "/")
	if len(parts) > 6 {
		return nil, errors.New("Invalid Path")
	}
	// Filter illigal characters
	for _, part := range parts {
		if strings.ContainsAny(part, " \"\\\b\f\n\r\t\v") {
			return nil, errors.New("Illigal character in path")
		}
	}
	if len(parts) == 2 && parts[1] == "" {
		return make([]string, 0), nil
	} else {
		return parts[1:], nil
	}
}
<commit_msg>When a job is added manually, assign the  type<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/phayes/hookserve/hookserve"
	"io"
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
)

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

	InitConfig()
	InitDB()
	InitANSI2HTML()

	// Set up HTTP paths
	githubreceive := hookserve.NewServer()
	if Config.Github.Enabled {
		githubreceive.Secret = Config.Github.Secret
		http.Handle("/postreceive", githubreceive)
		fmt.Println("Github webhook URL: http://" + Config.Host + ":" + strconv.Itoa(Config.Port) + "/postreceive")
	}
	http.HandleFunc("/", handleUI)

	// Listen and serve HTTP
	go func() {
		fmt.Println("Listening on port " + strconv.Itoa(Config.Port))
		err := http.ListenAndServe(":"+strconv.Itoa(Config.Port), nil)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	// Launch workers for running jobs
	// We have a number of workers equal to the number of cores
	for i := 1; i <= runtime.NumCPU(); i++ {
		go func() {
			for {
				event, err := PopEvent()
				if err != nil {
					log.Println(err)
				} else if event != nil {
					err = event.Report()
					if err != nil {
						log.Println(err)
					} else {
						go func() {
							status, err := event.Run()
							err = event.Finalize(status, err)
							if err != nil {
								log.Println(err)
							}
						}()
					}
				}
				time.Sleep(50 * time.Millisecond)
			}
		}()
	}

	// Loop for adding new events to the queue
	for {
		select {
		case commit := <-githubreceive.Events:
			event := Event{
				Event:  commit,
				Domain: "github.com", // For now we only support github
				Status: StatusPending,
				Time:   time.Now(),
			}

			// First check to see if the event already exists, and if it is reque it if it's not running
			checkEvent, err := GetEvent(event.Domain, event.Owner, event.Repo, event.Branch, event.Commit)
			if err != nil {
				log.Println(err)
			}
			if checkEvent != nil {
				// It's an old event, requeue it if we can
				if checkEvent.Status != StatusRunning {
					checkEvent.Status = StatusPending
					err = checkEvent.Update()
					if err != nil {
						log.Println(err)
					}
					err = checkEvent.Report()
					if err != nil {
						log.Println(err)
					}
				}
			} else {
				// It's a new event, insert it anew
				err = event.Insert()
				if err != nil {
					log.Println(err)
				}
				err = event.Report()
				if err != nil {
					log.Println(err)
				}
			}
		default:
			time.Sleep(50 * time.Millisecond)
		}
	}
}

// Handle regular UI requests
func handleUI(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	path, err := parsePath(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	// If it's a POST we re-run it
	if r.Method == "POST" {
		handleReRun(path, w, r)
		return
	}

	// Check the method
	if r.Method != "GET" {
		http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	if len(path) == 5 { // It's a single item
		handleView(path, w, r)
	} else { // It's an index request
		handleIndex(path, w, r)
	}
}

func handleReRun(path []string, w http.ResponseWriter, r *http.Request) {
	if len(path) != 5 {
		http.NotFound(w, r)
		return
	}

	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		// For now we only support github
		if path[0] != "github.com" {
			http.Error(w, "Only github.com currently supported", http.StatusInternalServerError)
		}

		// Event doesn't exist, create it and mark pending to queue it
		event := Event{
			Event: hookserve.Event{
				Owner:  path[1],
				Repo:   path[2],
				Branch: path[3],
				Commit: path[4],
				Type:   "push",
			},
			Domain: "github.com", // For now we only support github
			Status: StatusPending,
			Time:   time.Now(),
		}
		err := event.Insert()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/"+event.Path(), http.StatusSeeOther)
	} else {
		if event.Status == StatusRunning {
			http.Error(w, "Unable to re-run already running item", http.StatusInternalServerError)
			return
		}

		// We have the event, run it again
		// Save it back to the database marked as running
		event.Status = StatusRunning
		event.Log = []byte("Retrying...\n")
		err := event.Update()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}

		go func() {
			status, err := event.Run()
			err = event.Finalize(status, err)
			if err != nil {
				log.Println(err)
			}
		}()

		http.Redirect(w, r, "/"+event.Path(), 303)
	}
}

func handleView(path []string, w http.ResponseWriter, r *http.Request) {
	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		http.NotFound(w, r)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(event, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else { // Serve HTML
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		ansi2html, err := ANSI2HTML(event.String())
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Print output
		fmt.Fprintln(w, "")
		io.Copy(w, ansi2html)
		if event.Status == StatusSuccess || event.Status == StatusFailed || event.Status == StatusFailedBoot {
			fmt.Fprintln(w, "<form method='POST'><input type='submit' value='re-run'></form>")
		}
		fmt.Fprintln(w, "")
	}
}

func handleIndex(path []string, w http.ResponseWriter, r *http.Request) {
	// Handle main index -- list all events
	events, err := GetEvents(path...)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(events, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else {
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		fmt.Fprintln(w, "
")
		for _, event := range events {
			fmt.Fprintln(w, "
")
			fmt.Fprintln(w, ""+event.Time.String()+"	"+event.Status+"	"+event.Path()+"	")
			fmt.Fprintln(w, "
")
		}
		fmt.Fprintln(w, "
")
	}
}

func parsePath(path string) ([]string, error) {
	parts := strings.Split(path, "/")
	if len(parts) > 6 {
		return nil, errors.New("Invalid Path")
	}
	// Filter illigal characters
	for _, part := range parts {
		if strings.ContainsAny(part, " \"\\\b\f\n\r\t\v") {
			return nil, errors.New("Illigal character in path")
		}
	}
	if len(parts) == 2 && parts[1] == "" {
		return make([]string, 0), nil
	} else {
		return parts[1:], nil
	}
}
<|endoftext|>


<commit_before>// main.go
package main

import (
	"github.com/jessevdk/go-flags"
	"os"
	"log"
	"strings"
	"bufio"
	"encoding/base64"
	"github.com/beplus/makeicon/app/helper/image-helper"
	"fmt"
)

var version = "master"

var args struct {
	Filename string `short:"f" long:"file" description:"filename to make assets"`
}

func main() {
	println(version)
	_, err := flags.ParseArgs(&args, os.Args)
	if err == nil {

		if args.Filename == "" {
			log.Fatal("No file set use -n or --file to set it")
		}

		// todo windows \
		s := strings.Split(args.Filename, "/")
		filename := s[len(s)-1]
		// prepare json body

		filenameArray := strings.Split(filename, ".")
		name, extension := filenameArray[0], filenameArray[1]

		myImage, err := image_helper.NewMyImageFromBase64(getImageBase64(args.Filename), name, extension)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Println("Processing icons... It could few seconds...")

		_, err = myImage.Upload()
		if err != nil {
			log.Println(err)
		} else {
			fmt.Println("Icons saved to folder 'AppIcon'.")
		}
	}
}

func getImageBase64(filename string) string {
	imgFile, err := os.Open(filename)
	if err != nil {
		log.Fatal("Open file fail")
	}
	defer imgFile.Close()

	// create a new buffer base on file size
	fInfo, _ := imgFile.Stat()
	var size int64 = fInfo.Size()
	buf := make([]byte, size)

	// read file content into buffer
	fReader := bufio.NewReader(imgFile)
	fReader.Read(buf)

	// convert the buffer bytes to base64 string - use buf.Bytes() for new image
	return base64.StdEncoding.EncodeToString(buf)
}
<commit_msg>version -v<commit_after>// main.go
package main

import (
	"github.com/jessevdk/go-flags"
	"os"
	"log"
	"strings"
	"bufio"
	"encoding/base64"
	"github.com/beplus/makeicon/app/helper/image-helper"
	"fmt"
)

var version = "master"

var args struct {
	Filename string `short:"f" long:"file" description:"filename to make assets"`
	Version  bool `short:"v" long:"version" description:"show version"`
}

func main() {

	_, err := flags.ParseArgs(&args, os.Args)
	if err == nil {
		if args.Version {

			fmt.Printf(" Version: %v \n License: MIT \n Copyright (c) 2017 Be Bplus s.r.o. ", version)

			println(version)
		} else {
			if args.Filename == "" {
				log.Fatal("No file set use -n or --file to set it")
			}

			// todo windows \
			s := strings.Split(args.Filename, "/")
			filename := s[len(s)-1]

			// prepare json body
			filenameArray := strings.Split(filename, ".")
			name, extension := filenameArray[0], filenameArray[1]

			myImage, err := image_helper.NewMyImageFromBase64(getImageBase64(args.Filename), name, extension)
			if err != nil {
				log.Fatal(err)
			}

			fmt.Println("Processing icons... It could few seconds...")

			_, err = myImage.Upload()
			if err != nil {
				log.Println(err)
			} else {
				fmt.Println("Icons saved to folder 'AppIcon'.")
			}
		}
	}
}

func getImageBase64(filename string) string {
	imgFile, err := os.Open(filename)
	if err != nil {
		log.Fatal("Open file fail")
	}
	defer imgFile.Close()

	// create a new buffer base on file size
	fInfo, _ := imgFile.Stat()
	var size int64 = fInfo.Size()
	buf := make([]byte, size)

	// read file content into buffer
	fReader := bufio.NewReader(imgFile)
	fReader.Read(buf)

	// convert the buffer bytes to base64 string - use buf.Bytes() for new image
	return base64.StdEncoding.EncodeToString(buf)
}
<|endoftext|>


<commit_before>// 4 march 2014
package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	"github.com/andlabs/ui"
)

const (
	defCmdLine = "mpv -loop inf ~/ring.wav"
	defTime    = "10:30 AM"
	timeFmt    = "3:04 PM"
)

// If later hasn't happened yet, make it happen on the day of now; if not, the day after.
func bestTime(now time.Time, later time.Time) time.Time {
	now = now.Local() // use local time to make things make sense
	nowh, nowm, nows := now.Clock()
	laterh, laterm, laters := later.Clock()
	add := false
	if nowh > laterh {
		add = true
	} else if (nowh == laterh) && (nowm > laterm) {
		add = true
	} else if (nowh == laterh) && (nowm == laterm) && (nows >= laters) {
		// >= in the case we're on the exact second; add a day because the alarm should have gone off by now otherwise!
		add = true
	}
	if add {
		now = now.AddDate(0, 0, 1)
	}
	return time.Date(now.Year(), now.Month(), now.Day(),
		laterh, laterm, laters, 0,
		now.Location())
}

func myMain() {
	var cmd *exec.Cmd
	var timer *time.Timer
	var timerChan <-chan time.Time
	var w *ui.Window

	status := ui.NewLabel("")

	stop := func() {
		if cmd != nil { // stop the command if it's running
			err := cmd.Process.Kill()
			if err != nil {
				<-w.MsgBoxError(
					fmt.Sprintf("Error killing process: %v", err),
					"You may need to kill it manually.")
			}
			err = cmd.Process.Release()
			if err != nil {
				<-w.MsgBoxError(
					fmt.Sprintf("Error releasing process: %v", err),
					"")
			}
			cmd = nil
		}
		if timer != nil { // stop the timer if we started it
			timer.Stop()
			timer = nil
			timerChan = nil
		}
		status.SetText("")
	}

	w = ui.NewWindow("wakeup", 400, 100)
	ui.AppQuit = w.Closing // treat application close as main window close
	cmdbox := ui.NewLineEdit(defCmdLine)
	timebox := ui.NewLineEdit(defTime)
	bStart := ui.NewButton("Start")
	bStop := ui.NewButton("Stop")

	// a Stack to keep both buttons at the same size
	btnbox := ui.NewHorizontalStack(bStart, bStop)
	btnbox.SetStretchy(0)
	btnbox.SetStretchy(1)
	// and a Stack around that Stack to keep them at a reasonable size, with space to their right
	btnbox = ui.NewHorizontalStack(btnbox, status)

	// the main layout
	grid := ui.NewGrid(2,
		ui.NewLabel("Command"), cmdbox,
		ui.NewLabel("Time"), timebox,
		ui.Space(), ui.Space(), // the Space on the right will consume the window blank space
		ui.Space(), btnbox)
	grid.SetStretchy(2, 1) // make the Space noted above consume
	grid.SetFilling(0, 1)  // make the two textboxes grow horizontally
	grid.SetFilling(1, 1)

	w.Open(grid)

mainloop:
	for {
		select {
		case <-w.Closing:
			break mainloop
		case <-bStart.Clicked:
			stop() // only one alarm at a time
			alarmTime, err := time.Parse(timeFmt, timebox.Text())
			if err != nil {
				<-w.MsgBoxError(
					fmt.Sprintf("Error parsing time %q: %v", timebox.Text(), err),
					fmt.Sprintf("Make sure your time is in the form %q (without quotes).", timeFmt))
				continue
			}
			now := time.Now()
			later := bestTime(now, alarmTime)
			timer = time.NewTimer(later.Sub(now))
			timerChan = timer.C
			status.SetText("Started")
		case <-timerChan:
			cmd = exec.Command("/bin/sh", "-c", "exec "+cmdbox.Text())
			// keep stdin /dev/null in case user wants to run multiple alarms on one instance (TODO should I allow this program to act as a pipe?)
			// keep stdout /dev/null to avoid stty mucking
			cmd.Stderr = os.Stderr
			err := cmd.Start()
			status.SetText("Firing")
			if err != nil {
				<-w.MsgBoxError(
					fmt.Sprintf("Error running program: %v", err),
					"")
				cmd = nil
				status.SetText("")
			}
			timer = nil
			timerChan = nil
		case <-bStop.Clicked:
			stop()
		}
	}

	// clean up
	stop()
}

func main() {
	err := ui.Go(myMain)
	if err != nil {
		panic(fmt.Errorf("error initializing UI library: %v", err))
	}
}
<commit_msg>Rewrote for the new ui API. Still need to implement ui.Window.Send()...<commit_after>// 4 march 2014
package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	"github.com/andlabs/ui"
)

const (
	defCmdLine = "mpv -loop inf ~/ring.wav"
	defTime    = "10:30 AM"
	timeFmt    = "3:04 PM"
)

// If later hasn't happened yet, make it happen on the day of now; if not, the day after.
func bestTime(now time.Time, later time.Time) time.Time {
	now = now.Local() // use local time to make things make sense
	nowh, nowm, nows := now.Clock()
	laterh, laterm, laters := later.Clock()
	add := false
	if nowh > laterh {
		add = true
	} else if (nowh == laterh) && (nowm > laterm) {
		add = true
	} else if (nowh == laterh) && (nowm == laterm) && (nows >= laters) {
		// >= in the case we're on the exact second; add a day because the alarm should have gone off by now otherwise!
		add = true
	}
	if add {
		now = now.AddDate(0, 0, 1)
	}
	return time.Date(now.Year(), now.Month(), now.Day(),
		laterh, laterm, laters, 0,
		now.Location())
}

type MainWindow struct {
	cmd			*exec.Cmd
	stopchan		chan struct{}{}

	win			*ui.Window
	cmdbox		*ui.LineEdit
	timebox		*ui.LineEdit
	bStart		*ui.Button
	bStop		*ui.Button
	status		*ui.Label
}

const TimerFired = ui.CustomEvent

// this is run as a separate goroutine
// mw.stopChan must be valid before this function starts and must be closed after this function returns
func (mw *MainWindow) timer(t time.Time) {
	timer := time.NewTimer(t)
	for {
		select {
		case <-timer.C:
			// TODO
			// send a signal to the main window that we're ready to run the command it has
//			mw.win.Send(TimerFired, nil)
			return
		case <-mw.stopchan:
			timer.Stop()
			return
		}
	}
	panic("unreachable")		// just in case
}

// this is called by mw.Event() when we need to stop the alarm
// it must run on the same OS thread as mw.Event()
func (mw *MainWindow) stop() {
	if mw.cmd != nil { // stop the command if it's running
		err := mw.cmd.Process.Kill()
		if err != nil {
			mw.win.MsgBoxError(
				fmt.Sprintf("Error killing process: %v", err),
				"You may need to kill it manually.")
		}
		err = mw.cmd.Process.Release()
		if err != nil {
			mw.win.MsgBoxError(
				fmt.Sprintf("Error releasing process: %v", err),
				"")
		}
		mw.cmd = nil
	}
	if mw.stopChan != nil { // stop the timer if it's still running
		mw.stopChan <- struct{}{}
		close(mw.stopChan)
		mw.stopChan = nil
	}
	mw.status.SetText("")
}

func NewMainWindow() (mw *MainWindow) {
	mw = new(MainWindow)

	mw.win = ui.NewWindow("wakeup", 400, 100, mw)
	mw.cmdbox = ui.NewLineEdit(defCmdLine)
	mw.timebox = ui.NewLineEdit(defTime)
	mw.bStart = ui.NewButton("Start")
	mw.bStop = ui.NewButton("Stop")
	mw.status := ui.NewLabel("")

	// a Stack to keep both buttons at the same size
	btnbox := ui.NewHorizontalStack(mw.bStart, mw.bStop)
	btnbox.SetStretchy(0)
	btnbox.SetStretchy(1)
	// and a Stack around that Stack to keep them at a reasonable size, with space to their right
	btnbox = ui.NewHorizontalStack(btnbox, mw.status)

	// the main layout
	grid := ui.NewGrid(2,
		ui.NewLabel("Command"), mw.cmdbox,
		ui.NewLabel("Time"), mw.timebox,
		ui.Space(), ui.Space(), // the Space on the right will consume the window blank space
		ui.Space(), btnbox)
	grid.SetStretchy(2, 1) // make the Space noted above consume
	grid.SetFilling(0, 1)  // make the two textboxes grow horizontally
	grid.SetFilling(1, 1)

	mw.win.Open(grid)
}

func (mw *MainWindow) Event(e ui.Event, d interface{}) {
	switch e {
	case ui.Closing:
		mw.stop()
		*(d.(*bool)) = true
	case ui.Clicked:
		switch d {
		case mw.bStart:
			mw.stop() // only one alarm at a time
			alarmTime, err := time.Parse(timeFmt, timebox.Text())
			if err != nil {
				mw.win.MsgBoxError(
					fmt.Sprintf("Error parsing time %q: %v", timebox.Text(), err),
					fmt.Sprintf("Make sure your time is in the form %q (without quotes).", timeFmt))
				return
			}
			now := time.Now()
			later := bestTime(now, alarmTime)
			mw.stopChan = make(chan struct{}{})
			go mw.timer(later.Sub(now))
			mw.status.SetText("Started")
		case bStop:
			mw.stop()
		}
//	case TimerFired:
	case 0://TODO
		mw.cmd = exec.Command("/bin/sh", "-c", "exec "+cmdbox.Text())
		// keep stdin /dev/null in case user wants to run multiple alarms on one instance (TODO should I allow this program to act as a pipe?)
		// keep stdout /dev/null to avoid stty mucking
		mw.cmd.Stderr = os.Stderr
		err := mw.cmd.Start()
		mw.status.SetText("Firing")
		if err != nil {
			mw.win.MsgBoxError(
				fmt.Sprintf("Error running program: %v", err),
				"")
			mw.cmd = nil
				mw.status.SetText("")
		}
		// we're done with the timer, but the goroutine that handles it has returned (or will after we do)
		// so close the stopChan now so that the next call to mw.stop() doesn't hang or crash
		close(mw.stopChan)
		mw.stopChan = nil
	}
}

func main() {
	go func() {
		<-ui.Start
		NewMainWindow()
	}()
	err := ui.Go()
	if err != nil {
		panic(fmt.Errorf("error initializing UI library: %v", err))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"reflect"

	"code.cloudfoundry.org/cli/cf/cmd"
	"code.cloudfoundry.org/cli/commands"
	"code.cloudfoundry.org/cli/commands/ui"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/utils/config"
	"code.cloudfoundry.org/cli/utils/panichandler"
	"github.com/jessevdk/go-flags"
)

type UI interface {
	DisplayError(err ui.TranslatableError)
	DisplayErrorMessage(err string, keys ...map[string]interface{})
}

var ErrFailed = errors.New("command failed")

func main() {
	defer panichandler.HandlePanic()
	parse(os.Args[1:])
}

func parse(args []string) {
	parser := flags.NewParser(&v2.Commands, flags.HelpFlag)
	parser.CommandHandler = executionWrapper
	extraArgs, err := parser.ParseArgs(args)
	if err == nil {
		return
	}

	if flagErr, ok := err.(*flags.Error); ok {
		switch flagErr.Type {
		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument:
			_, found := reflect.TypeOf(v2.Commands).FieldByNameFunc(
				func(fieldName string) bool {
					field, _ := reflect.TypeOf(v2.Commands).FieldByName(fieldName)
					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
				},
			)

			if found && flagErr.Type == flags.ErrUnknownFlag && parser.Active.Name == "set-env" {
				newArgs := []string{}
				for _, arg := range args {
					if arg[0] == '-' {
						newArgs = append(newArgs, fmt.Sprintf("%s%s", v2.WorkAroundPrefix, arg))
					} else {
						newArgs = append(newArgs, arg)
					}
				}
				parse(newArgs)
				return
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			}

			if found {
				parse([]string{"help", parser.Active.Name})
			} else {
				switch len(extraArgs) {
				case 0:
					parse([]string{"help"})
				case 1:
					parse([]string{"help", extraArgs[0]})
				default:
					parse(extraArgs[1:])
				}
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				os.Exit(1)
			}
		case flags.ErrRequired:
			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			parse(append([]string{"help"}, args...))
			os.Exit(1)
		case flags.ErrUnknownCommand:
			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
		case flags.ErrCommandRequired:
			if v2.Commands.VerboseOrVersion {
				parse([]string{"version"})
			} else {
				parse([]string{"help"})
			}
		default:
			fmt.Fprintf(os.Stderr, "Unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
		}
	} else if err == ErrFailed {
		os.Exit(1)
	} else {
		fmt.Fprintf(os.Stderr, "Unexpected error: %s\n", err.Error())
		os.Exit(1)
	}
}

func executionWrapper(cmd flags.Commander, args []string) error {
	cfConfig, err := config.LoadConfig()
	if err != nil {
		return err
	}
	defer config.WriteConfig(cfConfig)

	if extendedCmd, ok := cmd.(commands.ExtendedCommander); ok {
		commandUI, err := ui.NewUI(cfConfig)
		if err != nil {
			return err
		}

		err = extendedCmd.Setup(cfConfig, commandUI)
		if err != nil {
			return handleError(err, commandUI)
		}
		return handleError(extendedCmd.Execute(args), commandUI)
	}

	return fmt.Errorf("command does not conform to ExtendedCommander")
}

func handleError(err error, commandUI UI) error {
	if err == nil {
		return nil
	}

	if e, ok := err.(ui.TranslatableError); ok {
		commandUI.DisplayError(e)
	} else {
		commandUI.DisplayErrorMessage(err.Error())
	}
	return ErrFailed
}
<commit_msg>Remove duplicate invalid option message<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"

	"code.cloudfoundry.org/cli/cf/cmd"
	"code.cloudfoundry.org/cli/commands"
	"code.cloudfoundry.org/cli/commands/ui"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/utils/config"
	"code.cloudfoundry.org/cli/utils/panichandler"
	"github.com/jessevdk/go-flags"
)

type UI interface {
	DisplayError(err ui.TranslatableError)
	DisplayErrorMessage(err string, keys ...map[string]interface{})
}

var ErrFailed = errors.New("command failed")

func main() {
	defer panichandler.HandlePanic()
	parse(os.Args[1:])
}

func parse(args []string) {
	parser := flags.NewParser(&v2.Commands, flags.HelpFlag)
	parser.CommandHandler = executionWrapper
	extraArgs, err := parser.ParseArgs(args)
	if err == nil {
		return
	}

	if flagErr, ok := err.(*flags.Error); ok {
		switch flagErr.Type {
		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument:
			_, found := reflect.TypeOf(v2.Commands).FieldByNameFunc(
				func(fieldName string) bool {
					field, _ := reflect.TypeOf(v2.Commands).FieldByName(fieldName)
					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
				},
			)

			if found && flagErr.Type == flags.ErrUnknownFlag && parser.Active.Name == "set-env" {
				newArgs := []string{}
				for _, arg := range args {
					if arg[0] == '-' {
						newArgs = append(newArgs, fmt.Sprintf("%s%s", v2.WorkAroundPrefix, arg))
					} else {
						newArgs = append(newArgs, arg)
					}
				}
				parse(newArgs)
				return
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			}

			if found {
				parse([]string{"help", parser.Active.Name})
			} else {
				switch len(extraArgs) {
				case 0:
					parse([]string{"help"})
				case 1:
					if !isOption(extraArgs[0]) || (len(args) > 1 && extraArgs[0] == "-a") {
						parse([]string{"help", extraArgs[0]})
					} else {
						parse([]string{"help"})
					}
				default:
					parse(extraArgs[1:])
				}
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				os.Exit(1)
			}
		case flags.ErrRequired:
			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			parse(append([]string{"help"}, args...))
			os.Exit(1)
		case flags.ErrUnknownCommand:
			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
		case flags.ErrCommandRequired:
			if v2.Commands.VerboseOrVersion {
				parse([]string{"version"})
			} else {
				parse([]string{"help"})
			}
		default:
			fmt.Fprintf(os.Stderr, "Unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
		}
	} else if err == ErrFailed {
		os.Exit(1)
	} else {
		fmt.Fprintf(os.Stderr, "Unexpected error: %s\n", err.Error())
		os.Exit(1)
	}
}

func isOption(s string) bool {
	return strings.HasPrefix(s, "-")
}

func executionWrapper(cmd flags.Commander, args []string) error {
	cfConfig, err := config.LoadConfig()
	if err != nil {
		return err
	}
	defer config.WriteConfig(cfConfig)

	if extendedCmd, ok := cmd.(commands.ExtendedCommander); ok {
		commandUI, err := ui.NewUI(cfConfig)
		if err != nil {
			return err
		}

		err = extendedCmd.Setup(cfConfig, commandUI)
		if err != nil {
			return handleError(err, commandUI)
		}
		return handleError(extendedCmd.Execute(args), commandUI)
	}

	return fmt.Errorf("command does not conform to ExtendedCommander")
}

func handleError(err error, commandUI UI) error {
	if err == nil {
		return nil
	}

	if e, ok := err.(ui.TranslatableError); ok {
		commandUI.DisplayError(e)
	} else {
		commandUI.DisplayErrorMessage(err.Error())
	}
	return ErrFailed
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/nfnt/resize"
	"image"
	_ "image/jpeg"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

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

	var imgPath string
	var targetWidth, targetHeight, targetPercent uint
	var ratioWidth, ratioHeight bool

	flag.StringVar(&imgPath, "p", "./", "Path to resize images from")
	flag.UintVar(&targetWidth, "w", 1152, "Resized width of image")
	flag.UintVar(&targetHeight, "h", 768, "Resized height of image")
	flag.BoolVar(&ratioWidth, "rw", false, "Use only width input, and height will be calculated maintaining ratio")
	flag.BoolVar(&ratioHeight, "rh", false, "Use only height input, and height will be calculated maintaining ratio")
	flag.UintVar(&targetPercent, "percent", 100, "Resizes the image by a percentage, maintianing ratio")
	flag.Parse()

	if ratioHeight && ratioWidth {
		log.Fatalln("Cannot use both calculated ration for height and width")
	}
	if (ratioHeight || ratioWidth) && targetPercent != 100 {
		log.Fatalln("Cannot use both ratio Height/Width and percentage")
	}

	fileInfos, err := ioutil.ReadDir(imgPath)
	if err != nil {
		log.Fatalln("Failed to read directory", imgPath, "because", err)
	}

	for _, v := range fileInfos {
		// No need to resize the image if it was already done.
		if strings.Contains(v.Name(), "-resized-") || v.IsDir() {
			continue
		}

		img, format, err := openImage(filepath.Join(imgPath, v.Name()))
		if err != nil {
			log.Println("Failed to resize", v.Name(), err)
			continue
		}

		if format != "jpeg" {
			log.Println("Unsupported format", format, v.Name())
			continue
		}

		if targetPercent != 100 {
			// Calculates the target width and height for the given percentage resize.
			ratioWidth = true
			targetWidth = uint(float64(img.Bounds().Max.X) * (float64(targetPercent) / float64(100)))
		}

		if ratioWidth {
			// Calculates the height from a target width maintaing the image's ration;
			// e.g. 1200/1600 * 400 = 300
			targetHeight = uint(img.Bounds().Max.X/img.Bounds().Max.Y) * targetWidth
		} else if ratioHeight {
			// Calculates the width from a target height maintaing the image's ration;
			// e.g. 1600/1200 * 300 = 400
			targetWidth = uint(img.Bounds().Max.Y/img.Bounds().Max.X) * targetHeight
		}

		resizedImg := resize.Resize(targetWidth, targetHeight, img, resize.NearestNeighbor)

		newFilename := makeNewFilName(v.Name(), resizedImg.Bounds())
		newFilePath := filepath.Join(imgPath, newFilename)
		if err := saveImage(newFilePath, resizedImg, format); err != nil {
			log.Println("Failed to save resized image", err)
		}

		log.Println("Resized", v.Name(), "to", newFilename, "format", format)
	}
}

func openImage(filePath string) (image.Image, string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		log.Println("Failed to open image")
		return nil, "", err
	}
	defer file.Close()

	img, format, err := image.Decode(file)
	if err != nil {
		log.Println("Failed to decode image")
		return nil, "", err
	}

	return img, format, nil
}

func saveImage(filePath string, img image.Image, format string) error {
	file, err := os.Create(filePath)
	if err != nil {
		log.Println("Failed to create resized image file")
		return err
	}
	defer file.Close()

	if format == "jpeg" {
		if err = saveJPEGImage(file, img); err != nil {
			log.Println("Failed writing image as JPEG to file")
			return err
		}
	}

	return nil
}

func makeNewFilName(origName string, bounds image.Rectangle) string {
	extention := filepath.Ext(origName)
	filename := strings.TrimSuffix(origName, extention)
	return fmt.Sprintf("%s-resized-%dx%d%s", filename, bounds.Max.X, bounds.Max.Y, extention)
}
<commit_msg>fixed error logging to make sense<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/nfnt/resize"
	"image"
	_ "image/jpeg"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

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

	var imgPath string
	var targetWidth, targetHeight, targetPercent uint
	var ratioWidth, ratioHeight bool

	flag.StringVar(&imgPath, "p", "./", "Path to resize images from")
	flag.UintVar(&targetWidth, "w", 1152, "Resized width of image")
	flag.UintVar(&targetHeight, "h", 768, "Resized height of image")
	flag.BoolVar(&ratioWidth, "rw", false, "Use only width input, and height will be calculated maintaining ratio")
	flag.BoolVar(&ratioHeight, "rh", false, "Use only height input, and height will be calculated maintaining ratio")
	flag.UintVar(&targetPercent, "percent", 100, "Resizes the image by a percentage, maintianing ratio")
	flag.Parse()

	if ratioHeight && ratioWidth {
		log.Fatalln("Cannot use both calculated ration for height and width")
	}
	if (ratioHeight || ratioWidth) && targetPercent != 100 {
		log.Fatalln("Cannot use both ratio Height/Width and percentage")
	}

	fileInfos, err := ioutil.ReadDir(imgPath)
	if err != nil {
		log.Fatalln("Failed to read directory", imgPath, "because", err)
	}

	for _, v := range fileInfos {
		// No need to resize the image if it was already done.
		if strings.Contains(v.Name(), "-resized-") || v.IsDir() {
			continue
		}

		img, format, err := openImage(filepath.Join(imgPath, v.Name()))
		if err != nil {
			log.Println("Image Open failed:", v.Name(), err)
			continue
		}

		if format != "jpeg" {
			log.Println("Unsupported format:", format, v.Name())
			continue
		}

		if targetPercent != 100 {
			// Calculates the target width and height for the given percentage resize.
			ratioWidth = true
			targetWidth = uint(float64(img.Bounds().Max.X) * (float64(targetPercent) / float64(100)))
		}

		if ratioWidth {
			// Calculates the height from a target width maintaing the image's ration;
			// e.g. 1200/1600 * 400 = 300
			targetHeight = uint(img.Bounds().Max.X/img.Bounds().Max.Y) * targetWidth
		} else if ratioHeight {
			// Calculates the width from a target height maintaing the image's ration;
			// e.g. 1600/1200 * 300 = 400
			targetWidth = uint(img.Bounds().Max.Y/img.Bounds().Max.X) * targetHeight
		}

		resizedImg := resize.Resize(targetWidth, targetHeight, img, resize.NearestNeighbor)

		newFilename := makeNewFilName(v.Name(), resizedImg.Bounds())
		newFilePath := filepath.Join(imgPath, newFilename)
		if err := saveImage(newFilePath, resizedImg, format); err != nil {
			log.Println("Failed to save resized image", err)
		}

		log.Println("Resized", v.Name(), "to", newFilename, "format", format)
	}
}

func openImage(filePath string) (image.Image, string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, "", fmt.Errorf("Failed to open image: %s", err)
	}
	defer file.Close()

	img, format, err := image.Decode(file)
	if err != nil {
		return nil, "", fmt.Errorf("Failed to decode image: %s", err)
	}

	return img, format, nil
}

func saveImage(filePath string, img image.Image, format string) error {
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("Failed to create resized image file: %s", err)
	}
	defer file.Close()

	if format == "jpeg" {
		if err = saveJPEGImage(file, img); err != nil {
			return fmt.Errorf("Failed writing image as JPEG to file: %s", err)
		}
	}

	return nil
}

func makeNewFilName(origName string, bounds image.Rectangle) string {
	extention := filepath.Ext(origName)
	filename := strings.TrimSuffix(origName, extention)
	return fmt.Sprintf("%s-resized-%dx%d%s", filename, bounds.Max.X, bounds.Max.Y, extention)
}
<|endoftext|>


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

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

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

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.14.3 Oganesson 2017-08-12"

var stderr io.Writer = os.Stderr

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

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

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

type treeNode struct {
	indent int
	node   ast.Node
}

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

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

	return nodes
}

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

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

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

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

	return results
}

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

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

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

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

				if len(v) == 0 {
					continue
				}

				value = toJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

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

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

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

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

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

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

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

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

		return nil
	}

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)

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

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

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)

		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

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

	return nil
}

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

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

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

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

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

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

	flag.Parse()

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

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

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

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

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

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

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

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

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

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

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

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

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.14.4 Oganesson 2017-08-20"

var stderr io.Writer = os.Stderr

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

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

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

type treeNode struct {
	indent int
	node   ast.Node
}

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

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

	return nodes
}

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

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

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

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

	return results
}

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

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

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

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

				if len(v) == 0 {
					continue
				}

				value = toJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

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

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

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

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

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

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

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

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

		return nil
	}

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)

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

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

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)

		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

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

	return nil
}

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

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

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

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

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

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

	flag.Parse()

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

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

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

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

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

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

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

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

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

	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/thoas/stats"
	"github.com/unrolled/render"
)

type env struct {
	Metrics *stats.Stats
	Render  *render.Render
}

var port *string

func init() {
	// parse command line flags
	fixturesLocation := flag.String("fixtures", "./fixtures.json", "location of fixtures.json file")
	port = flag.String("port", "3009", "location of fixtures.json file")
	flag.Parse()

	// read JSON fixtures file
	var jsonObject map[string][]User
	fmt.Println("Location of fixtures.json file: " + *fixturesLocation)
	file, err := ioutil.ReadFile(*fixturesLocation)
	if err != nil {
		log.Fatalf("File error: %v\n", err)
	}
	err = json.Unmarshal(file, &jsonObject)
	if err != nil {
		log.Fatal(err)
	}
	// load data in database
	list := make(map[int]User)
	list[0] = jsonObject["users"][0]
	list[1] = jsonObject["users"][1]
	db = &Database{
		UserList:  list,
		MaxUserID: 1,
	}
}

func main() {
	env := env{
		Metrics: stats.New(),
		Render:  render.New(),
	}
	router := mux.NewRouter()

	router.HandleFunc("/", makeHandler(env, HomeHandler))
	router.HandleFunc("/healthcheck", makeHandler(env, HealthcheckHandler)).Methods("GET")
	router.HandleFunc("/metrics", makeHandler(env, MetricsHandler)).Methods("GET")

	router.HandleFunc("/users", makeHandler(env, ListUsersHandler)).Methods("GET")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, GetUserHandler)).Methods("GET")
	router.HandleFunc("/users", makeHandler(env, CreateUserHandler)).Methods("POST")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, UpdateUserHandler)).Methods("PUT")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, DeleteUserHandler)).Methods("DELETE")

	router.HandleFunc("/users/{uid}/passports", makeHandler(env, PassportsHandler)).Methods("GET")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("GET")
	router.HandleFunc("/users/{uid}/passports", makeHandler(env, PassportsHandler)).Methods("POST")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("PUT")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("DELETE")

	n := negroni.Classic()
	n.Use(env.Metrics)
	n.UseHandler(router)
	fmt.Println("Starting server on port: " + *port)
	n.Run(":" + *port)
}
<commit_msg>fixed description of port flag<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/thoas/stats"
	"github.com/unrolled/render"
)

type env struct {
	Metrics *stats.Stats
	Render  *render.Render
}

var port *string

func init() {
	// parse command line flags
	fixturesLocation := flag.String("fixtures", "./fixtures.json", "location of fixtures.json file")
	port = flag.String("port", "3009", "serve traffic on this port")
	flag.Parse()

	// read JSON fixtures file
	var jsonObject map[string][]User
	fmt.Println("Location of fixtures.json file: " + *fixturesLocation)
	file, err := ioutil.ReadFile(*fixturesLocation)
	if err != nil {
		log.Fatalf("File error: %v\n", err)
	}
	err = json.Unmarshal(file, &jsonObject)
	if err != nil {
		log.Fatal(err)
	}
	// load data in database
	list := make(map[int]User)
	list[0] = jsonObject["users"][0]
	list[1] = jsonObject["users"][1]
	db = &Database{
		UserList:  list,
		MaxUserID: 1,
	}
}

func main() {
	env := env{
		Metrics: stats.New(),
		Render:  render.New(),
	}
	router := mux.NewRouter()

	router.HandleFunc("/", makeHandler(env, HomeHandler))
	router.HandleFunc("/healthcheck", makeHandler(env, HealthcheckHandler)).Methods("GET")
	router.HandleFunc("/metrics", makeHandler(env, MetricsHandler)).Methods("GET")

	router.HandleFunc("/users", makeHandler(env, ListUsersHandler)).Methods("GET")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, GetUserHandler)).Methods("GET")
	router.HandleFunc("/users", makeHandler(env, CreateUserHandler)).Methods("POST")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, UpdateUserHandler)).Methods("PUT")
	router.HandleFunc("/users/{uid:[0-9]+}", makeHandler(env, DeleteUserHandler)).Methods("DELETE")

	router.HandleFunc("/users/{uid}/passports", makeHandler(env, PassportsHandler)).Methods("GET")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("GET")
	router.HandleFunc("/users/{uid}/passports", makeHandler(env, PassportsHandler)).Methods("POST")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("PUT")
	router.HandleFunc("/passports/{pid:[0-9]+}", makeHandler(env, PassportsHandler)).Methods("DELETE")

	n := negroni.Classic()
	n.Use(env.Metrics)
	n.UseHandler(router)
	fmt.Println("Starting server on port: " + *port)
	n.Run(":" + *port)
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Glamor authors.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"net/mail"
	"net/smtp"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

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

const version = "1.1"

const (
	returnOk = iota
	returnHelp
	returnSignal
)

const (
	statusUp = iota
	statusDown
)

type host struct {
	name   string
	status byte
	down   uint64
	up     uint64
}

var opts struct {
	Config                    func(s string) error `long:"config" description:"INI config file" no-ini:"true"`
	ConfigWrite               string               `long:"config-write" description:"Write all arguments to an INI config file and exit" no-ini:"true"`
	Host                      []string             `long:"host" description:"A host to ping" required:"true"`
	Interval                  uint64               `long:"interval" default:"60" description:"Ping interval in seconds"`
	MaxDown                   uint64               `long:"max-down" default:"5" description:"How many pings must fail (in a row) before the host status is down"`
	MaxUp                     uint64               `long:"max-up" default:"20" description:"How many pings must succeed (in a row) before the host status is up again"`
	PingPacketSize            int                  `long:"ping-packet-size" default:"64" description:"Packet size of one ping. Minimum is 64 bytes maximum is 65535 bytes"`
	SMTP                      string               `long:"smtp" description:"The SMTP server + port for sending report mails"`
	SMTPFrom                  string               `long:"smtp-from" description:"From-mail address"`
	SMTPSkipCertificateVerify bool                 `long:"smtp-skip-certificate-verify" description:"Do not verify the SMTP certificate"`
	SMTPTLS                   bool                 `long:"smtp-tls" description:"Use TLS for the SMTP connection"`
	SMTPTo                    []string             `long:"smtp-to" description:"A To-mail address"`
	Verbose                   bool                 `long:"verbose" description:"Do verbose output"`
	Version                   bool                 `long:"version" description:"Print the version of this program" no-ini:"true"`

	configFile string
}

func checkArguments() {
	p := flags.NewNamedParser("glamor", flags.HelpFlag)
	p.ShortDescription = "A daemon for monitoring hosts via ICMP echo request (ping)"

	opts.Config = func(s string) error {
		ini := flags.NewIniParser(p)

		opts.configFile = s

		return ini.ParseFile(s)
	}

	p.AddGroup("Glamor", "Glamor arguments", &opts)

	if _, err := p.ParseArgs(os.Args); err != nil {
		if opts.Version {
			fmt.Printf("Glamor v%s\n", version)

			os.Exit(returnOk)
		}

		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
			panic(err)
		} else {
			p.WriteHelp(os.Stdout)

			os.Exit(returnHelp)
		}
	}

	if opts.Interval < 1 {
		panic("interval must be at least 1")
	} else if opts.MaxDown < 1 {
		panic("max-down must be at least 1")
	} else if opts.MaxUp < 1 {
		panic("max-up must be at least 1")
	}

	if opts.PingPacketSize < 64 || opts.PingPacketSize > 65535 {
		panic("ping-packet-size must be in range of [64,65535]")
	}

	if _, err := mail.ParseAddress(opts.SMTPFrom); opts.SMTPFrom != "" && err != nil {
		panic("smtp-from is not a valid mail address")
	}

	for _, m := range opts.SMTPTo {
		if _, err := mail.ParseAddress(m); m == "" || err != nil {
			panic(fmt.Sprintf("smtp-to \"%s\" is not a valid mail address", m))
		}
	}

	if opts.ConfigWrite != "" {
		ini := flags.NewIniParser(p)

		ini.WriteFile(opts.ConfigWrite, flags.IniIncludeComments)

		os.Exit(returnOk)
	}
}

func checkHost(wg *sync.WaitGroup, host *host) {
	defer wg.Done()

	var cmd = exec.Command("ping", "-w", "1", "-c", "1", "-s", strconv.Itoa(opts.PingPacketSize-8), host.name)

	out, err := cmd.CombinedOutput()
	if err != nil {
		v("ping to %s failed: %v", host.name, err)
	}

	if strings.Contains(string(out), "1 received") {
		if host.status == statusDown {
			host.up++

			if host.up >= opts.MaxUp {
				host.down = 0
				host.up = 0

				host.status = statusUp

				subject := fmt.Sprintf("host %s is up", host.name)

				v(subject)

				if opts.SMTP != "" {
					if err := sendMail(subject, host.name+" is reachable again via ping"); err != nil {
						v("Cannot send mail: %v", err)
					}
				}
			}
		} else {
			host.down = 0
		}
	} else {
		host.down++

		if host.status == statusUp {
			if host.down >= opts.MaxDown {
				host.down = 0
				host.up = 0

				host.status = statusDown

				subject := fmt.Sprintf("host %s is down", host.name)

				v(subject)

				if opts.SMTP != "" {
					if err := sendMail(subject, host.name+" is not reachable via ping"); err != nil {
						v("Cannot send mail: %v", err)
					}
				}
			}
		} else {
			host.up = 0
		}
	}
}

func sendMail(subject string, message string) error {
	if opts.SMTP == "" {
		return fmt.Errorf("no SMTP server defined")
	}

	c, err := smtp.Dial(opts.SMTP)
	if err != nil {
		return fmt.Errorf("cannot open SMTP connection: %v", err)
	}

	if opts.SMTPTLS {
		if err := c.StartTLS(&tls.Config{InsecureSkipVerify: opts.SMTPSkipCertificateVerify}); err != nil {
			return fmt.Errorf("cannot start SMTP TLS: %v", err)
		}
	}

	c.Mail(opts.SMTPFrom)
	for _, m := range opts.SMTPTo {
		c.Rcpt(m)
	}

	wc, err := c.Data()
	if err != nil {
		return fmt.Errorf("cannot open Data writer: %v", err)
	}

	defer wc.Close()

	buf := bytes.NewBufferString(`Return-path: <` + opts.SMTPFrom + `>
From: ` + opts.SMTPFrom + `
To: ` + strings.Join(opts.SMTPTo, ", ") + `
Subject: ` + subject + `
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="us-ascii"

` + message + `
`)

	if _, err = buf.WriteTo(wc); err != nil {
		return fmt.Errorf("cannot write mail body: %v", err)
	}

	return nil
}

func v(format string, a ...interface{}) {
	if opts.Verbose {
		fmt.Fprintf(os.Stderr, format+"\n", a...)
	}
}

func main() {
	checkArguments()

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)

	go func() {
		s := <-sig
		v("caught signal \"%v\", will exit now", s)

		os.Exit(returnSignal)
	}()

	hosts := make([]host, len(opts.Host))

	for i, name := range opts.Host {
		hosts[i].name = name
		hosts[i].status = statusUp
	}

	var wg sync.WaitGroup

	for {
		for i := range hosts {
			wg.Add(1)

			go checkHost(&wg, &hosts[i])
		}

		wg.Wait()

		time.Sleep(time.Duration(opts.Interval) * time.Second)
	}
}
<commit_msg>use new ini writer options of go-flags<commit_after>// Copyright 2013-2014 The Glamor authors.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"net/mail"
	"net/smtp"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

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

const version = "1.1"

const (
	returnOk = iota
	returnHelp
	returnSignal
)

const (
	statusUp = iota
	statusDown
)

type host struct {
	name   string
	status byte
	down   uint64
	up     uint64
}

var opts struct {
	Config                    func(s string) error `long:"config" description:"INI config file" no-ini:"true"`
	ConfigWrite               string               `long:"config-write" description:"Write all arguments to an INI config file and exit" no-ini:"true"`
	Host                      []string             `long:"host" description:"A host to ping" required:"true"`
	Interval                  uint64               `long:"interval" default:"60" description:"Ping interval in seconds"`
	MaxDown                   uint64               `long:"max-down" default:"5" description:"How many pings must fail (in a row) before the host status is down"`
	MaxUp                     uint64               `long:"max-up" default:"20" description:"How many pings must succeed (in a row) before the host status is up again"`
	PingPacketSize            int                  `long:"ping-packet-size" default:"64" description:"Packet size of one ping. Minimum is 64 bytes maximum is 65535 bytes"`
	SMTP                      string               `long:"smtp" description:"The SMTP server + port for sending report mails"`
	SMTPFrom                  string               `long:"smtp-from" description:"From-mail address"`
	SMTPSkipCertificateVerify bool                 `long:"smtp-skip-certificate-verify" description:"Do not verify the SMTP certificate"`
	SMTPTLS                   bool                 `long:"smtp-tls" description:"Use TLS for the SMTP connection"`
	SMTPTo                    []string             `long:"smtp-to" description:"A To-mail address"`
	Verbose                   bool                 `long:"verbose" description:"Do verbose output"`
	Version                   bool                 `long:"version" description:"Print the version of this program" no-ini:"true"`

	configFile string
}

func checkArguments() {
	p := flags.NewNamedParser("glamor", flags.HelpFlag)
	p.ShortDescription = "A daemon for monitoring hosts via ICMP echo request (ping)"

	opts.Config = func(s string) error {
		ini := flags.NewIniParser(p)

		opts.configFile = s

		return ini.ParseFile(s)
	}

	p.AddGroup("Glamor", "Glamor arguments", &opts)

	if _, err := p.ParseArgs(os.Args); err != nil {
		if opts.Version {
			fmt.Printf("Glamor v%s\n", version)

			os.Exit(returnOk)
		}

		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
			panic(err)
		} else {
			p.WriteHelp(os.Stdout)

			os.Exit(returnHelp)
		}
	}

	if opts.Interval < 1 {
		panic("interval must be at least 1")
	} else if opts.MaxDown < 1 {
		panic("max-down must be at least 1")
	} else if opts.MaxUp < 1 {
		panic("max-up must be at least 1")
	}

	if opts.PingPacketSize < 64 || opts.PingPacketSize > 65535 {
		panic("ping-packet-size must be in range of [64,65535]")
	}

	if _, err := mail.ParseAddress(opts.SMTPFrom); opts.SMTPFrom != "" && err != nil {
		panic("smtp-from is not a valid mail address")
	}

	for _, m := range opts.SMTPTo {
		if _, err := mail.ParseAddress(m); m == "" || err != nil {
			panic(fmt.Sprintf("smtp-to \"%s\" is not a valid mail address", m))
		}
	}

	if opts.ConfigWrite != "" {
		ini := flags.NewIniParser(p)

		ini.WriteFile(opts.ConfigWrite, flags.IniIncludeComments|flags.IniIncludeDefaults|flags.IniCommentDefaults)

		os.Exit(returnOk)
	}
}

func checkHost(wg *sync.WaitGroup, host *host) {
	defer wg.Done()

	var cmd = exec.Command("ping", "-w", "1", "-c", "1", "-s", strconv.Itoa(opts.PingPacketSize-8), host.name)

	out, err := cmd.CombinedOutput()
	if err != nil {
		v("ping to %s failed: %v", host.name, err)
	}

	if strings.Contains(string(out), "1 received") {
		if host.status == statusDown {
			host.up++

			if host.up >= opts.MaxUp {
				host.down = 0
				host.up = 0

				host.status = statusUp

				subject := fmt.Sprintf("host %s is up", host.name)

				v(subject)

				if opts.SMTP != "" {
					if err := sendMail(subject, host.name+" is reachable again via ping"); err != nil {
						v("Cannot send mail: %v", err)
					}
				}
			}
		} else {
			host.down = 0
		}
	} else {
		host.down++

		if host.status == statusUp {
			if host.down >= opts.MaxDown {
				host.down = 0
				host.up = 0

				host.status = statusDown

				subject := fmt.Sprintf("host %s is down", host.name)

				v(subject)

				if opts.SMTP != "" {
					if err := sendMail(subject, host.name+" is not reachable via ping"); err != nil {
						v("Cannot send mail: %v", err)
					}
				}
			}
		} else {
			host.up = 0
		}
	}
}

func sendMail(subject string, message string) error {
	if opts.SMTP == "" {
		return fmt.Errorf("no SMTP server defined")
	}

	c, err := smtp.Dial(opts.SMTP)
	if err != nil {
		return fmt.Errorf("cannot open SMTP connection: %v", err)
	}

	if opts.SMTPTLS {
		if err := c.StartTLS(&tls.Config{InsecureSkipVerify: opts.SMTPSkipCertificateVerify}); err != nil {
			return fmt.Errorf("cannot start SMTP TLS: %v", err)
		}
	}

	c.Mail(opts.SMTPFrom)
	for _, m := range opts.SMTPTo {
		c.Rcpt(m)
	}

	wc, err := c.Data()
	if err != nil {
		return fmt.Errorf("cannot open Data writer: %v", err)
	}

	defer wc.Close()

	buf := bytes.NewBufferString(`Return-path: <` + opts.SMTPFrom + `>
From: ` + opts.SMTPFrom + `
To: ` + strings.Join(opts.SMTPTo, ", ") + `
Subject: ` + subject + `
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="us-ascii"

` + message + `
`)

	if _, err = buf.WriteTo(wc); err != nil {
		return fmt.Errorf("cannot write mail body: %v", err)
	}

	return nil
}

func v(format string, a ...interface{}) {
	if opts.Verbose {
		fmt.Fprintf(os.Stderr, format+"\n", a...)
	}
}

func main() {
	checkArguments()

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)

	go func() {
		s := <-sig
		v("caught signal \"%v\", will exit now", s)

		os.Exit(returnSignal)
	}()

	hosts := make([]host, len(opts.Host))

	for i, name := range opts.Host {
		hosts[i].name = name
		hosts[i].status = statusUp
	}

	var wg sync.WaitGroup

	for {
		for i := range hosts {
			wg.Add(1)

			go checkHost(&wg, &hosts[i])
		}

		wg.Wait()

		time.Sleep(time.Duration(opts.Interval) * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

type StubHandler struct {
	stubs map[string]Stub
}

type Stub struct {
	Method string `json:"method"`
	Path   string `json:"path"`
	Body   string `json:"body"`
}

func (h *StubHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/stub" && req.Method == "POST" {
		h.createStubHandler(w, req)
	} else {
		h.returnStubHandler(w, req)
	}
}

func (h *StubHandler) createStubHandler(w http.ResponseWriter, req *http.Request) {
	var stub Stub
	jsonDecoder := json.NewDecoder(req.Body)
	err := jsonDecoder.Decode(&stub)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		_, err = fmt.Fprintf(w, "Invalid JSON: %v", err)
		if err != nil {
			log.Printf("Could not send response to client due to: %v", err)
		}
	}

	h.stubs[stub.Path] = stub
}

func (h *StubHandler) returnStubHandler(w http.ResponseWriter, req *http.Request) {
	if stub, ok := h.stubs[req.URL.Path]; ok {
		if stub.Method == req.Method {
			_, err := io.WriteString(w, stub.Body)
			if err != nil {
				log.Printf("Could not send response to client due to: %v", err)
			}
		}
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func NewStubHandler() *StubHandler {
	var s StubHandler
	s.stubs = make(map[string]Stub)
	return &s
}

func main() {
}
<commit_msg>Syncronize access to stub map<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"sync"
)

type StubHandler struct {
	stubs     map[string]Stub
	stubMutex sync.Mutex
}

type Stub struct {
	Method string `json:"method"`
	Path   string `json:"path"`
	Body   string `json:"body"`
}

func (h *StubHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Always lock the stubs map for the duration of the request.
	// Note that this effectively serializes all calls through StubHandler.
	// As this is only used for testing this is deemed acceptable.
	h.stubMutex.Lock()
	defer h.stubMutex.Unlock()

	if req.URL.Path == "/stub" && req.Method == "POST" {
		h.createStubHandler(w, req)
	} else {
		h.returnStubHandler(w, req)
	}
}

func (h *StubHandler) createStubHandler(w http.ResponseWriter, req *http.Request) {
	var stub Stub
	jsonDecoder := json.NewDecoder(req.Body)
	err := jsonDecoder.Decode(&stub)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		_, err = fmt.Fprintf(w, "Invalid JSON: %v", err)
		if err != nil {
			log.Printf("Could not send response to client due to: %v", err)
		}
	}

	h.stubs[stub.Path] = stub
}

func (h *StubHandler) returnStubHandler(w http.ResponseWriter, req *http.Request) {
	if stub, ok := h.stubs[req.URL.Path]; ok {
		if stub.Method == req.Method {
			_, err := io.WriteString(w, stub.Body)
			if err != nil {
				log.Printf("Could not send response to client due to: %v", err)
			}
		}
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func NewStubHandler() *StubHandler {
	var s StubHandler
	s.stubs = make(map[string]Stub)
	return &s
}

func main() {
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
)

var configFile, dataDir string
var isPrintVersion bool

func init() {
	flag.StringVar(&configFile, "config", "", "Path to config file")
	flag.StringVar(&dataDir, "data", "", "Path to data dir for cache")
	flag.BoolVar(&isPrintVersion, "version", false, "Whether showing version")

	flag.Parse()
}

func main() {
	if isPrintVersion {
		printVersion()
		return
	}

	if len(configFile) == 0 || len(dataDir) == 0 {
		flag.PrintDefaults()
		return
	}

	config, err := LoadConfigFromFile(configFile)

	if err != nil {
		panic(err)
	}

	for name, values := range config {
		perform(name, values)
	}
}

func printVersion() {
	fmt.Printf("zatsu_monitor v%s\n", VERSION)
}

func perform(name string, values map[string]string) {
	notifier_type := values["type"]

	var notifier Notifier

	switch notifier_type {
	case "chatwork":
		notifier = NewChatworkNotifier(values["api_token"], values["room_id"])
	case "slack":
		notifier = NewSlackNotifier(values["api_token"], values["user_name"], values["channel"])
	default:
		panic(fmt.Sprintf("Unknown type: %s in %s", notifier_type, configFile))
	}

	// If it does not exist even one expected key, skip
	for _, expectedKey := range notifier.ExpectedKeys() {
		if _, ok := values[expectedKey]; !ok {
			return
		}
	}

	checkUrl := values["check_url"]
	currentStatusCode, httpError := GetStatusCode(checkUrl)
	log.Printf("%s [status %d] %v\n", checkUrl, currentStatusCode, httpError)

	store := NewStatusStore(dataDir)
	beforeStatusCode, err := store.GetDbStatus(name)

	if err != nil {
		panic(err)
	}

	err = store.SaveDbStatus(name, currentStatusCode)

	if err != nil {
		panic(err)
	}

	if beforeStatusCode != NOT_FOUND_KEY && beforeStatusCode != currentStatusCode {
		// When status code changes from the previous, notify
		param := PostStatusParam{
			CheckUrl:          checkUrl,
			BeforeStatusCode:  beforeStatusCode,
			CurrentStatusCode: currentStatusCode,
			HttpError:         httpError,
		}
		notifier.PostStatus(&param)
	}
}
<commit_msg>Use ltsv log format instead of plain text<commit_after>package main

import (
	"flag"
	"fmt"
	"time"
)

var configFile, dataDir string
var isPrintVersion bool

func init() {
	flag.StringVar(&configFile, "config", "", "Path to config file")
	flag.StringVar(&dataDir, "data", "", "Path to data dir for cache")
	flag.BoolVar(&isPrintVersion, "version", false, "Whether showing version")

	flag.Parse()
}

func main() {
	if isPrintVersion {
		printVersion()
		return
	}

	if len(configFile) == 0 || len(dataDir) == 0 {
		flag.PrintDefaults()
		return
	}

	config, err := LoadConfigFromFile(configFile)

	if err != nil {
		panic(err)
	}

	for name, values := range config {
		perform(name, values)
	}
}

func printVersion() {
	fmt.Printf("zatsu_monitor v%s\n", VERSION)
}

func perform(name string, values map[string]string) {
	notifier_type := values["type"]

	var notifier Notifier

	switch notifier_type {
	case "chatwork":
		notifier = NewChatworkNotifier(values["api_token"], values["room_id"])
	case "slack":
		notifier = NewSlackNotifier(values["api_token"], values["user_name"], values["channel"])
	default:
		panic(fmt.Sprintf("Unknown type: %s in %s", notifier_type, configFile))
	}

	// If it does not exist even one expected key, skip
	for _, expectedKey := range notifier.ExpectedKeys() {
		if _, ok := values[expectedKey]; !ok {
			return
		}
	}

	checkUrl := values["check_url"]
	currentStatusCode, httpError := GetStatusCode(checkUrl)
	fmt.Printf("time:%v\tcheck_url:%s\tstatus:%d\terror:%v\n", time.Now(), checkUrl, currentStatusCode, httpError)

	store := NewStatusStore(dataDir)
	beforeStatusCode, err := store.GetDbStatus(name)

	if err != nil {
		panic(err)
	}

	err = store.SaveDbStatus(name, currentStatusCode)

	if err != nil {
		panic(err)
	}

	if beforeStatusCode != NOT_FOUND_KEY && beforeStatusCode != currentStatusCode {
		// When status code changes from the previous, notify
		param := PostStatusParam{
			CheckUrl:          checkUrl,
			BeforeStatusCode:  beforeStatusCode,
			CurrentStatusCode: currentStatusCode,
			HttpError:         httpError,
		}
		notifier.PostStatus(&param)
	}
}
<|endoftext|>


<commit_before>package main

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import (
	"io/ioutil"

	"code.google.com/p/go.net/websocket"
	flags "github.com/jessevdk/go-flags"
	"github.com/mozilla-services/FindMyDevice/util"
	"github.com/mozilla-services/FindMyDevice/wmf"

	// Only add the following for devel.
	//	_ "net/http/pprof"

	"bytes"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"
)

var opts struct {
	ConfigFile string `short:"c" long:"config" description:"Configuration file"`
	Profile    string `long:"profile"`
	MemProfile string `long:"memprofile"`
	LogLevel   int    `short:"l" long:"loglevel"`
	LogFile    string `short:"o" long:"logfile"`

	Ddlcreate    string `long:"ddlcreate" description:"Create a new version"`
	Ddldowngrade string `long:"ddldowngrade" description:"Downgrade to a specific version"`
	Ddlupgrade   bool   `long:"ddlupgrade" description:"Upgrade database to latest"`
	Ddllog       bool   `long:"ddllog" description:"Show a revision history of the database"`
}

const (
	// VERSION is the version number for system.
	VERSION = "1.4.3"
	SERVER  = "FindMyDevice"
)

// get the latest version from the file, "GITREF"
func getCodeVersionFromFile() string {
	vers, err := ioutil.ReadFile("GITREF")
	if err != nil {
		log.Print(err)
		return ""
	}
	return strings.TrimSpace(string(vers))
}

// get the latest version from git.
// If this isn't a git install, report "Unknown"
func getCodeVersion() string {
	if vers := getCodeVersionFromFile(); vers != "" {
		return vers
	}
	var buffer = new(bytes.Buffer)
	cmd := exec.Command("git", "rev-parse", "HEAD")
	cmd.Stdout = buffer
	err := cmd.Run()
	if err != nil {
		log.Printf("Could not get Git Version: %s", err.Error())
		return "Unknown"
	}
	return strings.TrimSpace(buffer.String())
}

func main() {
	if _, err := flags.ParseArgs(&opts, os.Args); err != nil {
		log.Fatalf(err.Error())
		return
	}

	// Configuration
	// TODO: switch to regular go flag package
	// defaults don't appear to work.
	if opts.ConfigFile == "" {
		opts.ConfigFile = "config.ini"
	}

	config, err := util.ReadMzConfig(opts.ConfigFile)
	if err != nil {
		log.Fatalf("Could not read config file %s: %s", opts.ConfigFile, err.Error())
		return
	}

	fullVers := fmt.Sprintf("%s-%s", config.Get("VERSION", VERSION),
		getCodeVersion())
	config.Override("VERSION", fullVers)
	config.Override("SERVER", SERVER)
	config.Override("ddl.create", opts.Ddlcreate)
	config.Override("ddl.downgrade", opts.Ddldowngrade)
	if opts.LogFile != "" {
		config.Override("logger.output", opts.LogFile)
	}
	if opts.Ddlupgrade {
		config.SetDefaultFlag("ddl.upgrade", true)
	}
	if opts.Ddllog {
		config.SetDefaultFlag("ddl.log", true)
	}
	sock_secret, _ := util.GenUUID4()
	config.SetDefault("ws.socket_secret", sock_secret)

	// Rest Config
	errChan := make(chan error)
	host := config.Get("host", "localhost")
	port := config.Get("port", "8080")

	if config.GetFlag("aws.get_hostname") {
		if hostname, err := util.GetAWSPublicHostname(); err == nil {
			config.SetDefault("ws_hostname", hostname)
		}
		if port != "80" {
			config.SetDefault("ws_hostname", config.Get("ws_hostname", "")+":"+port)
		}
	}

	// Partner cert pool contains the various self-signed certs that
	// partners may require to access their servers (for Proprietary
	// wake mechanisms like UDP)
	// This would be where you collect the certs and store them into
	// the config map as something like:
	// config["partnerCertPool"] = self.loadCerts()

	if opts.Profile != "" {
		log.Printf("Creating profile %s...\n", opts.Profile)
		f, err := os.Create(opts.Profile)
		if err != nil {
			log.Fatal(fmt.Sprintf("Profile creation failed:\n%s\n",
				err.Error()))
			return
		}
		defer func() {
			log.Printf("Writing app profile...\n")
			pprof.StopCPUProfile()
		}()
		pprof.StartCPUProfile(f)
	}
	if opts.MemProfile != "" {
		defer func() {
			profFile, err := os.Create(opts.MemProfile)
			if err != nil {
				log.Fatal(fmt.Sprintf("Memory Profile creation failed:\n%s\n", err.Error()))
				return
			}
			log.Printf("Writing memory profile...\n")
			pprof.WriteHeapProfile(profFile)
			profFile.Close()
		}()
	}

	runtime.GOMAXPROCS(runtime.NumCPU())
	logger := util.NewLogger(config)
	metrics := util.NewMetrics(config.Get(
		"metrics.prefix",
		"wmf"), logger, config)
	if err != nil {
		logger.Error("main", "Unable to connect to database. Have you configured it yet?", nil)
		return
	}
	if hawkCount := config.Get("hawk.nonce_cache", "1000"); hawkCount != "1000" {
		count, err := strconv.ParseInt(hawkCount, 10, 32)
		if err != nil {
			log.Printf("Could not read hawk.nonce_cache, defaulting to 1000")
		} else {
			wmf.InitHawkNonces(count)
		}
	}
	handlers := wmf.NewHandler(config, logger, metrics)
	if handlers == nil {
		log.Fatalf("Could not start server. Please check config.ini")
	}

	// Signal handler
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGHUP, syscall.SIGUSR1)

	var RESTMux = http.DefaultServeMux
	var WSMux = http.DefaultServeMux
	var verRoot = strings.SplitN(VERSION, ".", 2)[0]

	// REST calls

	RESTMux.HandleFunc(fmt.Sprintf("/%s/register/", verRoot),
		handlers.Register)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/cmd/", verRoot),
		handlers.Cmd)
	// Web UI calls
	RESTMux.HandleFunc(fmt.Sprintf("/%s/queue/", verRoot),
		handlers.RestQueue)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/state/", verRoot),
		handlers.State)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/l10n/client.json", verRoot),
		handlers.Language)
	// Static files (served by nginx in production)
	if config.GetFlag("use_insecure_static") {
		RESTMux.HandleFunc("/bower_components/",
			handlers.Static)
		RESTMux.HandleFunc("/images/",
			handlers.Static)
		RESTMux.HandleFunc("/scripts/",
			handlers.Static)
		RESTMux.HandleFunc("/styles/",
			handlers.Static)
	}
	// Metrics
	RESTMux.HandleFunc("/metrics/",
		handlers.Metrics)
	// Operations call
	RESTMux.HandleFunc("/status/",
		handlers.Status)
	//Signin
	// set state nonce & check if valid at signin
	RESTMux.HandleFunc("/signin/",
		handlers.Signin)
	//Signout
	RESTMux.HandleFunc("/signout/",
		handlers.Signout)
	// Config option because there are other teams involved.
	auth := config.Get("fxa.redir_uri", "/oauth/")
	RESTMux.HandleFunc(auth, handlers.OAuthCallback)

	WSMux.Handle(fmt.Sprintf("/%s/ws/", verRoot),
		websocket.Handler(handlers.WSSocketHandler))
	// Handle root calls as webUI
	// Get a list of registered devices for the currently logged in user
	RESTMux.HandleFunc(fmt.Sprintf("/%s/devices/", verRoot),
		handlers.UserDevices)
	// Get an object describing the data for a user's device
	// e.g. http://host/0/data/0123deviceid
	RESTMux.HandleFunc(fmt.Sprintf("/%s/data/", verRoot),
		handlers.InitDataJson)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/validate/", verRoot),
		handlers.Validate)
	RESTMux.HandleFunc("/",
		handlers.Index)

	logger.Info("main", "startup...",
		util.Fields{"host": host, "port": port, "version": fullVers})

	go func() {
		errChan <- http.ListenAndServe(host+":"+port, nil)
	}()

	select {
	case err := <-errChan:
		if err != nil {
			log.Fatalf("ListenAndServe: " + err.Error())
		}
	case <-sigChan:
		logger.Info("main", "Shutting down...", nil)
	}
}
<commit_msg>Up version<commit_after>package main

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import (
	"io/ioutil"

	"code.google.com/p/go.net/websocket"
	flags "github.com/jessevdk/go-flags"
	"github.com/mozilla-services/FindMyDevice/util"
	"github.com/mozilla-services/FindMyDevice/wmf"

	// Only add the following for devel.
	//	_ "net/http/pprof"

	"bytes"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"
)

var opts struct {
	ConfigFile string `short:"c" long:"config" description:"Configuration file"`
	Profile    string `long:"profile"`
	MemProfile string `long:"memprofile"`
	LogLevel   int    `short:"l" long:"loglevel"`
	LogFile    string `short:"o" long:"logfile"`

	Ddlcreate    string `long:"ddlcreate" description:"Create a new version"`
	Ddldowngrade string `long:"ddldowngrade" description:"Downgrade to a specific version"`
	Ddlupgrade   bool   `long:"ddlupgrade" description:"Upgrade database to latest"`
	Ddllog       bool   `long:"ddllog" description:"Show a revision history of the database"`
}

const (
	// VERSION is the version number for system.
	VERSION = "1.4.5"
	SERVER  = "FindMyDevice"
)

// get the latest version from the file, "GITREF"
func getCodeVersionFromFile() string {
	vers, err := ioutil.ReadFile("GITREF")
	if err != nil {
		log.Print(err)
		return ""
	}
	return strings.TrimSpace(string(vers))
}

// get the latest version from git.
// If this isn't a git install, report "Unknown"
func getCodeVersion() string {
	if vers := getCodeVersionFromFile(); vers != "" {
		return vers
	}
	var buffer = new(bytes.Buffer)
	cmd := exec.Command("git", "rev-parse", "HEAD")
	cmd.Stdout = buffer
	err := cmd.Run()
	if err != nil {
		log.Printf("Could not get Git Version: %s", err.Error())
		return "Unknown"
	}
	return strings.TrimSpace(buffer.String())
}

func main() {
	if _, err := flags.ParseArgs(&opts, os.Args); err != nil {
		log.Fatalf(err.Error())
		return
	}

	// Configuration
	// TODO: switch to regular go flag package
	// defaults don't appear to work.
	if opts.ConfigFile == "" {
		opts.ConfigFile = "config.ini"
	}

	config, err := util.ReadMzConfig(opts.ConfigFile)
	if err != nil {
		log.Fatalf("Could not read config file %s: %s", opts.ConfigFile, err.Error())
		return
	}

	fullVers := fmt.Sprintf("%s-%s", config.Get("VERSION", VERSION),
		getCodeVersion())
	config.Override("VERSION", fullVers)
	config.Override("SERVER", SERVER)
	config.Override("ddl.create", opts.Ddlcreate)
	config.Override("ddl.downgrade", opts.Ddldowngrade)
	if opts.LogFile != "" {
		config.Override("logger.output", opts.LogFile)
	}
	if opts.Ddlupgrade {
		config.SetDefaultFlag("ddl.upgrade", true)
	}
	if opts.Ddllog {
		config.SetDefaultFlag("ddl.log", true)
	}
	sock_secret, _ := util.GenUUID4()
	config.SetDefault("ws.socket_secret", sock_secret)

	// Rest Config
	errChan := make(chan error)
	host := config.Get("host", "localhost")
	port := config.Get("port", "8080")

	if config.GetFlag("aws.get_hostname") {
		if hostname, err := util.GetAWSPublicHostname(); err == nil {
			config.SetDefault("ws_hostname", hostname)
		}
		if port != "80" {
			config.SetDefault("ws_hostname", config.Get("ws_hostname", "")+":"+port)
		}
	}

	// Partner cert pool contains the various self-signed certs that
	// partners may require to access their servers (for Proprietary
	// wake mechanisms like UDP)
	// This would be where you collect the certs and store them into
	// the config map as something like:
	// config["partnerCertPool"] = self.loadCerts()

	if opts.Profile != "" {
		log.Printf("Creating profile %s...\n", opts.Profile)
		f, err := os.Create(opts.Profile)
		if err != nil {
			log.Fatal(fmt.Sprintf("Profile creation failed:\n%s\n",
				err.Error()))
			return
		}
		defer func() {
			log.Printf("Writing app profile...\n")
			pprof.StopCPUProfile()
		}()
		pprof.StartCPUProfile(f)
	}
	if opts.MemProfile != "" {
		defer func() {
			profFile, err := os.Create(opts.MemProfile)
			if err != nil {
				log.Fatal(fmt.Sprintf("Memory Profile creation failed:\n%s\n", err.Error()))
				return
			}
			log.Printf("Writing memory profile...\n")
			pprof.WriteHeapProfile(profFile)
			profFile.Close()
		}()
	}

	runtime.GOMAXPROCS(runtime.NumCPU())
	logger := util.NewLogger(config)
	metrics := util.NewMetrics(config.Get(
		"metrics.prefix",
		"wmf"), logger, config)
	if err != nil {
		logger.Error("main", "Unable to connect to database. Have you configured it yet?", nil)
		return
	}
	if hawkCount := config.Get("hawk.nonce_cache", "1000"); hawkCount != "1000" {
		count, err := strconv.ParseInt(hawkCount, 10, 32)
		if err != nil {
			log.Printf("Could not read hawk.nonce_cache, defaulting to 1000")
		} else {
			wmf.InitHawkNonces(count)
		}
	}
	handlers := wmf.NewHandler(config, logger, metrics)
	if handlers == nil {
		log.Fatalf("Could not start server. Please check config.ini")
	}

	// Signal handler
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGHUP, syscall.SIGUSR1)

	var RESTMux = http.DefaultServeMux
	var WSMux = http.DefaultServeMux
	var verRoot = strings.SplitN(VERSION, ".", 2)[0]

	// REST calls

	RESTMux.HandleFunc(fmt.Sprintf("/%s/register/", verRoot),
		handlers.Register)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/cmd/", verRoot),
		handlers.Cmd)
	// Web UI calls
	RESTMux.HandleFunc(fmt.Sprintf("/%s/queue/", verRoot),
		handlers.RestQueue)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/state/", verRoot),
		handlers.State)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/l10n/client.json", verRoot),
		handlers.Language)
	// Static files (served by nginx in production)
	if config.GetFlag("use_insecure_static") {
		RESTMux.HandleFunc("/bower_components/",
			handlers.Static)
		RESTMux.HandleFunc("/images/",
			handlers.Static)
		RESTMux.HandleFunc("/scripts/",
			handlers.Static)
		RESTMux.HandleFunc("/styles/",
			handlers.Static)
	}
	// Metrics
	RESTMux.HandleFunc("/metrics/",
		handlers.Metrics)
	// Operations call
	RESTMux.HandleFunc("/status/",
		handlers.Status)
	//Signin
	// set state nonce & check if valid at signin
	RESTMux.HandleFunc("/signin/",
		handlers.Signin)
	//Signout
	RESTMux.HandleFunc("/signout/",
		handlers.Signout)
	// Config option because there are other teams involved.
	auth := config.Get("fxa.redir_uri", "/oauth/")
	RESTMux.HandleFunc(auth, handlers.OAuthCallback)

	WSMux.Handle(fmt.Sprintf("/%s/ws/", verRoot),
		websocket.Handler(handlers.WSSocketHandler))
	// Handle root calls as webUI
	// Get a list of registered devices for the currently logged in user
	RESTMux.HandleFunc(fmt.Sprintf("/%s/devices/", verRoot),
		handlers.UserDevices)
	// Get an object describing the data for a user's device
	// e.g. http://host/0/data/0123deviceid
	RESTMux.HandleFunc(fmt.Sprintf("/%s/data/", verRoot),
		handlers.InitDataJson)
	RESTMux.HandleFunc(fmt.Sprintf("/%s/validate/", verRoot),
		handlers.Validate)
	RESTMux.HandleFunc("/",
		handlers.Index)

	logger.Info("main", "startup...",
		util.Fields{"host": host, "port": port, "version": fullVers})

	go func() {
		errChan <- http.ListenAndServe(host+":"+port, nil)
	}()

	select {
	case err := <-errChan:
		if err != nil {
			log.Fatalf("ListenAndServe: " + err.Error())
		}
	case <-sigChan:
		logger.Info("main", "Shutting down...", nil)
	}
}
<|endoftext|>