<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/craigfurman/woodhouse-ci/builds"
	"github.com/craigfurman/woodhouse-ci/db"
	"github.com/craigfurman/woodhouse-ci/jobs"
	"github.com/craigfurman/woodhouse-ci/runner"
	"github.com/craigfurman/woodhouse-ci/web"

	"github.com/codegangsta/negroni"
)

func main() {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	must(err)
	distBase := filepath.Join(dir, "..")

	port := flag.Uint("port", 8080, "port to listen on")
	templateDir := flag.String("templateDir", filepath.Join(distBase, "web", "templates"), "path to html templates")
	storeDir := flag.String("storeDir", filepath.Join(distBase, "db"), "directory for saving persistent data")
	buildsDir := flag.String("buildsDir", filepath.Join(distBase, "builds"), "directory for saving build output")
	assetsDir := flag.String("assetsDir", filepath.Join(distBase, "web", "assets"), "path to static web assets")
	gooseCmd := flag.String("gooseCmd", filepath.Join(distBase, "bin", "goose"), `path to "goose" database migration tool`)
	flag.Parse()

	dbDir := filepath.Join(*storeDir, "sqlite")
	must(os.MkdirAll(dbDir, 0755))

	migrateCmd := exec.Command(*gooseCmd, "up")
	migrateCmd.Dir = filepath.Join(*storeDir, "..")
	must(migrateCmd.Run())

	jobRepo, err := db.NewJobRepository(filepath.Join(dbDir, "store.db"))
	must(err)

	handler := web.New(&jobs.Service{
		JobRepository: jobRepo,
		Runner:        runner.NewDockerRunner(),
		BuildRepository: &builds.Repository{
			BuildsDir: *buildsDir,
		},
	}, *templateDir)

	server := negroni.New(negroni.NewRecovery(), negroni.NewLogger(), negroni.NewStatic(http.Dir(*assetsDir)))
	server.UseHandler(handler)
	server.Run(fmt.Sprintf("0.0.0.0:%d", *port))
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>set GOMAXPROCS to number of logical CPUs at startup<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/craigfurman/woodhouse-ci/builds"
	"github.com/craigfurman/woodhouse-ci/db"
	"github.com/craigfurman/woodhouse-ci/jobs"
	"github.com/craigfurman/woodhouse-ci/runner"
	"github.com/craigfurman/woodhouse-ci/web"

	"github.com/codegangsta/negroni"
)

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

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	must(err)
	distBase := filepath.Join(dir, "..")

	port := flag.Uint("port", 8080, "port to listen on")
	templateDir := flag.String("templateDir", filepath.Join(distBase, "web", "templates"), "path to html templates")
	storeDir := flag.String("storeDir", filepath.Join(distBase, "db"), "directory for saving persistent data")
	buildsDir := flag.String("buildsDir", filepath.Join(distBase, "builds"), "directory for saving build output")
	assetsDir := flag.String("assetsDir", filepath.Join(distBase, "web", "assets"), "path to static web assets")
	gooseCmd := flag.String("gooseCmd", filepath.Join(distBase, "bin", "goose"), `path to "goose" database migration tool`)
	flag.Parse()

	dbDir := filepath.Join(*storeDir, "sqlite")
	must(os.MkdirAll(dbDir, 0755))

	migrateCmd := exec.Command(*gooseCmd, "up")
	migrateCmd.Dir = filepath.Join(*storeDir, "..")
	must(migrateCmd.Run())

	jobRepo, err := db.NewJobRepository(filepath.Join(dbDir, "store.db"))
	must(err)

	handler := web.New(&jobs.Service{
		JobRepository: jobRepo,
		Runner:        runner.NewDockerRunner(),
		BuildRepository: &builds.Repository{
			BuildsDir: *buildsDir,
		},
	}, *templateDir)

	server := negroni.New(negroni.NewRecovery(), negroni.NewLogger(), negroni.NewStatic(http.Dir(*assetsDir)))
	server.UseHandler(handler)
	server.Run(fmt.Sprintf("0.0.0.0:%d", *port))
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/manabu/dockerlayer/cmd"
	"github.com/manabu/dockerlayer/config"
)

const version = "0.1.3-dev"

func init() {
	config.VersionString = version
}

func main() {
	if err := cmd.RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}
<commit_msg>release 0.1.3<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/manabu/dockerlayer/cmd"
	"github.com/manabu/dockerlayer/config"
)

const version = "0.1.3"

func init() {
	config.VersionString = version
}

func main() {
	if err := cmd.RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"

	auth "github.com/abbot/go-http-auth"
)

type SubnetRoute struct {
	inside, outside http.Handler
	*net.IPNet
}

func (s *SubnetRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	ip := net.ParseIP(host)
	if ip == nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	if s.Contains(ip) {
		s.inside.ServeHTTP(w, r)
	} else {
		s.outside.ServeHTTP(w, r)
	}
}

func main() {
	var (
		listen, cert, key, htpasswdFile, where, subnet string
	)
	flag.StringVar(&listen, "listen", ":443", "Bind address to listen on")
	flag.StringVar(&key, "key", "/etc/ssl/private/key.pem", "Path to PEM key")
	flag.StringVar(&cert, "cert", "/etc/ssl/private/cert.pem", "Path to PEM certificate")
	flag.StringVar(&htpasswdFile, "htpasswdFile", "", "File to use for htpasswd protected access")
	flag.StringVar(&where, "where", "http://localhost:80", "Place to forward connections to")
	flag.StringVar(&subnet, "subnet", "", "If specified, subnet which can circumvent htpasswd authorization")
	flag.Parse()

	url, err := url.Parse(where)
	if err != nil {
		log.Fatalln("Fatal parsing -where:", err)
	}

	var ipNet *net.IPNet
	if subnet != "" {
		_, ipNet, err = net.ParseCIDR(subnet)
		if err != nil {
			log.Fatalln("Error parsing -subnet:", err)
		}
	}

	proxy := NewWebsocketCapableReverseProxy(url)

	var handler, authenticated http.Handler

	handler = proxy

	// Only really authenticated if htpasswdFile is specified
	authenticated = handler

	if htpasswdFile != "" {
		// First check that the htpasswdFile exists and is readable
		fd, err := os.Open(htpasswdFile)
		if err != nil {
			log.Fatalln("Error opening htpasswdFile:", err)
		}
		fd.Close()

		secrets := auth.HtpasswdFileProvider(htpasswdFile)
		authenticator := auth.NewBasicAuthenticator(where, secrets)
		authenticated = auth.JustCheck(authenticator, handler.ServeHTTP)
	}

	if subnet != "" {
		handler = &SubnetRoute{handler, authenticated, ipNet}
	} else {
		handler = authenticated
	}

	config := &tls.Config{
		MinVersion: tls.VersionTLS10,
		CipherSuites: []uint16{
			// Note: RC4 is removed.
			tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		},
	}
	server := &http.Server{Addr: listen, Handler: handler, TLSConfig: config}
	err = server.ListenAndServeTLS(cert, key)
	if err != nil {
		log.Fatalln("http.ListenAndServeTLS:", err)
	}
}
<commit_msg>Add the -tls flag<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"

	auth "github.com/abbot/go-http-auth"
)

type SubnetRoute struct {
	inside, outside http.Handler
	*net.IPNet
}

func (s *SubnetRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	host, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	ip := net.ParseIP(host)
	if ip == nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	if s.Contains(ip) {
		s.inside.ServeHTTP(w, r)
	} else {
		s.outside.ServeHTTP(w, r)
	}
}

func main() {
	var (
		listen, cert, key, htpasswdFile, where, subnet string
		tlsFlag                                        bool
	)
	flag.StringVar(&listen, "listen", ":443", "Bind address to listen on")
	flag.StringVar(&key, "key", "/etc/ssl/private/key.pem", "Path to PEM key")
	flag.StringVar(&cert, "cert", "/etc/ssl/private/cert.pem", "Path to PEM certificate")
	flag.StringVar(&htpasswdFile, "htpasswdFile", "", "File to use for htpasswd protected access")
	flag.StringVar(&where, "where", "http://localhost:80", "Place to forward connections to")
	flag.StringVar(&subnet, "subnet", "", "If specified, subnet which can circumvent htpasswd authorization")
	flag.BoolVar(&tlsFlag, "tls", true, "accept HTTPS connections")
	flag.Parse()

	url, err := url.Parse(where)
	if err != nil {
		log.Fatalln("Fatal parsing -where:", err)
	}

	var ipNet *net.IPNet
	if subnet != "" {
		_, ipNet, err = net.ParseCIDR(subnet)
		if err != nil {
			log.Fatalln("Error parsing -subnet:", err)
		}
	}

	proxy := NewWebsocketCapableReverseProxy(url)

	var handler, authenticated http.Handler

	handler = proxy

	// Only really authenticated if htpasswdFile is specified
	authenticated = handler

	if htpasswdFile != "" {
		// First check that the htpasswdFile exists and is readable
		fd, err := os.Open(htpasswdFile)
		if err != nil {
			log.Fatalln("Error opening htpasswdFile:", err)
		}
		fd.Close()

		secrets := auth.HtpasswdFileProvider(htpasswdFile)
		authenticator := auth.NewBasicAuthenticator(where, secrets)
		authenticated = auth.JustCheck(authenticator, handler.ServeHTTP)
	}

	if subnet != "" {
		handler = &SubnetRoute{handler, authenticated, ipNet}
	} else {
		handler = authenticated
	}

	config := &tls.Config{
		MinVersion: tls.VersionTLS10,
		CipherSuites: []uint16{
			// Note: RC4 is removed.
			tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
		},
	}

	server := &http.Server{Addr: listen, Handler: handler, TLSConfig: config}
	if tlsFlag {
		err = server.ListenAndServeTLS(cert, key)
		if err != nil {
			log.Fatalln("http.ListenAndServeTLS:", err)
		}
	} else {
		err = server.ListenAndServe()
		if err != nil {
			log.Fatalln("http.ListenAndServe:", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import "krishnak.org/krishproxy/server"

func main() {
	gameServer := server.NewGameServer()
	gameServer.Start("", 4500)
}
<commit_msg>Updates package path after GitHub migration.<commit_after>package main

import "github.com/untermina/krishproxy/server"

func main() {
	gameServer := server.NewGameServer()
	gameServer.Start("", 4500)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"strings"
)

type proxii struct {
	config *Config
	etcd   *etcdConnector
}

func (p *proxii) handler(w http.ResponseWriter, r *http.Request) {
	host := strings.Split(r.Host, ":")[0]

	uri, err := p.etcd.resolve(host)
	if err != nil {
		log.Println("Error while looking up host: ", err)
		return
	}

	proxy := newReverseProxy(uri)
	proxy.ServeHTTP(w, r)
}

func main() {
	p := newProxii(parseFlags())
	http.HandleFunc("/", p.handler)

	err := http.ListenAndServe(fmt.Sprintf(":%d", p.config.port), nil)
	if err != nil {
		log.Fatal(err)
	}
}

func newProxii(config *Config) *proxii {
	etcd, err := newEtcdConnector(config)
	if err != nil {
		panic(err)
	}

	etcd.init()
	return &proxii{config, etcd}
}
<commit_msg>Didn't run tests before<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

type proxii struct {
	config *Config
	etcd   *etcdConnector
}

func (p *proxii) handler(w http.ResponseWriter, r *http.Request) {
	host := strings.Split(r.Host, ":")[0]

	uri, err := p.etcd.resolve(host)
	if err != nil {
		log.Println("Error while looking up host: ", err)
		return
	}

	proxy := newReverseProxy(uri)
	proxy.ServeHTTP(w, r)
}

func main() {
	p := newProxii(parseFlags())
	http.HandleFunc("/", p.handler)

	err := http.ListenAndServe(fmt.Sprintf(":%d", p.config.port), nil)
	if err != nil {
		log.Fatal(err)
	}
}

func newProxii(config *Config) *proxii {
	etcd, err := newEtcdConnector(config)
	if err != nil {
		panic(err)
	}

	etcd.init()
	return &proxii{config, etcd}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/opencredo/terrahelp/terrahelp"
)

func main() {

	app := cli.NewApp()
	app.Name = "terrahelp"
	app.Usage = "Provides additional functions helpful with terraform development"
	app.Version = "0.4.2"
	app.Author = "https://github.com/opencredo OpenCredo - Nicki Watt"
	app.Commands = []cli.Command{
		vaultAutoConfigCommand(newTerraHelperFunc()),
		encryptCommand(newTerraHelperFunc()),
		decryptCommand(newTerraHelperFunc()),
		maskCommand(),
	}
	app.Run(os.Args)
}

func newTerraHelperFunc() func(provider string) *terrahelp.CryptoHandler {
	return func(provider string) *terrahelp.CryptoHandler {

		switch {
		case (provider == terrahelp.ThEncryptProviderSimple):
			e := terrahelp.NewSimpleEncrypter()
			return &terrahelp.CryptoHandler{Encrypter: e}
		case (provider == terrahelp.ThEncryptProviderVault):
			e, err := terrahelp.NewVaultEncrypter()
			if err != nil {
				exitIfError(err)
			}
			return &terrahelp.CryptoHandler{Encrypter: e}
		case (provider == terrahelp.ThEncryptProviderVaultCli):
			e, err := terrahelp.NewVaultCliEncrypter()
			if err != nil {
				exitIfError(err)
			}
			return &terrahelp.CryptoHandler{Encrypter: e}
		}

		exitIfError(fmt.Errorf("Invalid provider %s specified ", provider))
		return nil
	}
}
<commit_msg>Increase version for next development work<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/opencredo/terrahelp/terrahelp"
)

func main() {

	app := cli.NewApp()
	app.Name = "terrahelp"
	app.Usage = "Provides additional functions helpful with terraform development"
	app.Version = "0.4.3-dev"
	app.Author = "https://github.com/opencredo OpenCredo - Nicki Watt"
	app.Commands = []cli.Command{
		vaultAutoConfigCommand(newTerraHelperFunc()),
		encryptCommand(newTerraHelperFunc()),
		decryptCommand(newTerraHelperFunc()),
		maskCommand(),
	}
	app.Run(os.Args)
}

func newTerraHelperFunc() func(provider string) *terrahelp.CryptoHandler {
	return func(provider string) *terrahelp.CryptoHandler {

		switch {
		case (provider == terrahelp.ThEncryptProviderSimple):
			e := terrahelp.NewSimpleEncrypter()
			return &terrahelp.CryptoHandler{Encrypter: e}
		case (provider == terrahelp.ThEncryptProviderVault):
			e, err := terrahelp.NewVaultEncrypter()
			if err != nil {
				exitIfError(err)
			}
			return &terrahelp.CryptoHandler{Encrypter: e}
		case (provider == terrahelp.ThEncryptProviderVaultCli):
			e, err := terrahelp.NewVaultCliEncrypter()
			if err != nil {
				exitIfError(err)
			}
			return &terrahelp.CryptoHandler{Encrypter: e}
		}

		exitIfError(fmt.Errorf("Invalid provider %s specified ", provider))
		return nil
	}
}
<|endoftext|>


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

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.2"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>cmd/tsuru-admin: version 0.2.1.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.2.1"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

func main() {
	var env = GetEnv()
	var args = os.Args

	err := CommandsDispatch(env, args)
	if err != nil {
		fmt.Sprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>Fixes printing of errors<commit_after>package main

import (
	"fmt"
	"os"
)

func main() {
	var env = GetEnv()
	var args = os.Args

	err := CommandsDispatch(env, args)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"sync"
	"time"

	"github.com/calmh/syncthing/discover"
)

type Node struct {
	IP      []byte
	Port    uint16
	Updated time.Time
}

var (
	nodes   = make(map[string]Node)
	lock    sync.Mutex
	queries = 0
)

func main() {
	addr, _ := net.ResolveUDPAddr("udp", ":22025")
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		panic(err)
	}

	go func() {
		for {
			time.Sleep(600 * time.Second)

			lock.Lock()

			var deleted = 0
			for id, node := range nodes {
				if time.Since(node.Updated) > 60*time.Minute {
					delete(nodes, id)
					deleted++
				}
			}
			log.Printf("Expired %d nodes; %d nodes in registry; %d queries", deleted, len(nodes), queries)
			queries = 0

			lock.Unlock()
		}
	}()

	var buf = make([]byte, 1024)
	for {
		n, addr, err := conn.ReadFromUDP(buf)
		if err != nil {
			panic(err)
		}
		pkt, err := discover.DecodePacket(buf[:n])
		if err != nil {
			log.Println("Warning:", err)
			continue
		}

		switch pkt.Magic {
		case 0x20121025:
			// Announcement
			lock.Lock()
			ip := addr.IP.To4()
			if ip == nil {
				ip = addr.IP.To16()
			}
			node := Node{
				IP:      ip,
				Port:    uint16(pkt.Port),
				Updated: time.Now(),
			}
			//log.Println("<-", pkt.ID, node)
			nodes[pkt.ID] = node
			lock.Unlock()
		case 0x19760309:
			// Query
			lock.Lock()
			node, ok := nodes[pkt.ID]
			queries++
			lock.Unlock()
			if ok {
				pkt := discover.Packet{
					Magic: 0x20121025,
					ID:    pkt.ID,
					Port:  node.Port,
					IP:    node.IP,
				}
				_, _, err = conn.WriteMsgUDP(discover.EncodePacket(pkt), nil, addr)
				if err != nil {
					log.Println("Warning:", err)
				}
			}
		}
	}
}
<commit_msg>Rework XDR encoding<commit_after>package main

import (
	"encoding/binary"
	"encoding/hex"
	"flag"
	"log"
	"net"
	"os"
	"sync"
	"time"

	"github.com/calmh/syncthing/discover"
)

type Node struct {
	Addresses []Address
	Updated   time.Time
}

type Address struct {
	IP   []byte
	Port uint16
}

var (
	nodes    = make(map[string]Node)
	lock     sync.Mutex
	queries  = 0
	answered = 0
)

func main() {
	var debug bool
	var listen string
	var timestamp bool

	flag.StringVar(&listen, "listen", ":22025", "Listen address")
	flag.BoolVar(&debug, "debug", false, "Enable debug output")
	flag.BoolVar(&timestamp, "timestamp", true, "Timestamp the log output")
	flag.Parse()

	log.SetOutput(os.Stdout)
	if !timestamp {
		log.SetFlags(0)
	}

	addr, _ := net.ResolveUDPAddr("udp", listen)
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		panic(err)
	}

	go func() {
		for {
			time.Sleep(600 * time.Second)

			lock.Lock()

			var deleted = 0
			for id, node := range nodes {
				if time.Since(node.Updated) > 60*time.Minute {
					delete(nodes, id)
					deleted++
				}
			}
			log.Printf("Expired %d nodes; %d nodes in registry; %d queries (%d answered)", deleted, len(nodes), queries, answered)
			queries = 0
			answered = 0

			lock.Unlock()
		}
	}()

	var buf = make([]byte, 1024)
	for {
		buf = buf[:cap(buf)]
		n, addr, err := conn.ReadFromUDP(buf)
		if err != nil {
			panic(err)
		}
		if n < 4 {
			log.Printf("Received short packet (%d bytes)", n)
			continue
		}

		buf = buf[:n]
		magic := binary.BigEndian.Uint32(buf)

		switch magic {
		case discover.AnnouncementMagicV1:
			var pkt discover.AnnounceV1
			err := pkt.UnmarshalXDR(buf)
			if err != nil {
				log.Println("AnnounceV1 Unmarshal:", err)
				log.Println(hex.Dump(buf))
				continue
			}
			if debug {
				log.Printf("<- %v %#v", addr, pkt)
			}

			ip := addr.IP.To4()
			if ip == nil {
				ip = addr.IP.To16()
			}
			node := Node{
				Addresses: []Address{{
					IP:   ip,
					Port: pkt.Port,
				}},
				Updated: time.Now(),
			}

			lock.Lock()
			nodes[pkt.NodeID] = node
			lock.Unlock()

		case discover.QueryMagicV1:
			var pkt discover.QueryV1
			err := pkt.UnmarshalXDR(buf)
			if err != nil {
				log.Println("QueryV1 Unmarshal:", err)
				log.Println(hex.Dump(buf))
				continue
			}
			if debug {
				log.Printf("<- %v %#v", addr, pkt)
			}

			lock.Lock()
			node, ok := nodes[pkt.NodeID]
			queries++
			lock.Unlock()

			if ok && len(node.Addresses) > 0 {
				pkt := discover.AnnounceV1{
					Magic:  discover.AnnouncementMagicV1,
					NodeID: pkt.NodeID,
					Port:   node.Addresses[0].Port,
					IP:     node.Addresses[0].IP,
				}
				if debug {
					log.Printf("-> %v %#v", addr, pkt)
				}

				tb := pkt.MarshalXDR()
				_, _, err = conn.WriteMsgUDP(tb, nil, addr)
				if err != nil {
					log.Println("QueryV1 response write:", err)
				}

				lock.Lock()
				answered++
				lock.Unlock()
			}

		case discover.AnnouncementMagicV2:
			var pkt discover.AnnounceV2
			err := pkt.UnmarshalXDR(buf)
			if err != nil {
				log.Println("AnnounceV2 Unmarshal:", err)
				log.Println(hex.Dump(buf))
				continue
			}
			if debug {
				log.Printf("<- %v %#v", addr, pkt)
			}

			ip := addr.IP.To4()
			if ip == nil {
				ip = addr.IP.To16()
			}

			var addrs []Address
			for _, addr := range pkt.Addresses {
				tip := addr.IP
				if len(tip) == 0 {
					tip = ip
				}
				addrs = append(addrs, Address{
					IP:   tip,
					Port: addr.Port,
				})
			}

			node := Node{
				Addresses: addrs,
				Updated:   time.Now(),
			}

			lock.Lock()
			nodes[pkt.NodeID] = node
			lock.Unlock()

		case discover.QueryMagicV2:
			var pkt discover.QueryV2
			err := pkt.UnmarshalXDR(buf)
			if err != nil {
				log.Println("QueryV2 Unmarshal:", err)
				log.Println(hex.Dump(buf))
				continue
			}
			if debug {
				log.Printf("<- %v %#v", addr, pkt)
			}

			lock.Lock()
			node, ok := nodes[pkt.NodeID]
			queries++
			lock.Unlock()

			if ok && len(node.Addresses) > 0 {
				pkt := discover.AnnounceV2{
					Magic:  discover.AnnouncementMagicV2,
					NodeID: pkt.NodeID,
				}
				for _, addr := range node.Addresses {
					pkt.Addresses = append(pkt.Addresses, discover.Address{IP: addr.IP, Port: addr.Port})
				}
				if debug {
					log.Printf("-> %v %#v", addr, pkt)
				}

				tb := pkt.MarshalXDR()
				_, _, err = conn.WriteMsgUDP(tb, nil, addr)
				if err != nil {
					log.Println("QueryV2 response write:", err)
				}

				lock.Lock()
				answered++
				lock.Unlock()
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/nats-io/nats"

	"gopkg.in/mgo.v2"
)

const (
	metricsAPIPath = "/api/metrics"
	agentsAPIPath  = "/api/agents"
)

var (
	// agents collection
	agentsC *mgo.Collection
)

var (
	flagAddr    = flag.String("addr", ":8080", "serve HTTP on `address`")
	flagNatsURL = flag.String("nats", nats.DefaultURL, "nats URL")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("marksman: ")
	flag.Parse()

	http.HandleFunc(metricsAPIPath, metricsHandler)
	http.HandleFunc(agentsAPIPath, agentsHandler)
	http.Handle("/", http.FileServer(http.Dir("./public")))

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	// Optional. Switch the session to a monotonic behavior.
	session.SetMode(mgo.Monotonic, true)
	agentsC = session.DB("recon-dev").C("agents")

	log.Println("Server started: http://localhost" + *flagAddr)
	log.Fatal(http.ListenAndServe(*flagAddr, nil))
}

func metricsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "TODO")
}

func agentsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	switch r.Method {
	case "GET":
		var R []Agent
		err := agentsC.Find(nil).All(&R)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		enc := json.NewEncoder(w)
		if err := enc.Encode(R); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	case "POST":
		var a Agent
		dec := json.NewDecoder(r.Body)
		if err := dec.Decode(&a); err != nil {
			http.Error(w, "unable to decode json", http.StatusBadRequest)
			return
		}
		if a.UID == "" {
			http.Error(w, "UID can't be empty", http.StatusBadRequest)
			return
		}
		err := agentsC.Insert(a)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusCreated)
		nurl := struct {
			NatsURL string `json:"nats_url"`
		}{
			NatsURL: *flagNatsURL,
		}
		enc := json.NewEncoder(w)
		if err := enc.Encode(nurl); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	default:
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}
}

// Agent represents a recon agent running on
// a machine.
type Agent struct {
	UID string
}
<commit_msg>add comments<commit_after>package main

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

	"github.com/nats-io/nats"

	"gopkg.in/mgo.v2"
)

const (
	metricsAPIPath = "/api/metrics"
	agentsAPIPath  = "/api/agents"
)

// TODO: Instead of using a global for each collection,
// abstract this into an interface, which makes it
// easier for testing.
var (
	// agents collection
	agentsC *mgo.Collection
)

// Command line flags
// prepend flag to variable names to not pollute the global namespace.
var (
	flagAddr    = flag.String("addr", ":8080", "serve HTTP on `address`")
	flagNatsURL = flag.String("nats", nats.DefaultURL, "nats URL")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("marksman: ")

	flag.Parse()

	http.HandleFunc(metricsAPIPath, metricsHandler)
	http.HandleFunc(agentsAPIPath, agentsHandler)
	http.Handle("/", http.FileServer(http.Dir("./public")))

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	// Optional. Switch the session to a monotonic behavior.
	session.SetMode(mgo.Monotonic, true)
	agentsC = session.DB("recon-dev").C("agents")

	log.Println("Server started: http://localhost" + *flagAddr)
	log.Fatal(http.ListenAndServe(*flagAddr, nil))
}

func metricsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, "TODO")
}

func agentsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	switch r.Method {
	case "GET":
		var R []Agent
		err := agentsC.Find(nil).All(&R)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		enc := json.NewEncoder(w)
		if err := enc.Encode(R); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	case "POST":
		var a Agent
		dec := json.NewDecoder(r.Body)
		if err := dec.Decode(&a); err != nil {
			http.Error(w, "unable to decode json", http.StatusBadRequest)
			return
		}
		if a.UID == "" {
			http.Error(w, "UID can't be empty", http.StatusBadRequest)
			return
		}
		err := agentsC.Insert(a)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusCreated)
		nurl := struct {
			NatsURL string `json:"nats_url"`
		}{
			NatsURL: *flagNatsURL,
		}
		enc := json.NewEncoder(w)
		if err := enc.Encode(nurl); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	default:
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}
}

// Agent represents a recon agent running on
// a machine.
type Agent struct {
	UID string
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/verath/archipelago/lib"
	"net/http"
	"os"
	"os/signal"
	"time"
)

const (
	httpReadTimeout  = 10 * time.Second
	httpWriteTimeout = 10 * time.Second
)

func main() {
	var (
		debug       bool
		serveStatic bool
		staticPath  string
		serverAddr  string
	)
	flag.BoolVar(&debug, "debug", false, "Set to true to log debug messages.")
	flag.BoolVar(&serveStatic, "servestatic", false, "Enable serving of static assets.")
	flag.StringVar(&staticPath, "staticpath", "./web/dist", "Specifies the path to static assets "+
		"directory. Only applicable if servestatic is true.")
	flag.StringVar(&serverAddr, "addr", ":8080", "TCP address for the http server to listen on.")
	flag.Parse()

	logger := logrus.New()
	logger.Formatter = &logrus.TextFormatter{}
	if debug {
		logger.Level = logrus.DebugLevel
	}

	archipelagoServer, err := archipelago.New(logger)
	if err != nil {
		logger.Fatalf("Error creating game: %+v", err)
	}

	http.Handle("/ws", archipelagoServer.WebsocketHandler())
	if serveStatic {
		http.Handle("/", http.FileServer(http.Dir(staticPath)))
	}
	httpServer := &http.Server{
		Addr:         serverAddr,
		ReadTimeout:  httpReadTimeout,
		WriteTimeout: httpWriteTimeout,
	}

	ctx, cancel := context.WithCancel(lifetimeContext(logger))
	errCh := make(chan error)
	go func() { errCh <- archipelagoServer.Run(ctx) }()
	go func() { errCh <- runHTTPServer(ctx, httpServer) }()
	err = <-errCh
	cancel()
	<-errCh
	if errors.Cause(err) == context.Canceled {
		logger.Debugf("Error caught in main: %+v", err)
	} else {
		logger.Fatalf("Error caught in main: %+v", err)
	}
}

// lifetimeContext returns a context that is cancelled on the first SIGINT or
// SIGKILL signal received. The application is force closed if more than
// one signal is received.
func lifetimeContext(logger *logrus.Logger) context.Context {
	ctx, cancel := context.WithCancel(context.Background())
	stopSigs := make(chan os.Signal, 2)
	signal.Notify(stopSigs, os.Interrupt, os.Kill)
	go func() {
		<-stopSigs
		logger.Info("Caught interrupt, shutting down")
		cancel()
		<-stopSigs
		logger.Fatal("Caught second interrupt, force closing")
	}()
	return ctx
}

// runHTTPServer starts and runs the given HTTP server until either an error
// occurs or the context is cancelled.
func runHTTPServer(ctx context.Context, server *http.Server) error {
	errCh := make(chan error)
	go func() { errCh <- server.ListenAndServe() }()
	select {
	case err := <-errCh:
		return err
	case <-ctx.Done():
		server.Close()
		return ctx.Err()
	}
}
<commit_msg>Explicit max-age=0 when go serving static<commit_after>package main

import (
	"context"
	"flag"
	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/verath/archipelago/lib"
	"net/http"
	"os"
	"os/signal"
	"path"
	"time"
)

const (
	httpReadTimeout  = 10 * time.Second
	httpWriteTimeout = 10 * time.Second
)

func main() {
	var (
		debug       bool
		serveStatic bool
		staticPath  string
		serverAddr  string
	)
	flag.BoolVar(&debug, "debug", false, "Set to true to log debug messages.")
	flag.BoolVar(&serveStatic, "servestatic", false, "Enable serving of static assets.")
	flag.StringVar(&staticPath, "staticpath", "./web/dist", "Specifies the path to static assets "+
		"directory. Only applicable if servestatic is true.")
	flag.StringVar(&serverAddr, "addr", ":8080", "TCP address for the http server to listen on.")
	flag.Parse()

	logger := logrus.New()
	logger.Formatter = &logrus.TextFormatter{}
	if debug {
		logger.Level = logrus.DebugLevel
	}

	archipelagoServer, err := archipelago.New(logger)
	if err != nil {
		logger.Fatalf("Error creating game: %+v", err)
	}

	http.Handle("/ws", archipelagoServer.WebsocketHandler())
	if serveStatic {
		// Explicitly set a max-age of 0 for service worker script.
		http.HandleFunc("/sw.js", func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Cache-Control", "max-age=0")
			http.ServeFile(w, r, path.Join(staticPath, "sw.js"))
		})
		http.Handle("/", http.FileServer(http.Dir(staticPath)))
	}
	httpServer := &http.Server{
		Addr:         serverAddr,
		ReadTimeout:  httpReadTimeout,
		WriteTimeout: httpWriteTimeout,
	}

	ctx, cancel := context.WithCancel(lifetimeContext(logger))
	errCh := make(chan error)
	go func() { errCh <- archipelagoServer.Run(ctx) }()
	go func() { errCh <- runHTTPServer(ctx, httpServer) }()
	err = <-errCh
	cancel()
	<-errCh
	if errors.Cause(err) == context.Canceled {
		logger.Debugf("Error caught in main: %+v", err)
	} else {
		logger.Fatalf("Error caught in main: %+v", err)
	}
}

// lifetimeContext returns a context that is cancelled on the first SIGINT or
// SIGKILL signal received. The application is force closed if more than
// one signal is received.
func lifetimeContext(logger *logrus.Logger) context.Context {
	ctx, cancel := context.WithCancel(context.Background())
	stopSigs := make(chan os.Signal, 2)
	signal.Notify(stopSigs, os.Interrupt, os.Kill)
	go func() {
		<-stopSigs
		logger.Info("Caught interrupt, shutting down")
		cancel()
		<-stopSigs
		logger.Fatal("Caught second interrupt, force closing")
	}()
	return ctx
}

// runHTTPServer starts and runs the given HTTP server until either an error
// occurs or the context is cancelled.
func runHTTPServer(ctx context.Context, server *http.Server) error {
	errCh := make(chan error)
	go func() { errCh <- server.ListenAndServe() }()
	select {
	case err := <-errCh:
		return err
	case <-ctx.Done():
		server.Close()
		return ctx.Err()
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

package main

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"

	"github.com/mk12/lindenmayer/system"
)

// parameters are a collection of accepted URL parameters.
type parameters struct {
	name      string
	depth     string
	thickness string
	color     string
	precision string
	onlySVG   bool
}

// pageData contains information used to render templates.
type pageData struct {
	Name      string
	Query     string
	Thickness string
	Color     string
	Depth     int
	MaxDepth  int
	HasPrev   bool
	HasNext   bool
	SVG       template.HTML
	Systems   []string
}

// systemNames contains the names of the systems shown in the sidebar.
var systemNames = []string{
	"koch", "hilbert", "peano", "gosper", "sierpinski", "rings", "tree",
	"plant", "willow", "dragon", "island",
}

// Limitations on parameters.
const (
	minimumDepth     = 0
	minimumPrecision = 1
	maximumPrecision = 15
)

// Default parameter values.
var defaultParams = parameters{
	name:      "koch",
	depth:     "2",
	thickness: "2.2",
	color:     "black",
	precision: "3",
	onlySVG:   false,
}

// Compile all templates on startup.
var templateSet *template.Template

func init() {
	add := func(a, b int) int { return a + b }
	capitalize := func(s string) string {
		runes := []rune(s)
		runes[0] = unicode.ToUpper(runes[0])
		return string(runes)
	}
	funcs := template.FuncMap{"add": add, "capitalize": capitalize}

	paths := []string{"header", "footer", "index", "404"}
	for i, name := range paths {
		paths[i] = "templates/" + name + ".html"
	}
	templateSet = template.Must(
		template.New("main").Funcs(funcs).ParseFiles(paths...))
}

// display finds a template by name and executes it with the given data.
func display(w http.ResponseWriter, templateName string, data interface{}) {
	err := templateSet.ExecuteTemplate(w, templateName, data)
	if err != nil {
		log.Println("500 Internal Server Error:", err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// fail logs a failure message and responds with a 404 Not Found status.
func fail(w http.ResponseWriter, reason string) {
	log.Println("404 Not Found:", reason)
	w.WriteHeader(http.StatusNotFound)
	display(w, "404", nil)
}

// splitPath returns a slice of URL path segments by splitting on slashes. The
// presence of a leading or trailing slash does not affect the result.
func splitPath(path string) []string {
	segs := strings.Split(path, "/")
	if len(segs) > 0 && segs[0] == "" {
		segs = segs[1:]
	}
	if s := len(segs); s > 0 && segs[s-1] == "" {
		segs = segs[:s-1]
	}
	return segs
}

// parseParams parses the parameters from the URL, and uses defaultParams if
// there are missing values.
func parseParams(href *url.URL) parameters {
	params := defaultParams

	path := splitPath(href.Path)
	if len(path) >= 1 {
		params.name = path[0]
	}
	if len(path) >= 2 {
		params.depth = path[1]
	}

	query := href.Query()
	if thickness := query.Get("t"); thickness != "" {
		params.thickness = thickness
	}
	if color := query.Get("c"); color != "" {
		params.color = color
	}
	if precision := query.Get("p"); precision != "" {
		params.precision = precision
	}
	if onlySVG := query.Get("svg"); onlySVG == "1" {
		params.onlySVG = true
	}

	return params
}

// renderSVG generates the SVG data for the specified curve.
func renderSVG(params parameters) (string, error) {
	sys := system.Named(params.name)
	if sys == nil {
		return "", fmt.Errorf("no system named %q", params.name)
	}

	depth, err := strconv.Atoi(params.depth)
	if err != nil {
		return "", err
	}
	if depth < minimumDepth || depth > sys.MaxDepth() {
		return "", fmt.Errorf("invalid depth %d", depth)
	}

	thickness, err := strconv.ParseFloat(params.thickness, 64)
	if err != nil {
		return "", err
	}
	if thickness <= 0 {
		return "", fmt.Errorf("invalid thickness %f", thickness)
	}

	if params.color == "" {
		return "", fmt.Errorf("invalid color \"\"")
	}

	precision, err := strconv.Atoi(params.precision)
	if err != nil {
		return "", err
	}
	if precision < minimumPrecision || precision > maximumPrecision {
		return "", fmt.Errorf("invalid precision %d", precision)
	}

	opts := system.Options{
		Depth:     depth,
		Thickness: thickness,
		Color:     params.color,
		Precision: precision,
	}
	return sys.SVG(&opts), nil
}

// mainHandler responds to an HTTP request.
func mainHandler(w http.ResponseWriter, req *http.Request) {
	log.SetPrefix(fmt.Sprintf("[%s %s] ", req.Method, req.URL))
	if req.Method != "GET" {
		fail(w, "invalid request method")
		return
	}

	params := parseParams(req.URL)
	svg, err := renderSVG(params)
	if err != nil {
		fail(w, err.Error())
		return
	}

	log.Printf("Rendering %+v\n", params)

	if params.onlySVG {
		w.Header().Set("Content-Type", "image/svg+xml")
		io.WriteString(w, svg)
	} else {
		depth, _ := strconv.Atoi(params.depth)
		max := system.Named(params.name).MaxDepth()
		query := "?" + req.URL.RawQuery
		if query == "?" {
			query = ""
		}
		page := pageData{
			Name:      params.name,
			Thickness: params.thickness,
			Color:     params.color,
			Query:     query,
			Depth:     depth,
			MaxDepth:  max,
			HasPrev:   depth-1 >= minimumDepth,
			HasNext:   depth+1 <= max,
			SVG:       template.HTML(svg),
			Systems:   systemNames,
		}
		display(w, "index", page)
	}
}

func main() {
	log.SetFlags(0) // don't show timestamps in logs

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

	staticHandler := http.StripPrefix(
		"/static/",
		http.FileServer(http.Dir("static")),
	)
	http.HandleFunc("/", mainHandler)
	http.Handle("/static/", staticHandler)

	log.Println("=> Serving on http://localhost" + port)
	log.Println("=> Ctrl-C to shutdown server")
	err := http.ListenAndServe(port, nil)
	if err != nil {
		log.Fatalln("ListenAndServe:", err)
	}
}
<commit_msg>Change default thickness from 2.2 to 3<commit_after>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

package main

import (
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"

	"github.com/mk12/lindenmayer/system"
)

// parameters are a collection of accepted URL parameters.
type parameters struct {
	name      string
	depth     string
	thickness string
	color     string
	precision string
	onlySVG   bool
}

// pageData contains information used to render templates.
type pageData struct {
	Name      string
	Query     string
	Thickness string
	Color     string
	Depth     int
	MaxDepth  int
	HasPrev   bool
	HasNext   bool
	SVG       template.HTML
	Systems   []string
}

// systemNames contains the names of the systems shown in the sidebar.
var systemNames = []string{
	"koch", "hilbert", "peano", "gosper", "sierpinski", "rings", "tree",
	"plant", "willow", "dragon", "island",
}

// Limitations on parameters.
const (
	minimumDepth     = 0
	minimumPrecision = 1
	maximumPrecision = 15
)

// Default parameter values.
var defaultParams = parameters{
	name:      "koch",
	depth:     "2",
	thickness: "3",
	color:     "black",
	precision: "3",
	onlySVG:   false,
}

// Compile all templates on startup.
var templateSet *template.Template

func init() {
	add := func(a, b int) int { return a + b }
	capitalize := func(s string) string {
		runes := []rune(s)
		runes[0] = unicode.ToUpper(runes[0])
		return string(runes)
	}
	funcs := template.FuncMap{"add": add, "capitalize": capitalize}

	paths := []string{"header", "footer", "index", "404"}
	for i, name := range paths {
		paths[i] = "templates/" + name + ".html"
	}
	templateSet = template.Must(
		template.New("main").Funcs(funcs).ParseFiles(paths...))
}

// display finds a template by name and executes it with the given data.
func display(w http.ResponseWriter, templateName string, data interface{}) {
	err := templateSet.ExecuteTemplate(w, templateName, data)
	if err != nil {
		log.Println("500 Internal Server Error:", err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// fail logs a failure message and responds with a 404 Not Found status.
func fail(w http.ResponseWriter, reason string) {
	log.Println("404 Not Found:", reason)
	w.WriteHeader(http.StatusNotFound)
	display(w, "404", nil)
}

// splitPath returns a slice of URL path segments by splitting on slashes. The
// presence of a leading or trailing slash does not affect the result.
func splitPath(path string) []string {
	segs := strings.Split(path, "/")
	if len(segs) > 0 && segs[0] == "" {
		segs = segs[1:]
	}
	if s := len(segs); s > 0 && segs[s-1] == "" {
		segs = segs[:s-1]
	}
	return segs
}

// parseParams parses the parameters from the URL, and uses defaultParams if
// there are missing values.
func parseParams(href *url.URL) parameters {
	params := defaultParams

	path := splitPath(href.Path)
	if len(path) >= 1 {
		params.name = path[0]
	}
	if len(path) >= 2 {
		params.depth = path[1]
	}

	query := href.Query()
	if thickness := query.Get("t"); thickness != "" {
		params.thickness = thickness
	}
	if color := query.Get("c"); color != "" {
		params.color = color
	}
	if precision := query.Get("p"); precision != "" {
		params.precision = precision
	}
	if onlySVG := query.Get("svg"); onlySVG == "1" {
		params.onlySVG = true
	}

	return params
}

// renderSVG generates the SVG data for the specified curve.
func renderSVG(params parameters) (string, error) {
	sys := system.Named(params.name)
	if sys == nil {
		return "", fmt.Errorf("no system named %q", params.name)
	}

	depth, err := strconv.Atoi(params.depth)
	if err != nil {
		return "", err
	}
	if depth < minimumDepth || depth > sys.MaxDepth() {
		return "", fmt.Errorf("invalid depth %d", depth)
	}

	thickness, err := strconv.ParseFloat(params.thickness, 64)
	if err != nil {
		return "", err
	}
	if thickness <= 0 {
		return "", fmt.Errorf("invalid thickness %f", thickness)
	}

	if params.color == "" {
		return "", fmt.Errorf("invalid color \"\"")
	}

	precision, err := strconv.Atoi(params.precision)
	if err != nil {
		return "", err
	}
	if precision < minimumPrecision || precision > maximumPrecision {
		return "", fmt.Errorf("invalid precision %d", precision)
	}

	opts := system.Options{
		Depth:     depth,
		Thickness: thickness,
		Color:     params.color,
		Precision: precision,
	}
	return sys.SVG(&opts), nil
}

// mainHandler responds to an HTTP request.
func mainHandler(w http.ResponseWriter, req *http.Request) {
	log.SetPrefix(fmt.Sprintf("[%s %s] ", req.Method, req.URL))
	if req.Method != "GET" {
		fail(w, "invalid request method")
		return
	}

	params := parseParams(req.URL)
	svg, err := renderSVG(params)
	if err != nil {
		fail(w, err.Error())
		return
	}

	log.Printf("Rendering %+v\n", params)

	if params.onlySVG {
		w.Header().Set("Content-Type", "image/svg+xml")
		io.WriteString(w, svg)
	} else {
		depth, _ := strconv.Atoi(params.depth)
		max := system.Named(params.name).MaxDepth()
		query := "?" + req.URL.RawQuery
		if query == "?" {
			query = ""
		}
		page := pageData{
			Name:      params.name,
			Thickness: params.thickness,
			Color:     params.color,
			Query:     query,
			Depth:     depth,
			MaxDepth:  max,
			HasPrev:   depth-1 >= minimumDepth,
			HasNext:   depth+1 <= max,
			SVG:       template.HTML(svg),
			Systems:   systemNames,
		}
		display(w, "index", page)
	}
}

func main() {
	log.SetFlags(0) // don't show timestamps in logs

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

	staticHandler := http.StripPrefix(
		"/static/",
		http.FileServer(http.Dir("static")),
	)
	http.HandleFunc("/", mainHandler)
	http.Handle("/static/", staticHandler)

	log.Println("=> Serving on http://localhost" + port)
	log.Println("=> Ctrl-C to shutdown server")
	err := http.ListenAndServe(port, nil)
	if err != nil {
		log.Fatalln("ListenAndServe:", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/{clone}/{pasteId}", cloneHandler)
	router.HandleFunc("/{download}/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Add download handler<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.Copy(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"regexp"
	"strconv"
	"time"
)

const (
	DefaultNumOfResultToShow = 3
)

type Time struct {
	hour, minute int
}

func departureTime(departure string) (int, int) {
	ret, _ := regexp.MatchString("^[0-9]{1,2}:[0-9]{1,2}$", departure)
	var hour int
	var minute int
	if ret {
		re := regexp.MustCompile("^([0-9]{1,2}):([0-9]{1,2})$")
		bs := []byte(departure)
		group := re.FindSubmatch(bs)
		h, _ := strconv.Atoi(string(group[1]))
		m, _ := strconv.Atoi(string(group[2]))
		if h >= 0 && h < 24 && m >= 0 && m < 60 {
			hour = h
			minute = m
		} else {
			now := time.Now()
			hour = now.Hour()
			minute = now.Minute()
		}
	} else {
		now := time.Now()
		hour = now.Hour()
		minute = now.Minute()
	}
	return hour, minute
}

func getSelector() string {
	weekday := time.Now().Weekday().String()
	if weekday == "Saturday" {
		return "#tab-2 .standard2"
	} else if weekday == "Sunday" {
		return "#tab-3 .standard2"
	} else {
		return "#tab-1 .standard2"
	}
}

func createTimetable(selector string) []Time {
	var timetable = make([]Time, 0)
	doc, _ := goquery.NewDocument("http://www.keiseibus.co.jp/jikoku/bs_tt.php?key=04159_01a")
	doc.Find(selector).Each(func(_ int, s *goquery.Selection) {
		s.Find("tbody tr").Each(func(_ int, s *goquery.Selection) {
			key, _ := strconv.Atoi(s.Find("th").Text())
			s.Find("td>span").Each(func(_ int, s *goquery.Selection) {
				s.Find(".notes").Remove()
				s.Find("br").Remove()
				if s.Text() != "" {
					value, _ := strconv.Atoi(s.Text())
					timetable = append(timetable, Time{key, value})
				}
			})
		})
	})
	return timetable
}

func printTimes(times []Time) {
	for _, v := range times {
		if v.minute < 10 {
			fmt.Println(fmt.Sprintf("%d:0%d ", v.hour, v.minute))
		} else {
			fmt.Println(fmt.Sprintf("%d:%d ", v.hour, v.minute))
		}
	}
}

func main() {
	var departure string
	var numOfResult int
	flag.StringVar(&departure, "t", "", "specify departure time.")
	flag.IntVar(&numOfResult, "n", DefaultNumOfResultToShow, "specify amount of result.")
	flag.Parse()

	hour, minute := departureTime(departure)
	timetable := createTimetable(getSelector())

	result := make([]Time, 0, numOfResult)
	for _, v := range timetable {
		if v.minute > minute && v.hour >= hour {
			result = append(result, v)
			if len(result) >= numOfResult {
				break
			}
		}
	}
	printTimes(result)
}
<commit_msg>call os.Exit(2) in case the parameter for -n is negative.<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"os"
	"regexp"
	"strconv"
	"time"
)

const (
	DefaultNumOfResultToShow = 3
)

type Time struct {
	hour, minute int
}

func departureTime(departure string) (int, int) {
	ret, _ := regexp.MatchString("^[0-9]{1,2}:[0-9]{1,2}$", departure)
	var hour int
	var minute int
	if ret {
		re := regexp.MustCompile("^([0-9]{1,2}):([0-9]{1,2})$")
		bs := []byte(departure)
		group := re.FindSubmatch(bs)
		h, _ := strconv.Atoi(string(group[1]))
		m, _ := strconv.Atoi(string(group[2]))
		if h >= 0 && h < 24 && m >= 0 && m < 60 {
			hour = h
			minute = m
		} else {
			now := time.Now()
			hour = now.Hour()
			minute = now.Minute()
		}
	} else {
		now := time.Now()
		hour = now.Hour()
		minute = now.Minute()
	}
	return hour, minute
}

func getSelector() string {
	weekday := time.Now().Weekday().String()
	if weekday == "Saturday" {
		return "#tab-2 .standard2"
	} else if weekday == "Sunday" {
		return "#tab-3 .standard2"
	} else {
		return "#tab-1 .standard2"
	}
}

func createTimetable(selector string) []Time {
	var timetable = make([]Time, 0)
	doc, _ := goquery.NewDocument("http://www.keiseibus.co.jp/jikoku/bs_tt.php?key=04159_01a")
	doc.Find(selector).Each(func(_ int, s *goquery.Selection) {
		s.Find("tbody tr").Each(func(_ int, s *goquery.Selection) {
			key, _ := strconv.Atoi(s.Find("th").Text())
			s.Find("td>span").Each(func(_ int, s *goquery.Selection) {
				s.Find(".notes").Remove()
				s.Find("br").Remove()
				if s.Text() != "" {
					value, _ := strconv.Atoi(s.Text())
					timetable = append(timetable, Time{key, value})
				}
			})
		})
	})
	return timetable
}

func printTimes(times []Time) {
	for _, v := range times {
		if v.minute < 10 {
			fmt.Println(fmt.Sprintf("%d:0%d ", v.hour, v.minute))
		} else {
			fmt.Println(fmt.Sprintf("%d:%d ", v.hour, v.minute))
		}
	}
}

func main() {
	var departure string
	var numOfResult int
	flag.StringVar(&departure, "t", "", "specify departure time.")
	flag.IntVar(&numOfResult, "n", DefaultNumOfResultToShow, "specify amount of result.")
	flag.Parse()

	if numOfResult < 0 {
		fmt.Fprintf(os.Stderr, "parameter for -n must be greater than 0.\n")
		os.Exit(2)
	}

	hour, minute := departureTime(departure)
	timetable := createTimetable(getSelector())

	result := make([]Time, 0, numOfResult)
	for _, v := range timetable {
		if v.minute > minute && v.hour >= hour {
			result = append(result, v)
			if len(result) >= numOfResult {
				break
			}
		}
	}
	printTimes(result)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/tealeg/xlsx"
	"os"
)

var xlsxPath = flag.String("f", "", "Path to an XLSX file")
var sheetIndex = flag.Int("i", 0, "Index of sheet to convert, zero based")
var delimiter = flag.String("d", ";", "Delimiter to use between fields")

type Outputer func(s string)

type XLSX2CSVError struct {
	error string
}

func (e XLSX2CSVError) Error() string {
	return e.error
}

func generateCSVFromXLSXFile(excelFileName string, sheetIndex int, outputf Outputer) error {
	var xlFile *xlsx.File
	var error error
	var sheetLen int
	var rowString string

	xlFile, error = xlsx.OpenFile(excelFileName)
	if error != nil {
		return error
	}
	sheetLen = len(xlFile.Sheets)
	switch {
	case sheetLen == 0:
		e := new(XLSX2CSVError)
		e.error = "This XLSX file contains no sheets.\n"
		return *e
	case sheetIndex >= sheetLen:
		e := new(XLSX2CSVError)
		e.error = fmt.Sprintf("No sheet %d available, please select a sheet between 0 and %d\n", sheetIndex, sheetLen-1)
		return *e
	}
	sheet := xlFile.Sheets[sheetIndex]
	for _, row := range sheet.Rows {
		rowString = ""
		if row != nil {
			for cellIndex, cell := range row.Cells {
				if cellIndex > 0 {
					rowString = fmt.Sprintf("%s%s\"%s\"", rowString, *delimiter, cell.String())
				} else {
					rowString = fmt.Sprintf("\"%s\"", cell.String())
				}
			}
			rowString = fmt.Sprintf("%s\n", rowString)
			outputf(rowString)
		}
	}
	return nil
}

func usage() {
	fmt.Printf(`%s: -f=<XLSXFile> -i=<SheetIndex> -d=<Delimiter>

Note: SheetIndex should be a number, zero based
`,
		os.Args[0])
}

func main() {
	flag.Parse()
	var error error
	if len(os.Args) < 3 {
		usage()
		return
	}
	flag.Parse()
	error = generateCSVFromXLSXFile(*xlsxPath, *sheetIndex, func(s string) { fmt.Printf("%s", s) })
	if error != nil {
		fmt.Printf(error.Error())
		return
	}
}
<commit_msg>string quoting fix & minor formatting fix<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/tealeg/xlsx"
)

var xlsxPath = flag.String("f", "", "Path to an XLSX file")
var sheetIndex = flag.Int("i", 0, "Index of sheet to convert, zero based")
var delimiter = flag.String("d", ";", "Delimiter to use between fields")

type Outputer func(s string)

type XLSX2CSVError struct {
	error string
}

func (e XLSX2CSVError) Error() string {
	return e.error
}

func generateCSVFromXLSXFile(excelFileName string, sheetIndex int, outputf Outputer) error {
	var xlFile *xlsx.File
	var error error
	var sheetLen int
	var rowString string

	xlFile, error = xlsx.OpenFile(excelFileName)
	if error != nil {
		return error
	}
	sheetLen = len(xlFile.Sheets)
	switch {
	case sheetLen == 0:
		e := new(XLSX2CSVError)
		e.error = "This XLSX file contains no sheets.\n"
		return *e
	case sheetIndex >= sheetLen:
		e := new(XLSX2CSVError)
		e.error = fmt.Sprintf("No sheet %d available, please select a sheet between 0 and %d\n", sheetIndex, sheetLen-1)
		return *e
	}
	sheet := xlFile.Sheets[sheetIndex]
	for _, row := range sheet.Rows {
		rowString = ""
		if row != nil {
			for cellIndex, cell := range row.Cells {
				if cellIndex > 0 {
					rowString = fmt.Sprintf("%s%s%q", rowString, *delimiter, cell.String())
				} else {
					rowString = fmt.Sprintf("%q", cell.String())
				}
			}
			rowString = fmt.Sprintf("%s\n", rowString)
			outputf(rowString)
		}
	}
	return nil
}

func usage() {
	fmt.Printf(`%s: -f=<XLSXFile> -i=<SheetIndex> -d=<Delimiter>

Note: SheetIndex should be a number, zero based
`,
		os.Args[0])
}

func main() {
	flag.Parse()
	var error error
	if len(os.Args) < 3 {
		usage()
		return
	}
	flag.Parse()
	error = generateCSVFromXLSXFile(*xlsxPath, *sheetIndex, func(s string) { fmt.Printf("%s", s) })
	if error != nil {
		fmt.Printf(error.Error())
		return
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"time"

	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"golang.org/x/oauth2/google"
)

var projectID = ""

const (
	service        = "devops-demo"
	serviceVersion = "1.0.0"
	metricPrefix   = "devops-"
)

// A IndexVariables represents variables used in a template (index.html)
type IndexVariables struct {
	WebsiteTitle string
	RandomNumber string
}

func logRequest(r *http.Request, traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"UserAgent":                     r.UserAgent(),
		"RequestURL":                    r.Host,
		"RequestURI":                    r.RequestURI,
		"RequestMethod":                 r.Method,
		"Host":                          r.Host,
		"Proto":                         r.Proto,
		"ProtoMajor":                    r.ProtoMajor,
		"ProtoMinor":                    r.ProtoMinor,
		"RemoteAddr":                    r.RemoteAddr,
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func logMethod(traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func mainHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, span := trace.StartSpan(context.Background(), "/")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from mainHandler")

		iv := &IndexVariables{
			WebsiteTitle: "MainController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}

		renderTemplate(w, iv)
	})
}

func benchHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, span := trace.StartSpan(context.Background(), "/bench1")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from benchHandler")
		log.Printf("context: %v\n", ctx)

		// Stress
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))

		iv := &IndexVariables{
			WebsiteTitle: "BenchController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}
		renderTemplate(w, iv)
	})
}

func addAttributesToSpan(span *trace.Span, r *http.Request) {
	span.AddAttributes(
		trace.StringAttribute("Method", r.Method),
		trace.StringAttribute("Host", r.Host),
		trace.StringAttribute("Proto", r.Proto),
		trace.Int64Attribute("ProtoMajor", int64(r.ProtoMajor)),
		trace.Int64Attribute("ProtoMinor", int64(r.ProtoMinor)),
		trace.Int64Attribute("ContentLength", int64(r.ContentLength)),
		trace.StringAttribute("RequestURI", r.RequestURI),
		trace.StringAttribute("RemoteAddr", r.RemoteAddr),
		trace.StringAttribute("UserAgent", r.UserAgent()),
		trace.StringAttribute("Referer", r.Referer()),
	)
}

func waitRandomMilliseconds(ctx context.Context) {
	_, span := trace.StartSpan(ctx, "waitRandomMilliseconds")
	defer span.End()
	time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
}

func fibonacci(ctx context.Context, loopNum int) {
	_, span := trace.StartSpan(ctx, "fibonacci")
	s := span.SpanContext()
	defer span.End()
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
	span.AddAttributes(trace.Int64Attribute("loopNum", int64(loopNum)))

	logMethod(s.TraceID.String(), s.SpanID.String(), fmt.Sprintf("Fibonacci calculation completed: %v loops", loopNum))
}

var templates = template.Must(template.ParseFiles("./template/index.html"))

func renderTemplate(w http.ResponseWriter, iv *IndexVariables) {
	err := templates.Execute(w, iv)
	if err != nil {
		log.Printf("Failed to render a template: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func initLogSettings() {
	log.SetFormatter(&log.JSONFormatter{
		FieldMap: log.FieldMap{
			log.FieldKeyTime:  "time",
			log.FieldKeyLevel: "severity",
			log.FieldKeyMsg:   "message",
		},
		TimestampFormat: time.RFC3339Nano,
	})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.InfoLevel)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initLogSettings()

	// Initialize the credential and projectID with Application Default Credentials (ADC)
	ctx := context.Background()
	cred, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		log.Fatal(err.Error())
	}
	projectID = cred.ProjectID
	log.Infof("Successfully retrieved GCP Project ID: %v", projectID)

	// Initialize Profiler
	if err := profiler.Start(profiler.Config{
		Service:        service,
		ServiceVersion: serviceVersion,
		ProjectID:      projectID,
	}); err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized profiler")

	// Initialize exporter
	exporter, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID:    projectID,
		MetricPrefix: metricPrefix,
	})
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized exporter")
	defer exporter.Flush()
	trace.RegisterExporter(exporter)
	trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})

	// Serve static files under /static/ directory
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	// Register handlers
	http.Handle("/", mainHandler())
	http.Handle("/bench1", benchHandler())

	log.Info("Start listening : 8080...")
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Update the sample application to provide REST APIs<commit_after>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"fmt"
	"math/rand"
	"net/http"
	"os"
	"time"

	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"golang.org/x/oauth2/google"
)

var projectID = ""
var isLocal = false

const (
	service        = "devops-demo"
	serviceVersion = "1.0.0"
	metricPrefix   = "devops-"
)

func logRequest(r *http.Request, traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"UserAgent":                     r.UserAgent(),
		"RequestURL":                    r.Host,
		"RequestURI":                    r.RequestURI,
		"RequestMethod":                 r.Method,
		"Host":                          r.Host,
		"Proto":                         r.Proto,
		"ProtoMajor":                    r.ProtoMajor,
		"ProtoMinor":                    r.ProtoMinor,
		"RemoteAddr":                    r.RemoteAddr,
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func logMethod(traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func normalHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		if !isLocal {
			_, span := trace.StartSpan(context.Background(), "/normal")
			defer span.End()
			s := span.SpanContext()

			addAttributesToSpan(span, r)
			logRequest(r, s.TraceID.String(), s.SpanID.String(), "Access to normal")
		}

		returnElapsedTimeAsJSON(w, start)
	})
}

func benchHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		if isLocal {
			fibonacciOnLocal(rand.Intn(3000000000))
			fibonacciOnLocal(rand.Intn(3000000000))
			fibonacciOnLocal(rand.Intn(3000000000))
		} else {
			ctx, span := trace.StartSpan(context.Background(), "/bench")
			defer span.End()
			s := span.SpanContext()

			addAttributesToSpan(span, r)
			logRequest(r, s.TraceID.String(), s.SpanID.String(), "Access to bench")
			log.Printf("context: %v\n", ctx)

			// Stress
			fibonacci(ctx, rand.Intn(3000000000))
			fibonacci(ctx, rand.Intn(3000000000))
			fibonacci(ctx, rand.Intn(3000000000))
		}

		returnElapsedTimeAsJSON(w, start)
	})
}

func returnElapsedTimeAsJSON(w http.ResponseWriter, start time.Time) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`{"elapsed": %d}`, time.Now().Sub(start).Milliseconds())))
}

func addAttributesToSpan(span *trace.Span, r *http.Request) {
	span.AddAttributes(
		trace.StringAttribute("Method", r.Method),
		trace.StringAttribute("Host", r.Host),
		trace.StringAttribute("Proto", r.Proto),
		trace.Int64Attribute("ProtoMajor", int64(r.ProtoMajor)),
		trace.Int64Attribute("ProtoMinor", int64(r.ProtoMinor)),
		trace.Int64Attribute("ContentLength", int64(r.ContentLength)),
		trace.StringAttribute("RequestURI", r.RequestURI),
		trace.StringAttribute("RemoteAddr", r.RemoteAddr),
		trace.StringAttribute("UserAgent", r.UserAgent()),
		trace.StringAttribute("Referer", r.Referer()),
	)
}

func fibonacci(ctx context.Context, loopNum int) {
	_, span := trace.StartSpan(ctx, "fibonacci")
	s := span.SpanContext()
	defer span.End()
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
	span.AddAttributes(trace.Int64Attribute("loopNum", int64(loopNum)))

	logMethod(s.TraceID.String(), s.SpanID.String(), fmt.Sprintf("Fibonacci calculation completed: %v loops", loopNum))
}

func fibonacciOnLocal(loopNum int) {
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
}

func initLogSettings() {
	log.SetFormatter(&log.JSONFormatter{
		FieldMap: log.FieldMap{
			log.FieldKeyTime:  "time",
			log.FieldKeyLevel: "severity",
			log.FieldKeyMsg:   "message",
		},
		TimestampFormat: time.RFC3339Nano,
	})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.InfoLevel)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initLogSettings()

	// Initialize the credential and projectID with Application Default Credentials (ADC)
	ctx := context.Background()
	cred, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		log.Fatal(err.Error())
	}

	projectID = cred.ProjectID
	if len(projectID) == 0 {
		log.Println("Failed to get the credential. Trying to enter Local mode...")
		isLocal = true
	} else {
		log.Infof("Successfully retrieved GCP Project ID: %v", projectID)
	}

	if !isLocal {
		// Initialize Profiler
		if err := profiler.Start(profiler.Config{
			Service:        service,
			ServiceVersion: serviceVersion,
			ProjectID:      projectID,
		}); err != nil {
			log.Fatal(err.Error())
		}
		log.Info("Successfully initialized profiler")

		// Initialize exporter
		exporter, err := stackdriver.NewExporter(stackdriver.Options{
			ProjectID:    projectID,
			MetricPrefix: metricPrefix,
		})
		if err != nil {
			log.Fatal(err.Error())
		}
		log.Info("Successfully initialized exporter")
		defer exporter.Flush()
		trace.RegisterExporter(exporter)
		trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
	}

	// Serve Frontend scripts under /static/ directory
	http.Handle("/", http.FileServer(http.Dir("./static")))

	// Register handlers
	http.Handle("/normal", normalHandler())
	http.Handle("/bench", benchHandler())

	log.Info("Start listening : 8080...")
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/ziputil"
	"github.com/bitrise-io/steps-deploy-to-bitrise-io/uploaders"
	"github.com/bitrise-tools/go-steputils/input"
	"github.com/bitrise-tools/go-steputils/tools"
)

var fileBaseNamesToSkip = []string{".DS_Store"}

// ConfigsModel ...
type ConfigsModel struct {
	BuildURL            string
	APIToken            string
	IsCompress          string
	DeployPath          string
	NotifyUserGroups    string
	NotifyEmailList     string
	IsPublicPageEnabled string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		BuildURL:            os.Getenv("build_url"),
		APIToken:            os.Getenv("build_api_token"),
		IsCompress:          os.Getenv("is_compress"),
		DeployPath:          os.Getenv("deploy_path"),
		NotifyUserGroups:    os.Getenv("notify_user_groups"),
		NotifyEmailList:     os.Getenv("notify_email_list"),
		IsPublicPageEnabled: os.Getenv("is_enable_public_page"),
	}
}

func (configs ConfigsModel) validate() error {
	if err := input.ValidateIfNotEmpty(configs.BuildURL); err != nil {
		return fmt.Errorf("BuildURL - %s", err)
	}
	if err := input.ValidateIfNotEmpty(configs.APIToken); err != nil {
		return fmt.Errorf("APIToken - %s", err)
	}
	if err := input.ValidateWithOptions(configs.IsCompress, "true", "false"); err != nil {
		return fmt.Errorf("IsCompress - %s", err)
	}
	if err := input.ValidateIfPathExists(configs.DeployPath); err != nil {
		return fmt.Errorf("DeployPath - %s", err)
	}
	if err := input.ValidateWithOptions(configs.IsPublicPageEnabled, "true", "false"); err != nil {
		return fmt.Errorf("IsPublicPageEnabled - %s", err)
	}
	return nil
}

func (configs ConfigsModel) print() {
	log.Infof("Configs:")
	log.Printf("- BuildURL: %s", configs.BuildURL)
	log.Printf("- APIToken: %s", configs.APIToken)
	log.Printf("- IsCompress: %s", configs.IsCompress)
	log.Printf("- DeployPath: %s", configs.DeployPath)
	log.Printf("- NotifyUserGroups: %s", configs.NotifyUserGroups)
	log.Printf("- NotifyEmailList: %s", configs.NotifyEmailList)
	log.Printf("- IsPublicPageEnabled: %s", configs.IsPublicPageEnabled)
}

func fail(format string, v ...interface{}) {
	log.Errorf(format, v...)
	os.Exit(1)
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		fail("Issue with input: %s", err)
	}

	filesToDeploy := []string{}

	tmpDir, err := pathutil.NormalizedOSTempDirPath("__deploy-to-bitrise-io__")
	if err != nil {
		fail("Failed to create tmp dir, error: %s", err)
	}

	// Collect files to deploy
	isDeployPathDir, err := pathutil.IsDirExists(configs.DeployPath)
	if err != nil {
		fail("Failed to check if DeployPath (%s) is a directory or a file, error: %s", configs.DeployPath, err)
	}

	if !isDeployPathDir {
		fmt.Println()
		log.Infof("Deploying single file")

		filesToDeploy = []string{configs.DeployPath}
	} else if configs.IsCompress == "true" {
		fmt.Println()
		log.Infof("Deploying compressed Deploy directory")

		dirName := filepath.Base(configs.DeployPath)
		tmpZipPath := filepath.Join(tmpDir, dirName+".zip")

		if err := ziputil.Zip(configs.DeployPath, tmpZipPath); err != nil {
			fail("Failed to zip output dir, error: %s", err)
		}

		filesToDeploy = []string{tmpZipPath}
	} else {
		fmt.Println()
		log.Infof("Deploying the content of the Deploy directory separately")

		pattern := filepath.Join(configs.DeployPath, "*")
		pths, err := filepath.Glob(pattern)
		if err != nil {
			fail("Failed to list files in DeployPath, error: %s", err)
		}

		for _, pth := range pths {
			if isDir, err := pathutil.IsDirExists(pth); err != nil {
				fail("Failed to check if path (%s) is a directory or a file, error: %s", pth, err)
			} else if !isDir {
				filesToDeploy = append(filesToDeploy, pth)
			}
		}
	}

	clearedFilesToDeploy := []string{}
	for _, pth := range filesToDeploy {
		for _, fileBaseNameToSkip := range fileBaseNamesToSkip {
			if filepath.Base(pth) == fileBaseNameToSkip {
				log.Warnf("skipping: %s", pth)
			} else {
				clearedFilesToDeploy = append(clearedFilesToDeploy, pth)
			}

		}
	}

	fmt.Println()
	log.Infof("List of files to deploy")
	for _, pth := range clearedFilesToDeploy {
		log.Printf("- %s", pth)
	}
	// ---

	// Deploy files
	fmt.Println()
	log.Infof("Deploying files")

	publicInstallPage := ""

	for _, pth := range clearedFilesToDeploy {
		ext := filepath.Ext(pth)

		fmt.Println()

		switch ext {
		case ".ipa":
			log.Donef("Uploading ipa file: %s", pth)

			installPage, err := uploaders.DeployIPA(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			}
		case ".apk":
			log.Donef("Uploading apk file: %s", pth)

			installPage, err := uploaders.DeployAPK(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			}
		default:
			log.Donef("Uploading file: %s", pth)

			installPage, err := uploaders.DeployFile(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			}
		}
	}

	fmt.Println()
	log.Donef("Success")
	log.Printf("You can find the Artifact on Bitrise, on the Build's page: %s", configs.BuildURL)

	if publicInstallPage != "" {
		if err := tools.ExportEnvironmentWithEnvman("BITRISE_PUBLIC_INSTALL_PAGE_URL", publicInstallPage); err != nil {
			fail("Failed to export BITRISE_PUBLIC_INSTALL_PAGE_URL, error: %s", err)
		}
		log.Printf("The public install page url is now available in the Environment Variable: BITRISE_PUBLIC_INSTALL_PAGE_URL (value: %s)", publicInstallPage)
	}
	// --

}
<commit_msg>warn if public install is not allowed (#31)<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/go-utils/ziputil"
	"github.com/bitrise-io/steps-deploy-to-bitrise-io/uploaders"
	"github.com/bitrise-tools/go-steputils/input"
	"github.com/bitrise-tools/go-steputils/tools"
)

var fileBaseNamesToSkip = []string{".DS_Store"}

// ConfigsModel ...
type ConfigsModel struct {
	BuildURL            string
	APIToken            string
	IsCompress          string
	DeployPath          string
	NotifyUserGroups    string
	NotifyEmailList     string
	IsPublicPageEnabled string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		BuildURL:            os.Getenv("build_url"),
		APIToken:            os.Getenv("build_api_token"),
		IsCompress:          os.Getenv("is_compress"),
		DeployPath:          os.Getenv("deploy_path"),
		NotifyUserGroups:    os.Getenv("notify_user_groups"),
		NotifyEmailList:     os.Getenv("notify_email_list"),
		IsPublicPageEnabled: os.Getenv("is_enable_public_page"),
	}
}

func (configs ConfigsModel) validate() error {
	if err := input.ValidateIfNotEmpty(configs.BuildURL); err != nil {
		return fmt.Errorf("BuildURL - %s", err)
	}
	if err := input.ValidateIfNotEmpty(configs.APIToken); err != nil {
		return fmt.Errorf("APIToken - %s", err)
	}
	if err := input.ValidateWithOptions(configs.IsCompress, "true", "false"); err != nil {
		return fmt.Errorf("IsCompress - %s", err)
	}
	if err := input.ValidateIfPathExists(configs.DeployPath); err != nil {
		return fmt.Errorf("DeployPath - %s", err)
	}
	if err := input.ValidateWithOptions(configs.IsPublicPageEnabled, "true", "false"); err != nil {
		return fmt.Errorf("IsPublicPageEnabled - %s", err)
	}
	return nil
}

func (configs ConfigsModel) print() {
	log.Infof("Configs:")
	log.Printf("- BuildURL: %s", configs.BuildURL)
	log.Printf("- APIToken: %s", configs.APIToken)
	log.Printf("- IsCompress: %s", configs.IsCompress)
	log.Printf("- DeployPath: %s", configs.DeployPath)
	log.Printf("- NotifyUserGroups: %s", configs.NotifyUserGroups)
	log.Printf("- NotifyEmailList: %s", configs.NotifyEmailList)
	log.Printf("- IsPublicPageEnabled: %s", configs.IsPublicPageEnabled)
}

func fail(format string, v ...interface{}) {
	log.Errorf(format, v...)
	os.Exit(1)
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		fail("Issue with input: %s", err)
	}

	filesToDeploy := []string{}

	tmpDir, err := pathutil.NormalizedOSTempDirPath("__deploy-to-bitrise-io__")
	if err != nil {
		fail("Failed to create tmp dir, error: %s", err)
	}

	// Collect files to deploy
	isDeployPathDir, err := pathutil.IsDirExists(configs.DeployPath)
	if err != nil {
		fail("Failed to check if DeployPath (%s) is a directory or a file, error: %s", configs.DeployPath, err)
	}

	if !isDeployPathDir {
		fmt.Println()
		log.Infof("Deploying single file")

		filesToDeploy = []string{configs.DeployPath}
	} else if configs.IsCompress == "true" {
		fmt.Println()
		log.Infof("Deploying compressed Deploy directory")

		dirName := filepath.Base(configs.DeployPath)
		tmpZipPath := filepath.Join(tmpDir, dirName+".zip")

		if err := ziputil.Zip(configs.DeployPath, tmpZipPath); err != nil {
			fail("Failed to zip output dir, error: %s", err)
		}

		filesToDeploy = []string{tmpZipPath}
	} else {
		fmt.Println()
		log.Infof("Deploying the content of the Deploy directory separately")

		pattern := filepath.Join(configs.DeployPath, "*")
		pths, err := filepath.Glob(pattern)
		if err != nil {
			fail("Failed to list files in DeployPath, error: %s", err)
		}

		for _, pth := range pths {
			if isDir, err := pathutil.IsDirExists(pth); err != nil {
				fail("Failed to check if path (%s) is a directory or a file, error: %s", pth, err)
			} else if !isDir {
				filesToDeploy = append(filesToDeploy, pth)
			}
		}
	}

	clearedFilesToDeploy := []string{}
	for _, pth := range filesToDeploy {
		for _, fileBaseNameToSkip := range fileBaseNamesToSkip {
			if filepath.Base(pth) == fileBaseNameToSkip {
				log.Warnf("skipping: %s", pth)
			} else {
				clearedFilesToDeploy = append(clearedFilesToDeploy, pth)
			}

		}
	}

	fmt.Println()
	log.Infof("List of files to deploy")
	for _, pth := range clearedFilesToDeploy {
		log.Printf("- %s", pth)
	}
	// ---

	// Deploy files
	fmt.Println()
	log.Infof("Deploying files")

	publicInstallPage := ""

	for _, pth := range clearedFilesToDeploy {
		ext := filepath.Ext(pth)

		fmt.Println()

		switch ext {
		case ".ipa":
			log.Donef("Uploading ipa file: %s", pth)

			installPage, err := uploaders.DeployIPA(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			}
		case ".apk":
			log.Donef("Uploading apk file: %s", pth)

			installPage, err := uploaders.DeployAPK(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			}
		default:
			log.Donef("Uploading file: %s", pth)

			installPage, err := uploaders.DeployFile(pth, configs.BuildURL, configs.APIToken, configs.NotifyUserGroups, configs.NotifyEmailList, configs.IsPublicPageEnabled)
			if err != nil {
				fail("Deploy failed, error: %s", err)
			}

			if installPage != "" {
				publicInstallPage = installPage
			} else if configs.IsPublicPageEnabled == "true" {
				log.Warnf("is_enable_public_page is set, but public download isn't allowed for this type of file")
			}
		}
	}

	fmt.Println()
	log.Donef("Success")
	log.Printf("You can find the Artifact on Bitrise, on the Build's page: %s", configs.BuildURL)

	if publicInstallPage != "" {
		if err := tools.ExportEnvironmentWithEnvman("BITRISE_PUBLIC_INSTALL_PAGE_URL", publicInstallPage); err != nil {
			fail("Failed to export BITRISE_PUBLIC_INSTALL_PAGE_URL, error: %s", err)
		}
		log.Printf("The public install page url is now available in the Environment Variable: BITRISE_PUBLIC_INSTALL_PAGE_URL (value: %s)", publicInstallPage)
	}
	// --

}
<|endoftext|>