<commit_before>// Go programs sometime generate output you can't easily control like panics and
// net/http recovered panics. By default, those output contains multiple lines
// with stack traces. This does not play well with most logging systems that will
// generate one log event per outputed line.
//
// The golp is a simple program that reads those kinds of log on its standard
// input, and merge all lines of a given panic or standard multi-lines Go log message
// into a single quoted line.
//
// Usage
//
// Send panics and other program panics to syslog:
//
//     mygoprogram 2>&1 | golp | logger -t mygoprogram -p local7.err
//
// Options:
//
//      -ctx value
//          A key=value to add to the JSON output (can be repeated).
//      -json
//          Wrap messages to JSON one object per line.
//      -json-key string
//          The key name to use for the message in JSON mode. (default "message")
//      -max-len int
//          Strip messages to not exceed this length.
//      -prefix string
//          Go logger prefix set in the application if any.
//      -strip
//          Strip log line timestamps on output.
//
// Send panics and other program panics to syslog:
//
//     mygoprogram 2>&1 | golp | logger -t mygoprogram -p local7.err
//
//     > Jan  8 16:59:26 host mygoprogram: panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
//
// Send panics as JSON:
//
//     mygoprogram 2>&1 | golp --json | logger -t mygoprogram -p local7.err
//
//     > Jan  8 16:59:26 host mygoprogram: {"message": "panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
// Add context:
//
//     mygoprogram 2>&1 | golp --json --ctx level=error --ctx program=mygoprogram
//
//     > {"level":"error","program":"mygoprogram","message":"panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/rs/golp/event"
	"github.com/rs/golp/parser"
)

type context map[string]string

func (c *context) String() string {
	return fmt.Sprint(*c)
}

func (c *context) Set(value string) error {
	i := strings.IndexByte(value, '=')
	if i == -1 {
		return errors.New("missing context value")
	}
	(*c)[value[:i]] = value[i+1:]
	return nil
}

func main() {
	maxLen := flag.Int("max-len", 0, "Strip messages to not exceed this length.")
	prefix := flag.String("prefix", "", "Go logger prefix set in the application if any.")
	strip := flag.Bool("strip", false, "Strip log line timestamps on output.")
	json := flag.Bool("json", false, "Wrap messages to JSON one object per line.")
	jsonKey := flag.String("json-key", "message", "The key name to use for the message in JSON mode.")
	ctx := context{}
	flag.Var(&ctx, "ctx", "A key=value to add to the JSON output (can be repeated).")
	flag.Parse()
	if !*json {
		*jsonKey = ""
	}
	run(os.Stdin, os.Stdout, ctx, *maxLen, *prefix, *strip, *jsonKey)
}

func run(in io.Reader, out io.Writer, ctx map[string]string, maxLen int, prefix string, strip bool, jsonKey string) {
	r := bufio.NewReader(in)
	cont := false
	e, err := event.New(out, ctx, maxLen, "\n", jsonKey)
	if err != nil {
		log.Fatal(err)
	}
	autoFlushDelay := 5 * time.Millisecond
	go func() {
		// Flush before exit
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, os.Kill)
		<-c
		e.Flush()
	}()
	for {
		line, isPrefix, err := r.ReadLine()
		if err != nil {
			e.Flush()
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		// Stop the previous auto-flush if any so we don't accidently flush
		// before reading the new line.
		e.Stop()
		if !cont {
			if parser.IsPanic(line) {
				// Flush previous event if any
				e.Flush()
			} else if index := parser.IsLog(line, prefix); index > 0 {
				// Flush previous event if any
				e.Flush()
				if strip {
					// Strip log message header (prefix, timestamp)
					line = line[index:]
				}
			} else if !e.Empty() {
				// The line is a continuation, add a quoted carriage return before
				// appending it to the current event.
				e.Write([]byte{'\n'})
			}
		}
		e.Write(line)
		// Auto-flush the event after if no new line is read for the given delay.
		e.AutoFlush(autoFlushDelay)
		cont = isPrefix
	}
}
<commit_msg>Add missing exit on signal<commit_after>// Go programs sometime generate output you can't easily control like panics and
// net/http recovered panics. By default, those output contains multiple lines
// with stack traces. This does not play well with most logging systems that will
// generate one log event per outputed line.
//
// The golp is a simple program that reads those kinds of log on its standard
// input, and merge all lines of a given panic or standard multi-lines Go log message
// into a single quoted line.
//
// Usage
//
// Send panics and other program panics to syslog:
//
//     mygoprogram 2>&1 | golp | logger -t mygoprogram -p local7.err
//
// Options:
//
//      -ctx value
//          A key=value to add to the JSON output (can be repeated).
//      -json
//          Wrap messages to JSON one object per line.
//      -json-key string
//          The key name to use for the message in JSON mode. (default "message")
//      -max-len int
//          Strip messages to not exceed this length.
//      -prefix string
//          Go logger prefix set in the application if any.
//      -strip
//          Strip log line timestamps on output.
//
// Send panics and other program panics to syslog:
//
//     mygoprogram 2>&1 | golp | logger -t mygoprogram -p local7.err
//
//     > Jan  8 16:59:26 host mygoprogram: panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
//
// Send panics as JSON:
//
//     mygoprogram 2>&1 | golp --json | logger -t mygoprogram -p local7.err
//
//     > Jan  8 16:59:26 host mygoprogram: {"message": "panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
// Add context:
//
//     mygoprogram 2>&1 | golp --json --ctx level=error --ctx program=mygoprogram
//
//     > {"level":"error","program":"mygoprogram","message":"panic: panic: test\n\ngoroutine 1 [running]:\npanic(0x…
package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/rs/golp/event"
	"github.com/rs/golp/parser"
)

type context map[string]string

func (c *context) String() string {
	return fmt.Sprint(*c)
}

func (c *context) Set(value string) error {
	i := strings.IndexByte(value, '=')
	if i == -1 {
		return errors.New("missing context value")
	}
	(*c)[value[:i]] = value[i+1:]
	return nil
}

func main() {
	maxLen := flag.Int("max-len", 0, "Strip messages to not exceed this length.")
	prefix := flag.String("prefix", "", "Go logger prefix set in the application if any.")
	strip := flag.Bool("strip", false, "Strip log line timestamps on output.")
	json := flag.Bool("json", false, "Wrap messages to JSON one object per line.")
	jsonKey := flag.String("json-key", "message", "The key name to use for the message in JSON mode.")
	ctx := context{}
	flag.Var(&ctx, "ctx", "A key=value to add to the JSON output (can be repeated).")
	flag.Parse()
	if !*json {
		*jsonKey = ""
	}
	run(os.Stdin, os.Stdout, ctx, *maxLen, *prefix, *strip, *jsonKey)
}

func run(in io.Reader, out io.Writer, ctx map[string]string, maxLen int, prefix string, strip bool, jsonKey string) {
	r := bufio.NewReader(in)
	cont := false
	e, err := event.New(out, ctx, maxLen, "\n", jsonKey)
	if err != nil {
		log.Fatal(err)
	}
	autoFlushDelay := 5 * time.Millisecond
	go func() {
		// Flush before exit
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, os.Kill)
		<-c
		e.Flush()
		os.Exit(1)
	}()
	for {
		line, isPrefix, err := r.ReadLine()
		if err != nil {
			e.Flush()
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		// Stop the previous auto-flush if any so we don't accidently flush
		// before reading the new line.
		e.Stop()
		if !cont {
			if parser.IsPanic(line) {
				// Flush previous event if any
				e.Flush()
			} else if index := parser.IsLog(line, prefix); index > 0 {
				// Flush previous event if any
				e.Flush()
				if strip {
					// Strip log message header (prefix, timestamp)
					line = line[index:]
				}
			} else if !e.Empty() {
				// The line is a continuation, add a quoted carriage return before
				// appending it to the current event.
				e.Write([]byte{'\n'})
			}
		}
		e.Write(line)
		// Auto-flush the event after if no new line is read for the given delay.
		e.AutoFlush(autoFlushDelay)
		cont = isPrefix
	}
}
<|endoftext|>


<commit_before>package main

import (
	"gopkg.in/mgo.v2"
	"log"
	"net/http"
	"os"
	"time"
)

var session *mgo.Session

// Dial session. Copy session for creating concurrent connections to the db.
// Reads from environment variable MGO. (default="localhost:27017")
// maxWait for TTL if connection issue to db
func init() {
	var err error
	dial := os.Getenv("MONGO_PORT_27017_TCP_ADDR")
	maxWait := time.Duration(5 * time.Second)

	session, err = mgo.DialWithTimeout(dial, maxWait)
	if err != nil {
		panic(err)
	}
}

// serve on 8080
func main() {
	router := NewRouter()
	log.Fatal(http.ListenAndServe(":8080", router))
}
<commit_msg>Update main.go<commit_after>package main

import (
	"gopkg.in/mgo.v2"
	"log"
	"net/http"
	"os"
	"time"
)

var session *mgo.Session

// Dial session. Copy session for creating concurrent connections to the db.
// Reads from environment variable MGO. (default="localhost:27017")
// maxWait for TTL if connection issue to db
func init() {
	var err error
	dial := os.Getenv("MONGO_PORT_27017_TCP_ADDR")
	maxWait := time.Duration(5 * time.Second)

	session, err = mgo.DialWithTimeout(dial, maxWait)
	if err != nil {
		panic(err)
	}
	session.SetMode(mgo.Strong, true)
}

// serve on 8080
func main() {
	router := NewRouter()
	log.Fatal(http.ListenAndServe(":8080", router))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/fraenkel/candiedyaml"
	"github.com/garyburd/redigo/redis"
	"github.com/tedsuo/router"

	proleroutes "github.com/winston-ci/prole/routes"

	"github.com/winston-ci/winston/api"
	apiroutes "github.com/winston-ci/winston/api/routes"
	"github.com/winston-ci/winston/builder"
	"github.com/winston-ci/winston/config"
	"github.com/winston-ci/winston/db"
	"github.com/winston-ci/winston/server"
)

var configPath = flag.String(
	"config",
	"",
	"path to winston server config .yml",
)

var templatesDir = flag.String(
	"templates",
	"",
	"path to directory containing the html templates",
)

var proleURL = flag.String(
	"proleURL",
	"http://127.0.0.1:4637",
	"address denoting the prole service",
)

var redisAddr = flag.String(
	"redisAddr",
	"127.0.0.1:6379",
	"redis server address",
)

var peerURL = flag.String(
	"peerURL",
	"http://127.0.0.1:8081",
	"external URL of the api server",
)

var listenAddr = flag.String(
	"listenAddr",
	":8080",
	"port for the web server to listen on",
)

var apiListenAddr = flag.String(
	"apiListenAddr",
	":8081",
	"port for the api to listen on",
)

func main() {
	flag.Parse()

	if *configPath == "" {
		fatal(errors.New("must specify -config"))
	}

	configFile, err := os.Open(*configPath)
	if err != nil {
		fatal(err)
	}

	var config config.Config
	err = candiedyaml.NewDecoder(configFile).Decode(&config)
	if err != nil {
		fatal(err)
	}

	configFile.Close()

	redisDB := db.NewRedis(redis.NewPool(func() (redis.Conn, error) {
		return redis.DialTimeout("tcp", *redisAddr, 5*time.Second, 0, 0)
	}, 20))

	winstonEndpoint := router.NewRequestGenerator(*peerURL, apiroutes.Routes)
	proleEndpoint := router.NewRequestGenerator(*proleURL, proleroutes.Routes)
	builder := builder.NewBuilder(redisDB, proleEndpoint, winstonEndpoint)

	serverHandler, err := server.New(config, redisDB, *templatesDir, builder)
	if err != nil {
		fatal(err)
	}

	apiHandler, err := api.New(redisDB)
	if err != nil {
		fatal(err)
	}

	errs := make(chan error, 2)

	go func() {
		log.Println("serving web on", *listenAddr)
		errs <- http.ListenAndServe(*listenAddr, serverHandler)
	}()

	go func() {
		log.Println("serving api on", *apiListenAddr)
		errs <- http.ListenAndServe(*apiListenAddr, apiHandler)
	}()

	fatal(<-errs)
}

func fatal(err error) {
	println(err.Error())
	os.Exit(1)
}
<commit_msg>clarify -peerURL flag<commit_after>package main

import (
	"errors"
	"flag"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/fraenkel/candiedyaml"
	"github.com/garyburd/redigo/redis"
	"github.com/tedsuo/router"

	proleroutes "github.com/winston-ci/prole/routes"

	"github.com/winston-ci/winston/api"
	apiroutes "github.com/winston-ci/winston/api/routes"
	"github.com/winston-ci/winston/builder"
	"github.com/winston-ci/winston/config"
	"github.com/winston-ci/winston/db"
	"github.com/winston-ci/winston/server"
)

var configPath = flag.String(
	"config",
	"",
	"path to winston server config .yml",
)

var templatesDir = flag.String(
	"templates",
	"",
	"path to directory containing the html templates",
)

var proleURL = flag.String(
	"proleURL",
	"http://127.0.0.1:4637",
	"address denoting the prole service",
)

var redisAddr = flag.String(
	"redisAddr",
	"127.0.0.1:6379",
	"redis server address",
)

var peerURL = flag.String(
	"peerURL",
	"http://127.0.0.1:8081",
	"external URL of the api server, used for callbacks",
)

var listenAddr = flag.String(
	"listenAddr",
	":8080",
	"port for the web server to listen on",
)

var apiListenAddr = flag.String(
	"apiListenAddr",
	":8081",
	"port for the api to listen on",
)

func main() {
	flag.Parse()

	if *configPath == "" {
		fatal(errors.New("must specify -config"))
	}

	configFile, err := os.Open(*configPath)
	if err != nil {
		fatal(err)
	}

	var config config.Config
	err = candiedyaml.NewDecoder(configFile).Decode(&config)
	if err != nil {
		fatal(err)
	}

	configFile.Close()

	redisDB := db.NewRedis(redis.NewPool(func() (redis.Conn, error) {
		return redis.DialTimeout("tcp", *redisAddr, 5*time.Second, 0, 0)
	}, 20))

	winstonEndpoint := router.NewRequestGenerator(*peerURL, apiroutes.Routes)
	proleEndpoint := router.NewRequestGenerator(*proleURL, proleroutes.Routes)
	builder := builder.NewBuilder(redisDB, proleEndpoint, winstonEndpoint)

	serverHandler, err := server.New(config, redisDB, *templatesDir, builder)
	if err != nil {
		fatal(err)
	}

	apiHandler, err := api.New(redisDB)
	if err != nil {
		fatal(err)
	}

	errs := make(chan error, 2)

	go func() {
		log.Println("serving web on", *listenAddr)
		errs <- http.ListenAndServe(*listenAddr, serverHandler)
	}()

	go func() {
		log.Println("serving api on", *apiListenAddr)
		errs <- http.ListenAndServe(*apiListenAddr, apiHandler)
	}()

	fatal(<-errs)
}

func fatal(err error) {
	println(err.Error())
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/cors"
	"github.com/eirka/eirka-libs/csrf"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
	"github.com/eirka/eirka-libs/validate"

	local "github.com/eirka/eirka-admin/config"
	c "github.com/eirka/eirka-admin/controllers"
)

func init() {

	// Database connection settings
	dbase := db.Database{

		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

	// redis settings
	r := redis.Redis{
		// Redis address and max pool connections
		Protocol:       local.Settings.Redis.Protocol,
		Address:        local.Settings.Redis.Address,
		MaxIdle:        local.Settings.Redis.MaxIdle,
		MaxConnections: local.Settings.Redis.MaxConnections,
	}

	// Set up Redis connection
	r.NewRedisCache()

	// set auth middleware secret
	user.Secret = local.Settings.Session.Secret

	// set cors domains
	cors.SetDomains(local.Settings.CORS.Sites, strings.Split("GET,POST,DELETE", ","))

}

func main() {
	r := gin.Default()

	r.Use(cors.CORS())
	// verified the csrf token from the request
	r.Use(csrf.Verify())

	r.GET("/uptime", c.UptimeController)
	r.NoRoute(c.ErrorController)

	// requires mod perms
	admin := r.Group("/")

	admin.Use(validate.ValidateParams())
	admin.Use(user.Auth(true))
	admin.Use(user.Protect())

	admin.GET("/statistics/:ib", c.StatisticsController)
	admin.DELETE("/tag/:ib/:id", c.DeleteTagController)
	admin.POST("/tag/:ib/", c.UpdateTagController)
	admin.DELETE("/imagetag/:ib/:image/:tag", c.DeleteImageTagController)
	admin.DELETE("/thread/:ib/:id", c.DeleteThreadController)
	admin.DELETE("/post/:ib/:thread/:id", c.DeletePostController)
	admin.POST("/sticky/:ib/:thread", c.StickyThreadController)
	admin.POST("/close/:ib/:thread", c.CloseThreadController)

	//admin.DELETE("/thread/:id", c.PurgeThreadController)
	//admin.DELETE("/post/:thread/:id", c.PurgePostController)
	//admin.POST("/ban/:ip", c.BanIpController)
	//admin.DELETE("/flushcache", c.DeleteCacheController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Admin.Address, local.Settings.Admin.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<commit_msg>add protect middleware<commit_after>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/cors"
	"github.com/eirka/eirka-libs/csrf"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
	"github.com/eirka/eirka-libs/validate"

	local "github.com/eirka/eirka-admin/config"
	c "github.com/eirka/eirka-admin/controllers"
)

func init() {

	// Database connection settings
	dbase := db.Database{

		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

	// redis settings
	r := redis.Redis{
		// Redis address and max pool connections
		Protocol:       local.Settings.Redis.Protocol,
		Address:        local.Settings.Redis.Address,
		MaxIdle:        local.Settings.Redis.MaxIdle,
		MaxConnections: local.Settings.Redis.MaxConnections,
	}

	// Set up Redis connection
	r.NewRedisCache()

	// set auth middleware secret
	user.Secret = local.Settings.Session.Secret

	// set cors domains
	cors.SetDomains(local.Settings.CORS.Sites, strings.Split("GET,POST,DELETE", ","))

}

func main() {
	r := gin.Default()

	r.Use(cors.CORS())
	// verified the csrf token from the request
	r.Use(csrf.Verify())

	r.GET("/uptime", c.UptimeController)
	r.NoRoute(c.ErrorController)

	// requires mod perms
	admin := r.Group("/")

	admin.Use(validate.ValidateParams())
	admin.Use(user.Auth(true))
	admin.Use(user.Protect())

	admin.GET("/statistics/:ib", c.StatisticsController)
	admin.DELETE("/tag/:ib/:id", c.DeleteTagController)
	admin.POST("/tag/:ib", c.UpdateTagController)
	admin.DELETE("/imagetag/:ib/:image/:tag", c.DeleteImageTagController)
	admin.DELETE("/thread/:ib/:id", c.DeleteThreadController)
	admin.DELETE("/post/:ib/:thread/:id", c.DeletePostController)
	admin.POST("/sticky/:ib/:thread", c.StickyThreadController)
	admin.POST("/close/:ib/:thread", c.CloseThreadController)

	//admin.DELETE("/thread/:id", c.PurgeThreadController)
	//admin.DELETE("/post/:thread/:id", c.PurgePostController)
	//admin.POST("/ban/:ip", c.BanIpController)
	//admin.DELETE("/flushcache", c.DeleteCacheController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Admin.Address, local.Settings.Admin.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<|endoftext|>


<commit_before>package main

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

	"os"

	"bitbucket.org/mundipagg/boletoapi/app"
	"bitbucket.org/mundipagg/boletoapi/config"
	"bitbucket.org/mundipagg/boletoapi/log"
)

var (
	processID  = os.Getpid()
	totalProcs = runtime.NumCPU()
	devMode    = flag.Bool("dev", false, "-dev To run in dev mode")
	mockMode   = flag.Bool("mock", false, "-mock To run mock requests")
	disableLog = flag.Bool("nolog", false, "-nolog disable seq log")
)

func init() {
	createPIDfile()
	// Configure signal handler
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go handleSignal(c)
}

func handleSignal(c chan os.Signal) {
	<-c
	config.Stop()
	log.Info("Quiting BoletoApi")
	log.Close()
	//db.GetDB().Close()
	fmt.Println("Done")
	os.Exit(1)
}

func createPIDfile() {
	p := strconv.Itoa(processID)
	ioutil.WriteFile("boletoapi.pid", []byte(p), 0644)
}

func main() {
	flag.Parse()
	logo1()
	app.Run(*devMode, *mockMode, *disableLog)
}

func logo1() {
	l := `
$$$$$$$\            $$\            $$\                $$$$$$\            $$\
$$  __$$\           $$ |           $$ |              $$  __$$\           \__|
$$ |  $$ | $$$$$$\  $$ | $$$$$$\ $$$$$$\    $$$$$$\  $$ /  $$ | $$$$$$\  $$\
$$$$$$$\ |$$  __$$\ $$ |$$  __$$\\_$$  _|  $$  __$$\ $$$$$$$$ |$$  __$$\ $$ |
$$  __$$\ $$ /  $$ |$$ |$$$$$$$$ | $$ |    $$ /  $$ |$$  __$$ |$$ /  $$ |$$ |
$$ |  $$ |$$ |  $$ |$$ |$$   ____| $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |
$$$$$$$  |\$$$$$$  |$$ |\$$$$$$$\  \$$$$  |\$$$$$$  |$$ |  $$ |$$$$$$$  |$$ |
\_______/  \______/ \__| \_______|  \____/  \______/ \__|  \__|$$  ____/ \__|
                                                               $$ |
                                                               $$ |
                                                               \__|
	`
	fmt.Println(l)
	fmt.Println("Version: " + config.Get().Version)
}
<commit_msg>:bulb: adiciona o modo avião na api para rodar -dev -mock -nolog com apenas a opção -airplane-mode<commit_after>package main

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

	"os"

	"bitbucket.org/mundipagg/boletoapi/app"
	"bitbucket.org/mundipagg/boletoapi/config"
	"bitbucket.org/mundipagg/boletoapi/log"
)

var (
	processID    = os.Getpid()
	totalProcs   = runtime.NumCPU()
	devMode      = flag.Bool("dev", false, "-dev To run in dev mode")
	mockMode     = flag.Bool("mock", false, "-mock To run mock requests")
	disableLog   = flag.Bool("nolog", false, "-nolog disable seq log")
	airPlaneMode = flag.Bool("airplane-mode", false, "-airplane-mode run api in dev, mock and nolog mode")
)

func init() {
	createPIDfile()
	// Configure signal handler
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go handleSignal(c)
}

func handleSignal(c chan os.Signal) {
	<-c
	config.Stop()
	log.Info("Quiting BoletoApi")
	log.Close()
	//db.GetDB().Close()
	fmt.Println("Done")
	os.Exit(1)
}

func createPIDfile() {
	p := strconv.Itoa(processID)
	ioutil.WriteFile("boletoapi.pid", []byte(p), 0644)
}

func main() {
	flag.Parse()
	logo1()
	if *airPlaneMode {
		app.Run(true, true, true)
	} else {
		app.Run(*devMode, *mockMode, *disableLog)
	}

}

func logo1() {
	l := `
$$$$$$$\            $$\            $$\                $$$$$$\            $$\
$$  __$$\           $$ |           $$ |              $$  __$$\           \__|
$$ |  $$ | $$$$$$\  $$ | $$$$$$\ $$$$$$\    $$$$$$\  $$ /  $$ | $$$$$$\  $$\
$$$$$$$\ |$$  __$$\ $$ |$$  __$$\\_$$  _|  $$  __$$\ $$$$$$$$ |$$  __$$\ $$ |
$$  __$$\ $$ /  $$ |$$ |$$$$$$$$ | $$ |    $$ /  $$ |$$  __$$ |$$ /  $$ |$$ |
$$ |  $$ |$$ |  $$ |$$ |$$   ____| $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |
$$$$$$$  |\$$$$$$  |$$ |\$$$$$$$\  \$$$$  |\$$$$$$  |$$ |  $$ |$$$$$$$  |$$ |
\_______/  \______/ \__| \_______|  \____/  \______/ \__|  \__|$$  ____/ \__|
                                                               $$ |
                                                               $$ |
                                                               \__|
	`
	fmt.Println(l)
	fmt.Println("Version: " + config.Get().Version)
}
<|endoftext|>


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

// The stress utility is intended for catching of episodic failures.
// It runs a given process in parallel in a loop and collects any failures.
// Usage:
// 	$ stress ./fmt.test -test.run=TestSometing -test.cpu=10
// You can also specify a number of parallel processes with -p flag;
// instruct the utility to not kill hanged processes for gdb attach;
// or specify the failure output you are looking for (if you want to
// ignore some other episodic failures).
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	flagP        = flag.Int("p", runtime.NumCPU(), "run `N` processes in parallel")
	flagTimeout  = flag.Duration("timeout", 0, "timeout each process after `duration`")
	flagKill     = flag.Bool("kill", true, "kill timed out processes if true, otherwise just print pid (to attach with gdb)")
	flagFailure  = flag.String("failure", "", "fail only if output matches `regexp`")
	flagIgnore   = flag.String("ignore", "", "ignore failure if output matches `regexp`")
	flagMaxTime  = flag.Duration("maxtime", 0, "maximum time to run")
	flagMaxRuns  = flag.Int("maxruns", 0, "maximum number of runs")
	flagMaxFails = flag.Int("maxfails", 1, "maximum number of failures")
	flagStdErr   = flag.Bool("stderr", true, "output failures to STDERR instead of to a temp file")
)

func roundToSeconds(d time.Duration) time.Duration {
	return time.Duration(d.Seconds()+0.5) * time.Second
}

func main() {
	flag.Parse()
	if *flagP <= 0 || *flagTimeout <= 0 || len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}
	var failureRe, ignoreRe *regexp.Regexp
	if *flagFailure != "" {
		var err error
		if failureRe, err = regexp.Compile(*flagFailure); err != nil {
			fmt.Println("bad failure regexp:", err)
			os.Exit(1)
		}
	}
	if *flagIgnore != "" {
		var err error
		if ignoreRe, err = regexp.Compile(*flagIgnore); err != nil {
			fmt.Println("bad ignore regexp:", err)
			os.Exit(1)
		}
	}
	startTime := time.Now()
	finishTime := time.Now().Add(*flagMaxTime)
	res := make(chan []byte)
	var exitFlag int32
	for i := 0; i < *flagP; i++ {
		go func() {
			for atomic.LoadInt32(&exitFlag) == 0 {
				cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
				done := make(chan bool)
				if *flagTimeout > 0 {
					go func() {
						select {
						case <-done:
							return
						case <-time.After(*flagTimeout):
						}
						if !*flagKill {
							fmt.Printf("process %v timed out\n", cmd.Process.Pid)
							return
						}
						cmd.Process.Signal(syscall.SIGABRT)
						select {
						case <-done:
							return
						case <-time.After(10 * time.Second):
						}
						cmd.Process.Kill()
					}()
				}
				out, err := cmd.CombinedOutput()
				close(done)
				if err != nil && (failureRe == nil || failureRe.Match(out)) && (ignoreRe == nil || !ignoreRe.Match(out)) {
					out = append(out, fmt.Sprintf("\n\nERROR: %v\n", err)...)
				} else {
					out = []byte{}
				}
				res <- out
			}
		}()
	}
	runs, fails := 0, 0
	ticker := time.NewTicker(5 * time.Second).C
	for atomic.LoadInt32(&exitFlag) == 0 {
		select {
		case out := <-res:
			runs++
			if ((*flagMaxTime > 0) && (time.Now().After(finishTime))) ||
				((*flagMaxRuns > 0) && (runs >= *flagMaxRuns)) {
				atomic.StoreInt32(&exitFlag, 1)
			}
			if len(out) == 0 {
				continue
			}
			fails++
			if (*flagMaxFails > 0) && (fails >= *flagMaxFails) {
				atomic.StoreInt32(&exitFlag, 1)
			}
			if *flagStdErr {
				fmt.Fprintf(os.Stderr, "\n%s\n", out)
			} else {
				f, err := ioutil.TempFile("", "go-stress")
				if err != nil {
					fmt.Printf("failed to create temp file: %v\n", err)
					os.Exit(1)
				}
				f.Write(out)
				f.Close()
				if len(out) > 2<<10 {
					out = out[:2<<10]
				}
				fmt.Printf("\n%s\n%s\n", f.Name(), out)
			}
		case <-ticker:
			fmt.Printf("%v runs so far, %v failures, over %s\n",
				runs, fails, roundToSeconds(time.Since(startTime)))
		}
	}
	fmt.Printf("%v runs completed, %v failures, over %s\n",
		runs, fails, roundToSeconds(time.Since(startTime)))
	if fails > 0 {
		fmt.Println("FAIL")
		os.Exit(1)
	} else {
		fmt.Println("SUCCESS")
	}
}
<commit_msg>allow zero timeout<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The stress utility is intended for catching of episodic failures.
// It runs a given process in parallel in a loop and collects any failures.
// Usage:
// 	$ stress ./fmt.test -test.run=TestSometing -test.cpu=10
// You can also specify a number of parallel processes with -p flag;
// instruct the utility to not kill hanged processes for gdb attach;
// or specify the failure output you are looking for (if you want to
// ignore some other episodic failures).
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	flagP        = flag.Int("p", runtime.NumCPU(), "run `N` processes in parallel")
	flagTimeout  = flag.Duration("timeout", 0, "timeout each process after `duration`")
	flagKill     = flag.Bool("kill", true, "kill timed out processes if true, otherwise just print pid (to attach with gdb)")
	flagFailure  = flag.String("failure", "", "fail only if output matches `regexp`")
	flagIgnore   = flag.String("ignore", "", "ignore failure if output matches `regexp`")
	flagMaxTime  = flag.Duration("maxtime", 0, "maximum time to run")
	flagMaxRuns  = flag.Int("maxruns", 0, "maximum number of runs")
	flagMaxFails = flag.Int("maxfails", 1, "maximum number of failures")
	flagStdErr   = flag.Bool("stderr", true, "output failures to STDERR instead of to a temp file")
)

func roundToSeconds(d time.Duration) time.Duration {
	return time.Duration(d.Seconds()+0.5) * time.Second
}

func main() {
	flag.Parse()
	if *flagP <= 0 || *flagTimeout < 0 || len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}
	var failureRe, ignoreRe *regexp.Regexp
	if *flagFailure != "" {
		var err error
		if failureRe, err = regexp.Compile(*flagFailure); err != nil {
			fmt.Println("bad failure regexp:", err)
			os.Exit(1)
		}
	}
	if *flagIgnore != "" {
		var err error
		if ignoreRe, err = regexp.Compile(*flagIgnore); err != nil {
			fmt.Println("bad ignore regexp:", err)
			os.Exit(1)
		}
	}
	startTime := time.Now()
	finishTime := time.Now().Add(*flagMaxTime)
	res := make(chan []byte)
	var exitFlag int32
	for i := 0; i < *flagP; i++ {
		go func() {
			for atomic.LoadInt32(&exitFlag) == 0 {
				cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
				done := make(chan bool)
				if *flagTimeout > 0 {
					go func() {
						select {
						case <-done:
							return
						case <-time.After(*flagTimeout):
						}
						if !*flagKill {
							fmt.Printf("process %v timed out\n", cmd.Process.Pid)
							return
						}
						cmd.Process.Signal(syscall.SIGABRT)
						select {
						case <-done:
							return
						case <-time.After(10 * time.Second):
						}
						cmd.Process.Kill()
					}()
				}
				out, err := cmd.CombinedOutput()
				close(done)
				if err != nil && (failureRe == nil || failureRe.Match(out)) && (ignoreRe == nil || !ignoreRe.Match(out)) {
					out = append(out, fmt.Sprintf("\n\nERROR: %v\n", err)...)
				} else {
					out = []byte{}
				}
				res <- out
			}
		}()
	}
	runs, fails := 0, 0
	ticker := time.NewTicker(5 * time.Second).C
	for atomic.LoadInt32(&exitFlag) == 0 {
		select {
		case out := <-res:
			runs++
			if ((*flagMaxTime > 0) && (time.Now().After(finishTime))) ||
				((*flagMaxRuns > 0) && (runs >= *flagMaxRuns)) {
				atomic.StoreInt32(&exitFlag, 1)
			}
			if len(out) == 0 {
				continue
			}
			fails++
			if (*flagMaxFails > 0) && (fails >= *flagMaxFails) {
				atomic.StoreInt32(&exitFlag, 1)
			}
			if *flagStdErr {
				fmt.Fprintf(os.Stderr, "\n%s\n", out)
			} else {
				f, err := ioutil.TempFile("", "go-stress")
				if err != nil {
					fmt.Printf("failed to create temp file: %v\n", err)
					os.Exit(1)
				}
				f.Write(out)
				f.Close()
				if len(out) > 2<<10 {
					out = out[:2<<10]
				}
				fmt.Printf("\n%s\n%s\n", f.Name(), out)
			}
		case <-ticker:
			fmt.Printf("%v runs so far, %v failures, over %s\n",
				runs, fails, roundToSeconds(time.Since(startTime)))
		}
	}
	fmt.Printf("%v runs completed, %v failures, over %s\n",
		runs, fails, roundToSeconds(time.Since(startTime)))
	if fails > 0 {
		fmt.Println("FAIL")
		os.Exit(1)
	} else {
		fmt.Println("SUCCESS")
	}
}
<|endoftext|>


<commit_before>package main

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

	"gopkg.in/yaml.v2"

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

var addr = flag.String("web.listen-address", ":9115", "The address to listen on for HTTP requests.")
var configFile = flag.String("config.file", "blackbox.yml", "Blackbox exporter configuration file.")

type Config struct {
	Modules map[string]Module `yaml:"modules"`
}

type Module struct {
	Prober  string        `yaml:"prober"`
	Timeout time.Duration `yaml:"timeout"`
	HTTP    HTTPProbe     `yaml:"http"`
	TCP     TCPProbe      `yaml:"tcp"`
	ICMP    ICMPProbe     `yaml:"icmp"`
}

type HTTPProbe struct {
	// Defaults to 2xx.
	ValidStatusCodes       []int    `yaml:"valid_status_codes"`
	NoFollowRedirects      bool     `yaml:"no_follow_redirects"`
	FailIfSSL              bool     `yaml:"fail_if_ssl"`
	FailIfNotSSL           bool     `yaml:"fail_if_not_ssl"`
	Method                 string   `yaml:"method"`
	FailIfMatchesRegexp    []string `yaml:"fail_if_matches_regexp"`
	FailIfNotMatchesRegexp []string `yaml:"fail_if_not_matches_regexp"`
}

type QueryResponse struct {
	Expect string `yaml:"expect"`
	Send   string `yaml:"send"`
}

type TCPProbe struct {
	QueryResponse []QueryResponse `yaml:"query_response"`
}

type ICMPProbe struct {
}

var Probers = map[string]func(string, http.ResponseWriter, Module) bool{
	"http": probeHTTP,
	"tcp":  probeTCP,
	"icmp": probeICMP,
}

func probeHandler(w http.ResponseWriter, r *http.Request, config *Config) {
	params := r.URL.Query()
	target := params.Get("target")
	moduleName := params.Get("module")
	if target == "" {
		http.Error(w, "Target parameter is missing", 400)
		return
	}
	if moduleName == "" {
		moduleName = "http2xx"
	}
	module, ok := config.Modules[moduleName]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown module %s", moduleName), 400)
		return
	}
	prober, ok := Probers[module.Prober]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown prober %s", module.Prober), 400)
		return
	}
	start := time.Now()
	success := prober(target, w, module)
	fmt.Fprintf(w, "probe_duration_seconds %f\n", float64(time.Now().Sub(start))/1e9)
	if success {
		fmt.Fprintf(w, "probe_success %d\n", 1)
	} else {
		fmt.Fprintf(w, "probe_success %d\n", 0)
	}
}

func main() {
	flag.Parse()

	yamlFile, err := ioutil.ReadFile(*configFile)

	if err != nil {
		log.Fatalf("Error reading config file: %s", err)
	}

	config := Config{}

	err = yaml.Unmarshal(yamlFile, &config)
	if err != nil {
		log.Fatalf("Error parsing config file: %s", err)
	}

	http.Handle("/metrics", prometheus.Handler())
	http.HandleFunc("/probe",
		func(w http.ResponseWriter, r *http.Request) {
			probeHandler(w, r, &config)
		})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
            <title>Blackbox Exporter</title>

Blackbox Exporter

Probe prometheus.io for http_2xx

Metrics

            `))
	})
	if err := http.ListenAndServe(*addr, nil); err != nil {
		log.Fatalf("Error starting HTTP server: %s", err)
	}
}
<commit_msg>Fix typo<commit_after>package main

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

	"gopkg.in/yaml.v2"

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

var addr = flag.String("web.listen-address", ":9115", "The address to listen on for HTTP requests.")
var configFile = flag.String("config.file", "blackbox.yml", "Blackbox exporter configuration file.")

type Config struct {
	Modules map[string]Module `yaml:"modules"`
}

type Module struct {
	Prober  string        `yaml:"prober"`
	Timeout time.Duration `yaml:"timeout"`
	HTTP    HTTPProbe     `yaml:"http"`
	TCP     TCPProbe      `yaml:"tcp"`
	ICMP    ICMPProbe     `yaml:"icmp"`
}

type HTTPProbe struct {
	// Defaults to 2xx.
	ValidStatusCodes       []int    `yaml:"valid_status_codes"`
	NoFollowRedirects      bool     `yaml:"no_follow_redirects"`
	FailIfSSL              bool     `yaml:"fail_if_ssl"`
	FailIfNotSSL           bool     `yaml:"fail_if_not_ssl"`
	Method                 string   `yaml:"method"`
	FailIfMatchesRegexp    []string `yaml:"fail_if_matches_regexp"`
	FailIfNotMatchesRegexp []string `yaml:"fail_if_not_matches_regexp"`
}

type QueryResponse struct {
	Expect string `yaml:"expect"`
	Send   string `yaml:"send"`
}

type TCPProbe struct {
	QueryResponse []QueryResponse `yaml:"query_response"`
}

type ICMPProbe struct {
}

var Probers = map[string]func(string, http.ResponseWriter, Module) bool{
	"http": probeHTTP,
	"tcp":  probeTCP,
	"icmp": probeICMP,
}

func probeHandler(w http.ResponseWriter, r *http.Request, config *Config) {
	params := r.URL.Query()
	target := params.Get("target")
	moduleName := params.Get("module")
	if target == "" {
		http.Error(w, "Target parameter is missing", 400)
		return
	}
	if moduleName == "" {
		moduleName = "http_2xx"
	}
	module, ok := config.Modules[moduleName]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown module %s", moduleName), 400)
		return
	}
	prober, ok := Probers[module.Prober]
	if !ok {
		http.Error(w, fmt.Sprintf("Unkown prober %s", module.Prober), 400)
		return
	}
	start := time.Now()
	success := prober(target, w, module)
	fmt.Fprintf(w, "probe_duration_seconds %f\n", float64(time.Now().Sub(start))/1e9)
	if success {
		fmt.Fprintf(w, "probe_success %d\n", 1)
	} else {
		fmt.Fprintf(w, "probe_success %d\n", 0)
	}
}

func main() {
	flag.Parse()

	yamlFile, err := ioutil.ReadFile(*configFile)

	if err != nil {
		log.Fatalf("Error reading config file: %s", err)
	}

	config := Config{}

	err = yaml.Unmarshal(yamlFile, &config)
	if err != nil {
		log.Fatalf("Error parsing config file: %s", err)
	}

	http.Handle("/metrics", prometheus.Handler())
	http.HandleFunc("/probe",
		func(w http.ResponseWriter, r *http.Request) {
			probeHandler(w, r, &config)
		})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
            <title>Blackbox Exporter</title>

Blackbox Exporter

Probe prometheus.io for http_2xx

Metrics

            `))
	})
	if err := http.ListenAndServe(*addr, nil); err != nil {
		log.Fatalf("Error starting HTTP server: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"github.com/gorilla/mux"
)

const (
	// declarations
	a string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	base int = 62	// character's known in 'a'
	domain_name = "localhost:22222"
	prefix = "http://"
	sep = "/"
)

//	default handler
func (env *Env) notFound(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("route not found... sorry! :("))
}

func (env *Env) createEntry(res http.ResponseWriter, req *http.Request) {

	// declare content type 'json'
	res.Header().Set("Content-Type", "application/json; charset=UTF-8")

	// capture and decode the payload from stream
	url := new(Url)
	decoder := json.NewDecoder(req.Body)
	error := decoder.Decode(&url)
	checkErr(error)

	// prepare insert statement
	query, _ := env.db.Prepare("INSERT IGNORE INTO nin SET url=?")

	// execute
	execute, err := query.Exec(url.Url)
	checkErr(err)

	// grab the id, encode, and suffix it to domain_name
	id, err2 := execute.LastInsertId()
	checkErr(err2)
	shorterUrl := domain_name + sep + encode(int(id), base, a)

	// return the response
	res.WriteHeader(http.StatusCreated)
	if err3 := json.NewEncoder(res).Encode(&Url{
		shorterUrl,
		}); err3 != nil {
		log.Fatal(err)
	}
}

func (env *Env) retrieveEntry(res http.ResponseWriter, req *http.Request) {

	// declare content type 'json'
	res.Header().Set("Content-Type", "application/json; charset=UTF-8")

	vars := mux.Vars(req)
	shorterUrl := vars["encoded_value"]
	id := decode(shorterUrl, a)

	// query statement
	var decodedUri string
	err := env.db.QueryRow("SELECT URL FROM nin WHERE ID=?",
		strconv.Itoa(id)).Scan(&decodedUri)

	if len(decodedUri) == 0 || decodedUri == "" {
		decodedUri = domain_name + sep + "error"
	}
	fmt.Println(err)
	//checkErr(err)

	http.Redirect(res, req, prefix + decodedUri, 301)
}

func main() {

	// load config from file (remove this in the future, should use kub secret)
	config := loadConfig(".env/foxley_mock.json")

	dsn := config.DB_USER + ":" + config.DB_PASS + "@" + config.DB_HOST + "/" + config.DB_NAME
	//db, err := sql.Open("mysql", dsn)
	db, err := NewDB(dsn)
	checkErr(err)
	defer db.Close()

	env := &Env{db : db}
	var version string
	db.QueryRow("SELECT VERSION()").Scan(&version)
	fmt.Println("Connected to:", version)

	r := mux.NewRouter()
	r.HandleFunc("/p/{encoded_value}", env.retrieveEntry)
	r.HandleFunc("/create", env.createEntry).Methods("POST")
	r.NotFoundHandler = http.HandlerFunc(env.notFound)

	log.Fatal(http.ListenAndServe(":22222", r))
}
//
//curl -X POST -H "Content-Type: application/json" -d '{"url":"foxley.co/okay"}' http://127.0.0.1:8080/create -v
<commit_msg>modified main to take mock_config struct<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"github.com/gorilla/mux"
)

const (
	// declarations
	a string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	base int = 62	// character's known in 'a'
	domain_name = "foxley.co:22222"	// remove port when kube manifest are ready
	prefix = "http://"
	sep = "/"
)

//	default handler
func (env *Env) notFound(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("route not found... sorry! :("))
}

func (env *Env) createEntry(res http.ResponseWriter, req *http.Request) {

	// declare content type 'json'
	res.Header().Set("Content-Type", "application/json; charset=UTF-8")

	// capture and decode the payload from stream
	url := new(Url)
	decoder := json.NewDecoder(req.Body)
	error := decoder.Decode(&url)
	checkErr(error)

	// prepare insert statement
	query, _ := env.db.Prepare("INSERT IGNORE INTO nin SET url=?")

	// execute
	execute, err := query.Exec(url.Url)
	checkErr(err)

	// grab the id, encode, and suffix it to domain_name
	id, err2 := execute.LastInsertId()
	checkErr(err2)
	shorterUrl := domain_name + sep + encode(int(id), base, a)

	// return the response
	res.WriteHeader(http.StatusCreated)
	if err3 := json.NewEncoder(res).Encode(&Url{
		shorterUrl,
		}); err3 != nil {
		log.Fatal(err)
	}
}

func (env *Env) retrieveEntry(res http.ResponseWriter, req *http.Request) {

	// declare content type 'json'
	res.Header().Set("Content-Type", "application/json; charset=UTF-8")

	vars := mux.Vars(req)
	shorterUrl := vars["encoded_value"]
	id := decode(shorterUrl, a)

	// query statement
	var decodedUri string
	err := env.db.QueryRow("SELECT URL FROM nin WHERE ID=?",
		strconv.Itoa(id)).Scan(&decodedUri)

	if len(decodedUri) == 0 || decodedUri == "" {
		decodedUri = domain_name + sep + "error"
	}
	fmt.Println(err)
	//checkErr(err)

	http.Redirect(res, req, prefix + decodedUri, 301)
}

func main() {

	// load config from file (remove this in the future, should use kub secret)
	config := loadConfig(".env/foxley_mock.json")

	dsn := config.DB_USER + ":" + config.DB_PASS + "@" + config.DB_HOST + "/" + config.DB_NAME
	//db, err := sql.Open("mysql", dsn)
	db, err := NewDB(dsn)
	checkErr(err)
	defer db.Close()

	env := &Env{db : db}
	var version string
	db.QueryRow("SELECT VERSION()").Scan(&version)
	fmt.Println("Connected to:", version)

	r := mux.NewRouter()
	r.HandleFunc("/p/{encoded_value}", env.retrieveEntry)
	r.HandleFunc("/create", env.createEntry).Methods("POST")
	r.NotFoundHandler = http.HandlerFunc(env.notFound)

	log.Fatal(http.ListenAndServe(":22222", r))
}
//
//curl -X POST -H "Content-Type: application/json" -d '{"url":"foxley.co/okay"}' http://127.0.0.1:8080/create -v
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"

	"github.com/codegangsta/martini"
)

// Type which, through reflection, Martini uses to dependency inject the user
// found by the Authentication middleware
type User interface{}

func main() {
	// Starting a standard martini server,
	// with logging and panic recovery middleware built in
	m := martini.Classic()

	// Register middleware which authenticates the client
	m.Use(Authentication)

	// Register a route which does something with the authenticated user,
	// but doesn't care for security reasons (ie. No authorization check)
	m.Get("/", func(u User) string {
		return fmt.Sprintf("Hello %s!", u)
	})

	// Register a route which requires the authenticated user to have specific authorization
	m.Get("/secret", Authorization("secret access"), func(u User) string {
		return fmt.Sprintf("Hello Secret Agent %s!", u)
	})

	// Start the server
	m.Run()
}

func Authentication(c martini.Context, req *http.Request, res http.ResponseWriter) {
	// Get the Authorization header
	a := req.Header.Get("Authorization")
	if a == "" {
		// No header, user must be guest
		c.MapTo("guest", (*User)(nil))
		return
	}

	// Remove the 'Basic ' prefix
	a = strings.TrimPrefix(a, "Basic ")

	// Decode the Authorization header
	data, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		// Bad Authorization value - return 401 Unauthorized
		http.Error(res, "Could not decode Authorization header", http.StatusUnauthorized)
		// Note: If the response gets written to, Martini doesn't call any subsequent handlers
		return
	}

	// Split out the username and password
	s := strings.Split(string(data), ":")
	if len(s) < 2 {
		// Bad Authorization value - return 401 Unauthorized
		http.Error(res, "Authorization header requires a username and password", http.StatusUnauthorized)
		// Note: If the response gets written to, Martini doesn't call any subsequent handlers
		return
	}

	// At this point, you would normally lookup a user database
	// Since this is an example - we're just accepting the username as is
	c.MapTo(s[0], (*User)(nil))
}

func Authorization(access string) func(User, http.ResponseWriter) {
	// Returning a handler function that checks for the required access
	return func(u User, res http.ResponseWriter) {
		// For brevity, we're just checking that the username is 'admin'
		if u != "admin" {
			// If not, return a response that stops Martini calling the next handler
			http.Error(res, "Not Authorized", http.StatusUnauthorized)
		}
	}
}
<commit_msg>Updated comments.<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"

	"github.com/codegangsta/martini"
)

// Type which, through reflection, Martini uses to dependency inject the user
// found by the Authentication middleware
type User interface{}

func main() {
	// Starting a standard martini server,
	// with logging and panic recovery middleware built in
	m := martini.Classic()

	// Register middleware which authenticates the client
	m.Use(Authentication)

	// Register a route which does something with the authenticated user,
	// but doesn't care for security reasons (ie. No authorization check)
	m.Get("/", func(u User) string {
		return fmt.Sprintf("Hello %s!", u)
	})

	// Register a route which requires the authenticated user to have specific authorization
	m.Get("/secret", Authorization("secret access"), func(u User) string {
		return fmt.Sprintf("Hello Secret Agent %s!", u)
	})

	// Start the server
	m.Run()
}

// Middleware for Martini which tries to identify the request user by the Authorization header.
// If no such header exists, it assumes it's a guest.
// If the header exists but can't be decoded, it returns a 401 status.
// It uses Martini's dependency injection system to register the user for later consumption.
func Authentication(c martini.Context, req *http.Request, res http.ResponseWriter) {
	// Get the Authorization header
	a := req.Header.Get("Authorization")
	if a == "" {
		// No header, user must be guest
		c.MapTo("guest", (*User)(nil))
		return
	}

	// Remove the 'Basic ' prefix
	a = strings.TrimPrefix(a, "Basic ")

	// Decode the Authorization header
	data, err := base64.StdEncoding.DecodeString(a)
	if err != nil {
		// Bad Authorization value - return 401 Unauthorized
		http.Error(res, "Could not decode Authorization header", http.StatusUnauthorized)
		// Note: If the response gets written to, Martini doesn't call any subsequent handlers
		return
	}

	// Split out the username and password
	s := strings.Split(string(data), ":")
	if len(s) < 2 {
		// Bad Authorization value - return 401 Unauthorized
		http.Error(res, "Authorization header requires a username and password", http.StatusUnauthorized)
		// Note: If the response gets written to, Martini doesn't call any subsequent handlers
		return
	}

	// At this point, you would normally lookup a user database
	// Since this is an example - we're just accepting the username as is
	c.MapTo(s[0], (*User)(nil))
}

// Returns a handler function which checks that the authenticated user for the request
// has a particular type of access.
// If they don't, a 401 status resposne is made.
// Otherwise, nothing happens - letting the next handler in the chain do it's work
func Authorization(access string) func(User, http.ResponseWriter) {
	// Returning a handler function that checks for the required access
	return func(u User, res http.ResponseWriter) {
		// For brevity, we're just checking that the username is 'admin'
		if u != "admin" {
			// If not, return a response that stops Martini calling the next handler
			http.Error(res, "Not Authorized", http.StatusUnauthorized)
		}
	}
}
<|endoftext|>


<commit_before>package logrus

import (
	"encoding/json"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/ggicci/jungo/program"
)

var (
	std       = log.New()
	formatter = new(log.TextFormatter)
)

func init() {
	formatter.DisableColors = true
	formatter.TimestampFormat = time.RFC3339Nano
}

func NewConfig() *config { return &config{} }

type config struct {
	// The directory in which the log files stay.
	LogDir string `json:"log_dir"`

	// The basic filename of the logs. If not set, defaults to "logrus.log".
	// And according to different roll period, final filenames are:
	//
	// Period    	Filename
	// none		 	logrus.go
	// hourly		logrus.20060102.15
	// daily		logrus.20060102
	//
	// NB: slash("/") in the filename will be replace with an underscore character("_"),
	// and dots(".") and spaces will be trimmed.
	LogFilename string `json:"log_filename"`

	// Like, `LogFilename`.
	// If set, logs with level >= "error" will also be written to the error log file.
	// No rolling.
	LogErrorFilename string `json:"log_error_filename"`

	// Log level, valid levels are: "panic", "fatal", "error", "warn" or "warning", "info", "debug".
	LogLevelString string `json:"log_level"`

	// Log roll period, "none", "hourly", "daily".
	LogRollPeriodString string `json:"log_roll_period"`

	logLevel      log.Level
	logRollPeriod RollPeriod
}

func loadConfigs(filename string) (*config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	cfg := NewConfig()
	if err = json.NewDecoder(f).Decode(cfg); err != nil {
		return nil, err
	}

	return cfg, nil
}

func normConfigs(cfg *config) *config {
	// Check the config items.

	if cfg.LogDir = strings.TrimSpace(cfg.LogDir); cfg.LogDir == "" {
		cfg.LogDir = program.AbsPath("../logs")
		std.Warnf("logrus config: log_dir not set, defaults to %q", cfg.LogDir)
	} else {
		cfg.LogDir = program.AbsPath(cfg.LogDir)
	}

	cfg.LogFilename = strings.TrimSpace(cfg.LogFilename)
	cfg.LogFilename = strings.Replace(cfg.LogFilename, "/", "_", -1)
	cfg.LogFilename = strings.Trim(cfg.LogFilename, ".")
	if cfg.LogFilename == "" {
		cfg.LogFilename = "logrus.log"
		std.Warnf("logrus config: log_filename not set, defaults to %q", cfg.LogFilename)
	}

	cfg.LogErrorFilename = strings.TrimSpace(cfg.LogErrorFilename)
	cfg.LogErrorFilename = strings.Replace(cfg.LogErrorFilename, "/", "_", -1)
	cfg.LogErrorFilename = strings.Trim(cfg.LogErrorFilename, ".")
	if cfg.LogErrorFilename == cfg.LogFilename {
		cfg.LogErrorFilename = cfg.LogFilename + ".error"
	}

	if level, err := log.ParseLevel(cfg.LogLevelString); err != nil {
		std.Warnf("logrus config: log_level was %s (parse error: %v), reset to %q",
			cfg.LogLevelString, err, LogLevelString(log.InfoLevel))
		cfg.LogLevelString = LogLevelString(log.InfoLevel)
		cfg.logLevel = log.InfoLevel
	} else {
		cfg.logLevel = level
	}

	if period, err := ParseRollPeriod(cfg.LogRollPeriodString); err != nil {
		std.Warnf("logrus config: log_roll_period was %s (parse error: %v), reset to %q",
			cfg.LogRollPeriodString, err, RollPeriodString(ROLL_PERIOD_NONE))
		cfg.LogRollPeriodString = RollPeriodString(ROLL_PERIOD_NONE)
		cfg.logRollPeriod = ROLL_PERIOD_NONE
	} else {
		cfg.logRollPeriod = period
	}

	return cfg
}

func LogLevelString(level log.Level) string {
	return map[log.Level]string{
		log.PanicLevel: "panic",
		log.FatalLevel: "fatal",
		log.ErrorLevel: "error",
		log.WarnLevel:  "warn",
		log.InfoLevel:  "info",
		log.DebugLevel: "debug",
	}[level]
}
<commit_msg>Truncate "jungo" prefix in warnning log.<commit_after>package logrus

import (
	"encoding/json"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/ggicci/jungo/program"
)

var (
	std       = log.New()
	formatter = new(log.TextFormatter)
)

func init() {
	formatter.DisableColors = true
	formatter.TimestampFormat = time.RFC3339Nano
}

func NewConfig() *config { return &config{} }

type config struct {
	// The directory in which the log files stay.
	LogDir string `json:"log_dir"`

	// The basic filename of the logs. If not set, defaults to "logrus.log".
	// And according to different roll period, final filenames are:
	//
	// Period    	Filename
	// none		 	logrus.go
	// hourly		logrus.20060102.15
	// daily		logrus.20060102
	//
	// NB: slash("/") in the filename will be replace with an underscore character("_"),
	// and dots(".") and spaces will be trimmed.
	LogFilename string `json:"log_filename"`

	// Like, `LogFilename`.
	// If set, logs with level >= "error" will also be written to the error log file.
	// No rolling.
	LogErrorFilename string `json:"log_error_filename"`

	// Log level, valid levels are: "panic", "fatal", "error", "warn" or "warning", "info", "debug".
	LogLevelString string `json:"log_level"`

	// Log roll period, "none", "hourly", "daily".
	LogRollPeriodString string `json:"log_roll_period"`

	logLevel      log.Level
	logRollPeriod RollPeriod
}

func loadConfigs(filename string) (*config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	cfg := NewConfig()
	if err = json.NewDecoder(f).Decode(cfg); err != nil {
		return nil, err
	}

	return cfg, nil
}

func normConfigs(cfg *config) *config {
	// Check the config items.

	if cfg.LogDir = strings.TrimSpace(cfg.LogDir); cfg.LogDir == "" {
		cfg.LogDir = program.AbsPath("../logs")
		std.Warnf("config: log_dir not set, defaults to %q", cfg.LogDir)
	} else {
		cfg.LogDir = program.AbsPath(cfg.LogDir)
	}

	cfg.LogFilename = strings.TrimSpace(cfg.LogFilename)
	cfg.LogFilename = strings.Replace(cfg.LogFilename, "/", "_", -1)
	cfg.LogFilename = strings.Trim(cfg.LogFilename, ".")
	if cfg.LogFilename == "" {
		cfg.LogFilename = "logrus.log"
		std.Warnf("config: log_filename not set, defaults to %q", cfg.LogFilename)
	}

	cfg.LogErrorFilename = strings.TrimSpace(cfg.LogErrorFilename)
	cfg.LogErrorFilename = strings.Replace(cfg.LogErrorFilename, "/", "_", -1)
	cfg.LogErrorFilename = strings.Trim(cfg.LogErrorFilename, ".")
	if cfg.LogErrorFilename == cfg.LogFilename {
		cfg.LogErrorFilename = cfg.LogFilename + ".error"
	}

	if level, err := log.ParseLevel(cfg.LogLevelString); err != nil {
		std.Warnf("config: log_level was %s (parse error: %v), reset to %q",
			cfg.LogLevelString, err, LogLevelString(log.InfoLevel))
		cfg.LogLevelString = LogLevelString(log.InfoLevel)
		cfg.logLevel = log.InfoLevel
	} else {
		cfg.logLevel = level
	}

	if period, err := ParseRollPeriod(cfg.LogRollPeriodString); err != nil {
		std.Warnf("config: log_roll_period was %s (parse error: %v), reset to %q",
			cfg.LogRollPeriodString, err, RollPeriodString(ROLL_PERIOD_NONE))
		cfg.LogRollPeriodString = RollPeriodString(ROLL_PERIOD_NONE)
		cfg.logRollPeriod = ROLL_PERIOD_NONE
	} else {
		cfg.logRollPeriod = period
	}

	return cfg
}

func LogLevelString(level log.Level) string {
	return map[log.Level]string{
		log.PanicLevel: "panic",
		log.FatalLevel: "fatal",
		log.ErrorLevel: "error",
		log.WarnLevel:  "warn",
		log.InfoLevel:  "info",
		log.DebugLevel: "debug",
	}[level]
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-tools/go-steputils/cache"
	"github.com/kballard/go-shellquote"
)

// ConfigsModel ...
type ConfigsModel struct {
	// Gradle Inputs
	GradleFile               string
	GradleTasks              string
	GradlewPath              string
	GradleOptions            string
	ApkFileIncludeFilter     string
	ApkFileExcludeFilter     string
	MappingFileIncludeFilter string
	MappingFileExcludeFilter string

	// Other configs
	DeployDir string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		GradleFile:               os.Getenv("gradle_file"),
		GradleTasks:              os.Getenv("gradle_task"),
		GradlewPath:              os.Getenv("gradlew_path"),
		GradleOptions:            os.Getenv("gradle_options"),
		ApkFileIncludeFilter:     os.Getenv("apk_file_include_filter"),
		ApkFileExcludeFilter:     os.Getenv("apk_file_exclude_filter"),
		MappingFileIncludeFilter: os.Getenv("mapping_file_include_filter"),
		MappingFileExcludeFilter: os.Getenv("mapping_file_exclude_filter"),
		//
		DeployDir: os.Getenv("BITRISE_DEPLOY_DIR"),
	}
}

func (configs ConfigsModel) print() {

	log.Infof("Configs:")
	log.Printf("- GradlewPath: %s", configs.GradlewPath)
	log.Printf("- GradleFile: %s", configs.GradleFile)
	log.Printf("- GradleTasks: %s", configs.GradleTasks)
	log.Printf("- GradleOptions: %s", configs.GradleOptions)
	log.Printf("- ApkFileIncludeFilter: %s", configs.ApkFileIncludeFilter)
	log.Printf("- ApkFileExcludeFilter: %s", configs.ApkFileExcludeFilter)
	log.Printf("- MappingFileIncludeFilter: %s", configs.MappingFileIncludeFilter)
	log.Printf("- MappingFileExcludeFilter: %s", configs.MappingFileExcludeFilter)
	log.Printf("- DeployDir: %s", configs.DeployDir)
}

func (configs ConfigsModel) validate() (string, error) {
	if configs.GradleFile != "" {
		if exist, err := pathutil.IsPathExists(configs.GradleFile); err != nil {
			return "", fmt.Errorf("Failed to check if GradleFile exists at: %s, error: %s", configs.GradleFile, err)
		} else if !exist {
			return "", fmt.Errorf("GradleFile does not exist at: %s", configs.GradleFile)
		}
	}

	if configs.GradleTasks == "" {
		return "", errors.New("no GradleTask parameter specified")
	}

	if configs.GradlewPath == "" {
		explanation := `
Using a Gradle Wrapper (gradlew) is required, as the wrapper is what makes sure
that the right Gradle version is installed and used for the build.

You can find more information about the Gradle Wrapper (gradlew),
and about how you can generate one (if you would not have one already
in the official guide at: https://docs.gradle.org/current/userguide/gradle_wrapper.html`

		return explanation, errors.New("no GradlewPath parameter specified")
	}
	if exist, err := pathutil.IsPathExists(configs.GradlewPath); err != nil {
		return "", fmt.Errorf("Failed to check if GradlewPath exist at: %s, error: %s", configs.GradlewPath, err)
	} else if !exist {
		return "", fmt.Errorf("GradlewPath not exist at: %s", configs.GradlewPath)
	}

	return "", nil
}

func runGradleTask(gradleTool, buildFile, tasks, options string) error {
	optionSlice, err := shellquote.Split(options)
	if err != nil {
		return err
	}

	taskSlice, err := shellquote.Split(tasks)
	if err != nil {
		return err
	}

	cmdSlice := []string{gradleTool}
	if buildFile != "" {
		cmdSlice = append(cmdSlice, "--build-file", buildFile)
	}
	cmdSlice = append(cmdSlice, taskSlice...)
	cmdSlice = append(cmdSlice, optionSlice...)

	log.Printf(command.PrintableCommandArgs(false, cmdSlice))
	fmt.Println()

	cmd := command.New(cmdSlice[0], cmdSlice[1:]...)
	cmd.SetStdout(os.Stdout)
	cmd.SetStderr(os.Stderr)
	return cmd.Run()
}

func find(dir, nameInclude, nameExclude string) ([]string, error) {
	cmdSlice := []string{"find", dir}
	cmdSlice = append(cmdSlice, "-path", nameInclude)
	cmdSlice = append(cmdSlice, "!", "-path", nameExclude)

	log.Printf(command.PrintableCommandArgs(false, cmdSlice))

	out, err := command.New(cmdSlice[0], cmdSlice[1:]...).RunAndReturnTrimmedOutput()
	if err != nil {
		return []string{}, err
	}

	split := strings.Split(out, "\n")
	files := []string{}
	for _, item := range split {
		trimmed := strings.TrimSpace(item)
		if trimmed != "" {
			files = append(files, trimmed)
		}
	}

	return files, nil
}

func createDeployPth(deployDir, apkName string) (string, error) {
	deployPth := filepath.Join(deployDir, apkName)

	if exist, err := pathutil.IsPathExists(deployPth); err != nil {
		return "", err
	} else if exist {
		return "", fmt.Errorf("file already exists at: %s", deployPth)
	}

	return deployPth, nil
}

func findDeployPth(deployDir, baseName, ext string) (string, error) {
	deployPth := ""
	retryApkName := baseName + ext

	err := retry.Times(10).Wait(1 * time.Second).Try(func(attempt uint) error {
		if attempt > 0 {
			log.Warnf("  Retrying...")
		}

		pth, pathErr := createDeployPth(deployDir, retryApkName)
		if pathErr != nil {
			log.Warnf("  %d attempt failed:", attempt+1)
			log.Printf(pathErr.Error())
		}

		t := time.Now()
		retryApkName = baseName + t.Format("20060102150405") + ext
		deployPth = pth

		return pathErr
	})

	return deployPth, err
}

func exportEnvironmentWithEnvman(keyStr, valueStr string) error {
	cmd := command.New("envman", "add", "--key", keyStr)
	cmd.SetStdin(strings.NewReader(valueStr))
	return cmd.Run()
}

func failf(message string, args ...interface{}) {
	log.Errorf(message, args...)
	os.Exit(1)
}

func main() {
	configs := createConfigsModelFromEnvs()
	configs.print()
	if explanation, err := configs.validate(); err != nil {
		fmt.Println()
		log.Errorf("Issue with input: %s", err)
		fmt.Println()

		if explanation != "" {
			fmt.Println(explanation)
			fmt.Println()
		}

		os.Exit(1)
	}

	if configs.ApkFileIncludeFilter == "" {
		configs.ApkFileIncludeFilter = "*.apk"
	}

	err := os.Chmod(configs.GradlewPath, 0770)
	if err != nil {
		failf("Failed to add executable permission on gradlew file (%s), error: %s", configs.GradlewPath, err)
	}

	log.Infof("Running gradle task...")
	if err := runGradleTask(configs.GradlewPath, configs.GradleFile, configs.GradleTasks, configs.GradleOptions); err != nil {
		failf("Gradle task failed, error: %s", err)
	}

	// Collecting caches
	fmt.Println()
	log.Infof("Collecting gradle caches...")

	gradleCache := cache.New()
	homeDir := pathutil.UserHomeDir()

	includePths := []string{
		filepath.Join(homeDir, ".gradle"),
		filepath.Join(homeDir, ".kotlin"),
		filepath.Join(homeDir, ".android", "build-cache"),
	}
	excludePths := []string{
		"/*.lock",
		"/*.bin",
		"/*/build/*.json",
		"/*/build/*.xml",
		"/*/build/*.properties",
		"/*/build/*/zip-cache/*",
		"/*.log",
		"/*.txt",
		"/*.rawproto",
		"/*.ap_",
		"/*.apk",
	}

	projectRoot, err := filepath.Abs(".")
	if err != nil {
		log.Warnf("Cache collection skipped: failed to determine project root path.")
	} else {
		if err := filepath.Walk(projectRoot, func(path string, f os.FileInfo, err error) error {
			if f.IsDir() {
				if f.Name() == "build" {
					includePths = append(includePths, path)
				}
				if f.Name() == ".gradle" {
					includePths = append(includePths, path)
				}
			}
			return nil
		}); err != nil {
			log.Warnf("Cache collection skipped: failed to determine cache paths.")
		} else {

			gradleCache.IncludePath(strings.Join(includePths, "\n"))
			gradleCache.ExcludePath(strings.Join(excludePths, "\n"))

			if err := gradleCache.Commit(); err != nil {
				log.Warnf("Cache collection skipped: failed to commit cache paths.")
			}
		}
	}

	// Move apk files
	fmt.Println()
	log.Infof("Move apk files...")
	apkFiles, err := find(".", configs.ApkFileIncludeFilter, configs.ApkFileExcludeFilter)
	if err != nil {
		failf("Failed to find apk files, error: %s", err)
	}

	if len(apkFiles) == 0 {
		log.Warnf("No apk matched the filters")
	}

	lastCopiedApkFile := ""
	for _, apkFile := range apkFiles {
		ext := filepath.Ext(apkFile)
		baseName := filepath.Base(apkFile)
		baseName = strings.TrimSuffix(baseName, ext)

		deployPth, err := findDeployPth(configs.DeployDir, baseName, ext)
		if err != nil {
			failf("Failed to create apk deploy path, error: %s", err)
		}

		log.Printf("copy %s to %s", apkFile, deployPth)
		command.CopyFile(apkFile, deployPth)

		lastCopiedApkFile = deployPth
	}

	if lastCopiedApkFile != "" {
		if err := exportEnvironmentWithEnvman("BITRISE_APK_PATH", lastCopiedApkFile); err != nil {
			failf("Failed to export enviroment (BITRISE_APK_PATH), error: %s", err)
		}
		log.Donef("The apk path is now available in the Environment Variable: $BITRISE_APK_PATH (value: %s)", lastCopiedApkFile)
	}

	// Move mapping files
	log.Infof("Move mapping files...")
	mappingFiles, err := find(".", configs.MappingFileIncludeFilter, configs.MappingFileExcludeFilter)
	if err != nil {
		failf("Failed to find mapping files, error: %s", err)
	}

	if len(mappingFiles) == 0 {
		log.Printf("No mapping file matched the filters")
	}

	lastCopiedMappingFile := ""
	for _, mappingFile := range mappingFiles {
		ext := filepath.Ext(mappingFile)
		baseName := filepath.Base(mappingFile)
		baseName = strings.TrimSuffix(baseName, ext)

		deployPth, err := findDeployPth(configs.DeployDir, baseName, ext)
		if err != nil {
			failf("Failed to create mapping deploy path, error: %s", err)
		}

		log.Printf("copy %s to %s", mappingFile, deployPth)
		command.CopyFile(mappingFile, deployPth)

		lastCopiedMappingFile = deployPth
	}

	if lastCopiedMappingFile != "" {
		if err := exportEnvironmentWithEnvman("BITRISE_MAPPING_PATH", lastCopiedMappingFile); err != nil {
			failf("Failed to export enviroment (BITRISE_MAPPING_PATH), error: %s", err)
		}
		log.Donef("The mapping path is now available in the Environment Variable: $BITRISE_MAPPING_PATH (value: %s)", lastCopiedMappingFile)
	}
}
<commit_msg>updated cache ignore paths (#33)<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/retry"
	"github.com/bitrise-tools/go-steputils/cache"
	"github.com/kballard/go-shellquote"
)

// ConfigsModel ...
type ConfigsModel struct {
	// Gradle Inputs
	GradleFile               string
	GradleTasks              string
	GradlewPath              string
	GradleOptions            string
	ApkFileIncludeFilter     string
	ApkFileExcludeFilter     string
	MappingFileIncludeFilter string
	MappingFileExcludeFilter string

	// Other configs
	DeployDir string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		GradleFile:               os.Getenv("gradle_file"),
		GradleTasks:              os.Getenv("gradle_task"),
		GradlewPath:              os.Getenv("gradlew_path"),
		GradleOptions:            os.Getenv("gradle_options"),
		ApkFileIncludeFilter:     os.Getenv("apk_file_include_filter"),
		ApkFileExcludeFilter:     os.Getenv("apk_file_exclude_filter"),
		MappingFileIncludeFilter: os.Getenv("mapping_file_include_filter"),
		MappingFileExcludeFilter: os.Getenv("mapping_file_exclude_filter"),
		//
		DeployDir: os.Getenv("BITRISE_DEPLOY_DIR"),
	}
}

func (configs ConfigsModel) print() {

	log.Infof("Configs:")
	log.Printf("- GradlewPath: %s", configs.GradlewPath)
	log.Printf("- GradleFile: %s", configs.GradleFile)
	log.Printf("- GradleTasks: %s", configs.GradleTasks)
	log.Printf("- GradleOptions: %s", configs.GradleOptions)
	log.Printf("- ApkFileIncludeFilter: %s", configs.ApkFileIncludeFilter)
	log.Printf("- ApkFileExcludeFilter: %s", configs.ApkFileExcludeFilter)
	log.Printf("- MappingFileIncludeFilter: %s", configs.MappingFileIncludeFilter)
	log.Printf("- MappingFileExcludeFilter: %s", configs.MappingFileExcludeFilter)
	log.Printf("- DeployDir: %s", configs.DeployDir)
}

func (configs ConfigsModel) validate() (string, error) {
	if configs.GradleFile != "" {
		if exist, err := pathutil.IsPathExists(configs.GradleFile); err != nil {
			return "", fmt.Errorf("Failed to check if GradleFile exists at: %s, error: %s", configs.GradleFile, err)
		} else if !exist {
			return "", fmt.Errorf("GradleFile does not exist at: %s", configs.GradleFile)
		}
	}

	if configs.GradleTasks == "" {
		return "", errors.New("no GradleTask parameter specified")
	}

	if configs.GradlewPath == "" {
		explanation := `
Using a Gradle Wrapper (gradlew) is required, as the wrapper is what makes sure
that the right Gradle version is installed and used for the build.

You can find more information about the Gradle Wrapper (gradlew),
and about how you can generate one (if you would not have one already
in the official guide at: https://docs.gradle.org/current/userguide/gradle_wrapper.html`

		return explanation, errors.New("no GradlewPath parameter specified")
	}
	if exist, err := pathutil.IsPathExists(configs.GradlewPath); err != nil {
		return "", fmt.Errorf("Failed to check if GradlewPath exist at: %s, error: %s", configs.GradlewPath, err)
	} else if !exist {
		return "", fmt.Errorf("GradlewPath not exist at: %s", configs.GradlewPath)
	}

	return "", nil
}

func runGradleTask(gradleTool, buildFile, tasks, options string) error {
	optionSlice, err := shellquote.Split(options)
	if err != nil {
		return err
	}

	taskSlice, err := shellquote.Split(tasks)
	if err != nil {
		return err
	}

	cmdSlice := []string{gradleTool}
	if buildFile != "" {
		cmdSlice = append(cmdSlice, "--build-file", buildFile)
	}
	cmdSlice = append(cmdSlice, taskSlice...)
	cmdSlice = append(cmdSlice, optionSlice...)

	log.Printf(command.PrintableCommandArgs(false, cmdSlice))
	fmt.Println()

	cmd := command.New(cmdSlice[0], cmdSlice[1:]...)
	cmd.SetStdout(os.Stdout)
	cmd.SetStderr(os.Stderr)
	return cmd.Run()
}

func find(dir, nameInclude, nameExclude string) ([]string, error) {
	cmdSlice := []string{"find", dir}
	cmdSlice = append(cmdSlice, "-path", nameInclude)
	cmdSlice = append(cmdSlice, "!", "-path", nameExclude)

	log.Printf(command.PrintableCommandArgs(false, cmdSlice))

	out, err := command.New(cmdSlice[0], cmdSlice[1:]...).RunAndReturnTrimmedOutput()
	if err != nil {
		return []string{}, err
	}

	split := strings.Split(out, "\n")
	files := []string{}
	for _, item := range split {
		trimmed := strings.TrimSpace(item)
		if trimmed != "" {
			files = append(files, trimmed)
		}
	}

	return files, nil
}

func createDeployPth(deployDir, apkName string) (string, error) {
	deployPth := filepath.Join(deployDir, apkName)

	if exist, err := pathutil.IsPathExists(deployPth); err != nil {
		return "", err
	} else if exist {
		return "", fmt.Errorf("file already exists at: %s", deployPth)
	}

	return deployPth, nil
}

func findDeployPth(deployDir, baseName, ext string) (string, error) {
	deployPth := ""
	retryApkName := baseName + ext

	err := retry.Times(10).Wait(1 * time.Second).Try(func(attempt uint) error {
		if attempt > 0 {
			log.Warnf("  Retrying...")
		}

		pth, pathErr := createDeployPth(deployDir, retryApkName)
		if pathErr != nil {
			log.Warnf("  %d attempt failed:", attempt+1)
			log.Printf(pathErr.Error())
		}

		t := time.Now()
		retryApkName = baseName + t.Format("20060102150405") + ext
		deployPth = pth

		return pathErr
	})

	return deployPth, err
}

func exportEnvironmentWithEnvman(keyStr, valueStr string) error {
	cmd := command.New("envman", "add", "--key", keyStr)
	cmd.SetStdin(strings.NewReader(valueStr))
	return cmd.Run()
}

func failf(message string, args ...interface{}) {
	log.Errorf(message, args...)
	os.Exit(1)
}

func main() {
	configs := createConfigsModelFromEnvs()
	configs.print()
	if explanation, err := configs.validate(); err != nil {
		fmt.Println()
		log.Errorf("Issue with input: %s", err)
		fmt.Println()

		if explanation != "" {
			fmt.Println(explanation)
			fmt.Println()
		}

		os.Exit(1)
	}

	if configs.ApkFileIncludeFilter == "" {
		configs.ApkFileIncludeFilter = "*.apk"
	}

	err := os.Chmod(configs.GradlewPath, 0770)
	if err != nil {
		failf("Failed to add executable permission on gradlew file (%s), error: %s", configs.GradlewPath, err)
	}

	log.Infof("Running gradle task...")
	if err := runGradleTask(configs.GradlewPath, configs.GradleFile, configs.GradleTasks, configs.GradleOptions); err != nil {
		failf("Gradle task failed, error: %s", err)
	}

	// Collecting caches
	fmt.Println()
	log.Infof("Collecting gradle caches...")

	gradleCache := cache.New()
	homeDir := pathutil.UserHomeDir()

	includePths := []string{
		filepath.Join(homeDir, ".gradle"),
		filepath.Join(homeDir, ".kotlin"),
		filepath.Join(homeDir, ".android", "build-cache"),
	}
	excludePths := []string{
		"~/.gradle/**",
		"~/.android/build-cache/**",
		"*.lock",
		"*.bin",
		"/**/build/**.json",
		"/**/build/**.xml",
		"/**/build/**.properties",
		"/**/build/**/zip-cache/**",
		"*.log",
		"*.txt",
		"*.rawproto",
		"!*.ap_",
		"!*.apk",
	}

	projectRoot, err := filepath.Abs(".")
	if err != nil {
		log.Warnf("Cache collection skipped: failed to determine project root path.")
	} else {
		if err := filepath.Walk(projectRoot, func(path string, f os.FileInfo, err error) error {
			if f.IsDir() {
				if f.Name() == "build" {
					includePths = append(includePths, path)
				}
				if f.Name() == ".gradle" {
					includePths = append(includePths, path)
				}
			}
			return nil
		}); err != nil {
			log.Warnf("Cache collection skipped: failed to determine cache paths.")
		} else {

			gradleCache.IncludePath(strings.Join(includePths, "\n"))
			gradleCache.ExcludePath(strings.Join(excludePths, "\n"))

			if err := gradleCache.Commit(); err != nil {
				log.Warnf("Cache collection skipped: failed to commit cache paths.")
			}
		}
	}

	// Move apk files
	fmt.Println()
	log.Infof("Move apk files...")
	apkFiles, err := find(".", configs.ApkFileIncludeFilter, configs.ApkFileExcludeFilter)
	if err != nil {
		failf("Failed to find apk files, error: %s", err)
	}

	if len(apkFiles) == 0 {
		log.Warnf("No apk matched the filters")
	}

	lastCopiedApkFile := ""
	for _, apkFile := range apkFiles {
		ext := filepath.Ext(apkFile)
		baseName := filepath.Base(apkFile)
		baseName = strings.TrimSuffix(baseName, ext)

		deployPth, err := findDeployPth(configs.DeployDir, baseName, ext)
		if err != nil {
			failf("Failed to create apk deploy path, error: %s", err)
		}

		log.Printf("copy %s to %s", apkFile, deployPth)
		command.CopyFile(apkFile, deployPth)

		lastCopiedApkFile = deployPth
	}

	if lastCopiedApkFile != "" {
		if err := exportEnvironmentWithEnvman("BITRISE_APK_PATH", lastCopiedApkFile); err != nil {
			failf("Failed to export enviroment (BITRISE_APK_PATH), error: %s", err)
		}
		log.Donef("The apk path is now available in the Environment Variable: $BITRISE_APK_PATH (value: %s)", lastCopiedApkFile)
	}

	// Move mapping files
	log.Infof("Move mapping files...")
	mappingFiles, err := find(".", configs.MappingFileIncludeFilter, configs.MappingFileExcludeFilter)
	if err != nil {
		failf("Failed to find mapping files, error: %s", err)
	}

	if len(mappingFiles) == 0 {
		log.Printf("No mapping file matched the filters")
	}

	lastCopiedMappingFile := ""
	for _, mappingFile := range mappingFiles {
		ext := filepath.Ext(mappingFile)
		baseName := filepath.Base(mappingFile)
		baseName = strings.TrimSuffix(baseName, ext)

		deployPth, err := findDeployPth(configs.DeployDir, baseName, ext)
		if err != nil {
			failf("Failed to create mapping deploy path, error: %s", err)
		}

		log.Printf("copy %s to %s", mappingFile, deployPth)
		command.CopyFile(mappingFile, deployPth)

		lastCopiedMappingFile = deployPth
	}

	if lastCopiedMappingFile != "" {
		if err := exportEnvironmentWithEnvman("BITRISE_MAPPING_PATH", lastCopiedMappingFile); err != nil {
			failf("Failed to export enviroment (BITRISE_MAPPING_PATH), error: %s", err)
		}
		log.Donef("The mapping path is now available in the Environment Variable: $BITRISE_MAPPING_PATH (value: %s)", lastCopiedMappingFile)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"os"
	"strconv"
	"time"

	"github.com/gizak/termui"
	"github.com/kolo/xmlrpc"
	"github.com/spf13/viper"
)

var selector int

// AccountReturn contains fields for informations about the Gandi account
type AccountReturn struct {
	AverageCreditCost     float64   `xmlrpc:"average_credit_cost"`
	Credits               int       `xmlrpc:"credits"`
	CycleDay              int       `xmlrpc:"cycle_day"`
	DateCreditsExpiration time.Time `xmlrpc:"date_credits_expiration"`
	FullName              string    `xmlrpc:"fullname"`
	Handle                string    `xmlrpc:"handle"`
	ID                    int       `xmlrpc:"id"`
}

// DiskReturn contains fields for informations about the Disks
type DiskReturn struct {
	CanSnapshot   bool      `xmlrpc:"can_snapshot"`
	DatacenterID  int       `xmlrpc:"datacenter_id"`
	DateCreated   time.Time `xmlrpc:"date_created"`
	DateUpdated   time.Time `xmlrpc:"date_updated"`
	ID            int       `xmlrpc:"id"`
	IsBootDisk    bool      `xmlrpc:"is_boot_disk"`
	KernelVersion string    `xmlrpc:"kernel_version"`
	Label         string    `xmlrpc:"label"`
	Name          string    `xmlrpc:"name"`
	Size          int       `xmlrpc:"size"`
	State         string    `xmlrpc:"state"`
	TotalSize     int       `xmlrpc:"total_size"`
	Type          string    `xmlrpc:"type"`
	Visibility    string    `xmlrpc:"visibility"`
}

// VMReturn contains fields for informations about the virtual machines
type VMReturn struct {
	AiActive     int          `xmlrpc:"ai_active"`
	Console      int          `xmlrpc:"console"`
	ConsoleURL   string       `xmlrpc:"console_url"`
	Cores        int          `xmlrpc:"cores"`
	DatacenterID int          `xmlrpc:"datacenter_id"`
	DateCreated  time.Time    `xmlrpc:"date_created"`
	DateUpdated  time.Time    `xmlrpc:"date_updated"`
	Description  string       `xmlrpc:"description"`
	Disks        []DiskReturn `xmlrpc:"disks"`
	Farm         string       `xmlrpc:"farm"`
	FlexShares   int          `xmlrpc:"flex_shares"`
	Hostname     string       `xmlrpc:"hostname"`
	HVMState     string       `xmlrpc:"hvm_state"`
	ID           int          `xmlrpc:"id"`
	Memory       int          `xmlrpc:"memory"`
	State        string       `xmlrpc:"state"`
	VMmaxMemory  int          `xmlrpc:"vm_max_memory"`
}

// LoadAPI returns the api and apiKey according to the settings defined in the
// configuration file, respectively.
func LoadAPI() (api *xmlrpc.Client, apiKey string, err error) {
	viper.SetConfigName("bapu")

	homePath := os.Getenv("HOME")
	viper.AddConfigPath(homePath)
	viper.AddConfigPath("/usr/local/etc")
	viper.AddConfigPath("/etc")

	err = viper.ReadInConfig()
	if err != nil {
		return api, apiKey, err
	}

	production := viper.GetBool("production.enabled")
	if production {
		apiKey = viper.GetString("production.apiKey")
		api, err = xmlrpc.NewClient("https://rpc.gandi.net/xmlrpc/", nil)
		if err != nil {
			return api, apiKey, err
		}
	}

	development := viper.GetBool("development.enabled")
	if development {
		log.Println("Development Config found")
		api, err = xmlrpc.NewClient("https://rpc.ote.gandi.net/xmlrpc/", nil)
		if err != nil {
			return api, apiKey, err
		}
		apiKey = viper.GetString("development.apiKey")
	}

	if api == nil {
		return api, apiKey, errors.New("neither production nor development environment enabled in config")
	}

	return api, apiKey, nil
}

func serverList(list []VMReturn) (servers [][]string) {

	servers = append(servers, []string{
		"Selected",
		"Hostname",
		"Datacenter",
		"Cores",
		"Memory",
		"State",
	})

	for i, val := range list {
		s := ""
		if selector == i {
			s = "*"
		}
		servers = append(servers, []string{
			s,
			val.Hostname,
			strconv.Itoa(val.DatacenterID),
			strconv.Itoa(val.Cores),
			strconv.Itoa(val.Memory) + "MB",
			val.State,
		})
	}

	return servers
}

func main() {
	// Load API
	api, apiKey, err := LoadAPI()
	if err != nil {
		log.Fatal(err)
	}

	// initialize termui
	err = termui.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termui.Close()

	// Title
	uiTitle := termui.NewPar("Bapu -- Control your Gandi Machines")
	uiTitle.Border = false
	uiTitle.Height = 3
	uiTitle.TextFgColor = termui.ColorMagenta

	// Summary
	var hostingVMCount *int
	err = api.Call("hosting.vm.count", apiKey, &hostingVMCount)
	if err != nil {
		log.Fatal(err)
	}
	var hostingAccountInfo *AccountReturn
	err = api.Call("hosting.account.info", apiKey, &hostingAccountInfo)
	if err != nil {
		log.Fatal(err)
	}

	info := *hostingAccountInfo

	uiSummary := termui.NewPar("Owner: " + info.FullName + "    Virtual Machines: " + strconv.Itoa(*hostingVMCount) + "    Remaining Credit: " + strconv.Itoa(info.Credits))
	uiSummary.Height = 3
	uiSummary.Border = true
	uiSummary.BorderLabel = "Summary"
	uiSummary.TextFgColor = termui.ColorWhite

	// List instances
	var hostingVMList *[]VMReturn
	err = api.Call("hosting.vm.list", apiKey, &hostingVMList)
	if err != nil {
		log.Fatal(err)
	}

	list := *hostingVMList

	uiTable := termui.NewTable()
	uiTable.Rows = serverList(list)
	uiTable.FgColor = termui.ColorWhite
	uiTable.BgColor = termui.ColorDefault
	uiTable.TextAlign = termui.AlignCenter
	uiTable.Seperator = false
	uiTable.Analysis()
	uiTable.SetSize()
	uiTable.BgColors[0] = termui.ColorWhite
	uiTable.FgColors[0] = termui.ColorBlack
	uiTable.Y = 20
	uiTable.X = 0
	uiTable.Border = false
	for i := 0; i < len(list); i++ {
		switch list[i].State {
		case "paused":
			uiTable.BgColors[i+1] = termui.ColorBlack
			uiTable.FgColors[i+1] = termui.ColorWhite
		case "running":
			uiTable.BgColors[i+1] = termui.ColorBlue
			uiTable.FgColors[i+1] = termui.ColorWhite
		case "halted":
			uiTable.BgColors[i+1] = termui.ColorYellow
			uiTable.FgColors[i+1] = termui.ColorBlack
		case "locked":
			uiTable.BgColors[i+1] = termui.ColorMagenta
			uiTable.FgColors[i+1] = termui.ColorGreen
		case "being_created":
			uiTable.BgColors[i+1] = termui.ColorWhite
			uiTable.FgColors[i+1] = termui.ColorBlack
		case "deleted":
			uiTable.BgColors[i+1] = termui.ColorBlack
			uiTable.FgColors[i+1] = termui.ColorRed
		}
	}

	// Commands
	uiCommands := termui.NewPar("<[S]tart>    <St[o]p>    <[R]eboot>  Virtual Machine |   <[Q]uit>")
	uiCommands.Height = 3
	uiCommands.Border = false
	uiCommands.BorderLabel = "Summary"
	uiCommands.TextFgColor = termui.ColorBlack
	uiCommands.TextBgColor = termui.ColorWhite

	// Create termui Grid system
	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(12, 0, uiTitle),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiSummary),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiTable),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiCommands),
		),
	)

	// calculate layout
	termui.Body.Align()
	termui.Render(termui.Body)

	// Quit with q
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/<up>", func(termui.Event) {
		if selector > 0 {
			selector--
		}
		uiTable.Rows = serverList(list)
		termui.Render(termui.Body)
	})

	termui.Handle("/sys/kbd/<down>", func(termui.Event) {
		if selector < len(list)-1 {
			selector++
		}
		uiTable.Rows = serverList(list)
		termui.Render(termui.Body)
	})

	termui.Handle("/sys/kbd/s", func(termui.Event) {
		err = api.Call("hosting.vm.start", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}
	})

	termui.Handle("/sys/kbd/o", func(termui.Event) {
		err = api.Call("hosting.vm.stop", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}
	})

	termui.Handle("/sys/kbd/r", func(termui.Event) {
		err = api.Call("hosting.vm.reboot", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}
	})

	termui.Handle("/timer/1s", func(e termui.Event) {
		t := e.Data.(termui.EvtTimer)
		// t is a EvtTimer
		if t.Count%2 == 0 {
			termui.Body.Align()
			termui.Render(termui.Body)
		}
	})
	termui.Handle("/timer/1s", func(e termui.Event) {
		t := e.Data.(termui.EvtTimer)
		// t is a EvtTimer
		if t.Count%4 == 0 {
			err = api.Call("hosting.vm.list", apiKey, &hostingVMList)
			if err != nil {
				log.Fatal(err)
			}

			list = *hostingVMList
			uiTable.Rows = serverList(list)
			for i := 0; i < len(list); i++ {
				switch list[i].State {
				case "paused":
					uiTable.BgColors[i+1] = termui.ColorBlack
					uiTable.FgColors[i+1] = termui.ColorWhite
				case "running":
					uiTable.BgColors[i+1] = termui.ColorBlue
					uiTable.FgColors[i+1] = termui.ColorWhite
				case "halted":
					uiTable.BgColors[i+1] = termui.ColorYellow
					uiTable.FgColors[i+1] = termui.ColorBlack
				case "locked":
					uiTable.BgColors[i+1] = termui.ColorMagenta
					uiTable.FgColors[i+1] = termui.ColorGreen
				case "being_created":
					uiTable.BgColors[i+1] = termui.ColorWhite
					uiTable.FgColors[i+1] = termui.ColorBlack
				case "deleted":
					uiTable.BgColors[i+1] = termui.ColorBlack
					uiTable.FgColors[i+1] = termui.ColorRed
				}
			}
			termui.Render(termui.Body)
		}
	})

	termui.Loop()
}
<commit_msg>add confirmations to actions<commit_after>package main

import (
	"errors"
	"log"
	"os"
	"strconv"
	"time"

	"github.com/gizak/termui"
	"github.com/kolo/xmlrpc"
	"github.com/spf13/viper"
)

var selector int

// AccountReturn contains fields for informations about the Gandi account
type AccountReturn struct {
	AverageCreditCost     float64   `xmlrpc:"average_credit_cost"`
	Credits               int       `xmlrpc:"credits"`
	CycleDay              int       `xmlrpc:"cycle_day"`
	DateCreditsExpiration time.Time `xmlrpc:"date_credits_expiration"`
	FullName              string    `xmlrpc:"fullname"`
	Handle                string    `xmlrpc:"handle"`
	ID                    int       `xmlrpc:"id"`
}

// DiskReturn contains fields for informations about the Disks
type DiskReturn struct {
	CanSnapshot   bool      `xmlrpc:"can_snapshot"`
	DatacenterID  int       `xmlrpc:"datacenter_id"`
	DateCreated   time.Time `xmlrpc:"date_created"`
	DateUpdated   time.Time `xmlrpc:"date_updated"`
	ID            int       `xmlrpc:"id"`
	IsBootDisk    bool      `xmlrpc:"is_boot_disk"`
	KernelVersion string    `xmlrpc:"kernel_version"`
	Label         string    `xmlrpc:"label"`
	Name          string    `xmlrpc:"name"`
	Size          int       `xmlrpc:"size"`
	State         string    `xmlrpc:"state"`
	TotalSize     int       `xmlrpc:"total_size"`
	Type          string    `xmlrpc:"type"`
	Visibility    string    `xmlrpc:"visibility"`
}

// VMReturn contains fields for informations about the virtual machines
type VMReturn struct {
	AiActive     int          `xmlrpc:"ai_active"`
	Console      int          `xmlrpc:"console"`
	ConsoleURL   string       `xmlrpc:"console_url"`
	Cores        int          `xmlrpc:"cores"`
	DatacenterID int          `xmlrpc:"datacenter_id"`
	DateCreated  time.Time    `xmlrpc:"date_created"`
	DateUpdated  time.Time    `xmlrpc:"date_updated"`
	Description  string       `xmlrpc:"description"`
	Disks        []DiskReturn `xmlrpc:"disks"`
	Farm         string       `xmlrpc:"farm"`
	FlexShares   int          `xmlrpc:"flex_shares"`
	Hostname     string       `xmlrpc:"hostname"`
	HVMState     string       `xmlrpc:"hvm_state"`
	ID           int          `xmlrpc:"id"`
	Memory       int          `xmlrpc:"memory"`
	State        string       `xmlrpc:"state"`
	VMmaxMemory  int          `xmlrpc:"vm_max_memory"`
}

// LoadAPI returns the api and apiKey according to the settings defined in the
// configuration file, respectively.
func LoadAPI() (api *xmlrpc.Client, apiKey string, err error) {
	viper.SetConfigName("bapu")

	homePath := os.Getenv("HOME")
	viper.AddConfigPath(homePath)
	viper.AddConfigPath("/usr/local/etc")
	viper.AddConfigPath("/etc")

	err = viper.ReadInConfig()
	if err != nil {
		return api, apiKey, err
	}

	production := viper.GetBool("production.enabled")
	if production {
		apiKey = viper.GetString("production.apiKey")
		api, err = xmlrpc.NewClient("https://rpc.gandi.net/xmlrpc/", nil)
		if err != nil {
			return api, apiKey, err
		}
	}

	development := viper.GetBool("development.enabled")
	if development {
		log.Println("Development Config found")
		api, err = xmlrpc.NewClient("https://rpc.ote.gandi.net/xmlrpc/", nil)
		if err != nil {
			return api, apiKey, err
		}
		apiKey = viper.GetString("development.apiKey")
	}

	if api == nil {
		return api, apiKey, errors.New("neither production nor development environment enabled in config")
	}

	return api, apiKey, nil
}

func serverList(list []VMReturn) (servers [][]string) {

	servers = append(servers, []string{
		"Selected",
		"Hostname",
		"Datacenter",
		"Cores",
		"Memory",
		"State",
	})

	for i, val := range list {
		s := ""
		if selector == i {
			s = "*"
		}
		servers = append(servers, []string{
			s,
			val.Hostname,
			strconv.Itoa(val.DatacenterID),
			strconv.Itoa(val.Cores),
			strconv.Itoa(val.Memory) + "MB",
			val.State,
		})
	}

	return servers
}

func main() {
	// Load API
	api, apiKey, err := LoadAPI()
	if err != nil {
		log.Fatal(err)
	}

	// initialize termui
	err = termui.Init()
	if err != nil {
		log.Fatal(err)
	}
	defer termui.Close()

	// Title
	uiTitle := termui.NewPar("Bapu -- Control your Gandi Machines")
	uiTitle.Border = false
	uiTitle.Height = 3
	uiTitle.TextFgColor = termui.ColorMagenta

	// Summary
	var hostingVMCount *int
	err = api.Call("hosting.vm.count", apiKey, &hostingVMCount)
	if err != nil {
		log.Fatal(err)
	}
	var hostingAccountInfo *AccountReturn
	err = api.Call("hosting.account.info", apiKey, &hostingAccountInfo)
	if err != nil {
		log.Fatal(err)
	}

	info := *hostingAccountInfo

	uiSummary := termui.NewPar("Owner: " + info.FullName + "    Virtual Machines: " + strconv.Itoa(*hostingVMCount) + "    Remaining Credit: " + strconv.Itoa(info.Credits))
	uiSummary.Height = 3
	uiSummary.Border = true
	uiSummary.BorderLabel = "Summary"
	uiSummary.TextFgColor = termui.ColorWhite

	// List instances
	var hostingVMList *[]VMReturn
	err = api.Call("hosting.vm.list", apiKey, &hostingVMList)
	if err != nil {
		log.Fatal(err)
	}

	list := *hostingVMList

	uiTable := termui.NewTable()
	uiTable.Rows = serverList(list)
	uiTable.FgColor = termui.ColorWhite
	uiTable.BgColor = termui.ColorDefault
	uiTable.TextAlign = termui.AlignCenter
	uiTable.Seperator = false
	uiTable.Analysis()
	uiTable.SetSize()
	uiTable.BgColors[0] = termui.ColorWhite
	uiTable.FgColors[0] = termui.ColorBlack
	uiTable.Y = 20
	uiTable.X = 0
	uiTable.Border = false
	for i := 0; i < len(list); i++ {
		switch list[i].State {
		case "paused":
			uiTable.BgColors[i+1] = termui.ColorBlack
			uiTable.FgColors[i+1] = termui.ColorWhite
		case "running":
			uiTable.BgColors[i+1] = termui.ColorBlue
			uiTable.FgColors[i+1] = termui.ColorWhite
		case "halted":
			uiTable.BgColors[i+1] = termui.ColorYellow
			uiTable.FgColors[i+1] = termui.ColorBlack
		case "locked":
			uiTable.BgColors[i+1] = termui.ColorMagenta
			uiTable.FgColors[i+1] = termui.ColorGreen
		case "being_created":
			uiTable.BgColors[i+1] = termui.ColorWhite
			uiTable.FgColors[i+1] = termui.ColorBlack
		case "deleted":
			uiTable.BgColors[i+1] = termui.ColorBlack
			uiTable.FgColors[i+1] = termui.ColorRed
		}
	}

	// Commands
	uiCommands := termui.NewPar("<[S]tart>    <St[o]p>    <[R]eboot>  Virtual Machine |   <[Q]uit>")
	uiCommands.Height = 3
	uiCommands.Border = false
	uiCommands.BorderLabel = "Summary"
	uiCommands.TextFgColor = termui.ColorBlack
	uiCommands.TextBgColor = termui.ColorWhite

	// Create termui Grid system
	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(12, 0, uiTitle),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiSummary),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiTable),
		),
		termui.NewRow(
			termui.NewCol(12, 0, uiCommands),
		),
	)

	// calculate layout
	termui.Body.Align()
	termui.Render(termui.Body)

	// Quit with q
	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/sys/kbd/<up>", func(termui.Event) {
		if selector > 0 {
			selector--
		}
		uiTable.Rows = serverList(list)
		termui.Render(termui.Body)
	})

	termui.Handle("/sys/kbd/<down>", func(termui.Event) {
		if selector < len(list)-1 {
			selector++
		}
		uiTable.Rows = serverList(list)
		termui.Render(termui.Body)
	})

	termui.Handle("/sys/kbd/s", func(termui.Event) {
		err = api.Call("hosting.vm.start", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}

		confirmation := termui.NewPar(list[selector].Hostname + " (ID " + strconv.Itoa(list[selector].ID) + ") is being started")
		confirmation.Height = 4
		confirmation.Width = 50
		confirmation.Y = 5
		confirmation.Border = true
		termui.Render(confirmation)
	})

	termui.Handle("/sys/kbd/o", func(termui.Event) {
		err = api.Call("hosting.vm.stop", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}
		confirmation := termui.NewPar(list[selector].Hostname + " (ID " + strconv.Itoa(list[selector].ID) + ") is being stopped")
		confirmation.Height = 4
		confirmation.Width = 50
		confirmation.Y = 5
		confirmation.Border = true
		termui.Render(confirmation)
	})

	termui.Handle("/sys/kbd/r", func(termui.Event) {
		err = api.Call("hosting.vm.reboot", []interface{}{apiKey, list[selector].ID}, nil)
		if err != nil {
			log.Fatal(err)
		}
		confirmation := termui.NewPar(list[selector].Hostname + " (ID " + strconv.Itoa(list[selector].ID) + ") is being rebooted")
		confirmation.Height = 4
		confirmation.Width = 50
		confirmation.Y = 5
		confirmation.Border = true
		termui.Render(confirmation)
	})

	termui.Handle("/timer/1s", func(e termui.Event) {
		t := e.Data.(termui.EvtTimer)
		// t is a EvtTimer
		if t.Count%2 == 0 {
			termui.Body.Align()
			termui.Render(termui.Body)
		}
	})
	termui.Handle("/timer/1s", func(e termui.Event) {
		t := e.Data.(termui.EvtTimer)
		// t is a EvtTimer
		if t.Count%4 == 0 {
			err = api.Call("hosting.vm.list", apiKey, &hostingVMList)
			if err != nil {
				log.Fatal(err)
			}

			list = *hostingVMList
			uiTable.Rows = serverList(list)
			for i := 0; i < len(list); i++ {
				switch list[i].State {
				case "paused":
					uiTable.BgColors[i+1] = termui.ColorBlack
					uiTable.FgColors[i+1] = termui.ColorWhite
				case "running":
					uiTable.BgColors[i+1] = termui.ColorBlue
					uiTable.FgColors[i+1] = termui.ColorWhite
				case "halted":
					uiTable.BgColors[i+1] = termui.ColorYellow
					uiTable.FgColors[i+1] = termui.ColorBlack
				case "locked":
					uiTable.BgColors[i+1] = termui.ColorMagenta
					uiTable.FgColors[i+1] = termui.ColorGreen
				case "being_created":
					uiTable.BgColors[i+1] = termui.ColorWhite
					uiTable.FgColors[i+1] = termui.ColorBlack
				case "deleted":
					uiTable.BgColors[i+1] = termui.ColorBlack
					uiTable.FgColors[i+1] = termui.ColorRed
				}
			}
			termui.Render(termui.Body)
		}
	})

	termui.Loop()
}
<|endoftext|>