<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
	version   string
	branch    string
	revision  string
	buildDate string
	goVersion = runtime.Version()
)

var (
	prometheusAddress     = flag.String("metrics-listen-address", ":9001", "The address to listen on for Prometheus metrics requests.")
	prometheusMetricsPath = flag.String("metrics-path", "/metrics", "The path to listen for Prometheus metrics requests.")
	apiAddress            = flag.String("api-listen-address", ":5000", "The address to listen on for api HTTP requests.")

	// seed random number
	r = rand.New(rand.NewSource(time.Now().UnixNano()))

	// define prometheus counter
	webhookTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "estafette_ci_api_webhook_totals",
			Help: "Total of received webhooks.",
		},
		[]string{"event", "source"},
	)
)

func init() {
	// Metrics have to be registered to be exposed:
	prometheus.MustRegister(webhookTotal)
}

func main() {

	// set some default fields added to all logs
	log := zerolog.New(os.Stdout).With().
		Timestamp().
		Str("app", "estafette-ci-api").
		Str("version", version).
		Logger()

	// log startup message
	log.Info().
		Str("branch", branch).
		Str("revision", revision).
		Str("buildDate", buildDate).
		Str("goVersion", goVersion).
		Msg("Starting estafette-ci-api...")

	// start prometheus
	go func() {
		log.Info().
			Str("port", *prometheusAddress).
			Str("path", *prometheusMetricsPath).
			Msg("Serving Prometheus metrics...")

		http.Handle(*prometheusMetricsPath, promhttp.Handler())

		if err := http.ListenAndServe(*prometheusAddress, nil); err != nil {
			log.Fatal().Err(err).Msg("Starting Prometheus listener failed")
		}
	}()

	log.Info().
		Str("port", *apiAddress).
		Msg("Serving api calls...")

	http.HandleFunc("/webhook/github", githubWebhookHandler)
	http.HandleFunc("/webhook/bitbucket", bitbucketWebhookHandler)
	http.HandleFunc("/liveness", livenessHandler)
	http.HandleFunc("/readiness", readinessHandler)

	if err := http.ListenAndServe(*apiAddress, nil); err != nil {
		log.Fatal().Err(err).Msg("Starting api listener failed")
	}
}

func githubWebhookHandler(w http.ResponseWriter, r *http.Request) {

	// https://developer.github.com/webhooks/
	eventType := r.Header.Get("X-GitHub-Event")
	webhookTotal.With(prometheus.Labels{"event": eventType, "source": "github"}).Inc()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error().Err(err).Msg("Reading body from Github webhook failed")
		http.Error(w, "Reading body from Github webhook failed", 500)
		return
	}

	// unmarshal json body
	var b interface{}
	err = json.Unmarshal(body, &b)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body from Github webhook failed")
		http.Error(w, "Deserializing body from Github webhook failed", 500)
		return
	}

	log.Info().
		Str("method", r.Method).
		Str("url", r.URL.String()).
		Interface("headers", r.Header).
		Interface("body", b).
		Msgf("Received webhook event '%v' from GitHub...", eventType)

	switch eventType {
	case "push":
		handleGithubPush(body)
	default:
		log.Warn().Str("event", eventType).Msgf("Unsupported Github webhook event '%v'", eventType)
	}

	fmt.Fprintf(w, "Aye aye!")
}

func bitbucketWebhookHandler(w http.ResponseWriter, r *http.Request) {

	// https://confluence.atlassian.com/bitbucket/manage-webhooks-735643732.html

	eventType := r.Header.Get("X-Event-Key")
	webhookTotal.With(prometheus.Labels{"event": eventType, "source": "bitbucket"}).Inc()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error().Err(err).Msg("Reading body from Bitbucket webhook failed")
		http.Error(w, "Reading body from Bitbucket webhook failed", 500)
		return
	}

	// unmarshal json body
	var b interface{}
	err = json.Unmarshal(body, &b)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body from Bitbucket webhook failed")
		http.Error(w, "Deserializing body from Bitbucket webhook failed", 500)
		return
	}

	log.Info().
		Str("method", r.Method).
		Str("url", r.URL.String()).
		Interface("headers", r.Header).
		Interface("body", string(body)).
		Msgf("Received webhook event '%v' from Bitbucket", eventType)

	switch eventType {
	case "repo:push":
		handleBitbucketPush(body)
	default:
		log.Warn().Str("event", eventType).Msgf("Unsupported Bitbucket webhook event '%v'", eventType)
	}

	fmt.Fprintf(w, "Aye aye!")
}

// GithubPushEvent represents a Github webhook push event
type GithubPushEvent struct {
	After      string           `json:"after"`
	Commits    []GithubCommit   `json:"commits"`
	HeadCommit GithubCommit     `json:"head_commit"`
	Pusher     GithubPusher     `json:"pusher"`
	Repository GithubRepository `json:"repository"`
}

// GithubCommit represents a Github commit
type GithubCommit struct {
	Author  GithubAuthor `json:"author"`
	Message string       `json:"message"`
	ID      string       `json:"id"`
}

// GithubAuthor represents a Github author
type GithubAuthor struct {
	Email    string `json:"email"`
	Name     string `json:"name"`
	UserName string `json:"username"`
}

// GithubPusher represents a Github pusher
type GithubPusher struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

// GithubRepository represents a Github repository
type GithubRepository struct {
	GitURL   string `json:"git_url"`
	HTMLURL  string `json:"html_url"`
	Name     string `json:"name"`
	FullName string `json:"full_name"`
}

func handleGithubPush(body []byte) {

	// unmarshal json body
	var pushEvent GithubPushEvent
	err := json.Unmarshal(body, &pushEvent)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body to GithubPushEvent failed")
		return
	}

	log.Info().Interface("pushEvent", pushEvent).Msg("Deserialized GitHub push event")
}

func handleBitbucketPush(body []byte) {

}

func livenessHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "I'm alive!")
}

func readinessHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "I'm ready!")
}
<commit_msg>update log messages<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
	version   string
	branch    string
	revision  string
	buildDate string
	goVersion = runtime.Version()
)

var (
	prometheusAddress     = flag.String("metrics-listen-address", ":9001", "The address to listen on for Prometheus metrics requests.")
	prometheusMetricsPath = flag.String("metrics-path", "/metrics", "The path to listen for Prometheus metrics requests.")
	apiAddress            = flag.String("api-listen-address", ":5000", "The address to listen on for api HTTP requests.")

	// seed random number
	r = rand.New(rand.NewSource(time.Now().UnixNano()))

	// define prometheus counter
	webhookTotal = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "estafette_ci_api_webhook_totals",
			Help: "Total of received webhooks.",
		},
		[]string{"event", "source"},
	)
)

func init() {
	// Metrics have to be registered to be exposed:
	prometheus.MustRegister(webhookTotal)
}

func main() {

	// set some default fields added to all logs
	log := zerolog.New(os.Stdout).With().
		Timestamp().
		Str("app", "estafette-ci-api").
		Str("version", version).
		Logger()

	// log startup message
	log.Info().
		Str("branch", branch).
		Str("revision", revision).
		Str("buildDate", buildDate).
		Str("goVersion", goVersion).
		Msg("Starting estafette-ci-api...")

	// start prometheus
	go func() {
		log.Info().
			Str("port", *prometheusAddress).
			Str("path", *prometheusMetricsPath).
			Msg("Serving Prometheus metrics...")

		http.Handle(*prometheusMetricsPath, promhttp.Handler())

		if err := http.ListenAndServe(*prometheusAddress, nil); err != nil {
			log.Fatal().Err(err).Msg("Starting Prometheus listener failed")
		}
	}()

	log.Info().
		Str("port", *apiAddress).
		Msg("Serving api calls...")

	http.HandleFunc("/webhook/github", githubWebhookHandler)
	http.HandleFunc("/webhook/bitbucket", bitbucketWebhookHandler)
	http.HandleFunc("/liveness", livenessHandler)
	http.HandleFunc("/readiness", readinessHandler)

	if err := http.ListenAndServe(*apiAddress, nil); err != nil {
		log.Fatal().Err(err).Msg("Starting api listener failed")
	}
}

func githubWebhookHandler(w http.ResponseWriter, r *http.Request) {

	// https://developer.github.com/webhooks/
	eventType := r.Header.Get("X-GitHub-Event")
	webhookTotal.With(prometheus.Labels{"event": eventType, "source": "github"}).Inc()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error().Err(err).Msg("Reading body from Github webhook failed")
		http.Error(w, "Reading body from Github webhook failed", 500)
		return
	}

	// unmarshal json body
	var b interface{}
	err = json.Unmarshal(body, &b)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body from Github webhook failed")
		http.Error(w, "Deserializing body from Github webhook failed", 500)
		return
	}

	log.Info().
		Str("method", r.Method).
		Str("url", r.URL.String()).
		Interface("headers", r.Header).
		Interface("body", b).
		Msgf("Received webhook event of type '%v' from GitHub...", eventType)

	switch eventType {
	case "push":
		handleGithubPush(body)
	default:
		log.Warn().Str("event", eventType).Msgf("Unsupported Github webhook event of type '%v'", eventType)
	}

	fmt.Fprintf(w, "Aye aye!")
}

func bitbucketWebhookHandler(w http.ResponseWriter, r *http.Request) {

	// https://confluence.atlassian.com/bitbucket/manage-webhooks-735643732.html

	eventType := r.Header.Get("X-Event-Key")
	webhookTotal.With(prometheus.Labels{"event": eventType, "source": "bitbucket"}).Inc()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Error().Err(err).Msg("Reading body from Bitbucket webhook failed")
		http.Error(w, "Reading body from Bitbucket webhook failed", 500)
		return
	}

	// unmarshal json body
	var b interface{}
	err = json.Unmarshal(body, &b)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body from Bitbucket webhook failed")
		http.Error(w, "Deserializing body from Bitbucket webhook failed", 500)
		return
	}

	log.Info().
		Str("method", r.Method).
		Str("url", r.URL.String()).
		Interface("headers", r.Header).
		Interface("body", string(body)).
		Msgf("Received webhook event of type '%v' from Bitbucket", eventType)

	switch eventType {
	case "repo:push":
		handleBitbucketPush(body)
	default:
		log.Warn().Str("event", eventType).Msgf("Unsupported Bitbucket webhook event of type '%v'", eventType)
	}

	fmt.Fprintf(w, "Aye aye!")
}

// GithubPushEvent represents a Github webhook push event
type GithubPushEvent struct {
	After      string           `json:"after"`
	Commits    []GithubCommit   `json:"commits"`
	HeadCommit GithubCommit     `json:"head_commit"`
	Pusher     GithubPusher     `json:"pusher"`
	Repository GithubRepository `json:"repository"`
}

// GithubCommit represents a Github commit
type GithubCommit struct {
	Author  GithubAuthor `json:"author"`
	Message string       `json:"message"`
	ID      string       `json:"id"`
}

// GithubAuthor represents a Github author
type GithubAuthor struct {
	Email    string `json:"email"`
	Name     string `json:"name"`
	UserName string `json:"username"`
}

// GithubPusher represents a Github pusher
type GithubPusher struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

// GithubRepository represents a Github repository
type GithubRepository struct {
	GitURL   string `json:"git_url"`
	HTMLURL  string `json:"html_url"`
	Name     string `json:"name"`
	FullName string `json:"full_name"`
}

func handleGithubPush(body []byte) {

	// unmarshal json body
	var pushEvent GithubPushEvent
	err := json.Unmarshal(body, &pushEvent)
	if err != nil {
		log.Error().Err(err).Str("body", string(body)).Msg("Deserializing body to GithubPushEvent failed")
		return
	}

	log.Info().Interface("pushEvent", pushEvent).Msg("Deserialized GitHub push event")
}

func handleBitbucketPush(body []byte) {

}

func livenessHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "I'm alive!")
}

func readinessHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "I'm ready!")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
)

var PipelineFlag = flag.String("pipeline", "", "Id of pipeline to run")
var MessageFlag = flag.String("message", "Started by Go", "Message to attach to run")

func main() {

	flag.Parse()

	if len(*PipelineFlag) < 1 {
		fmt.Println("Need to set --pipeline option")
		return
	}

	url := "https://app.wercker.com/api/v3/runs/"
	client := &http.Client{}

	form := struct {
		PipelineId string `json:"pipelineId"`
		Message    string `json:"message"`
	}{
		PipelineId: *PipelineFlag,
		Message:    *MessageFlag,
	}

	buf, _ := json.Marshal(form)
	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(buf))
	req.Header.Add("Content-Type", " application/json")
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", WerckerBearerToken))
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
	}
	log.Println(resp)

	respBuffer := new(bytes.Buffer)
	respBuffer.ReadFrom(resp.Body)
	fmt.Println(respBuffer.String())

	defer resp.Body.Close()
}
<commit_msg>Added default Pipeline Id to executable<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
)

var PipelineFlag = flag.String("pipeline", WerckerPipelineId, "Id of pipeline to run")
var MessageFlag = flag.String("message", "Started by Go", "Message to attach to run")

func main() {

	flag.Parse()

	if len(*PipelineFlag) < 1 {
		fmt.Println("Need to set --pipeline option")
		return
	}

	url := "https://app.wercker.com/api/v3/runs/"
	client := &http.Client{}

	form := struct {
		PipelineId string `json:"pipelineId"`
		Message    string `json:"message"`
	}{
		PipelineId: *PipelineFlag,
		Message:    *MessageFlag,
	}

	buf, _ := json.Marshal(form)
	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(buf))
	req.Header.Add("Content-Type", " application/json")
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", WerckerBearerToken))
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
	}
	log.Println(resp)

	respBuffer := new(bytes.Buffer)
	respBuffer.ReadFrom(resp.Body)
	fmt.Println(respBuffer.String())

	defer resp.Body.Close()
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

// Marauder is 2D turn-based hexagonal strategy game.
//
package main

import (
	"fmt"
	"github.com/ozkriff/marauder/game"
	userInterface "github.com/ozkriff/marauder/ui"
)

func setSomeUnwalkableTiles(m *game.Gameboard) {
	coordinates := []game.Pos{
		{X: 5, Y: 5},
		{X: 4, Y: 6},
		{X: 4, Y: 7},
		{X: 4, Y: 8},
		{X: 4, Y: 9},
		{X: 4, Y: 10},
		{X: 4, Y: 11},
		{X: 4, Y: 12},
		{X: 4, Y: 13},
		{X: 4, Y: 14},
		{X: 5, Y: 5},
		{X: 6, Y: 5},
		{X: 7, Y: 5},
		{X: 8, Y: 5},
		{X: 9, Y: 5},
	}
	for _, coord := range coordinates {
		m.Tile(coord).IsWalkable = false
	}
}

func main() {
	mapSize := game.Pos{X: 10, Y: 20}
	board := game.NewGameboard(mapSize)
	setSomeUnwalkableTiles(board)
	if true {
		// тест путенахождения
		pathfinder := game.Pathfinder{
			Board: board,
		}
		pathfinder.Fill(game.Pos{X: 1, Y: 2})
		game.PrintMapIsWalkable(*board)
		game.PrintMapCost(*board)
		p := pathfinder.GetPath(game.Pos{X: 9, Y: 9})
		fmt.Printf("%v\n", p)
		game.PrintPath(*board)
	} else {
		// нормальная игра
		core := game.NewCore(board)
		ui := userInterface.NewUserInterface(core)
		ui.Run()
		ui.Close()
	}
}
<commit_msg>main.go: ui <-> userInterface<commit_after>// See LICENSE file for copyright and license details.

// Marauder is 2D turn-based hexagonal strategy game.
//
package main

import (
	"fmt"
	"github.com/ozkriff/marauder/game"
	"github.com/ozkriff/marauder/ui"
)

func setSomeUnwalkableTiles(m *game.Gameboard) {
	coordinates := []game.Pos{
		{X: 5, Y: 5},
		{X: 4, Y: 6},
		{X: 4, Y: 7},
		{X: 4, Y: 8},
		{X: 4, Y: 9},
		{X: 4, Y: 10},
		{X: 4, Y: 11},
		{X: 4, Y: 12},
		{X: 4, Y: 13},
		{X: 4, Y: 14},
		{X: 5, Y: 5},
		{X: 6, Y: 5},
		{X: 7, Y: 5},
		{X: 8, Y: 5},
		{X: 9, Y: 5},
	}
	for _, coord := range coordinates {
		m.Tile(coord).IsWalkable = false
	}
}

func main() {
	mapSize := game.Pos{X: 10, Y: 20}
	board := game.NewGameboard(mapSize)
	setSomeUnwalkableTiles(board)
	if true {
		// тест путенахождения
		pathfinder := game.Pathfinder{
			Board: board,
		}
		pathfinder.Fill(game.Pos{X: 1, Y: 2})
		game.PrintMapIsWalkable(*board)
		game.PrintMapCost(*board)
		p := pathfinder.GetPath(game.Pos{X: 9, Y: 9})
		fmt.Printf("%v\n", p)
		game.PrintPath(*board)
	} else {
		// нормальная игра
		core := game.NewCore(board)
		userInterface := ui.NewUserInterface(core)
		userInterface.Run()
		userInterface.Close()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/bgentry/pflag"
	"github.com/flynn/flynn-controller/client"
)

type Command struct {
	// args does not include the command name
	Run  func(cmd *Command, args []string, client *controller.Client) error
	Flag pflag.FlagSet

	Usage string // first word is the command name
	Short string // `flynn help` output
	Long  string // `flynn help cmd` output

	NoClient bool
}

func (c *Command) printUsage(errExit bool) {
	if c.Runnable() {
		fmt.Printf("Usage: %s %s\n\n", os.Args[0], c.Usage)
	}
	fmt.Println(strings.Trim(c.Long, "\n"))
	if errExit {
		os.Exit(2)
	}
}

func (c *Command) Name() string {
	name := c.Usage
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Runnable() bool {
	return c.Run != nil
}

// Running `flynn help` will list commands in this order.
var commands = []*Command{
	cmdRun,
	cmdPs,
	cmdLog,
	cmdScale,
	cmdCreate,
	cmdServerAdd,
	cmdRouteAddHTTP,
	cmdKeys,
	cmdKeyAdd,
	cmdKeyRemove,
}

var (
	flagServer = os.Getenv("FLYNN_SERVER")
	flagApp    string
	flagLong   bool
)

func main() {
	log.SetFlags(0)

	args := os.Args[1:]

	if len(args) >= 2 && "-a" == args[0] {
		flagApp = args[1]
		args = args[2:]

		if err := readConfig(); err != nil {
			log.Fatal(err)
		}

		if ra, err := appFromGitRemote(flagApp); err == nil {
			serverConf = ra.Server
			flagApp = ra.Name
		}
	}

	if len(args) < 1 {
		usage()
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() {
				cmd.printUsage(false)
			}
			if err := cmd.Flag.Parse(args[1:]); err != nil {
				os.Exit(2)
			}

			var client *controller.Client
			if !cmd.NoClient {
				server, err := server()
				if err != nil {
					log.Fatal(err)
				}
				if server.TLSPin != "" {
					pin, err := base64.StdEncoding.DecodeString(server.TLSPin)
					if err != nil {
						log.Fatalln("error decoding tls pin:", err)
					}
					client, err = controller.NewClientWithPin(server.URL, server.Key, pin)
				} else {
					client, err = controller.NewClient(server.URL, server.Key)
				}
				if err != nil {
					log.Fatal(err)
				}
			}
			if err := cmd.Run(cmd, cmd.Flag.Args(), client); err != nil {
				log.Fatal(err)
			}
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown command: %s\n", args[0])
	usage()
}

type Config struct {
	Servers []*ServerConfig `toml:"server"`
}

type ServerConfig struct {
	Name    string `json:"name"`
	GitHost string `json:"git_host"`
	URL     string `json:"url"`
	Key     string `json:"key"`
	TLSPin  string `json:"tls_pin"`
}

var config *Config
var serverConf *ServerConfig

func configPath() string {
	p := os.Getenv("FLYNNRC")
	if p == "" {
		p = filepath.Join(homedir(), ".flynnrc")
	}
	return p
}

func readConfig() error {
	if config != nil {
		return nil
	}
	conf := &Config{}
	_, err := toml.DecodeFile(configPath(), conf)
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	config = conf
	return nil
}

func homedir() string {
	if runtime.GOOS == "windows" {
		return os.Getenv("%APPDATA%")
	}
	return os.Getenv("HOME")
}

var ErrNoServers = errors.New("no servers configured")

func server() (*ServerConfig, error) {
	if serverConf != nil {
		return serverConf, nil
	}
	if err := readConfig(); err != nil {
		return nil, err
	}
	if len(config.Servers) == 0 {
		return nil, ErrNoServers
	}
	if flagServer == "" {
		serverConf = config.Servers[0]
		return serverConf, nil
	}
	for _, s := range config.Servers {
		if s.Name == flagServer {
			serverConf = s
			return s, nil
		}
	}
	return nil, fmt.Errorf("unknown server %q", flagServer)
}

var appName string

func app() (string, error) {
	if flagApp != "" {
		return flagApp, nil
	}
	if app := os.Getenv("FLYNN_APP"); app != "" {
		flagApp = app
		return app, nil
	}
	if err := readConfig(); err != nil {
		return "", err
	}

	ra, err := appFromGitRemote(remoteFromGitConfig())
	if err != nil {
		return "", err
	}
	serverConf = ra.Server
	flagApp = ra.Name
	return ra.Name, nil
}

func mustApp() string {
	name, err := app()
	if err != nil {
		log.Fatal(err)
	}
	return name
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}
<commit_msg>cli: Hook up update<commit_after>package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/bgentry/pflag"
	"github.com/flynn/flynn-controller/client"
)

type Command struct {
	// args does not include the command name
	Run  func(cmd *Command, args []string, client *controller.Client) error
	Flag pflag.FlagSet

	Usage string // first word is the command name
	Short string // `flynn help` output
	Long  string // `flynn help cmd` output

	NoClient bool
}

func (c *Command) printUsage(errExit bool) {
	if c.Runnable() {
		fmt.Printf("Usage: %s %s\n\n", os.Args[0], c.Usage)
	}
	fmt.Println(strings.Trim(c.Long, "\n"))
	if errExit {
		os.Exit(2)
	}
}

func (c *Command) Name() string {
	name := c.Usage
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Runnable() bool {
	return c.Run != nil
}

// Running `flynn help` will list commands in this order.
var commands = []*Command{
	cmdRun,
	cmdPs,
	cmdLog,
	cmdScale,
	cmdCreate,
	cmdServerAdd,
	cmdRouteAddHTTP,
	cmdKeys,
	cmdKeyAdd,
	cmdKeyRemove,
}

var (
	flagServer = os.Getenv("FLYNN_SERVER")
	flagApp    string
	flagLong   bool
)

func main() {
	log.SetFlags(0)

	args := os.Args[1:]

	// Run the update command as early as possible to avoid the possibility of
	// installations being stranded without updates due to errors in other code
	if args[0] == cmdUpdate.Name() {
		cmdUpdate.Run(cmdUpdate, args, nil)
		return
	} else if updater != nil {
		defer updater.backgroundRun() // doesn't run if os.Exit is called
	}

	if len(args) >= 2 && "-a" == args[0] {
		flagApp = args[1]
		args = args[2:]

		if err := readConfig(); err != nil {
			log.Fatal(err)
		}

		if ra, err := appFromGitRemote(flagApp); err == nil {
			serverConf = ra.Server
			flagApp = ra.Name
		}
	}

	if len(args) < 1 {
		usage()
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() {
				cmd.printUsage(false)
			}
			if err := cmd.Flag.Parse(args[1:]); err != nil {
				os.Exit(2)
			}

			var client *controller.Client
			if !cmd.NoClient {
				server, err := server()
				if err != nil {
					log.Fatal(err)
				}
				if server.TLSPin != "" {
					pin, err := base64.StdEncoding.DecodeString(server.TLSPin)
					if err != nil {
						log.Fatalln("error decoding tls pin:", err)
					}
					client, err = controller.NewClientWithPin(server.URL, server.Key, pin)
				} else {
					client, err = controller.NewClient(server.URL, server.Key)
				}
				if err != nil {
					log.Fatal(err)
				}
			}
			if err := cmd.Run(cmd, cmd.Flag.Args(), client); err != nil {
				log.Fatal(err)
			}
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown command: %s\n", args[0])
	usage()
}

type Config struct {
	Servers []*ServerConfig `toml:"server"`
}

type ServerConfig struct {
	Name    string `json:"name"`
	GitHost string `json:"git_host"`
	URL     string `json:"url"`
	Key     string `json:"key"`
	TLSPin  string `json:"tls_pin"`
}

var config *Config
var serverConf *ServerConfig

func configPath() string {
	p := os.Getenv("FLYNNRC")
	if p == "" {
		p = filepath.Join(homedir(), ".flynnrc")
	}
	return p
}

func readConfig() error {
	if config != nil {
		return nil
	}
	conf := &Config{}
	_, err := toml.DecodeFile(configPath(), conf)
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	config = conf
	return nil
}

func homedir() string {
	if runtime.GOOS == "windows" {
		return os.Getenv("%APPDATA%")
	}
	return os.Getenv("HOME")
}

var ErrNoServers = errors.New("no servers configured")

func server() (*ServerConfig, error) {
	if serverConf != nil {
		return serverConf, nil
	}
	if err := readConfig(); err != nil {
		return nil, err
	}
	if len(config.Servers) == 0 {
		return nil, ErrNoServers
	}
	if flagServer == "" {
		serverConf = config.Servers[0]
		return serverConf, nil
	}
	for _, s := range config.Servers {
		if s.Name == flagServer {
			serverConf = s
			return s, nil
		}
	}
	return nil, fmt.Errorf("unknown server %q", flagServer)
}

var appName string

func app() (string, error) {
	if flagApp != "" {
		return flagApp, nil
	}
	if app := os.Getenv("FLYNN_APP"); app != "" {
		flagApp = app
		return app, nil
	}
	if err := readConfig(); err != nil {
		return "", err
	}

	ra, err := appFromGitRemote(remoteFromGitConfig())
	if err != nil {
		return "", err
	}
	serverConf = ra.Server
	flagApp = ra.Name
	return ra.Name, nil
}

func mustApp() string {
	name, err := app()
	if err != nil {
		log.Fatal(err)
	}
	return name
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	"sync"

	"sort"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("Cannot get the user home dir.\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("Cannot open the file %s, due to error '%s'.\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
	if err := configurationFileStructure.Process(); err != nil {
		traces.ErrorTracer.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	currentGroupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool {
		return configurationFileStructure.Groups[i].Name == configurationFileStructure.Local.Group
	})
	var newVisibleRepositories []string
	for _, visibleRepository := range configurationFileStructure.VisibleRepositories {
		newVisibleRepositories = append(newVisibleRepositories, visibleRepository.Name)
	}
	configurationFileStructure.Groups[currentGroupIndex].VisibleRepositories = newVisibleRepositories
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("Cannot save the current configurationFile structure!")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("Cannot access to your file to save the configurationFile structure!")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	var addCmd = &cobra.Command{
		Use:   "add",
		Short: "Add the current path as a VISIBLE repository",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if !utils.IsGitRepository(currentDir) {
				log.Fatalf("%s is not a git repository!\n", currentDir)
			}
			// If the path is/contains a .git directory, add this one as a VISIBLE repository
			if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
				traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
			}
		},
	}

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("There was an error retrieving your git repositories: '%s'\n", err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	var loadCmd = &cobra.Command{
		Use:   "load",
		Short: "Load the configuration file to restore your previous work space",
		Run: func(cmd *cobra.Command, args []string) {
			currentLocalhost := utils.GetLocalhost()
			configGroups := configurationFileStructure.Groups
			for {
				if utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost }) == -1 {
					traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
					fmt.Println("Please to choose one of those, to load the configuration file:")
					for _, group := range configGroups {
						fmt.Printf("\t%s\n", group)
					}
					scanner := bufio.NewScanner(os.Stdin)
					currentLocalhost = scanner.Text()
					continue
				}
				break
			}
		},
	}

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	var pathCmd = &cobra.Command{
		Use:   "path",
		Short: "Get the path of a given repository, if this one exists",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				log.Fatalln("Needs a repository name!")
			}
			repo := args[0]
			repoPath := configurationFileStructure.GetPathFromRepository(repo)
			if repoPath != "" {
				fmt.Println(repoPath)
			} else {
				log.Fatalf("The repository %s does not exists!\n", repo)
			}
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			var gitStructs []configurationFile.GitRepository
			if len(args) == 0 {
				gitStructs = configurationFileStructure.VisibleRepositories
			} else {
				// Sort visible repositories by name
				sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
				repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
				// Looking for given repository names - if the looking one does not exists, let the function prints a warning message.
				for _, repositoryName := range args {
					repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
					if repositoryIndex != repositoriesListLength {
						gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
					}
				}
			}
			var wg sync.WaitGroup
			for _, gitStruct := range gitStructs {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init()
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	var switchCmd = &cobra.Command{
		Use:   "switch",
		Short: "Switch the visibility of the current git repository (given by the current path)",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.VisibleFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.HiddenFlag)
				traces.InfoTracer.Printf("%s has been set to an hidden repository!", currentDir)
				return
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.HiddenFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
				traces.InfoTracer.Printf("%s has been set to a visible repository!", currentDir)
				return
			}
			log.Fatalf("The repository %s is not saved as a VISIBLE or HIDDEN repository! Please to add it before.\n", currentDir)
		},
	}

	rootCmd.AddCommand(addCmd, crawlCmd, loadCmd, pathCmd, stateCmd, switchCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>New command line behaviours<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	"sync"

	"sort"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/gitManip"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("Cannot get the user home dir.\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("Cannot open the file %s, due to error '%s'.\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	currentGroupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool {
		return configurationFileStructure.Groups[i].Name == configurationFileStructure.Local.Group
	})
	var newVisibleRepositories []string
	for _, visibleRepository := range configurationFileStructure.VisibleRepositories {
		newVisibleRepositories = append(newVisibleRepositories, visibleRepository.Name)
	}
	configurationFileStructure.Groups[currentGroupIndex].VisibleRepositories = newVisibleRepositories
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("Cannot save the current configurationFile structure!")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("Cannot access to your file to save the configurationFile structure!")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	var addCmd = &cobra.Command{
		Use:   "add",
		Short: "Add the current path as a VISIBLE repository",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if !utils.IsGitRepository(currentDir) {
				log.Fatalf("%s is not a git repository!\n", currentDir)
			}
			if err := configurationFileStructure.Process(); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			// If the path is/contains a .git directory, add this one as a VISIBLE repository
			if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
				traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
			}
		},
	}

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("There was an error retrieving your git repositories: '%s'\n", err)
			}
			if err := configurationFileStructure.Process(); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*loadCmd permits to load visible repositories from the goyave configuration file
	 */
	var loadCmd = &cobra.Command{
		Use:   "load",
		Short: "Load the configuration file to restore your previous work space",
		Run: func(cmd *cobra.Command, args []string) {
			currentLocalhost := utils.GetLocalhost()
			fmt.Printf("Current localhost is %s\n", currentLocalhost)
			configGroups := configurationFileStructure.Groups
			var visibleRepositories []string
			for {
				index := utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost })
				if index == -1 {
					traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
					fmt.Println("Please to choose one of those, to load the configuration file:")
					for _, group := range configGroups {
						fmt.Printf("\t%s\n", group.Name)
					}
					scanner := bufio.NewScanner(os.Stdin)
					currentLocalhost = scanner.Text()
					continue
				} else {
					visibleRepositories = configurationFileStructure.Groups[index].VisibleRepositories
				}
				break
			}
			traces.InfoTracer.Printf("Importing configuration from group %s\n", currentLocalhost)
			for _, visibleRepository := range visibleRepositories {
				traces.InfoTracer.Printf("* Importing %s...\n", visibleRepository)
				index := utils.SliceIndex(len(configurationFileStructure.Repositories), func(i int) bool { return configurationFileStructure.Repositories[i].Name == visibleRepository })
				// Check the local path, and the remote URL
				if index == -1 {
					traces.WarningTracer.Printf("\tThe repository \"%s\" does not exists in your configuration file.\n", visibleRepository)
					continue
				}
				// Check if the repository exists locally
				pathRepository, URLRepository := configurationFileStructure.Repositories[index].Path, configurationFileStructure.Repositories[index].URL
				if _, err := os.Stat(pathRepository); err == nil {
					traces.InfoTracer.Printf("\tThe repository \"%s\" already exists as a local git repository.\n", visibleRepository)
					continue
				}
				// If it does not exists, clone it
				if err := gitManip.Clone(pathRepository, URLRepository); err != nil {
					traces.ErrorTracer.Printf("\tThe repository \"%s\" can't be cloned: %s\n", visibleRepository, err)
				} else {
					traces.InfoTracer.Printf("\tThe repository \"%s\" has been successfully cloned!\n", visibleRepository)
				}
			}
		},
	}

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	var pathCmd = &cobra.Command{
		Use:   "path",
		Short: "Get the path of a given repository, if this one exists",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				log.Fatalln("Needs a repository name!")
			}
			repo := args[0]
			if err := configurationFileStructure.Process(); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			repoPath := configurationFileStructure.GetPathFromRepository(repo)
			if repoPath != "" {
				fmt.Println(repoPath)
			} else {
				log.Fatalf("The repository %s does not exists!\n", repo)
			}
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			if err := configurationFileStructure.Process(); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			var gitStructs []configurationFile.GitRepository
			if len(args) == 0 {
				gitStructs = configurationFileStructure.VisibleRepositories
			} else {
				// Sort visible repositories by name
				sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
				repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
				// Looking for given repository names - if the looking one does not exists, let the function prints a warning message.
				for _, repositoryName := range args {
					repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
					if repositoryIndex != repositoriesListLength {
						gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
					}
				}
			}
			var wg sync.WaitGroup
			for _, gitStruct := range gitStructs {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init()
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	var switchCmd = &cobra.Command{
		Use:   "switch",
		Short: "Switch the visibility of the current git repository (given by the current path)",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if err := configurationFileStructure.Process(); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.VisibleFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.HiddenFlag)
				traces.InfoTracer.Printf("%s has been set to an hidden repository!", currentDir)
				return
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.HiddenFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
				traces.InfoTracer.Printf("%s has been set to a visible repository!", currentDir)
				return
			}
			log.Fatalf("The repository %s is not saved as a VISIBLE or HIDDEN repository! Please to add it before.\n", currentDir)
		},
	}

	rootCmd.AddCommand(addCmd, crawlCmd, loadCmd, pathCmd, stateCmd, switchCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha1"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"time"
	"code.google.com/p/bencode-go"
)

type Files struct {
	Length int
	Md5sum string
	Path []string
}

type Info struct {
	PieceLength int "piece length"
	Pieces string
	Private int
	Name string
	Length int
	Md5sum string
	Files []Files
}

type Metainfo struct {
	Info Info
	Announce string
	AnnounceList [][]string "announce-list"
	CreationDate int "creation date"
	Comment string
	CreatedBy string "created by"
	Encoding string
}

var PeerId = [20]byte {
	'-',
	'T',
	'V',
	'0',
	'0',
	'0',
	'1',
}

func init() {
	// Initialize PeerId
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 7; i < 20; i++ {
		PeerId[i] = byte(r.Intn(256))
	}
}

func parseTorrent(torrent string) (metainfo Metainfo, infoHash []byte, err error) {
	file, err := os.Open(torrent)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	m, err := bencode.Decode(file)
	if err != nil {
		log.Fatal(err)
	}
	metaMap, ok := m.(map[string]interface{})
	if !ok {
		err = errors.New("Couldn't parse torrent file")
		return
	}
	infoDict, ok := metaMap["info"]
	if !ok {
		err = errors.New("Unable to locate info dict in torrent file")
		return
	}

	var b bytes.Buffer
	bencode.Marshal(&b, infoDict)

	// compute the info hash
	h := sha1.New()
	h.Write(b.Bytes())
	infoHash = append(infoHash, h.Sum(nil)...)

	// populate the metainfo structure
	file.Seek(0, 0)
	bencode.Unmarshal(file, &metainfo)

	return
}

func main() {
	var announceUrl *url.URL

	if len(os.Args) != 2 {
		log.Fatalf("Usage: %s: torrent\n", os.Args[0])
        }
	torrent := os.Args[1]

	metaInfo, infoHash, err := parseTorrent(torrent)
	if (err != nil) {
		log.Fatal(err)
	}

	// select the tracker to connect to
	if len(metaInfo.AnnounceList) > 0 {
		announceUrl, err = url.Parse(metaInfo.AnnounceList[0][0])
	} else {
		announceUrl, err = url.Parse(metaInfo.Announce)
	}
	if (err != nil) {
		log.Fatal(err)
	}
	if (announceUrl.Scheme != "http") {
		log.Fatalf("URL Scheme: %s not supported\n", announceUrl.Scheme)
	}

	// statically set these for now
	port := "6881"
	downloaded := "0"
	uploaded := "0"

	tracker_request := url.Values{}
	tracker_request.Set("info_hash", string(infoHash))
	tracker_request.Add("peer_id", string(PeerId[:]))
	tracker_request.Add("port", port)
	tracker_request.Add("uploaded", uploaded)
	tracker_request.Add("downloaded", downloaded)
	tracker_request.Add("left", string(metaInfo.Info.Length))
	tracker_request.Add("compact", "1")
	announceUrl.RawQuery = tracker_request.Encode()

	resp, err := http.Get(announceUrl.String())
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", body)
}
<commit_msg>Switch to camelCase<commit_after>package main

import (
	"bytes"
	"crypto/sha1"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"time"
	"code.google.com/p/bencode-go"
)

type Files struct {
	Length int
	Md5sum string
	Path []string
}

type Info struct {
	PieceLength int "piece length"
	Pieces string
	Private int
	Name string
	Length int
	Md5sum string
	Files []Files
}

type Metainfo struct {
	Info Info
	Announce string
	AnnounceList [][]string "announce-list"
	CreationDate int "creation date"
	Comment string
	CreatedBy string "created by"
	Encoding string
}

var PeerId = [20]byte {
	'-',
	'T',
	'V',
	'0',
	'0',
	'0',
	'1',
}

func init() {
	// Initialize PeerId
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 7; i < 20; i++ {
		PeerId[i] = byte(r.Intn(256))
	}
}

func parseTorrent(torrent string) (metaInfo Metainfo, infoHash []byte, err error) {
	file, err := os.Open(torrent)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	m, err := bencode.Decode(file)
	if err != nil {
		log.Fatal(err)
	}
	metaMap, ok := m.(map[string]interface{})
	if !ok {
		err = errors.New("Couldn't parse torrent file")
		return
	}
	infoDict, ok := metaMap["info"]
	if !ok {
		err = errors.New("Unable to locate info dict in torrent file")
		return
	}

	var b bytes.Buffer
	bencode.Marshal(&b, infoDict)

	// compute the info hash
	h := sha1.New()
	h.Write(b.Bytes())
	infoHash = append(infoHash, h.Sum(nil)...)

	// populate the metaInfo structure
	file.Seek(0, 0)
	bencode.Unmarshal(file, &metaInfo)

	return
}

func main() {
	var announceUrl *url.URL

	if len(os.Args) != 2 {
		log.Fatalf("Usage: %s: torrent\n", os.Args[0])
        }
	torrent := os.Args[1]

	metaInfo, infoHash, err := parseTorrent(torrent)
	if (err != nil) {
		log.Fatal(err)
	}

	// select the tracker to connect to
	if len(metaInfo.AnnounceList) > 0 {
		announceUrl, err = url.Parse(metaInfo.AnnounceList[0][0])
	} else {
		announceUrl, err = url.Parse(metaInfo.Announce)
	}
	if (err != nil) {
		log.Fatal(err)
	}
	if (announceUrl.Scheme != "http") {
		log.Fatalf("URL Scheme: %s not supported\n", announceUrl.Scheme)
	}

	// statically set these for now
	port := "6881"
	downloaded := "0"
	uploaded := "0"

	trackerRequest := url.Values{}
	trackerRequest.Set("info_hash", string(infoHash))
	trackerRequest.Add("peer_id", string(PeerId[:]))
	trackerRequest.Add("port", port)
	trackerRequest.Add("uploaded", uploaded)
	trackerRequest.Add("downloaded", downloaded)
	trackerRequest.Add("left", string(metaInfo.Info.Length))
	trackerRequest.Add("compact", "1")
	announceUrl.RawQuery = trackerRequest.Encode()

	resp, err := http.Get(announceUrl.String())
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", body)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"gologgen/loggenrunner"
	"gologgen/loghelper"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"time"

	log15 "gopkg.in/inconshreveable/log15.v2"
)

var log log15.Logger

// GlobalConfStore holds all the config data from the conf file
type GlobalConfStore struct {
	HTTPLoc     string               `json:"httpLoc"`
	OutputType  string               `json:"OutputType"`
	SyslogType  string               `json:"SyslogType"`
	SyslogLoc   string               `json:"SyslogLoc"`
	DataFiles   []DataFileMetaData   `json:"DataFiles"`
	ReplayFiles []ReplayFileMetaData `json:"ReplayFiles"`
	HTTPClient  http.Client
}

// DataFileMetaData stores the configs around data files
type DataFileMetaData struct {
	Path string `json:"Path"`
}

// ReplayFileMetaData stores all the info around a replay file
type ReplayFileMetaData struct {
	Path            string `json:"Path"`
	TimestampRegex  string `json:"TimestampRegex"`
	TimestampFormat string `json:"TimestampFormat"`
	RepeatInterval  int    `json:"RepeatInterval"`
}

func init() {
	log15.Root().SetHandler(log15.LvlFilterHandler(log15.LvlInfo, log15.StdoutHandler))
	log = log15.New("function", log15.Lazy{Fn: loghelper.Log15LazyFunctionName})
}

// InitializeRunTable will take a slice of LogLines and start times and put the various lines in their starting slots in the map
func InitializeRunTable(RunTable *map[time.Time][]loggenrunner.LogLineProperties, Lines []loggenrunner.LogLineProperties, tickerStart time.Time) {
	RunTableObj := *RunTable
	for _, line := range Lines {
		log.Debug("========== New Line ==========")
		log.Debug("The literal time string", "time", line.StartTime)
		// Get the log line target start time
		var targetTime time.Time
		if line.StartTime == "" {
			targetTime = tickerStart
		} else {
			re := regexp.MustCompile(`\d+`)
			targetHourMinSec := re.FindAllString(line.StartTime, -1)
			targetHour, _ := strconv.Atoi(targetHourMinSec[0])
			targetMin, _ := strconv.Atoi(targetHourMinSec[1])
			targetSec, _ := strconv.Atoi(targetHourMinSec[2])
			loc, _ := time.LoadLocation("America/Los_Angeles")
			targetTime = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), targetHour, targetMin, targetSec, 0, loc).Truncate(time.Second)
		}
		log.Debug("The target time is translated to", "targetTime", targetTime)
		log.Debug("The start time of the ticker is", "tickerStart", tickerStart)
		diff := targetTime.Sub(tickerStart)
		log.Debug("The diff between target and tickerStart is", "diff", diff)
		diffMod := int(math.Abs(float64(int(diff.Seconds()) % line.IntervalSecs)))

		switch {
		case targetTime.Equal(tickerStart) || targetTime.After(tickerStart):
			log.Debug("Target is equal to or after start, so appending to Run Table as is")
			RunTableObj[targetTime] = append(RunTableObj[targetTime], line)
		case targetTime.Before(tickerStart):
			if diffMod == 0 {
				log.Debug("TickerStart is a multiple of Target's interval, so setting to TickerStart")
				RunTableObj[tickerStart] = append(RunTableObj[tickerStart], line)
			} else {
				log.Debug("Setting a start after ticker start", "startTime", tickerStart.Add(time.Duration(diffMod)*time.Second))
				RunTableObj[tickerStart.Add(time.Duration(diffMod)*time.Second)] = append(RunTableObj[tickerStart.Add(time.Duration(diffMod)*time.Second)], line)
			}
		}

	}
	log.Info("Total RunTable buildup", "length", len(RunTableObj))

}

// storeDataFileLogLines takes the conf data, gets the associated files, and puts them in a big list of LogLine Objects
func storeDataFileLogLines(confData GlobalConfStore) (logLines []loggenrunner.LogLineProperties) {
	log.Info("Entering storeDataFileLogLines", "confData", confData, "logLines length", len(logLines))

	// Return if no data files
	if len(confData.DataFiles) == 0 && len(confData.ReplayFiles) == 0 {
		log.Error("No data files or replay files were found in the global config file.")
	}

	dataJSON := loggenrunner.LogGenDataFile{}

	// First, read in any data files
	for i := 0; i < len(confData.DataFiles); i++ {
		dataText, err := ioutil.ReadFile(confData.DataFiles[i].Path)
		if err != nil {
			log.Error("Something went amiss on data file read: ", err)
		}

		// Convert the data to something we can work with
		err = json.Unmarshal(dataText, &dataJSON)
		if err != nil {
			log.Error("Something went amiss on parsing the data file: ", err)
			return
		}

		// Add the parsed fields to the result value
		for i := 0; i < len(dataJSON.Lines); i++ {
			// Bail if no Text
			if dataJSON.Lines[i].PostBody == "" {
				log.Error("Data Line must have a Text value", "json", dataJSON.Lines[i])
				continue
			}
			logLines = append(logLines, dataJSON.Lines[i])
		}
	}

	// Second, read in the replay files
	for i := 0; i < len(confData.ReplayFiles); i++ {
		replayFile := confData.ReplayFiles[i]

		file, err := os.Open(replayFile.Path)
		if err != nil {
			log.Error("Something went amiss on replay file read: ", err)
		}
		defer file.Close()

		// Set the timestamp regex
		var timeRegex = regexp.MustCompile(replayFile.TimestampRegex)

		// Scan the file through line by line
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			log.Debug("Scanning file: ", file)
			line := scanner.Text()
			log.Debug("Current replay line: ", line)
			match := timeRegex.FindStringSubmatch(line)
			log.Debug("Current replay line matches: ", match)

			log.Debug("timeRegex.SubexpName(): ", timeRegex.SubexpNames())
			log.Debug("match: ", match[1])
			// Put the names for the capture groups in a new map[string]string
			result := make(map[string]string)
			for i, name := range timeRegex.SubexpNames() {
				if i != 0 {
					log.Debug("i = ", i, ", result[name]= ", result[name])
					result[name] = match[i]
				}
			}

			log.Debug("Remapping to named object: ", result)
			startTime := result["hour"] + ":" + result["minute"] + ":" + result["second"]
			log.Debug("New Start Time: ", startTime)
			augmentedLine := timeRegex.ReplaceAllString(line, "$[time,stamp]")
			log.Debug("New augmented line: ", augmentedLine)
			logLine := loggenrunner.LogLineProperties{PostBody: augmentedLine, IntervalSecs: replayFile.RepeatInterval, IntervalStdDev: 0, StartTime: startTime, TimestampFormat: replayFile.TimestampFormat}
			log.Debug("New LogLine Object: ", logLine)

			logLines = append(logLines, logLine)

		}
	}

	// Set individual log lines to global configs / defaults if need be
	for i := 0; i < len(logLines); i++ {
		logLines[i].HTTPClient = &confData.HTTPClient

		if logLines[i].OutputType == "" {
			logLines[i].OutputType = confData.OutputType
		}
		if logLines[i].HTTPLoc == "" {
			logLines[i].HTTPLoc = confData.HTTPLoc
		}
		if logLines[i].SyslogType == "" {
			logLines[i].SyslogType = confData.SyslogType
		}
		if logLines[i].SyslogLoc == "" {
			logLines[i].SyslogLoc = confData.SyslogLoc
		}
		if logLines[i].SumoName == "" {
			logLines[i].SumoName = "GeneratedFilename.txt"
		}
		if logLines[i].SumoCategory == "" {
			logLines[i].SumoCategory = "Generated_Category"
		}
		if logLines[i].SumoHost == "" {
			logLines[i].SumoHost = "GeneratedHost"
		}

	}

	log.Info("Finished storing normalized log lines", "count", len(logLines))
	return
}

func main() {
	log.Info("Starting main program")

	// Read in the config file
	confText, err := ioutil.ReadFile("config/gologgen.conf")
	if err != nil {
		log.Error("Something went amiss on global conf file read", "error_msg", err, "text", confText)
		return
	}

	// Unmarshal the Global Config JSON into a struct
	var confData GlobalConfStore
	err = json.Unmarshal(confText, &confData)
	if err != nil {
		log.Error("Something went amiss on parsing the global config file: ", "error_msg", err, "text", confText)
		return
	}
	log.Info("Parsed global config results", "results", confData)

	// Bail on essential missing configs
	if confData.OutputType == "" || (len(confData.DataFiles) == 0 && len(confData.ReplayFiles) == 0) {
		log.Error("Configuration was missing either an output type, or input files", "confg", confData)
		return
	}

	// Create an object to stare DataFile LogLines
	logLines := storeDataFileLogLines(confData)

	RunTable := make(map[time.Time][]loggenrunner.LogLineProperties)

	// Add in some delay before starting off the ticker because we're not sure how long it will take to initialize our lines into the RunTable
	targetTickerTime := time.Now().Add(5 * time.Second).Truncate(time.Second)

	InitializeRunTable(&RunTable, logLines, targetTickerTime)
	log.Debug("Finished RunTable:\n", "RunTable", RunTable)

	log.Info("==================== Starting the main event loop ==================")

	// Set up a Ticker and call the dispatcher to create the log lines
	tickerChannel := time.Tick(1 * time.Second)
	for thisTime := range tickerChannel {
		log.Debug("Tick for time", "thisTime", thisTime.Truncate(time.Second))
		go loggenrunner.DispatchLogs(&RunTable, thisTime.Truncate(time.Second))
	}

}
<commit_msg>Fix import paths for "go get"<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/ftwynn/gologgen/loggenrunner"
	"github.com/ftwynn/gologgen/loghelper"

	log15 "gopkg.in/inconshreveable/log15.v2"
)

var log log15.Logger

// GlobalConfStore holds all the config data from the conf file
type GlobalConfStore struct {
	HTTPLoc     string               `json:"httpLoc"`
	OutputType  string               `json:"OutputType"`
	SyslogType  string               `json:"SyslogType"`
	SyslogLoc   string               `json:"SyslogLoc"`
	DataFiles   []DataFileMetaData   `json:"DataFiles"`
	ReplayFiles []ReplayFileMetaData `json:"ReplayFiles"`
	HTTPClient  http.Client
}

// DataFileMetaData stores the configs around data files
type DataFileMetaData struct {
	Path string `json:"Path"`
}

// ReplayFileMetaData stores all the info around a replay file
type ReplayFileMetaData struct {
	Path            string `json:"Path"`
	TimestampRegex  string `json:"TimestampRegex"`
	TimestampFormat string `json:"TimestampFormat"`
	RepeatInterval  int    `json:"RepeatInterval"`
}

func init() {
	log15.Root().SetHandler(log15.LvlFilterHandler(log15.LvlInfo, log15.StdoutHandler))
	log = log15.New("function", log15.Lazy{Fn: loghelper.Log15LazyFunctionName})
}

// InitializeRunTable will take a slice of LogLines and start times and put the various lines in their starting slots in the map
func InitializeRunTable(RunTable *map[time.Time][]loggenrunner.LogLineProperties, Lines []loggenrunner.LogLineProperties, tickerStart time.Time) {
	RunTableObj := *RunTable
	for _, line := range Lines {
		log.Debug("========== New Line ==========")
		log.Debug("The literal time string", "time", line.StartTime)
		// Get the log line target start time
		var targetTime time.Time
		if line.StartTime == "" {
			targetTime = tickerStart
		} else {
			re := regexp.MustCompile(`\d+`)
			targetHourMinSec := re.FindAllString(line.StartTime, -1)
			targetHour, _ := strconv.Atoi(targetHourMinSec[0])
			targetMin, _ := strconv.Atoi(targetHourMinSec[1])
			targetSec, _ := strconv.Atoi(targetHourMinSec[2])
			loc, _ := time.LoadLocation("America/Los_Angeles")
			targetTime = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), targetHour, targetMin, targetSec, 0, loc).Truncate(time.Second)
		}
		log.Debug("The target time is translated to", "targetTime", targetTime)
		log.Debug("The start time of the ticker is", "tickerStart", tickerStart)
		diff := targetTime.Sub(tickerStart)
		log.Debug("The diff between target and tickerStart is", "diff", diff)
		diffMod := int(math.Abs(float64(int(diff.Seconds()) % line.IntervalSecs)))

		switch {
		case targetTime.Equal(tickerStart) || targetTime.After(tickerStart):
			log.Debug("Target is equal to or after start, so appending to Run Table as is")
			RunTableObj[targetTime] = append(RunTableObj[targetTime], line)
		case targetTime.Before(tickerStart):
			if diffMod == 0 {
				log.Debug("TickerStart is a multiple of Target's interval, so setting to TickerStart")
				RunTableObj[tickerStart] = append(RunTableObj[tickerStart], line)
			} else {
				log.Debug("Setting a start after ticker start", "startTime", tickerStart.Add(time.Duration(diffMod)*time.Second))
				RunTableObj[tickerStart.Add(time.Duration(diffMod)*time.Second)] = append(RunTableObj[tickerStart.Add(time.Duration(diffMod)*time.Second)], line)
			}
		}

	}
	log.Info("Total RunTable buildup", "length", len(RunTableObj))

}

// storeDataFileLogLines takes the conf data, gets the associated files, and puts them in a big list of LogLine Objects
func storeDataFileLogLines(confData GlobalConfStore) (logLines []loggenrunner.LogLineProperties) {
	log.Info("Entering storeDataFileLogLines", "confData", confData, "logLines length", len(logLines))

	// Return if no data files
	if len(confData.DataFiles) == 0 && len(confData.ReplayFiles) == 0 {
		log.Error("No data files or replay files were found in the global config file.")
	}

	dataJSON := loggenrunner.LogGenDataFile{}

	// First, read in any data files
	for i := 0; i < len(confData.DataFiles); i++ {
		dataText, err := ioutil.ReadFile(confData.DataFiles[i].Path)
		if err != nil {
			log.Error("Something went amiss on data file read: ", err)
		}

		// Convert the data to something we can work with
		err = json.Unmarshal(dataText, &dataJSON)
		if err != nil {
			log.Error("Something went amiss on parsing the data file: ", err)
			return
		}

		// Add the parsed fields to the result value
		for i := 0; i < len(dataJSON.Lines); i++ {
			// Bail if no Text
			if dataJSON.Lines[i].PostBody == "" {
				log.Error("Data Line must have a Text value", "json", dataJSON.Lines[i])
				continue
			}
			logLines = append(logLines, dataJSON.Lines[i])
		}
	}

	// Second, read in the replay files
	for i := 0; i < len(confData.ReplayFiles); i++ {
		replayFile := confData.ReplayFiles[i]

		file, err := os.Open(replayFile.Path)
		if err != nil {
			log.Error("Something went amiss on replay file read: ", err)
		}
		defer file.Close()

		// Set the timestamp regex
		var timeRegex = regexp.MustCompile(replayFile.TimestampRegex)

		// Scan the file through line by line
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			log.Debug("Scanning file: ", file)
			line := scanner.Text()
			log.Debug("Current replay line: ", line)
			match := timeRegex.FindStringSubmatch(line)
			log.Debug("Current replay line matches: ", match)

			log.Debug("timeRegex.SubexpName(): ", timeRegex.SubexpNames())
			log.Debug("match: ", match[1])
			// Put the names for the capture groups in a new map[string]string
			result := make(map[string]string)
			for i, name := range timeRegex.SubexpNames() {
				if i != 0 {
					log.Debug("i = ", i, ", result[name]= ", result[name])
					result[name] = match[i]
				}
			}

			log.Debug("Remapping to named object: ", result)
			startTime := result["hour"] + ":" + result["minute"] + ":" + result["second"]
			log.Debug("New Start Time: ", startTime)
			augmentedLine := timeRegex.ReplaceAllString(line, "$[time,stamp]")
			log.Debug("New augmented line: ", augmentedLine)
			logLine := loggenrunner.LogLineProperties{PostBody: augmentedLine, IntervalSecs: replayFile.RepeatInterval, IntervalStdDev: 0, StartTime: startTime, TimestampFormat: replayFile.TimestampFormat}
			log.Debug("New LogLine Object: ", logLine)

			logLines = append(logLines, logLine)

		}
	}

	// Set individual log lines to global configs / defaults if need be
	for i := 0; i < len(logLines); i++ {
		logLines[i].HTTPClient = &confData.HTTPClient

		if logLines[i].OutputType == "" {
			logLines[i].OutputType = confData.OutputType
		}
		if logLines[i].HTTPLoc == "" {
			logLines[i].HTTPLoc = confData.HTTPLoc
		}
		if logLines[i].SyslogType == "" {
			logLines[i].SyslogType = confData.SyslogType
		}
		if logLines[i].SyslogLoc == "" {
			logLines[i].SyslogLoc = confData.SyslogLoc
		}
		if logLines[i].SumoName == "" {
			logLines[i].SumoName = "GeneratedFilename.txt"
		}
		if logLines[i].SumoCategory == "" {
			logLines[i].SumoCategory = "Generated_Category"
		}
		if logLines[i].SumoHost == "" {
			logLines[i].SumoHost = "GeneratedHost"
		}

	}

	log.Info("Finished storing normalized log lines", "count", len(logLines))
	return
}

func main() {
	log.Info("Starting main program")

	// Read in the config file
	confText, err := ioutil.ReadFile("config/gologgen.conf")
	if err != nil {
		log.Error("Something went amiss on global conf file read", "error_msg", err, "text", confText)
		return
	}

	// Unmarshal the Global Config JSON into a struct
	var confData GlobalConfStore
	err = json.Unmarshal(confText, &confData)
	if err != nil {
		log.Error("Something went amiss on parsing the global config file: ", "error_msg", err, "text", confText)
		return
	}
	log.Info("Parsed global config results", "results", confData)

	// Bail on essential missing configs
	if confData.OutputType == "" || (len(confData.DataFiles) == 0 && len(confData.ReplayFiles) == 0) {
		log.Error("Configuration was missing either an output type, or input files", "confg", confData)
		return
	}

	// Create an object to stare DataFile LogLines
	logLines := storeDataFileLogLines(confData)

	RunTable := make(map[time.Time][]loggenrunner.LogLineProperties)

	// Add in some delay before starting off the ticker because we're not sure how long it will take to initialize our lines into the RunTable
	targetTickerTime := time.Now().Add(5 * time.Second).Truncate(time.Second)

	InitializeRunTable(&RunTable, logLines, targetTickerTime)
	log.Debug("Finished RunTable:\n", "RunTable", RunTable)

	log.Info("==================== Starting the main event loop ==================")

	// Set up a Ticker and call the dispatcher to create the log lines
	tickerChannel := time.Tick(1 * time.Second)
	for thisTime := range tickerChannel {
		log.Debug("Tick for time", "thisTime", thisTime.Truncate(time.Second))
		go loggenrunner.DispatchLogs(&RunTable, thisTime.Truncate(time.Second))
	}

}
<|endoftext|>


<commit_before>// gorerun is equivalent to "go run".
//
// The only difference is that every time you send it a SIGHUP, it will
// restart the process. This is very useful while developing.
package main

import (
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
)

var cmd *exec.Cmd

func main() {
	restart := true

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)

		// Trigger a restart whenever a SIGHUP comes in
		for {
			<-c
			restart = true
			cmd.Process.Kill()
		}
	}()

	for restart {
		restart = false

		// Start process
		args := append([]string{"run"}, os.Args[1:]...)
		cmd = exec.Command("go", args...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err := cmd.Run()

		if !restart && err != nil {
			if e, ok := err.(*exec.ExitError); ok {
				if status, ok := e.Sys().(syscall.WaitStatus); ok {
					os.Exit(status.ExitStatus())
				}
			} else {
				fmt.Print(err)
			}
		}
	}
}
<commit_msg>Hack: add a small wait to avoid port reuse problems with zombies<commit_after>// gorerun is equivalent to "go run".
//
// The only difference is that every time you send it a SIGHUP, it will
// restart the process. This is very useful while developing.
package main

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

var cmd *exec.Cmd

func main() {
	restart := true

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGHUP)

		// Trigger a restart whenever a SIGHUP comes in
		for {
			<-c
			restart = true
			cmd.Process.Kill()
		}
	}()

	for restart {
		restart = false

		// Start process
		args := append([]string{"run"}, os.Args[1:]...)
		cmd = exec.Command("go", args...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err := cmd.Run()

		if !restart && err != nil {
			if e, ok := err.(*exec.ExitError); ok {
				if status, ok := e.Sys().(syscall.WaitStatus); ok {
					os.Exit(status.ExitStatus())
				}
			} else {
				fmt.Print(err)
			}
		} else {
			// Sleep for a short time to avoid "port in use" by slayed processes
			<-time.After(500 * time.Millisecond)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// Input holds the user settable values.
type Input struct {
	Dir   string
	Dry   bool
	Force bool
}

// Link is a single symlink. A source and destination are required
type Link struct {
	Src  string
	Dest string
}

func (l Link) String() string {
	return fmt.Sprintf("%v -> %v", l.Src, l.Dest)
}

func (l Link) cmd(force bool) string {
	if force {
		return fmt.Sprintf("ls -sf %v %v", l.Src, l.Dest)
	}
	return fmt.Sprintf("ls -s %v %v", l.Src, l.Dest)
}

// Clean replaces the environment variables in the source and destination paths with the values.
func (l *Link) Clean() {
	l.Src = cleanPath(l.Src)
	l.Dest = cleanPath(l.Dest)
}

func cleanPath(path string) string {
	path = filepath.Clean(path)
	hasLeadingSlash := strings.HasPrefix(path, "/")
	var cleanPath []string
	for _, e := range strings.Split(path, "/") {
		if strings.HasPrefix(e, "$") {
			e = os.Getenv(strings.TrimPrefix(e, "$"))
		}
		cleanPath = append(cleanPath, e)
	}
	path = filepath.Join(cleanPath...)
	if hasLeadingSlash {
		path = "/" + path
	}
	return path
}

// Symlink creates a symlink using the Src and Dest. Dest will be removed if force is set.
func (l *Link) Symlink(force bool) error {
	if force {
		err := os.Remove(l.Dest)
		if err != nil {
			return err
		}
	}
	return os.Symlink(l.Src, l.Dest)
}

// DotDir is a directory containing a links file. The paths in the links file, if not absolute, will be relative to the Path attribute.
type DotDir struct {
	Path     string
	LinkFile string
}

// Links parses a list of links from the links file. The found links will be cleaned and returned. An error will be returned if parsing the links file fails.
func (d DotDir) Links() (links []Link, err error) {
	f, err := os.Open(d.LinkFile)
	if err != nil {
		log.Printf("Error openeing link file %v: %v", d.LinkFile, err)
		return nil, err
	}
	defer f.Close()

	var m map[string]string
	err = json.NewDecoder(f).Decode(&m)
	if err != nil {
		log.Printf("Error parsing link file %v: %v", d.LinkFile, err)
		return nil, err
	}
	for src, dest := range m {
		src = filepath.Join(d.Path, src)
		link := Link{Src: src, Dest: dest}
		link.Clean()
		links = append(links, link)
	}
	return
}

// Bootstrap manages a list of files that need to be symlinked.
type Bootstrap struct {
	DotDirs []DotDir
}

// AddDir adds a DotDir to the DotDirs given the directory path and path to the links file.
func (b *Bootstrap) AddDir(dir, links string) {
	b.DotDirs = append(b.DotDirs, DotDir{
		Path:     dir,
		LinkFile: links,
	})
}

// Walk traverses the specified directory. Any directories found containing a links file will be added to the DotDirs attribute. An error will be returned if the walking fails.
func (b *Bootstrap) Walk(dir string) error {
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		// Check for link file
		if info.Name() == LinkFile {
			d, _ := filepath.Split(path)
			b.AddDir(d, path)
		}
		return nil
	})
	if err != nil && err != io.EOF {
		return err
	}
	return nil
}

// Link adds the links from each of the DotDirs to the links chan. If an error occurs while getting a DotDirs links, the error will be added to the errors chan.
func (b *Bootstrap) Link(links chan Link, errors chan error) {
	toLinks := func(l Link) {
		if links != nil {
			links <- l
		}
	}
	toErrors := func(e error) {
		if errors != nil {
			errors <- e
		}
	}
	wg := &sync.WaitGroup{}
	for _, dotDir := range b.DotDirs {
		wg.Add(1)
		go func(dotDir DotDir) {
			defer wg.Done()
			links, err := dotDir.Links()
			if err != nil {
				toErrors(err)
			}
			for _, link := range links {
				toLinks(link)
			}
		}(dotDir)
	}
	wg.Wait()
}

// DotEnv is the name of the environment variable signifying the location of the dotfiles needing bootstrapping.
const DotEnv = "DOT"

// LinkFile is the name the file describing symlinks relative to the current directory.
const LinkFile = "links.json"

func main() {
	i := Input{
		Dir:   os.Getenv(DotEnv),
		Dry:   false,
		Force: false,
	}
	if i.Dir == "" {
		i.Dir = "../"
	}
	flag.StringVar(&i.Dir, "dir", i.Dir, "The dotfiles source.")
	flag.BoolVar(&i.Dry, "dry", i.Dry, "Only print out the changes.")
	flag.BoolVar(&i.Force, "force", i.Force, "Overwrite existing links.")
	flag.Parse()

	dir, err := filepath.Abs(i.Dir)
	if err != nil {
		log.Fatal(err)
	}

	// Create and populate the Bootstrap DotDirs
	b := &Bootstrap{}
	err = b.Walk(dir)
	if err != nil {
		log.Fatal(err)
	}

	// Create the needed chans
	links := make(chan Link)
	errors := make(chan error)

	wg := new(sync.WaitGroup)
	wg.Add(1) // Add 1 for the single go routine listening on the above chans
	messages := map[string][]string{}

	// Spawn a go routine to create the desired links
	go func(messages map[string][]string) {
		defer wg.Done()
		var linksDone, errorsDone bool
		for !linksDone || !errorsDone {
			select {
			case link, ok := <-links:
				if !ok {
					// The links chan has been closed.
					linksDone = true
					continue
				}

				if i.Dry {
					// Add the ln commands to the messages map.
					a := messages["Commands"]
					messages["Commands"] = append(a, link.cmd(i.Force))
					continue
				}

				// Write the symlink. Use the user specified force flag.
				err := link.Symlink(i.Force)
				if err != nil {
					if lerr, ok := err.(*os.LinkError); ok {
						// Grab the err causing the LinkError
						err = lerr.Err
					}
					// Add the Symlink error to the messages map.
					a := messages["Failures"]
					messages["Failures"] = append(a, fmt.Sprintf("%v: %v", err, link))
					continue
				}
				// Add the newly created Link string to the messages map.
				a := messages["Successes"]
				messages["Successes"] = append(a, link.String())
			case err, ok := <-errors:
				if !ok {
					// The errors chan has been closed
					errorsDone = true
					continue
				}
				// Add the bootstrap error to the messages map.
				a := messages["Errors"]
				messages["Errors"] = append(a, err.Error())
			}
		}
	}(messages)

	// Kick off the links method.
	b.Link(links, errors)

	// Links only returns once all the links or errors
	// have been added to the respective chan.We can
	// safley close the links and errors chans.
	close(links)
	close(errors)
	// Wait for all the symlinks to be created.
	wg.Wait()
	// Print out all the messages
	for header, msgs := range messages {
		if len(messages) > 1 {
			fmt.Println(header + ":")
		}
		fmt.Println(strings.Join(msgs, "\n"))
	}
	fmt.Println("Changes will take effect after sourcing your .*shrc")
}
<commit_msg>Only print suggestion if a message was also printed.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// Input holds the user settable values.
type Input struct {
	Dir   string
	Dry   bool
	Force bool
}

// Link is a single symlink. A source and destination are required
type Link struct {
	Src  string
	Dest string
}

func (l Link) String() string {
	return fmt.Sprintf("%v -> %v", l.Src, l.Dest)
}

func (l Link) cmd(force bool) string {
	if force {
		return fmt.Sprintf("ls -sf %v %v", l.Src, l.Dest)
	}
	return fmt.Sprintf("ls -s %v %v", l.Src, l.Dest)
}

// Clean replaces the environment variables in the source and destination paths with the values.
func (l *Link) Clean() {
	l.Src = cleanPath(l.Src)
	l.Dest = cleanPath(l.Dest)
}

func cleanPath(path string) string {
	path = filepath.Clean(path)
	hasLeadingSlash := strings.HasPrefix(path, "/")
	var cleanPath []string
	for _, e := range strings.Split(path, "/") {
		if strings.HasPrefix(e, "$") {
			e = os.Getenv(strings.TrimPrefix(e, "$"))
		}
		cleanPath = append(cleanPath, e)
	}
	path = filepath.Join(cleanPath...)
	if hasLeadingSlash {
		path = "/" + path
	}
	return path
}

// Symlink creates a symlink using the Src and Dest. Dest will be removed if force is set.
func (l *Link) Symlink(force bool) error {
	if force {
		err := os.Remove(l.Dest)
		if err != nil {
			return err
		}
	}
	return os.Symlink(l.Src, l.Dest)
}

// DotDir is a directory containing a links file. The paths in the links file, if not absolute, will be relative to the Path attribute.
type DotDir struct {
	Path     string
	LinkFile string
}

// Links parses a list of links from the links file. The found links will be cleaned and returned. An error will be returned if parsing the links file fails.
func (d DotDir) Links() (links []Link, err error) {
	f, err := os.Open(d.LinkFile)
	if err != nil {
		log.Printf("Error openeing link file %v: %v", d.LinkFile, err)
		return nil, err
	}
	defer f.Close()

	var m map[string]string
	err = json.NewDecoder(f).Decode(&m)
	if err != nil {
		log.Printf("Error parsing link file %v: %v", d.LinkFile, err)
		return nil, err
	}
	for src, dest := range m {
		src = filepath.Join(d.Path, src)
		link := Link{Src: src, Dest: dest}
		link.Clean()
		links = append(links, link)
	}
	return
}

// Bootstrap manages a list of files that need to be symlinked.
type Bootstrap struct {
	DotDirs []DotDir
}

// AddDir adds a DotDir to the DotDirs given the directory path and path to the links file.
func (b *Bootstrap) AddDir(dir, links string) {
	b.DotDirs = append(b.DotDirs, DotDir{
		Path:     dir,
		LinkFile: links,
	})
}

// Walk traverses the specified directory. Any directories found containing a links file will be added to the DotDirs attribute. An error will be returned if the walking fails.
func (b *Bootstrap) Walk(dir string) error {
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		// Check for link file
		if info.Name() == LinkFile {
			d, _ := filepath.Split(path)
			b.AddDir(d, path)
		}
		return nil
	})
	if err != nil && err != io.EOF {
		return err
	}
	return nil
}

// Link adds the links from each of the DotDirs to the links chan. If an error occurs while getting a DotDirs links, the error will be added to the errors chan.
func (b *Bootstrap) Link(links chan Link, errors chan error) {
	toLinks := func(l Link) {
		if links != nil {
			links <- l
		}
	}
	toErrors := func(e error) {
		if errors != nil {
			errors <- e
		}
	}
	wg := &sync.WaitGroup{}
	for _, dotDir := range b.DotDirs {
		wg.Add(1)
		go func(dotDir DotDir) {
			defer wg.Done()
			links, err := dotDir.Links()
			if err != nil {
				toErrors(err)
			}
			for _, link := range links {
				toLinks(link)
			}
		}(dotDir)
	}
	wg.Wait()
}

// DotEnv is the name of the environment variable signifying the location of the dotfiles needing bootstrapping.
const DotEnv = "DOT"

// LinkFile is the name the file describing symlinks relative to the current directory.
const LinkFile = "links.json"

func main() {
	i := Input{
		Dir:   os.Getenv(DotEnv),
		Dry:   false,
		Force: false,
	}
	if i.Dir == "" {
		i.Dir = "../"
	}
	flag.StringVar(&i.Dir, "dir", i.Dir, "The dotfiles source.")
	flag.BoolVar(&i.Dry, "dry", i.Dry, "Only print out the changes.")
	flag.BoolVar(&i.Force, "force", i.Force, "Overwrite existing links.")
	flag.Parse()

	dir, err := filepath.Abs(i.Dir)
	if err != nil {
		log.Fatal(err)
	}

	// Create and populate the Bootstrap DotDirs
	b := &Bootstrap{}
	err = b.Walk(dir)
	if err != nil {
		log.Fatal(err)
	}

	// Create the needed chans
	links := make(chan Link)
	errors := make(chan error)

	wg := new(sync.WaitGroup)
	wg.Add(1) // Add 1 for the single go routine listening on the above chans
	messages := map[string][]string{}

	// Spawn a go routine to create the desired links
	go func(messages map[string][]string) {
		defer wg.Done()
		var linksDone, errorsDone bool
		for !linksDone || !errorsDone {
			select {
			case link, ok := <-links:
				if !ok {
					// The links chan has been closed.
					linksDone = true
					continue
				}

				if i.Dry {
					// Add the ln commands to the messages map.
					a := messages["Commands"]
					messages["Commands"] = append(a, link.cmd(i.Force))
					continue
				}

				// Write the symlink. Use the user specified force flag.
				err := link.Symlink(i.Force)
				if err != nil {
					if lerr, ok := err.(*os.LinkError); ok {
						// Grab the err causing the LinkError
						err = lerr.Err
					}
					// Add the Symlink error to the messages map.
					a := messages["Failures"]
					messages["Failures"] = append(a, fmt.Sprintf("%v: %v", err, link))
					continue
				}
				// Add the newly created Link string to the messages map.
				a := messages["Successes"]
				messages["Successes"] = append(a, link.String())
			case err, ok := <-errors:
				if !ok {
					// The errors chan has been closed
					errorsDone = true
					continue
				}
				// Add the bootstrap error to the messages map.
				a := messages["Errors"]
				messages["Errors"] = append(a, err.Error())
			}
		}
	}(messages)

	// Kick off the links method.
	b.Link(links, errors)

	// Links only returns once all the links or errors
	// have been added to the respective chan.We can
	// safley close the links and errors chans.
	close(links)
	close(errors)
	// Wait for all the symlinks to be created.
	wg.Wait()
	// Print out all the messages
	for header, msgs := range messages {
		if len(messages) > 1 {
			fmt.Println(header + ":")
		}
		fmt.Println(strings.Join(msgs, "\n"))
	}
	if len(messages) > 0 {
		fmt.Println("Changes will take effect after sourcing your .*shrc")
	}
}
<|endoftext|>