<commit_before>package main

import (
	"bufio"
	"html/template"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/fsnotify/fsnotify"
)

const (
	cfgPath = "/etc/nginx-static/config"
	tplPath = "/etc/nginx/nginx.conf.tpl"
	outPath = "/etc/nginx/nginx.conf"
)

func main() {
	err := do()
	if err != nil {
		log.Fatal(err)
	}
}

func do() error {
	tpl, err := template.ParseFiles(tplPath)
	if err != nil {
		return err
	}

	// Write initial config
	err = writeConfig(tpl)
	if err != nil {
		return err
	}

	// Start nginx
	cmd := exec.Command("/usr/sbin/nginx", "-g", "daemon off;")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Start()
	if err != nil {
		return err
	}

	// Shutdown listener
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGTERM)

	// Config watcher
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
					err := process(tpl, cmd)
					if err != nil {
						log.Printf("Failed to process config: %s", err)
					}
				}
			case err := <-watcher.Errors:
				log.Printf("Config watch error: %s", err)

			case <-stop:
				// Wait for a while
				time.Sleep(30 * time.Second)
				err := cmd.Process.Signal(syscall.SIGINT)
				if err != nil {
					log.Println(err)
				}
				return
			}
		}
	}()

	err = watcher.Add(cfgPath)
	if err != nil {
		return err
	}

	return cmd.Wait()
}

type SiteConfig struct {
	Hostname string
	Path     string
}

func writeConfig(tpl *template.Template) error {
	cfg, err := os.Open(cfgPath)
	if err != nil {
		return err
	}
	defer cfg.Close()

	hosts, err := getConfig(cfg)
	if err != nil {
		return err
	}

	fp, err := os.Create(outPath)
	if err != nil {
		return err
	}
	defer fp.Close()

	return tpl.Execute(fp, hosts)
}

func getConfig(in io.Reader) ([]SiteConfig, error) {
	hosts := make([]SiteConfig, 0)

	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		parts := strings.SplitN(line, ":", 2)

		if len(parts) == 2 {
			hosts = append(hosts, SiteConfig{
				Hostname: strings.TrimSpace(parts[0]),
				Path:     strings.TrimSpace(parts[1]),
			})
		}
	}
	err := scanner.Err()
	if err != nil {
		return nil, err
	}

	return hosts, nil
}

func process(tpl *template.Template, cmd *exec.Cmd) error {
	err := writeConfig(tpl)
	if err != nil {
		return err
	}

	// Trigger reload of pgbouncer config
	return cmd.Process.Signal(syscall.SIGHUP)
}
<commit_msg>Fix comment<commit_after>package main

import (
	"bufio"
	"html/template"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/fsnotify/fsnotify"
)

const (
	cfgPath = "/etc/nginx-static/config"
	tplPath = "/etc/nginx/nginx.conf.tpl"
	outPath = "/etc/nginx/nginx.conf"
)

func main() {
	err := do()
	if err != nil {
		log.Fatal(err)
	}
}

func do() error {
	tpl, err := template.ParseFiles(tplPath)
	if err != nil {
		return err
	}

	// Write initial config
	err = writeConfig(tpl)
	if err != nil {
		return err
	}

	// Start nginx
	cmd := exec.Command("/usr/sbin/nginx", "-g", "daemon off;")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Start()
	if err != nil {
		return err
	}

	// Shutdown listener
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGTERM)

	// Config watcher
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
					err := process(tpl, cmd)
					if err != nil {
						log.Printf("Failed to process config: %s", err)
					}
				}
			case err := <-watcher.Errors:
				log.Printf("Config watch error: %s", err)

			case <-stop:
				// Wait for a while
				time.Sleep(30 * time.Second)
				err := cmd.Process.Signal(syscall.SIGINT)
				if err != nil {
					log.Println(err)
				}
				return
			}
		}
	}()

	err = watcher.Add(cfgPath)
	if err != nil {
		return err
	}

	return cmd.Wait()
}

type SiteConfig struct {
	Hostname string
	Path     string
}

func writeConfig(tpl *template.Template) error {
	cfg, err := os.Open(cfgPath)
	if err != nil {
		return err
	}
	defer cfg.Close()

	hosts, err := getConfig(cfg)
	if err != nil {
		return err
	}

	fp, err := os.Create(outPath)
	if err != nil {
		return err
	}
	defer fp.Close()

	return tpl.Execute(fp, hosts)
}

func getConfig(in io.Reader) ([]SiteConfig, error) {
	hosts := make([]SiteConfig, 0)

	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		parts := strings.SplitN(line, ":", 2)

		if len(parts) == 2 {
			hosts = append(hosts, SiteConfig{
				Hostname: strings.TrimSpace(parts[0]),
				Path:     strings.TrimSpace(parts[1]),
			})
		}
	}
	err := scanner.Err()
	if err != nil {
		return nil, err
	}

	return hosts, nil
}

func process(tpl *template.Template, cmd *exec.Cmd) error {
	err := writeConfig(tpl)
	if err != nil {
		return err
	}

	// Trigger reload of config
	return cmd.Process.Signal(syscall.SIGHUP)
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"

	"github.com/kr/beanstalk"
	"github.com/peterh/liner"
)

var (
	// Used for autocompletion.
	commands = []string{
		"clear",
		"help",
		"inspect",
		"exit",
		"quit",
		"kick",
		"list",
		"next",
		"pause",
		"stats",
		"use",
	}
	hf     = "/tmp/.bsa_history"
	conn   *beanstalk.Conn // Our one and only beanstalkd connection.
	line   *liner.State
	cTubes Tubes
	sigc   chan os.Signal // Signal channel.
)

// Prints help and usage.
func help() {
	fmt.Printf(`
clear <state>
	Deletes all jobs in given state and selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

help
	Show this wonderful help.

exit,
quit
	Exit the console.

inspect <job>
	Inspects a single job.

pause <delay>
	Pauses selected tubes for given number of seconds.

kick <bound>
	Kicks all jobs in selected tubes.

list
	Lists all selected tubes or if none is selected all exstings tubes
	and shows status of each.

next <state>
	Inspects next jobs in given state in selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

stats
	Shows server statistics.

use [<tube0>] [<tube1> ...]
	Selects one or multiple tubes. Separate multiple tubes by spaces.
	If no tube name is given resets selection.

`)
}

func cleanup() {
	conn.Close()

	if f, err := os.Create(hf); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
	line.Close()
}

func main() {
	host := flag.String("host", "localhost", "beanstalkd host")
	port := flag.String("port", "11300", "beanstalkd port")
	flag.Parse()

	addr := fmt.Sprintf("%s:%s", host, port)
	conn, err := beanstalk.Dial("tcp", addr)
	if err != nil {
		fmt.Printf("Fatal: failed to connect to beanstalkd server %s\n", addr)
		os.Exit(1)
	}
	cTubes.UseAll()

	// Register signal handler.
	sigc = make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt)
	go func() {
		for sig := range sigc {
			fmt.Printf("Caught %v. Bye.\n", sig)
			cleanup()
			os.Exit(1)
		}
	}()

	//
	line = liner.NewLiner()

	// Autocomplete commands, tube names and states.
	line.SetCompleter(func(line string) (c []string) {
		for _, cmd := range commands {
			if strings.HasPrefix(cmd, line) {
				c = append(c, cmd)
			}
		}
		if strings.HasPrefix(line, "use") {
			tns, _ := conn.ListTubes()
			for _, v := range tns {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		if strings.HasPrefix(line, "clear") || strings.HasPrefix(line, "next") {
			for _, v := range []string{"ready", "delayed", "buried"} {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		return c
	})

	// Load console history if possible.
	if f, err := os.Open(hf); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	fmt.Print("Enter 'help' for available commands and 'exit' to quit.\n\n")

	// Dispatch commands.
	for {
		// We may have a new set of selected tubes after an iteration, update prompt.
		// Show selected tubes in prompt, so that we know what commands operate on.

		var tStatus string
		if cTubes.All {
			tStatus = "*"
		} else {
			tStatus = strings.Join(cTubes.Names, ", ")
		}
		prompt := fmt.Sprintf("beanstalkd [%s] > ", tStatus)

		if input, err := line.Prompt(prompt); err == nil {
			// Always add input to history, even if it contains a syntax error. We
			// may want to skip back and correct ourselves.
			line.AppendHistory(input)

			args := strings.Split(input, " ")

			switch args[0] {
			case "exit", "quit":
				cleanup()
				os.Exit(0)
			case "help":
				help()
			case "stats":
				stats()
			case "use":
				if len(args) < 2 || args[1] == "*" {
					cTubes.UseAll()
					continue
				}
				cTubes.Use(args[1:])
			case "list":
				listTubes()
			case "pause":
				if len(args) < 2 {
					fmt.Printf("Error: no delay given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					pauseTubes(time.Duration(r) * time.Second)
					continue
				}
				fmt.Printf("Error: given delay is not a valid number.\n")
			case "kick":
				if len(args) < 2 {
					fmt.Printf("Error: no bound given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					kickTubes(int(r))
					continue
				}
				fmt.Printf("Error: given bound is not a valid number.\n")
			case "clear":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				clearTubes(args[1])
			case "next":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				nextJobs(args[1])
			case "inspect":
				if len(args) < 2 {
					fmt.Printf("Error: no job id given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					inspectJob(uint64(r))
					continue
				}
				fmt.Printf("Error: not a valid job id.\n")
			case "":
				continue
			default:
				fmt.Println("Error: unknown command.")
				continue
			}
		}
	}
}
<commit_msg>Fix address formatting.<commit_after>// Copyright 2014 David Persson. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"time"

	"github.com/kr/beanstalk"
	"github.com/peterh/liner"
)

var (
	// Used for autocompletion.
	commands = []string{
		"clear",
		"help",
		"inspect",
		"exit",
		"quit",
		"kick",
		"list",
		"next",
		"pause",
		"stats",
		"use",
	}
	hf     = "/tmp/.bsa_history"
	conn   *beanstalk.Conn // Our one and only beanstalkd connection.
	line   *liner.State
	cTubes Tubes
	sigc   chan os.Signal // Signal channel.
)

// Prints help and usage.
func help() {
	fmt.Printf(`
clear <state>
	Deletes all jobs in given state and selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

help
	Show this wonderful help.

exit,
quit
	Exit the console.

inspect <job>
	Inspects a single job.

pause <delay>
	Pauses selected tubes for given number of seconds.

kick <bound>
	Kicks all jobs in selected tubes.

list
	Lists all selected tubes or if none is selected all exstings tubes
	and shows status of each.

next <state>
	Inspects next jobs in given state in selected tubes.
	<state> may be either 'ready', 'buried' or 'delayed'.

stats
	Shows server statistics.

use [<tube0>] [<tube1> ...]
	Selects one or multiple tubes. Separate multiple tubes by spaces.
	If no tube name is given resets selection.

`)
}

func cleanup() {
	conn.Close()

	if f, err := os.Create(hf); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
	line.Close()
}

func main() {
	host := flag.String("host", "localhost", "beanstalkd host")
	port := flag.String("port", "11300", "beanstalkd port")
	flag.Parse()

	addr := fmt.Sprintf("%s:%s", *host, *port)
	conn, err := beanstalk.Dial("tcp", addr)
	if err != nil {
		fmt.Printf("Fatal: failed to connect to beanstalkd server %s\n", addr)
		os.Exit(1)
	}
	cTubes.UseAll()

	// Register signal handler.
	sigc = make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt)
	go func() {
		for sig := range sigc {
			fmt.Printf("Caught %v. Bye.\n", sig)
			cleanup()
			os.Exit(1)
		}
	}()

	//
	line = liner.NewLiner()

	// Autocomplete commands, tube names and states.
	line.SetCompleter(func(line string) (c []string) {
		for _, cmd := range commands {
			if strings.HasPrefix(cmd, line) {
				c = append(c, cmd)
			}
		}
		if strings.HasPrefix(line, "use") {
			tns, _ := conn.ListTubes()
			for _, v := range tns {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		if strings.HasPrefix(line, "clear") || strings.HasPrefix(line, "next") {
			for _, v := range []string{"ready", "delayed", "buried"} {
				c = append(c, fmt.Sprintf("%s%s", line, v))
			}
		}
		return c
	})

	// Load console history if possible.
	if f, err := os.Open(hf); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	fmt.Print("Enter 'help' for available commands and 'exit' to quit.\n\n")

	// Dispatch commands.
	for {
		// We may have a new set of selected tubes after an iteration, update prompt.
		// Show selected tubes in prompt, so that we know what commands operate on.

		var tStatus string
		if cTubes.All {
			tStatus = "*"
		} else {
			tStatus = strings.Join(cTubes.Names, ", ")
		}
		prompt := fmt.Sprintf("beanstalkd [%s] > ", tStatus)

		if input, err := line.Prompt(prompt); err == nil {
			// Always add input to history, even if it contains a syntax error. We
			// may want to skip back and correct ourselves.
			line.AppendHistory(input)

			args := strings.Split(input, " ")

			switch args[0] {
			case "exit", "quit":
				cleanup()
				os.Exit(0)
			case "help":
				help()
			case "stats":
				stats()
			case "use":
				if len(args) < 2 || args[1] == "*" {
					cTubes.UseAll()
					continue
				}
				cTubes.Use(args[1:])
			case "list":
				listTubes()
			case "pause":
				if len(args) < 2 {
					fmt.Printf("Error: no delay given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					pauseTubes(time.Duration(r) * time.Second)
					continue
				}
				fmt.Printf("Error: given delay is not a valid number.\n")
			case "kick":
				if len(args) < 2 {
					fmt.Printf("Error: no bound given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					kickTubes(int(r))
					continue
				}
				fmt.Printf("Error: given bound is not a valid number.\n")
			case "clear":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				clearTubes(args[1])
			case "next":
				if len(args) < 2 {
					fmt.Printf("Error: no state given.\n")
					continue
				}
				nextJobs(args[1])
			case "inspect":
				if len(args) < 2 {
					fmt.Printf("Error: no job id given.\n")
					continue
				}
				if r, err := strconv.ParseUint(args[1], 0, 0); err == nil {
					inspectJob(uint64(r))
					continue
				}
				fmt.Printf("Error: not a valid job id.\n")
			case "":
				continue
			default:
				fmt.Println("Error: unknown command.")
				continue
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).

package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"path/filepath"
	"strings"
	"time"

	"github.com/juju/ratelimit"
	"github.com/syncthing/syncthing/lib/relay/protocol"
	"github.com/syncthing/syncthing/lib/tlsutil"

	syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
)

var (
	listen string
	debug  bool = false

	sessionAddress []byte
	sessionPort    uint16

	networkTimeout time.Duration = 2 * time.Minute
	pingInterval   time.Duration = time.Minute
	messageTimeout time.Duration = time.Minute

	sessionLimitBps int
	globalLimitBps  int
	sessionLimiter  *ratelimit.Bucket
	globalLimiter   *ratelimit.Bucket

	statusAddr       string
	poolAddrs        string
	pools            []string
	providedBy       string
	defaultPoolAddrs string = "https://relays.syncthing.net/endpoint"
)

func main() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)

	var dir, extAddress string

	flag.StringVar(&listen, "listen", ":22067", "Protocol listen address")
	flag.StringVar(&dir, "keys", ".", "Directory where cert.pem and key.pem is stored")
	flag.DurationVar(&networkTimeout, "network-timeout", networkTimeout, "Timeout for network operations between the client and the relay.\n\tIf no data is received between the client and the relay in this period of time, the connection is terminated.\n\tFurthermore, if no data is sent between either clients being relayed within this period of time, the session is also terminated.")
	flag.DurationVar(&pingInterval, "ping-interval", pingInterval, "How often pings are sent")
	flag.DurationVar(&messageTimeout, "message-timeout", messageTimeout, "Maximum amount of time we wait for relevant messages to arrive")
	flag.IntVar(&sessionLimitBps, "per-session-rate", sessionLimitBps, "Per session rate limit, in bytes/s")
	flag.IntVar(&globalLimitBps, "global-rate", globalLimitBps, "Global rate limit, in bytes/s")
	flag.BoolVar(&debug, "debug", debug, "Enable debug output")
	flag.StringVar(&statusAddr, "status-srv", ":22070", "Listen address for status service (blank to disable)")
	flag.StringVar(&poolAddrs, "pools", defaultPoolAddrs, "Comma separated list of relay pool addresses to join")
	flag.StringVar(&providedBy, "provided-by", "", "An optional description about who provides the relay")

	flag.Parse()

	if extAddress == "" {
		extAddress = listen
	}

	addr, err := net.ResolveTCPAddr("tcp", extAddress)
	if err != nil {
		log.Fatal(err)
	}

	sessionAddress = addr.IP[:]
	sessionPort = uint16(addr.Port)

	certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Println("Failed to load keypair. Generating one, this might take a while...")
		cert, err = tlsutil.NewCertificate(certFile, keyFile, "relaysrv", 3072)
		if err != nil {
			log.Fatalln("Failed to generate X509 key pair:", err)
		}
	}

	tlsCfg := &tls.Config{
		Certificates:           []tls.Certificate{cert},
		NextProtos:             []string{protocol.ProtocolName},
		ClientAuth:             tls.RequestClientCert,
		SessionTicketsDisabled: true,
		InsecureSkipVerify:     true,
		MinVersion:             tls.VersionTLS12,
		CipherSuites: []uint16{
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
		},
	}

	id := syncthingprotocol.NewDeviceID(cert.Certificate[0])
	if debug {
		log.Println("ID:", id)
	}

	if sessionLimitBps > 0 {
		sessionLimiter = ratelimit.NewBucketWithRate(float64(sessionLimitBps), int64(2*sessionLimitBps))
	}
	if globalLimitBps > 0 {
		globalLimiter = ratelimit.NewBucketWithRate(float64(globalLimitBps), int64(2*globalLimitBps))
	}

	if statusAddr != "" {
		go statusService(statusAddr)
	}

	uri, err := url.Parse(fmt.Sprintf("relay://%s/?id=%s&pingInterval=%s&networkTimeout=%s&sessionLimitBps=%d&globalLimitBps=%d&statusAddr=%s&providedBy=%s", extAddress, id, pingInterval/time.Second, networkTimeout/time.Second, sessionLimitBps, globalLimitBps, statusAddr, providedBy))
	if err != nil {
		log.Fatalln("Failed to construct URI", err)
	}

	log.Println("URI:", uri.String())

	if poolAddrs == defaultPoolAddrs {
		log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
		log.Println("!!  Joining default relay pools, this relay will be available for public use. !!")
		log.Println(`!!      Use the -pools="" command line option to make the relay private.      !!`)
		log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
	}

	pools = strings.Split(poolAddrs, ",")
	for _, pool := range pools {
		pool = strings.TrimSpace(pool)
		if len(pool) > 0 {
			go poolHandler(pool, uri)
		}
	}

	listener(listen, tlsCfg)
}
<commit_msg>URLs should have Go units<commit_after>// Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).

package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net"
	"net/url"
	"path/filepath"
	"strings"
	"time"

	"github.com/juju/ratelimit"
	"github.com/syncthing/syncthing/lib/relay/protocol"
	"github.com/syncthing/syncthing/lib/tlsutil"

	syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
)

var (
	listen string
	debug  bool = false

	sessionAddress []byte
	sessionPort    uint16

	networkTimeout time.Duration = 2 * time.Minute
	pingInterval   time.Duration = time.Minute
	messageTimeout time.Duration = time.Minute

	sessionLimitBps int
	globalLimitBps  int
	sessionLimiter  *ratelimit.Bucket
	globalLimiter   *ratelimit.Bucket

	statusAddr       string
	poolAddrs        string
	pools            []string
	providedBy       string
	defaultPoolAddrs string = "https://relays.syncthing.net/endpoint"
)

func main() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)

	var dir, extAddress string

	flag.StringVar(&listen, "listen", ":22067", "Protocol listen address")
	flag.StringVar(&dir, "keys", ".", "Directory where cert.pem and key.pem is stored")
	flag.DurationVar(&networkTimeout, "network-timeout", networkTimeout, "Timeout for network operations between the client and the relay.\n\tIf no data is received between the client and the relay in this period of time, the connection is terminated.\n\tFurthermore, if no data is sent between either clients being relayed within this period of time, the session is also terminated.")
	flag.DurationVar(&pingInterval, "ping-interval", pingInterval, "How often pings are sent")
	flag.DurationVar(&messageTimeout, "message-timeout", messageTimeout, "Maximum amount of time we wait for relevant messages to arrive")
	flag.IntVar(&sessionLimitBps, "per-session-rate", sessionLimitBps, "Per session rate limit, in bytes/s")
	flag.IntVar(&globalLimitBps, "global-rate", globalLimitBps, "Global rate limit, in bytes/s")
	flag.BoolVar(&debug, "debug", debug, "Enable debug output")
	flag.StringVar(&statusAddr, "status-srv", ":22070", "Listen address for status service (blank to disable)")
	flag.StringVar(&poolAddrs, "pools", defaultPoolAddrs, "Comma separated list of relay pool addresses to join")
	flag.StringVar(&providedBy, "provided-by", "", "An optional description about who provides the relay")

	flag.Parse()

	if extAddress == "" {
		extAddress = listen
	}

	addr, err := net.ResolveTCPAddr("tcp", extAddress)
	if err != nil {
		log.Fatal(err)
	}

	sessionAddress = addr.IP[:]
	sessionPort = uint16(addr.Port)

	certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Println("Failed to load keypair. Generating one, this might take a while...")
		cert, err = tlsutil.NewCertificate(certFile, keyFile, "relaysrv", 3072)
		if err != nil {
			log.Fatalln("Failed to generate X509 key pair:", err)
		}
	}

	tlsCfg := &tls.Config{
		Certificates:           []tls.Certificate{cert},
		NextProtos:             []string{protocol.ProtocolName},
		ClientAuth:             tls.RequestClientCert,
		SessionTicketsDisabled: true,
		InsecureSkipVerify:     true,
		MinVersion:             tls.VersionTLS12,
		CipherSuites: []uint16{
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
		},
	}

	id := syncthingprotocol.NewDeviceID(cert.Certificate[0])
	if debug {
		log.Println("ID:", id)
	}

	if sessionLimitBps > 0 {
		sessionLimiter = ratelimit.NewBucketWithRate(float64(sessionLimitBps), int64(2*sessionLimitBps))
	}
	if globalLimitBps > 0 {
		globalLimiter = ratelimit.NewBucketWithRate(float64(globalLimitBps), int64(2*globalLimitBps))
	}

	if statusAddr != "" {
		go statusService(statusAddr)
	}

	uri, err := url.Parse(fmt.Sprintf("relay://%s/?id=%s&pingInterval=%s&networkTimeout=%s&sessionLimitBps=%d&globalLimitBps=%d&statusAddr=%s&providedBy=%s", extAddress, id, pingInterval, networkTimeout, sessionLimitBps, globalLimitBps, statusAddr, providedBy))
	if err != nil {
		log.Fatalln("Failed to construct URI", err)
	}

	log.Println("URI:", uri.String())

	if poolAddrs == defaultPoolAddrs {
		log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
		log.Println("!!  Joining default relay pools, this relay will be available for public use. !!")
		log.Println(`!!      Use the -pools="" command line option to make the relay private.      !!`)
		log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
	}

	pools = strings.Split(poolAddrs, ",")
	for _, pool := range pools {
		pool = strings.TrimSpace(pool)
		if len(pool) > 0 {
			go poolHandler(pool, uri)
		}
	}

	listener(listen, tlsCfg)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"strings"

	"github.com/darkowl91/rp-client/rp"
)

var (
	// Version for the application, passed on build
	Version = "No Version Provided"

	reportDir string

	debugFlag   bool
	hostFlag    string
	projectFlag string
	launchFlag  string
	tagsFlag    string
	uuidFlag    string
	helpFlag    bool
	versionFlag bool
)

func main() {
	flag.Usage = func() {
		u := " Usage:\n"
		u += "  rp-client [OPTIONS] (DIR|FILE)\n\n"
		u += " Options:\n"
		u += "	-r	--rp		Report Portal host\n"
		u += "	-d	--debug		Report Portal debug mode\n"
		u += "	-p	--project	Report Portal project\n"
		u += "	-l	--launch	Report Portal launch name\n"
		u += "	-t	--tags		Report Portal launch tags\n"
		u += "	-id	--uuid		Report Portal user id\n"
		u += "	-h,	--help		Print usage\n"
		u += "	-v,	--version	Print version information and quit\n\n"
		u += " Example:\n"
		u += "	rp-client -r http://example.com/api/v1/ -p PROJECT -l LAUNCH -t tag1,tag2,tag3 -id your_id ./examples/report"
		fmt.Fprintf(os.Stdout, u)
	}

	flag.StringVar(&hostFlag, "r", "", "Report Portal host. Example: http://example.com/api/v1/.")
	flag.StringVar(&hostFlag, "rp", "", "Report Portal host. Example: http://example.com/api/v1/.")

	flag.BoolVar(&debugFlag, "d", false, "Enable Report Portal debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable Report Portal debug mode.")

	flag.StringVar(&projectFlag, "p", "", "Report Portal project.")
	flag.StringVar(&projectFlag, "project", "", "Report Portal project.")

	flag.StringVar(&launchFlag, "l", "", "Report Portal launch name.")
	flag.StringVar(&launchFlag, "launch", "", "Report Portal launch.")

	flag.StringVar(&tagsFlag, "t", "", "Report Portal launch tags.")
	flag.StringVar(&tagsFlag, "tags", "", "Report Portal tags.")

	flag.StringVar(&uuidFlag, "id", "", "Report Portal user id.")
	flag.StringVar(&uuidFlag, "uuid", "", "Report Portal user id.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage.")
	flag.BoolVar(&helpFlag, "help", false, "Print usage.")

	flag.BoolVar(&versionFlag, "v", false, "Print version.")
	flag.BoolVar(&versionFlag, "version", false, "Print version.")
	flag.Parse()

	if versionFlag {
		fmt.Printf("rp version: %s\n", Version)
		os.Exit(1)
	}

	if helpFlag {
		flag.Usage()
		os.Exit(1)
	}

	reportDir = flag.Arg(0)
	if len(reportDir) == 0 {
		fmt.Println("specify directory with tests results")
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(reportDir); os.IsNotExist(err) {
		fmt.Printf("invalid tests results directory path '%s'\n", reportDir)
		flag.Usage()
		os.Exit(1)
	}

	if len(hostFlag) == 0 {
		fmt.Println("report portal host cold not be empty")
		flag.Usage()
		os.Exit(1)
	}

	if len(projectFlag) == 0 {
		fmt.Println("report portal project cold not be empty")
		flag.Usage()
		os.Exit(1)
	}

	if len(uuidFlag) == 0 {
		fmt.Println("report portal user id could not be empty")
		flag.Usage()
		os.Exit(1)
	}

	report, err := rp.LoadXMLReport(reportDir)

	if err != nil {
		fmt.Printf("could not load report")
		os.Exit(1)
	}

	if len(launchFlag) == 0 {
		fmt.Println("report portal launch name could not be empty")
		flag.Usage()
		os.Exit(1)
	}

	launchStart := report.LaunchStartTime()
	fmt.Printf("launch start: %s\n", launchStart.Format(rp.TimestampLayout))
	launch := &rp.Launch{}
	launch.StartTime = launchStart
	launch.Name = launchFlag
	if debugFlag {
		rp.InitLogger()
		launch.Mode = rp.ModeDebug
	}
	if len(tagsFlag) != 0 {
		launch.Tags = strings.Split(tagsFlag, ",")
	}

	rpClient := rp.NewClient(hostFlag, projectFlag, uuidFlag)

	launchID := rpClient.StartLaunch(launch)
	if launchID == nil {
		fmt.Println("could not start launch")
		os.Exit(1)
	}

	for i := 0; i < report.SuitesCount(); i++ {
		suite := report.Suite(i)
		suite.LaunchID = launchID.ID
		suiteID := rpClient.StartTestItem("", suite)

		for j := 0; j < report.TesCaseCount(i); j++ {
			tCase := report.TestCase(i, j)
			tCase.LaunchID = launchID.ID
			tCaseID := rpClient.StartTestItem(suiteID.ID, tCase)

			if report.HasTestCasefailure(i, j) {
				tFailure := report.TestCasefailure(i, j)
				tFailure.ItemID = tCaseID.ID
				rpClient.SendMesssage(tFailure)
				fDetails := report.TestCaseFailureDetails(i, j)
				fDetails.ItemID = tCaseID.ID
				rpClient.SendMesssage(fDetails)
			}

			tResult := report.TestCaseResult(i, j)
			rpClient.FinishTestItem(tCaseID.ID, tResult)
		}

		suiteResult := report.SuiteResult(i)
		rpClient.FinishTestItem(suiteID.ID, suiteResult)
	}

	launchEnd := report.LaunchEndTime()
	fmt.Printf("launch end: %s\n", launchEnd.Format(rp.TimestampLayout))
	rpClient.FinishLaunch(launchID.ID, &rp.ExecutionResult{
		EndTime: launchEnd,
	})

	os.Exit(0)
}
<commit_msg>Change exit value<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"strings"

	"github.com/darkowl91/rp-client/rp"
)

var (
	// Version for the application, passed on build
	Version = "No Version Provided"

	reportDir string

	debugFlag   bool
	hostFlag    string
	projectFlag string
	launchFlag  string
	tagsFlag    string
	uuidFlag    string
	helpFlag    bool
	versionFlag bool
)

func main() {
	flag.Usage = func() {
		u := " Usage:\n"
		u += "  rp-client [OPTIONS] (DIR|FILE)\n\n"
		u += " Options:\n"
		u += "	-r	--rp		Report Portal host\n"
		u += "	-d	--debug		Report Portal debug mode\n"
		u += "	-p	--project	Report Portal project\n"
		u += "	-l	--launch	Report Portal launch name\n"
		u += "	-t	--tags		Report Portal launch tags\n"
		u += "	-id	--uuid		Report Portal user id\n"
		u += "	-h,	--help		Print usage\n"
		u += "	-v,	--version	Print version information and quit\n\n"
		u += " Example:\n"
		u += "	rp-client -r http://example.com/api/v1/ -p PROJECT -l LAUNCH -t tag1,tag2,tag3 -id your_id ./examples/report"
		fmt.Fprintf(os.Stdout, u)
	}

	flag.StringVar(&hostFlag, "r", "", "Report Portal host. Example: http://example.com/api/v1/.")
	flag.StringVar(&hostFlag, "rp", "", "Report Portal host. Example: http://example.com/api/v1/.")

	flag.BoolVar(&debugFlag, "d", false, "Enable Report Portal debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable Report Portal debug mode.")

	flag.StringVar(&projectFlag, "p", "", "Report Portal project.")
	flag.StringVar(&projectFlag, "project", "", "Report Portal project.")

	flag.StringVar(&launchFlag, "l", "", "Report Portal launch name.")
	flag.StringVar(&launchFlag, "launch", "", "Report Portal launch.")

	flag.StringVar(&tagsFlag, "t", "", "Report Portal launch tags.")
	flag.StringVar(&tagsFlag, "tags", "", "Report Portal tags.")

	flag.StringVar(&uuidFlag, "id", "", "Report Portal user id.")
	flag.StringVar(&uuidFlag, "uuid", "", "Report Portal user id.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage.")
	flag.BoolVar(&helpFlag, "help", false, "Print usage.")

	flag.BoolVar(&versionFlag, "v", false, "Print version.")
	flag.BoolVar(&versionFlag, "version", false, "Print version.")
	flag.Parse()

	if versionFlag {
		fmt.Printf("rp version: %s\n", Version)
		os.Exit(0)
	}

	if helpFlag {
		flag.Usage()
		os.Exit(0)
	}

	reportDir = flag.Arg(0)
	if len(reportDir) == 0 {
		fmt.Println("specify directory with tests results")
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(reportDir); os.IsNotExist(err) {
		fmt.Printf("invalid tests results directory path '%s'\n", reportDir)
		flag.Usage()
		os.Exit(1)
	}

	if len(hostFlag) == 0 {
		fmt.Println("report portal host cold not be empty")
		flag.Usage()
		os.Exit(1)
	}

	if len(projectFlag) == 0 {
		fmt.Println("report portal project cold not be empty")
		flag.Usage()
		os.Exit(1)
	}

	if len(uuidFlag) == 0 {
		fmt.Println("report portal user id could not be empty")
		flag.Usage()
		os.Exit(1)
	}

	report, err := rp.LoadXMLReport(reportDir)

	if err != nil {
		fmt.Printf("could not load report")
		os.Exit(1)
	}

	if len(launchFlag) == 0 {
		fmt.Println("report portal launch name could not be empty")
		flag.Usage()
		os.Exit(1)
	}

	launchStart := report.LaunchStartTime()
	fmt.Printf("launch start: %s\n", launchStart.Format(rp.TimestampLayout))
	launch := &rp.Launch{}
	launch.StartTime = launchStart
	launch.Name = launchFlag
	if debugFlag {
		rp.InitLogger()
		launch.Mode = rp.ModeDebug
	}
	if len(tagsFlag) != 0 {
		launch.Tags = strings.Split(tagsFlag, ",")
	}

	rpClient := rp.NewClient(hostFlag, projectFlag, uuidFlag)

	launchID := rpClient.StartLaunch(launch)
	if launchID == nil {
		fmt.Println("could not start launch")
		os.Exit(1)
	}

	for i := 0; i < report.SuitesCount(); i++ {
		suite := report.Suite(i)
		suite.LaunchID = launchID.ID
		suiteID := rpClient.StartTestItem("", suite)

		for j := 0; j < report.TesCaseCount(i); j++ {
			tCase := report.TestCase(i, j)
			tCase.LaunchID = launchID.ID
			tCaseID := rpClient.StartTestItem(suiteID.ID, tCase)

			if report.HasTestCasefailure(i, j) {
				tFailure := report.TestCasefailure(i, j)
				tFailure.ItemID = tCaseID.ID
				rpClient.SendMesssage(tFailure)
				fDetails := report.TestCaseFailureDetails(i, j)
				fDetails.ItemID = tCaseID.ID
				rpClient.SendMesssage(fDetails)
			}

			tResult := report.TestCaseResult(i, j)
			rpClient.FinishTestItem(tCaseID.ID, tResult)
		}

		suiteResult := report.SuiteResult(i)
		rpClient.FinishTestItem(suiteID.ID, suiteResult)
	}

	launchEnd := report.LaunchEndTime()
	fmt.Printf("launch end: %s\n", launchEnd.Format(rp.TimestampLayout))
	rpClient.FinishLaunch(launchID.ID, &rp.ExecutionResult{
		EndTime: launchEnd,
	})

	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/negroni"
	"github.com/davecgh/go-spew/spew"
	"github.com/gorilla/mux"
	logging "github.com/op/go-logging"
	"github.com/unrolled/render"
)

type GithubPushEventPayload struct {
	Hook struct {
		Config struct {
			Secret string `json:"secret"`
		} `json:"config"`
	} `json:"hook"`
	Repository struct {
		FullName string `json:"full_name"`
		HtmlUrl  string `json:"html_url"`
	} `json:"repository"`
}

var log = logging.MustGetLogger("streamLog")
var format = "%{color}%{time:15:04:05} => %{color:reset} %{message}"

func streamCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Notice(scanner.Text())
		}
	}()
	err = cmd.Start()
	if err != nil {
		return err
	}
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(logBackend)
	logging.SetFormatter(logging.MustStringFormatter(format))
	logging.SetLevel(logging.NOTICE, "streamLog")
	homeDir := os.Getenv("HOME")

	app := cli.NewApp()
	app.Name = "tarzan"
	app.Usage = "naive cached automated build implementation"

	app.Action = func(c *cli.Context) {
		if _, err := os.Stat(fmt.Sprintf("%s/.dockercfg", homeDir)); err != nil {
			if os.IsNotExist(err) {
				log.Warning("Detected no Docker Hub login.  Please log in now.")
				cmd := exec.Command("docker", "login")
				cmd.Stdin = os.Stdin
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				if err := cmd.Run(); err != nil {
					fmt.Fprintln(os.Stderr, "Error running docker login")
					os.Exit(1)
				}
			}
		}
		r := render.New(render.Options{})
		router := mux.NewRouter()
		router.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
			var (
				payload GithubPushEventPayload
			)
			decoder := json.NewDecoder(req.Body)
			err := decoder.Decode(&payload)
			if err != nil {
				fmt.Fprintln(os.Stderr, "Error decoding Github push payload:", err)
			}
			spew.Dump(payload)
			fullName := payload.Repository.FullName
			repoPath := fmt.Sprintf("./repos/%s", fullName)
			repoUrl := payload.Repository.HtmlUrl
			if _, err := os.Stat(repoPath); err != nil {
				if os.IsNotExist(err) {
					fmt.Println("Executing command", "git clone --recursive", repoUrl, repoPath)
					if err := exec.Command("git", "clone", "--recursive", repoUrl, repoPath).Run(); err != nil {
						fmt.Fprintln(os.Stderr, "Error cloning git repository:", err)
					}
				} else {
					fmt.Fprintln(os.Stderr, "Error stat-ing directory", repoPath, ":", err)
				}
			} else {
				os.Chdir(repoPath)
				fmt.Println("Pulling existing repository")
				if err := exec.Command("git", "pull").Run(); err != nil {
					fmt.Fprintln(os.Stderr, "Error pulling git repository:", err)
					r.JSON(w, http.StatusInternalServerError, "")
				}

				fmt.Println("Building docker image")
				err := streamCommand("docker", "build", "-t", fullName, ".")
				if err != nil {
					fmt.Fprintln(os.Stderr, "Error building docker image for", fullName, ":", err)
					r.JSON(w, http.StatusInternalServerError, map[string]interface{}{
						"Error": err,
					})
				}

				fmt.Println("Pushing image back to Docker Hub")
				err = streamCommand("docker", "push", fullName)
				if err != nil {
					fmt.Fprintln(os.Stderr, "Error pushing docker image for", fullName, ":", err)
					r.JSON(w, http.StatusInternalServerError, map[string]interface{}{
						"Error": err,
					})
				}
			}

			r.JSON(w, http.StatusOK, "")
		}).Methods("POST")

		n := negroni.Classic()
		n.UseHandler(router)
		n.Run(":80")

	}

	app.Run(os.Args)
}
<commit_msg>Make more consistent with README<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/negroni"
	"github.com/davecgh/go-spew/spew"
	"github.com/gorilla/mux"
	logging "github.com/op/go-logging"
	"github.com/unrolled/render"
)

type GithubPushEventPayload struct {
	Hook struct {
		Config struct {
			Secret string `json:"secret"`
		} `json:"config"`
	} `json:"hook"`
	Repository struct {
		FullName string `json:"full_name"`
		HtmlUrl  string `json:"html_url"`
	} `json:"repository"`
}

var log = logging.MustGetLogger("streamLog")
var format = "%{color}%{time:15:04:05} => %{color:reset} %{message}"

func streamCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmdReader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	scanner := bufio.NewScanner(cmdReader)
	go func() {
		for scanner.Scan() {
			log.Notice(scanner.Text())
		}
	}()
	err = cmd.Start()
	if err != nil {
		return err
	}
	err = cmd.Wait()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(logBackend)
	logging.SetFormatter(logging.MustStringFormatter(format))
	logging.SetLevel(logging.NOTICE, "streamLog")
	homeDir := os.Getenv("HOME")

	app := cli.NewApp()
	app.Name = "tarzan"
	app.Usage = "naive cached automated build implementation"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "p,port",
			Value: "3000",
			Usage: "port to serve tarzan on",
		},
		cli.StringFlag{
			Name:  "alt-registry",
			Value: "",
			Usage: "alternative registry to push images to instead of Docker Hub",
		},
		cli.StringFlag{
			Name:  "secret",
			Value: "",
			Usage: "secret to use when receiving webhook payload",
		},
		cli.StringFlag{
			Name:  "hub-name",
			Value: "",
			Usage: "specify a username on Docker Hub which is different than your Github handle",
		},
	}

	app.Action = func(c *cli.Context) {
		if _, err := os.Stat(fmt.Sprintf("%s/.dockercfg", homeDir)); err != nil {
			if os.IsNotExist(err) {
				log.Warning("Detected no Docker Hub login.  Please log in now.")
				cmd := exec.Command("docker", "login")
				cmd.Stdin = os.Stdin
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				if err := cmd.Run(); err != nil {
					fmt.Fprintln(os.Stderr, "Error running docker login")
					os.Exit(1)
				}
			}
		}
		r := render.New(render.Options{})
		router := mux.NewRouter()
		router.HandleFunc("/build", func(w http.ResponseWriter, req *http.Request) {
			var (
				payload GithubPushEventPayload
			)
			decoder := json.NewDecoder(req.Body)
			err := decoder.Decode(&payload)
			if err != nil {
				fmt.Fprintln(os.Stderr, "Error decoding Github push payload:", err)
			}
			spew.Dump(payload)
			if c.String("secret") == "" || payload.Hook.Config.Secret == c.String("secret") {
				githubFullName := payload.Repository.FullName
				repoPath := fmt.Sprintf("./repos/%s", githubFullName)
				repoUrl := payload.Repository.HtmlUrl
				if _, err := os.Stat(repoPath); err != nil {
					if os.IsNotExist(err) {
						fmt.Println("Executing command", "git clone --recursive", repoUrl, repoPath)
						if err := exec.Command("git", "clone", "--recursive", repoUrl, repoPath).Run(); err != nil {
							fmt.Fprintln(os.Stderr, "Error cloning git repository:", err)
						}
					} else {
						fmt.Fprintln(os.Stderr, "Error stat-ing directory", repoPath, ":", err)
					}
				} else {
					os.Chdir(repoPath)
					fmt.Println("Pulling existing repository")
					if err := exec.Command("git", "pull").Run(); err != nil {
						fmt.Fprintln(os.Stderr, "Error pulling git repository:", err)
						r.JSON(w, http.StatusInternalServerError, "")
					}

					namespacedImage := ""
					splitImage := strings.Split(githubFullName, "/")
					imageBase := splitImage[len(splitImage)-1]
					if c.String("hub-name") == "" {
						if c.String("alt-registry") == "" {
							namespacedImage = githubFullName
						} else {
							namespacedImage = fmt.Sprintf("%s/%s", c.String("alt-registry"), imageBase)
						}
					} else {
						namespacedImage = fmt.Sprintf("%s/%s", c.String("hub-name"), imageBase)
					}

					fmt.Println("Building docker image")
					err := streamCommand("docker", "build", "-t", namespacedImage, ".")
					if err != nil {
						fmt.Fprintln(os.Stderr, "Error building docker image for", namespacedImage, ":", err)
						r.JSON(w, http.StatusInternalServerError, map[string]interface{}{
							"Error": err,
						})
					}

					registryName := ""
					if c.String("alt-registry") != "" {
						registryName = c.String("alt-registry")
					} else {
						registryName = "Docker Hub"
					}
					fmt.Println(fmt.Sprintf("Pushing image back to specified registry (%s)...", registryName))
					err = streamCommand("docker", "push", namespacedImage)
					if err != nil {
						fmt.Fprintln(os.Stderr, "Error pushing docker image for", namespacedImage, ":", err)
						r.JSON(w, http.StatusInternalServerError, map[string]interface{}{
							"Error": err,
						})
					}
				}
			} else {
				r.JSON(w, http.StatusInternalServerError, map[string]interface{}{
					"Error": "Secret from payload was invalid",
				})
			}

			r.JSON(w, http.StatusOK, "")
		}).Methods("POST")

		n := negroni.Classic()
		n.UseHandler(router)
		n.Run(fmt.Sprintf(":%s", c.String("port")))

	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/jesusrmoreno/toto/domain"
	"github.com/jesusrmoreno/toto/implementations"
	"github.com/jesusrmoreno/toto/utils"

	"github.com/jesusrmoreno/sad-squid"
)

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.json")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if err := json.NewDecoder(r).Decode(&dummy); err != nil {
			return nil, errors.New("Invalid JSON in file: " + f)
		}
		g := domain.Game{
			Players:        dummy.Players,
			Title:          dummy.Title,
			UUID:           dummy.UUID,
			ExamplePayload: dummy.ExamplePayload,
			Lobby: impl.Lobby{
				// We implement our lobby as a buffered channel that takes the number of
				// players specified in the config file for the game and makes that the
				// cap.
				Queue: make(chan domain.Player, dummy.Players),
			},
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " + gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) {
	data := map[string]interface{}{}
	data["message"] = "You are in the queue for game: " + g.Title
	r := Response{
		Kind: inQueue,
		Data: data,
	}
	p.Comm.Emit(inQueue, r)
	pq := g.Lobby
	pq.AddToQueue(p)
}

// GroupPlayers creates groups of players of size PlayerSize as defined in the
// game files.
func GroupPlayers(g domain.Game, server *socketio.Server, gi *GamesInfo) {
	pq := g.Lobby
	n := g.Players
	for {
		select {
		default:
			if g.Lobby.Size() >= n {
				team := []domain.Player{}
				// Generate a room id
				roomName := squid.GenerateSimpleID()
				for i := 0; i < n; i++ {
					p := pq.PopFromQueue()
					pID := p.Comm.Id()
					team = append(team, p)

					// Set the metadata
					gi.RoomMap.Set(pID, roomName)
					gi.TurnMap.Set(roomName+":"+pID, i)

					// Place the player in the created room.
					p.Comm.Join(roomName)

					// Create the response
					data := map[string]interface{}{}
					data["roomName"] = roomName
					data["turnNumber"] = i
					r := Response{
						Kind: inQueue,
						Data: data,
					}
					p.Comm.Emit(groupAssignment, r)
				}

				// Create the response
				data := map[string]interface{}{}
				data["message"] = fmt.Sprintf("Welcome to %s", roomName)
				r := Response{
					Kind: roomMessage,
					Data: data,
				}
				server.BroadcastTo(roomName, roomMessage, r)
			}
		}
	}
}

func main() {
	games, err := ReadGameFiles("./games")
	if err != nil {
		log.Fatal(err)
	}

	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}
	for key := range games {
		go GroupPlayers(games[key], server, &info)
	}
	server.On("connection", func(so socketio.Socket) {
		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		so.On(joinGame, func(req json.RawMessage) {
			m := map[string]string{}
			if err := json.Unmarshal(req, &m); err != nil {
				so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
			}
			gameID, exists := m["gameId"]
			if !exists {
				so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
			}
			// If the player attempts to connect to a game we first have to make
			// sure that they are joining a game that is registered with our server.
			if g, exists := games[gameID]; exists {
				QueuePlayers(g, domain.Player{
					Comm: so,
				})
			} else {
				so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				so.BroadcastTo(room, moveMade, r)
			} else {
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:5000...")
	log.Fatal(http.ListenAndServe(":5000", nil))
}
<commit_msg>Fix: Added port variable<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/jesusrmoreno/toto/domain"
	"github.com/jesusrmoreno/toto/implementations"
	"github.com/jesusrmoreno/toto/utils"

	"github.com/jesusrmoreno/sad-squid"
)

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.json")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if err := json.NewDecoder(r).Decode(&dummy); err != nil {
			return nil, errors.New("Invalid JSON in file: " + f)
		}
		g := domain.Game{
			Players:        dummy.Players,
			Title:          dummy.Title,
			UUID:           dummy.UUID,
			ExamplePayload: dummy.ExamplePayload,
			Lobby: impl.Lobby{
				// We implement our lobby as a buffered channel that takes the number of
				// players specified in the config file for the game and makes that the
				// cap.
				Queue: make(chan domain.Player, dummy.Players),
			},
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " + gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) {
	data := map[string]interface{}{}
	data["message"] = "You are in the queue for game: " + g.Title
	r := Response{
		Kind: inQueue,
		Data: data,
	}
	p.Comm.Emit(inQueue, r)
	pq := g.Lobby
	pq.AddToQueue(p)
}

// GroupPlayers creates groups of players of size PlayerSize as defined in the
// game files.
func GroupPlayers(g domain.Game, server *socketio.Server, gi *GamesInfo) {
	pq := g.Lobby
	n := g.Players
	for {
		select {
		default:
			if g.Lobby.Size() >= n {
				team := []domain.Player{}
				// Generate a room id
				roomName := squid.GenerateSimpleID()
				for i := 0; i < n; i++ {
					p := pq.PopFromQueue()
					pID := p.Comm.Id()
					team = append(team, p)

					// Set the metadata
					gi.RoomMap.Set(pID, roomName)
					gi.TurnMap.Set(roomName+":"+pID, i)

					// Place the player in the created room.
					p.Comm.Join(roomName)

					// Create the response
					data := map[string]interface{}{}
					data["roomName"] = roomName
					data["turnNumber"] = i
					r := Response{
						Kind: inQueue,
						Data: data,
					}
					p.Comm.Emit(groupAssignment, r)
				}

				// Create the response
				data := map[string]interface{}{}
				data["message"] = fmt.Sprintf("Welcome to %s", roomName)
				r := Response{
					Kind: roomMessage,
					Data: data,
				}
				server.BroadcastTo(roomName, roomMessage, r)
			}
		}
	}
}

func main() {
	games, err := ReadGameFiles("./games")
	if err != nil {
		log.Fatal(err)
	}

	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}
	for key := range games {
		go GroupPlayers(games[key], server, &info)
	}
	server.On("connection", func(so socketio.Socket) {
		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		so.On(joinGame, func(req json.RawMessage) {
			m := map[string]string{}
			if err := json.Unmarshal(req, &m); err != nil {
				so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
			}
			gameID, exists := m["gameId"]
			if !exists {
				so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
			}
			// If the player attempts to connect to a game we first have to make
			// sure that they are joining a game that is registered with our server.
			if g, exists := games[gameID]; exists {
				QueuePlayers(g, domain.Player{
					Comm: so,
				})
			} else {
				so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				so.BroadcastTo(room, moveMade, r)
			} else {
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})

	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}

	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


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

//
package main

import (
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

var httpPort = flag.String("http", "80", "http port")
var httpsPort = flag.String("https", "443", "https port")
var certPem = flag.String("cert", "certs/fullchain.pem", "path to cert pem file")
var keyPem = flag.String("key", "certs/privkey.pem", "path key pem file")
var domain = flag.String("domain", "localhost", "web domain")
var public = flag.String("pubdir", "public", "path to public directory")

func main() {
	flag.Parse()
	http.HandleFunc("/", indexServer)
	http.Handle("/pub/", http.StripPrefix("/pub/", http.FileServer(http.Dir(*public))))
	go func() {
		err := http.ListenAndServeTLS(":"+*httpsPort, *certPem, *keyPem, nil)
		if err != nil {
			log.Fatal("ListenAndServeTLS:", err)
		}
	}()
	err := http.ListenAndServe(":"+*httpPort, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// indexServer serves the index.html.
func indexServer(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadFile(*public + "/index.html")
	if err != nil {
		log.Fatal("Failed to read index.html")
	}
	io.WriteString(w, string(data))
}

// redirectUrl assembles the https url for redirect to TLS.
func redirectUrl() string {
	if *httpsPort == "443" {
		return "https://" + *domain
	}
	return "https://" + *domain + ":" + *httpsPort
}

// checkTLS returns true if TLS handshake is complete or false if not.
func checkTLS(r *http.Request) bool {
	if r.TLS != nil && r.TLS.HandshakeComplete {
		return true
	}
	return false
}
<commit_msg>indexServer now sends error to browser if ReadFile fails<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//
package main

import (
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

var httpPort = flag.String("http", "80", "http port")
var httpsPort = flag.String("https", "443", "https port")
var certPem = flag.String("cert", "certs/fullchain.pem", "path to cert pem file")
var keyPem = flag.String("key", "certs/privkey.pem", "path key pem file")
var domain = flag.String("domain", "localhost", "web domain")
var public = flag.String("pubdir", "public", "path to public directory")

func main() {
	flag.Parse()
	http.HandleFunc("/", indexServer)
	http.Handle("/pub/", http.StripPrefix("/pub/", http.FileServer(http.Dir(*public))))
	go func() {
		err := http.ListenAndServeTLS(":"+*httpsPort, *certPem, *keyPem, nil)
		if err != nil {
			log.Fatal("ListenAndServeTLS:", err)
		}
	}()
	err := http.ListenAndServe(":"+*httpPort, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// indexServer serves the index.html.
func indexServer(w http.ResponseWriter, r *http.Request) {
	data, err := ioutil.ReadFile(*public + "/index.html")
	if err != nil {
		io.WriteString(w, "
Failed to read index.html!
")
	} else {
		io.WriteString(w, string(data))
	}
}

// redirectUrl assembles the https url for redirect to TLS.
func redirectUrl() string {
	if *httpsPort == "443" {
		return "https://" + *domain
	}
	return "https://" + *domain + ":" + *httpsPort
}

// checkTLS returns true if TLS handshake is complete or false if not.
func checkTLS(r *http.Request) bool {
	if r.TLS != nil && r.TLS.HandshakeComplete {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/Unknwon/i18n"
	"github.com/go-xweb/log"
	"github.com/go-xweb/xweb"

	"github.com/go-xorm/website/actions"
	"github.com/go-xorm/website/models"
)

const (
	APP_VER = "0.2.0715"
)

func updateDoc(tmpPath, dstpath string) {
	os.RemoveAll(tmpPath)
	os.MkdirAll(tmpPath, os.ModePerm)

	resp, err := http.Get("https://github.com/go-xorm/xorm/archive/master.zip")
	if err != nil {
		log.Warn("download docs failed")
		return
	}

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Warn("read zip docs failed")
		return
	}

	zrd, err := zip.NewReader(bytes.NewReader(bs), int64(len(bs)))
	if err != nil {
		log.Warn("open zip docs failed")
		return
	}

	for _, f := range zrd.File {
		if !strings.HasPrefix(f.Name, "xorm-master/docs") {
			continue
		}

		fPath := filepath.Join(tmpPath, f.Name)
		os.MkdirAll(filepath.Dir(fPath), os.ModePerm)
		fInfo := f.FileInfo()
		if fInfo.IsDir() {
			os.MkdirAll(fPath, os.ModePerm)
			continue
		}

		ff, err := os.Create(fPath)
		if err != nil {
			log.Warnf("create file %s failed", f.Name)
			return
		}
		defer ff.Close()

		rd, err := f.Open()
		if err != nil {
			log.Warnf("open zip file %s failed", f.Name)
			return
		}

		_, err = io.Copy(ff, rd)
		if err != nil {
			log.Warnf("unzip file %s failed", f.Name)
			return
		}
	}

	os.RemoveAll(dstpath)

	err = os.Rename(filepath.Join(tmpPath, "xorm-master/docs"), dstpath)
	if err != nil {
		log.Warnf("move docs from %s to %s failed", filepath.Join(tmpPath, "xorm-master/docs"), dstpath)
	}
}

func timeUpdate(tmpPath, dstpath string) {
	time.AfterFunc(time.Minute, func() {
		updateDoc(tmpPath, dstpath)
		timeUpdate(tmpPath, dstpath)
	})
}

func main() {
	models.InitModels()

	mode, _ := models.Cfg.GetValue("app", "run_mode")
	var isPro bool = true
	if mode == "dev" {
		log.SetOutputLevel(log.Ldebug)
		isPro = false
	}
	log.Info("run in " + mode + " mode")

	actions.InitApp()

	go timeUpdate("./tmp", "./docs")

	// Register routers.
	xweb.AddAction(&actions.HomeAction{})
	xweb.AutoAction(&actions.DocsAction{}, &actions.LinkAction{})
	xweb.AddTmplVars(&xweb.T{
		"i18n":    i18n.Tr,
		"IsPro":   isPro,
		"AppVer":  APP_VER,
		"XwebVer": xweb.Version,
		"GoVer":   strings.Trim(runtime.Version(), "go"),
	})
	port, _ := models.Cfg.GetValue("app", "http_port")
	usessl, _ := models.Cfg.GetValue("app", "ssl")
	if usessl == "true" {
		tlsCfg, _ := xweb.SimpleTLSConfig("cert.pem", "key.pem")
		xweb.RunTLS(fmt.Sprintf(":%v", port), tlsCfg)
	} else {
		xweb.Run(fmt.Sprintf(":%v", port))
	}
}
<commit_msg>version to 0.3<commit_after>package main

import (
	"archive/zip"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/Unknwon/i18n"
	"github.com/go-xweb/log"
	"github.com/go-xweb/xweb"

	"github.com/go-xorm/website/actions"
	"github.com/go-xorm/website/models"
)

const (
	APP_VER = "0.3.0911"
)

func updateDoc(tmpPath, dstpath string) {
	os.RemoveAll(tmpPath)
	os.MkdirAll(tmpPath, os.ModePerm)

	resp, err := http.Get("https://github.com/go-xorm/xorm/archive/master.zip")
	if err != nil {
		log.Warn("download docs failed")
		return
	}

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Warn("read zip docs failed")
		return
	}

	zrd, err := zip.NewReader(bytes.NewReader(bs), int64(len(bs)))
	if err != nil {
		log.Warn("open zip docs failed")
		return
	}

	for _, f := range zrd.File {
		if !strings.HasPrefix(f.Name, "xorm-master/docs") {
			continue
		}

		fPath := filepath.Join(tmpPath, f.Name)
		os.MkdirAll(filepath.Dir(fPath), os.ModePerm)
		fInfo := f.FileInfo()
		if fInfo.IsDir() {
			os.MkdirAll(fPath, os.ModePerm)
			continue
		}

		ff, err := os.Create(fPath)
		if err != nil {
			log.Warnf("create file %s failed", f.Name)
			return
		}
		defer ff.Close()

		rd, err := f.Open()
		if err != nil {
			log.Warnf("open zip file %s failed", f.Name)
			return
		}

		_, err = io.Copy(ff, rd)
		if err != nil {
			log.Warnf("unzip file %s failed", f.Name)
			return
		}
	}

	os.RemoveAll(dstpath)

	err = os.Rename(filepath.Join(tmpPath, "xorm-master/docs"), dstpath)
	if err != nil {
		log.Warnf("move docs from %s to %s failed", filepath.Join(tmpPath, "xorm-master/docs"), dstpath)
	}
}

func timeUpdate(tmpPath, dstpath string) {
	time.AfterFunc(time.Minute, func() {
		updateDoc(tmpPath, dstpath)
		timeUpdate(tmpPath, dstpath)
	})
}

func main() {
	models.InitModels()

	mode, _ := models.Cfg.GetValue("app", "run_mode")
	var isPro bool = true
	if mode == "dev" {
		log.SetOutputLevel(log.Ldebug)
		isPro = false
	}
	log.Info("run in " + mode + " mode")

	actions.InitApp()

	go timeUpdate("./tmp", "./docs")

	// Register routers.
	xweb.AddAction(&actions.HomeAction{})
	xweb.AutoAction(&actions.DocsAction{}, &actions.LinkAction{})
	xweb.AddTmplVars(&xweb.T{
		"i18n":    i18n.Tr,
		"IsPro":   isPro,
		"AppVer":  APP_VER,
		"XwebVer": xweb.Version,
		"GoVer":   strings.Trim(runtime.Version(), "go"),
	})
	port, _ := models.Cfg.GetValue("app", "http_port")
	usessl, _ := models.Cfg.GetValue("app", "ssl")
	if usessl == "true" {
		tlsCfg, _ := xweb.SimpleTLSConfig("cert.pem", "key.pem")
		xweb.RunTLS(fmt.Sprintf(":%v", port), tlsCfg)
	} else {
		xweb.Run(fmt.Sprintf(":%v", port))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"sort"

	"github.com/fatih/color"
	"github.com/mattn/go-colorable"
	"github.com/nwidger/jsoncolor"
	"github.com/pkg/errors"
)

// Exit codes
const (
	exitOK = iota
	exitOpenFile
	exitReadInput
	exitFormStatements
	exitFetchURL
	exitParseStatements
	exitJSONEncode
)

// Option bitfields
const (
	optMonochrome = 1 << iota
	optNoSort
	optJSON
)

// Output colors
var (
	strColor   = color.New(color.FgYellow)
	braceColor = color.New(color.FgMagenta)
	bareColor  = color.New(color.FgBlue, color.Bold)
	numColor   = color.New(color.FgRed)
	boolColor  = color.New(color.FgCyan)
)

// gronVersion stores the current gron version, set at build
// time with the ldflags -X option
var gronVersion = "dev"

func init() {
	flag.Usage = func() {
		h := "Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable\n\n"

		h += "Usage:\n"
		h += "  gron [OPTIONS] [FILE|URL|-]\n\n"

		h += "Options:\n"
		h += "  -u, --ungron     Reverse the operation (turn assignments back into JSON)\n"
		h += "  -c, --colorize   Colorize output (default on tty)\n"
		h += "  -m, --monochrome Monochrome (don't colorize output)\n"
		h += "  -s, --stream     Treat each line of input as a separate JSON object\n"
		h += "  -k, --insecure   Disable certificate validation\n"
		h += "  -j, --json       Represent gron data as JSON stream\n"
		h += "      --no-sort    Don't sort output (faster)\n"
		h += "      --version    Print version information\n\n"

		h += "Exit Codes:\n"
		h += fmt.Sprintf("  %d\t%s\n", exitOK, "OK")
		h += fmt.Sprintf("  %d\t%s\n", exitOpenFile, "Failed to open file")
		h += fmt.Sprintf("  %d\t%s\n", exitReadInput, "Failed to read input")
		h += fmt.Sprintf("  %d\t%s\n", exitFormStatements, "Failed to form statements")
		h += fmt.Sprintf("  %d\t%s\n", exitFetchURL, "Failed to fetch URL")
		h += fmt.Sprintf("  %d\t%s\n", exitParseStatements, "Failed to parse statements")
		h += fmt.Sprintf("  %d\t%s\n", exitJSONEncode, "Failed to encode JSON")
		h += "\n"

		h += "Examples:\n"
		h += "  gron /tmp/apiresponse.json\n"
		h += "  gron http://jsonplaceholder.typicode.com/users/1 \n"
		h += "  curl -s http://jsonplaceholder.typicode.com/users/1 | gron\n"
		h += "  gron http://jsonplaceholder.typicode.com/users/1 | grep company | gron --ungron\n"

		fmt.Fprintf(os.Stderr, h)
	}
}

func main() {
	var (
		ungronFlag     bool
		colorizeFlag   bool
		monochromeFlag bool
		streamFlag     bool
		noSortFlag     bool
		versionFlag    bool
		insecureFlag   bool
		jsonFlag       bool
	)

	flag.BoolVar(&ungronFlag, "ungron", false, "")
	flag.BoolVar(&ungronFlag, "u", false, "")
	flag.BoolVar(&colorizeFlag, "colorize", false, "")
	flag.BoolVar(&colorizeFlag, "c", false, "")
	flag.BoolVar(&monochromeFlag, "monochrome", false, "")
	flag.BoolVar(&monochromeFlag, "m", false, "")
	flag.BoolVar(&streamFlag, "s", false, "")
	flag.BoolVar(&streamFlag, "stream", false, "")
	flag.BoolVar(&noSortFlag, "no-sort", false, "")
	flag.BoolVar(&versionFlag, "version", false, "")
	flag.BoolVar(&insecureFlag, "k", false, "")
	flag.BoolVar(&insecureFlag, "insecure", false, "")
	flag.BoolVar(&jsonFlag, "j", false, "")
	flag.BoolVar(&jsonFlag, "json", false, "")

	flag.Parse()

	// Print version information
	if versionFlag {
		fmt.Printf("gron version %s\n", gronVersion)
		os.Exit(exitOK)
	}

	// Determine what the program's input should be:
	// file, HTTP URL or stdin
	var rawInput io.Reader
	filename := flag.Arg(0)
	if filename == "" || filename == "-" {
		rawInput = os.Stdin
	} else if validURL(filename) {
		r, err := getURL(filename, insecureFlag)
		if err != nil {
			fatal(exitFetchURL, err)
		}
		rawInput = r
	} else {
		r, err := os.Open(filename)
		if err != nil {
			fatal(exitOpenFile, err)
		}
		rawInput = r
	}

	var opts int
	// The monochrome option should be forced if the output isn't a terminal
	// to avoid doing unnecessary work calling the color functions
	switch {
	case colorizeFlag:
		color.NoColor = false
	case monochromeFlag || color.NoColor:
		opts = opts | optMonochrome
	}
	if noSortFlag {
		opts = opts | optNoSort
	}
	if jsonFlag {
		opts = opts | optJSON
	}

	// Pick the appropriate action: gron, ungron or gronStream
	var a actionFn = gron
	if ungronFlag {
		a = ungron
	} else if streamFlag {
		a = gronStream
	}
	exitCode, err := a(rawInput, colorable.NewColorableStdout(), opts)

	if exitCode != exitOK {
		fatal(exitCode, err)
	}

	os.Exit(exitOK)
}

// an actionFn represents a main action of the program, it accepts
// an input, output and a bitfield of options; returning an exit
// code and any error that occurred
type actionFn func(io.Reader, io.Writer, int) (int, error)

// gron is the default action. Given JSON as the input it returns a list
// of assignment statements. Possible options are optNoSort and optMonochrome
func gron(r io.Reader, w io.Writer, opts int) (int, error) {
	var err error

	var conv statementconv
	if opts&optMonochrome > 0 {
		conv = statementToString
	} else {
		conv = statementToColorString
	}

	ss, err := statementsFromJSON(r, statement{{"json", typBare}})
	if err != nil {
		goto out
	}

	// Go's maps do not have well-defined ordering, but we want a consistent
	// output for a given input, so we must sort the statements
	if opts&optNoSort == 0 {
		sort.Sort(ss)
	}

	for _, s := range ss {
		if opts&optJSON > 0 {
			s, err = s.jsonify()
			if err != nil {
				goto out
			}
		}
		fmt.Fprintln(w, conv(s))
	}

out:
	if err != nil {
		return exitFormStatements, fmt.Errorf("failed to form statements: %s", err)
	}
	return exitOK, nil
}

// gronStream is like the gron action, but it treats the input as one
// JSON object per line. There's a bit of code duplication from the
// gron action, but it'd be fairly messy to combine the two actions
func gronStream(r io.Reader, w io.Writer, opts int) (int, error) {
	var err error
	errstr := "failed to form statements"
	var i int
	var sc *bufio.Scanner
	var buf []byte

	var conv func(s statement) string
	if opts&optMonochrome > 0 {
		conv = statementToString
	} else {
		conv = statementToColorString
	}

	// Helper function to make the prefix statements for each line
	makePrefix := func(index int) statement {
		return statement{
			{"json", typBare},
			{"[", typLBrace},
			{fmt.Sprintf("%d", index), typNumericKey},
			{"]", typRBrace},
		}
	}

	// The first line of output needs to establish that the top-level
	// thing is actually an array...
	top := statement{
		{"json", typBare},
		{"=", typEquals},
		{"[]", typEmptyArray},
		{";", typSemi},
	}

	if opts&optJSON > 0 {
		top, err = top.jsonify()
		if err != nil {
			goto out
		}
	}

	fmt.Fprintln(w, conv(top))

	// Read the input line by line
	sc = bufio.NewScanner(r)
	buf = make([]byte, 0, 64*1024)
	sc.Buffer(buf, 1024*1024)
	i = 0
	for sc.Scan() {

		line := bytes.NewBuffer(sc.Bytes())

		var ss statements
		ss, err = statementsFromJSON(line, makePrefix(i))
		i++
		if err != nil {
			goto out
		}

		// Go's maps do not have well-defined ordering, but we want a consistent
		// output for a given input, so we must sort the statements
		if opts&optNoSort == 0 {
			sort.Sort(ss)
		}

		for _, s := range ss {
			if opts&optJSON > 0 {
				s, err = s.jsonify()
				if err != nil {
					goto out
				}

			}
			fmt.Fprintln(w, conv(s))
		}
	}
	if err = sc.Err(); err != nil {
		errstr = "error reading multiline input: %s"
	}

out:
	if err != nil {
		return exitFormStatements, fmt.Errorf(errstr+": %s", err)
	}
	return exitOK, nil

}

// ungron is the reverse of gron. Given assignment statements as input,
// it returns JSON. The only option is optMonochrome
func ungron(r io.Reader, w io.Writer, opts int) (int, error) {
	scanner := bufio.NewScanner(r)
	var maker statementmaker

	if opts&optJSON > 0 {
		maker = statementFromJSONSpec
	} else {
		maker = statementFromStringMaker
	}

	// Make a list of statements from the input
	var ss statements
	for scanner.Scan() {
		s, err := maker(scanner.Text())
		if err != nil {
			return exitParseStatements, err
		}
		ss.add(s)
	}
	if err := scanner.Err(); err != nil {
		return exitReadInput, fmt.Errorf("failed to read input statements")
	}

	// turn the statements into a single merged interface{} type
	merged, err := ss.toInterface()
	if err != nil {
		return exitParseStatements, err
	}

	// If there's only one top level key and it's "json", make that the top level thing
	mergedMap, ok := merged.(map[string]interface{})
	if ok {
		if len(mergedMap) == 1 {
			if _, exists := mergedMap["json"]; exists {
				merged = mergedMap["json"]
			}
		}
	}

	// Marshal the output into JSON to display to the user
	out := &bytes.Buffer{}
	enc := json.NewEncoder(out)
	enc.SetIndent("", "  ")
	enc.SetEscapeHTML(false)
	err = enc.Encode(merged)
	if err != nil {
		return exitJSONEncode, errors.Wrap(err, "failed to convert statements to JSON")
	}
	j := out.Bytes()

	// If the output isn't monochrome, add color to the JSON
	if opts&optMonochrome == 0 {
		c, err := colorizeJSON(j)

		// If we failed to colorize the JSON for whatever reason,
		// we'll just fall back to monochrome output, otherwise
		// replace the monochrome JSON with glorious technicolor
		if err == nil {
			j = c
		}
	}

	fmt.Fprintf(w, "%s\n", j)

	return exitOK, nil
}

func colorizeJSON(src []byte) ([]byte, error) {
	out := &bytes.Buffer{}
	f := jsoncolor.NewFormatter()

	f.StringColor = strColor
	f.ObjectColor = braceColor
	f.ArrayColor = braceColor
	f.FieldColor = bareColor
	f.NumberColor = numColor
	f.TrueColor = boolColor
	f.FalseColor = boolColor
	f.NullColor = boolColor

	err := f.Format(out, src)
	if err != nil {
		return out.Bytes(), err
	}
	return out.Bytes(), nil
}

func fatal(code int, err error) {
	fmt.Fprintf(os.Stderr, "%s\n", err)
	os.Exit(code)
}
<commit_msg>Trims whitespace on monochrome output; fixes #43<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"sort"

	"github.com/fatih/color"
	"github.com/mattn/go-colorable"
	"github.com/nwidger/jsoncolor"
	"github.com/pkg/errors"
)

// Exit codes
const (
	exitOK = iota
	exitOpenFile
	exitReadInput
	exitFormStatements
	exitFetchURL
	exitParseStatements
	exitJSONEncode
)

// Option bitfields
const (
	optMonochrome = 1 << iota
	optNoSort
	optJSON
)

// Output colors
var (
	strColor   = color.New(color.FgYellow)
	braceColor = color.New(color.FgMagenta)
	bareColor  = color.New(color.FgBlue, color.Bold)
	numColor   = color.New(color.FgRed)
	boolColor  = color.New(color.FgCyan)
)

// gronVersion stores the current gron version, set at build
// time with the ldflags -X option
var gronVersion = "dev"

func init() {
	flag.Usage = func() {
		h := "Transform JSON (from a file, URL, or stdin) into discrete assignments to make it greppable\n\n"

		h += "Usage:\n"
		h += "  gron [OPTIONS] [FILE|URL|-]\n\n"

		h += "Options:\n"
		h += "  -u, --ungron     Reverse the operation (turn assignments back into JSON)\n"
		h += "  -c, --colorize   Colorize output (default on tty)\n"
		h += "  -m, --monochrome Monochrome (don't colorize output)\n"
		h += "  -s, --stream     Treat each line of input as a separate JSON object\n"
		h += "  -k, --insecure   Disable certificate validation\n"
		h += "  -j, --json       Represent gron data as JSON stream\n"
		h += "      --no-sort    Don't sort output (faster)\n"
		h += "      --version    Print version information\n\n"

		h += "Exit Codes:\n"
		h += fmt.Sprintf("  %d\t%s\n", exitOK, "OK")
		h += fmt.Sprintf("  %d\t%s\n", exitOpenFile, "Failed to open file")
		h += fmt.Sprintf("  %d\t%s\n", exitReadInput, "Failed to read input")
		h += fmt.Sprintf("  %d\t%s\n", exitFormStatements, "Failed to form statements")
		h += fmt.Sprintf("  %d\t%s\n", exitFetchURL, "Failed to fetch URL")
		h += fmt.Sprintf("  %d\t%s\n", exitParseStatements, "Failed to parse statements")
		h += fmt.Sprintf("  %d\t%s\n", exitJSONEncode, "Failed to encode JSON")
		h += "\n"

		h += "Examples:\n"
		h += "  gron /tmp/apiresponse.json\n"
		h += "  gron http://jsonplaceholder.typicode.com/users/1 \n"
		h += "  curl -s http://jsonplaceholder.typicode.com/users/1 | gron\n"
		h += "  gron http://jsonplaceholder.typicode.com/users/1 | grep company | gron --ungron\n"

		fmt.Fprintf(os.Stderr, h)
	}
}

func main() {
	var (
		ungronFlag     bool
		colorizeFlag   bool
		monochromeFlag bool
		streamFlag     bool
		noSortFlag     bool
		versionFlag    bool
		insecureFlag   bool
		jsonFlag       bool
	)

	flag.BoolVar(&ungronFlag, "ungron", false, "")
	flag.BoolVar(&ungronFlag, "u", false, "")
	flag.BoolVar(&colorizeFlag, "colorize", false, "")
	flag.BoolVar(&colorizeFlag, "c", false, "")
	flag.BoolVar(&monochromeFlag, "monochrome", false, "")
	flag.BoolVar(&monochromeFlag, "m", false, "")
	flag.BoolVar(&streamFlag, "s", false, "")
	flag.BoolVar(&streamFlag, "stream", false, "")
	flag.BoolVar(&noSortFlag, "no-sort", false, "")
	flag.BoolVar(&versionFlag, "version", false, "")
	flag.BoolVar(&insecureFlag, "k", false, "")
	flag.BoolVar(&insecureFlag, "insecure", false, "")
	flag.BoolVar(&jsonFlag, "j", false, "")
	flag.BoolVar(&jsonFlag, "json", false, "")

	flag.Parse()

	// Print version information
	if versionFlag {
		fmt.Printf("gron version %s\n", gronVersion)
		os.Exit(exitOK)
	}

	// Determine what the program's input should be:
	// file, HTTP URL or stdin
	var rawInput io.Reader
	filename := flag.Arg(0)
	if filename == "" || filename == "-" {
		rawInput = os.Stdin
	} else if validURL(filename) {
		r, err := getURL(filename, insecureFlag)
		if err != nil {
			fatal(exitFetchURL, err)
		}
		rawInput = r
	} else {
		r, err := os.Open(filename)
		if err != nil {
			fatal(exitOpenFile, err)
		}
		rawInput = r
	}

	var opts int
	// The monochrome option should be forced if the output isn't a terminal
	// to avoid doing unnecessary work calling the color functions
	switch {
	case colorizeFlag:
		color.NoColor = false
	case monochromeFlag || color.NoColor:
		opts = opts | optMonochrome
	}
	if noSortFlag {
		opts = opts | optNoSort
	}
	if jsonFlag {
		opts = opts | optJSON
	}

	// Pick the appropriate action: gron, ungron or gronStream
	var a actionFn = gron
	if ungronFlag {
		a = ungron
	} else if streamFlag {
		a = gronStream
	}
	exitCode, err := a(rawInput, colorable.NewColorableStdout(), opts)

	if exitCode != exitOK {
		fatal(exitCode, err)
	}

	os.Exit(exitOK)
}

// an actionFn represents a main action of the program, it accepts
// an input, output and a bitfield of options; returning an exit
// code and any error that occurred
type actionFn func(io.Reader, io.Writer, int) (int, error)

// gron is the default action. Given JSON as the input it returns a list
// of assignment statements. Possible options are optNoSort and optMonochrome
func gron(r io.Reader, w io.Writer, opts int) (int, error) {
	var err error

	var conv statementconv
	if opts&optMonochrome > 0 {
		conv = statementToString
	} else {
		conv = statementToColorString
	}

	ss, err := statementsFromJSON(r, statement{{"json", typBare}})
	if err != nil {
		goto out
	}

	// Go's maps do not have well-defined ordering, but we want a consistent
	// output for a given input, so we must sort the statements
	if opts&optNoSort == 0 {
		sort.Sort(ss)
	}

	for _, s := range ss {
		if opts&optJSON > 0 {
			s, err = s.jsonify()
			if err != nil {
				goto out
			}
		}
		fmt.Fprintln(w, conv(s))
	}

out:
	if err != nil {
		return exitFormStatements, fmt.Errorf("failed to form statements: %s", err)
	}
	return exitOK, nil
}

// gronStream is like the gron action, but it treats the input as one
// JSON object per line. There's a bit of code duplication from the
// gron action, but it'd be fairly messy to combine the two actions
func gronStream(r io.Reader, w io.Writer, opts int) (int, error) {
	var err error
	errstr := "failed to form statements"
	var i int
	var sc *bufio.Scanner
	var buf []byte

	var conv func(s statement) string
	if opts&optMonochrome > 0 {
		conv = statementToString
	} else {
		conv = statementToColorString
	}

	// Helper function to make the prefix statements for each line
	makePrefix := func(index int) statement {
		return statement{
			{"json", typBare},
			{"[", typLBrace},
			{fmt.Sprintf("%d", index), typNumericKey},
			{"]", typRBrace},
		}
	}

	// The first line of output needs to establish that the top-level
	// thing is actually an array...
	top := statement{
		{"json", typBare},
		{"=", typEquals},
		{"[]", typEmptyArray},
		{";", typSemi},
	}

	if opts&optJSON > 0 {
		top, err = top.jsonify()
		if err != nil {
			goto out
		}
	}

	fmt.Fprintln(w, conv(top))

	// Read the input line by line
	sc = bufio.NewScanner(r)
	buf = make([]byte, 0, 64*1024)
	sc.Buffer(buf, 1024*1024)
	i = 0
	for sc.Scan() {

		line := bytes.NewBuffer(sc.Bytes())

		var ss statements
		ss, err = statementsFromJSON(line, makePrefix(i))
		i++
		if err != nil {
			goto out
		}

		// Go's maps do not have well-defined ordering, but we want a consistent
		// output for a given input, so we must sort the statements
		if opts&optNoSort == 0 {
			sort.Sort(ss)
		}

		for _, s := range ss {
			if opts&optJSON > 0 {
				s, err = s.jsonify()
				if err != nil {
					goto out
				}

			}
			fmt.Fprintln(w, conv(s))
		}
	}
	if err = sc.Err(); err != nil {
		errstr = "error reading multiline input: %s"
	}

out:
	if err != nil {
		return exitFormStatements, fmt.Errorf(errstr+": %s", err)
	}
	return exitOK, nil

}

// ungron is the reverse of gron. Given assignment statements as input,
// it returns JSON. The only option is optMonochrome
func ungron(r io.Reader, w io.Writer, opts int) (int, error) {
	scanner := bufio.NewScanner(r)
	var maker statementmaker

	if opts&optJSON > 0 {
		maker = statementFromJSONSpec
	} else {
		maker = statementFromStringMaker
	}

	// Make a list of statements from the input
	var ss statements
	for scanner.Scan() {
		s, err := maker(scanner.Text())
		if err != nil {
			return exitParseStatements, err
		}
		ss.add(s)
	}
	if err := scanner.Err(); err != nil {
		return exitReadInput, fmt.Errorf("failed to read input statements")
	}

	// turn the statements into a single merged interface{} type
	merged, err := ss.toInterface()
	if err != nil {
		return exitParseStatements, err
	}

	// If there's only one top level key and it's "json", make that the top level thing
	mergedMap, ok := merged.(map[string]interface{})
	if ok {
		if len(mergedMap) == 1 {
			if _, exists := mergedMap["json"]; exists {
				merged = mergedMap["json"]
			}
		}
	}

	// Marshal the output into JSON to display to the user
	out := &bytes.Buffer{}
	enc := json.NewEncoder(out)
	enc.SetIndent("", "  ")
	enc.SetEscapeHTML(false)
	err = enc.Encode(merged)
	if err != nil {
		return exitJSONEncode, errors.Wrap(err, "failed to convert statements to JSON")
	}
	j := out.Bytes()

	// If the output isn't monochrome, add color to the JSON
	if opts&optMonochrome == 0 {
		c, err := colorizeJSON(j)

		// If we failed to colorize the JSON for whatever reason,
		// we'll just fall back to monochrome output, otherwise
		// replace the monochrome JSON with glorious technicolor
		if err == nil {
			j = c
		}
	}

	// For whatever reason, the monochrome version of the JSON
	// has a trailing newline character, but the colorized version
	// does not. Strip the whitespace so that neither has the newline
	// character on the end, and then we'll add a newline in the
	// Fprintf below
	j = bytes.TrimSpace(j)

	fmt.Fprintf(w, "%s\n", j)

	return exitOK, nil
}

func colorizeJSON(src []byte) ([]byte, error) {
	out := &bytes.Buffer{}
	f := jsoncolor.NewFormatter()

	f.StringColor = strColor
	f.ObjectColor = braceColor
	f.ArrayColor = braceColor
	f.FieldColor = bareColor
	f.NumberColor = numColor
	f.TrueColor = boolColor
	f.FalseColor = boolColor
	f.NullColor = boolColor

	err := f.Format(out, src)
	if err != nil {
		return out.Bytes(), err
	}
	return out.Bytes(), nil
}

func fatal(code int, err error) {
	fmt.Fprintf(os.Stderr, "%s\n", err)
	os.Exit(code)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gopkg.in/v1/yaml"
	"io/ioutil"
	"os"
	"path"
)

var commands = map[string]string{
	"help":    "helps you out when in dire need of information",
	"token":   "outputs the secret API token",
	"version": "outputs the client version",
}

const (
	version = "0.0.1dev"
)

type ConfigEndpoint struct {
	AccessToken string "access_token"
}

type ConfigLastCheck struct {
	Etag    string "etag"
	Version string "version"
	At      int    "at"
}

type Config struct {
	LastCheck         ConfigLastCheck           "last_check"
	CheckedCompletion bool                      "checked_completion"
	CompletionVersion string                    "completion_version"
	Endpoints         map[string]ConfigEndpoint "endpoints"
}

func (config Config) Copy() Config {
	return config
}

var config = Config{}
var original_config = Config{}
var access_token string
var isDebug bool

func main() {
	if len(os.Args) > 1 {
		isDebug = containts(os.Args, "--debug")
		switch os.Args[1] {
		default:
			fmt.Printf("unknown command %s\n", os.Args[1])
			os.Exit(1)
		case "help":
			RunHelp()
		case "token":
			RunToken()
		case "version":
			RunVersion()
		case "load_config":
			LoadConfig()
		}
	} else {
		RunHelp()
	}
}

func RunHelp() {
	fmt.Println("Usage: travis COMMAND ...\n\nAvailable commands:\n")
	for command, description := range commands {
		fmt.Printf("\t%s\t%s\n",
			ColorCommand(command),
			ColorInfo(description))
	}
	fmt.Printf("\nrun `%s help COMMAND` for more infos\n", os.Args[0])
}

func RunVersion() {
	fmt.Println(version)
}

func RunToken() {

	if access_token == "" {
		fmt.Fprintf(os.Stderr,
			ColorError("not logged in, please run %s\n"),
			command("login"))
		os.Exit(1)
	} else {
		fmt.Printf("Your access token is %s\n", ColotImportant(access_token))
	}
}

func authenticate() {

}

func fetchToken() string {
	token := os.Getenv("TRAVIS_TOKEN")
	return token
}

func command(name string) string {
	return ColorCommand(fmt.Sprintf("%s %s", os.Args[0], name))
}

func debug(line string) {
	if !isDebug {
		return
	}
	fmt.Fprintln(os.Stderr, ColorDebug(fmt.Sprintf("** %s", line)))
}

func warn(line string) {
	fmt.Fprintln(os.Stderr, ColorError(line))
}

func ColorCommand(s string) string {
	return fmt.Sprintf("\x1b[1m%s\x1b[0m", s)
}

func ColorInfo(s string) string {
	return fmt.Sprintf("\x1b[33m%s\x1b[0m", s)
}

func ColotImportant(s string) string {
	return fmt.Sprintf("\x1b[1;4m%s\x1b[0m", s)
}

func ColorError(s string) string {
	return fmt.Sprintf("\x1b[31m%s\x1b[0m", s)
}

func ColorDebug(s string) string {
	return fmt.Sprintf("\x1b[35m%s\x1b[0m", s)
}
func LoadConfig() {
	data, err := loadFile("config.yml")
	if err != nil {
		if !os.IsNotExist(err) {
			exitIfErr(err)
		}
	} else {
		err = yaml.Unmarshal(data, &config)
		exitIfErr(err)
		fmt.Println(config)
		original_config = config.Copy()
	}
}

func loadFile(name string) ([]byte, error) {
	config_path := configPath(name)
	debug(fmt.Sprintf("Loading ‘%s‘", config_path))
	return ioutil.ReadFile(config_path)
}

func containts(slice []string, element string) bool {
	for _, e := range slice {
		if element == e {
			return true
		}
	}
	return false
}

func configPath(name string) string {
	config_path := os.Getenv("TRAVIS_CONFIG_PATH")
	if config_path == "" {
		config_path = path.Join(os.Getenv("HOME"), ".travis")
	}

	err := os.MkdirAll(config_path, 0700)
	exitIfErr(err)

	return path.Join(config_path, "config.yml")
}

func exitIfErr(err error) {
	if err != nil {
		warn(fmt.Sprint(err))
		os.Exit(1)
	}
}
<commit_msg>Update cmd token to receive token from default endpoint.<commit_after>package main

import (
	"fmt"
	"gopkg.in/v1/yaml"
	"io/ioutil"
	"os"
	"path"
)

var commands = map[string]string{
	"help":    "helps you out when in dire need of information",
	"token":   "outputs the secret API token",
	"version": "outputs the client version",
}

const (
	version = "0.0.1dev"
	ORG_URI = "https://api.travis-ci.org/"
	PRO_URI = "https://api.travis-ci.com/"
)

type EndpointConfig struct {
	AccessToken string "access_token"
}

type LastCheckConfig struct {
	Etag    string "etag"
	Version string "version"
	At      int    "at"
}

type Config struct {
	LastCheck         LastCheckConfig            "last_check"
	CheckedCompletion bool                       "checked_completion"
	CompletionVersion string                     "completion_version"
	Endpoints         map[string]*EndpointConfig "endpoints"
}

func (config Config) Copy() Config {
	return config
}

var config = Config{}
var original_config = Config{}
var access_token string
var isDebug bool
var api_endpoint = ORG_URI // TODO: Fetch from session

func main() {
	if len(os.Args) > 1 {
		isDebug = containts(os.Args, "--debug")
		switch os.Args[1] {
		default:
			fmt.Printf("unknown command %s\n", os.Args[1])
			os.Exit(1)
		case "help":
			RunHelp()
		case "token":
			apiExecute(RunToken)
		case "version":
			RunVersion()
		case "load_config":
			LoadConfig()
		}
	} else {
		RunHelp()
	}
}

func RunHelp() {
	fmt.Println("Usage: travis COMMAND ...\n\nAvailable commands:\n")
	for command, description := range commands {
		fmt.Printf("\t%s\t%s\n",
			ColorCommand(command),
			ColorInfo(description))
	}
	fmt.Printf("\nrun `%s help COMMAND` for more infos\n", os.Args[0])
}

func RunVersion() {
	fmt.Println(version)
}

func RunToken() {
	authenticate()
	fmt.Printf("Your access token is %s\n", ColotImportant(access_token))
}

func authenticate() {
	if access_token == "" {
		fmt.Fprintf(os.Stderr,
			ColorError("not logged in, please run %s\n"),
			command("login"))
		os.Exit(1)
	}
}

func fetchToken() string {
	token := os.Getenv("TRAVIS_TOKEN")
	if token == "" {
		return endpoint_config().AccessToken
	}
	return token
}

func endpoint_config() *EndpointConfig {
	if config.Endpoints == nil {
		config.Endpoints = make(map[string]*EndpointConfig)
	}

	if endpoint, found := config.Endpoints[api_endpoint]; found {
		return endpoint
	}

	config.Endpoints[api_endpoint] = &EndpointConfig{}
	return config.Endpoints[api_endpoint]
}

func command(name string) string {
	return ColorCommand(fmt.Sprintf("%s %s", os.Args[0], name))
}

func debug(line string) {
	if !isDebug {
		return
	}
	fmt.Fprintln(os.Stderr, ColorDebug(fmt.Sprintf("** %s", line)))
}

func warn(line string) {
	fmt.Fprintln(os.Stderr, ColorError(line))
}

func ColorCommand(s string) string {
	return fmt.Sprintf("\x1b[1m%s\x1b[0m", s)
}

func ColorInfo(s string) string {
	return fmt.Sprintf("\x1b[33m%s\x1b[0m", s)
}

func ColotImportant(s string) string {
	return fmt.Sprintf("\x1b[1;4m%s\x1b[0m", s)
}

func ColorError(s string) string {
	return fmt.Sprintf("\x1b[31m%s\x1b[0m", s)
}

func ColorDebug(s string) string {
	return fmt.Sprintf("\x1b[35m%s\x1b[0m", s)
}
func LoadConfig() {
	data, err := loadFile("config.yml")
	if err != nil {
		if !os.IsNotExist(err) {
			exitIfErr(err)
		}
	} else {
		err = yaml.Unmarshal(data, &config)
		exitIfErr(err)

		original_config = config.Copy()
	}
}

func loadFile(name string) ([]byte, error) {
	config_path := configPath(name)
	debug(fmt.Sprintf("Loading ‘%s‘", config_path))
	return ioutil.ReadFile(config_path)
}

func containts(slice []string, element string) bool {
	for _, e := range slice {
		if element == e {
			return true
		}
	}
	return false
}

func configPath(name string) string {
	config_path := os.Getenv("TRAVIS_CONFIG_PATH")
	if config_path == "" {
		config_path = path.Join(os.Getenv("HOME"), ".travis")
	}

	err := os.MkdirAll(config_path, 0700)
	exitIfErr(err)

	return path.Join(config_path, "config.yml")
}

func exitIfErr(err error) {
	if err != nil {
		warn(fmt.Sprint(err))
		os.Exit(1)
	}
}

func execute(cmd func()) {
	// setup_trap
	// check_ruby
	// check_arity(method(:run), *arguments)
	LoadConfig()
	// check_version
	// check_completion
	// setup
	cmd()
	// clear_error
	// store_config
	// rescue Travis::Client::NotLoggedIn => e
	// raise(e) if explode?
	// error "#{e.message} - try running #{command("login#{endpoint_option}")}"
	// rescue StandardError => e
	// raise(e) if explode?
	// message = e.message
	// message += color("\nfor a full error report, run #{command("report#{endpoint_option}")}", :error) if interactive?
	// store_error(e)
	// error(message)

}

func apiSetup() {
	// setup_enterprise
	// self.api_endpoint = default_endpoint if default_endpoint and not explicit_api_endpoint?
	access_token = fetchToken()
	if endpoint_config().AccessToken == "" {
		endpoint_config().AccessToken = access_token
	}
	// endpoint_config['access_token'] ||= access_token
	// endpoint_config['insecure']       = insecure unless insecure.nil?
	// self.insecure                     = endpoint_config['insecure']
	// session.ssl                       = { :verify => false } if insecure?
	// authenticate if pro? or enterprise?

	data, err := yaml.Marshal(&config)
	if err != nil {
		// log.Fatalf("error: %v", err)
	}
	fmt.Print(string(data))
}

func apiExecute(cmd func()) {
	execute(func() {
		apiSetup()
		cmd()
	})
}
<|endoftext|>