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

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/tsuru/bs/bslog"
	"github.com/tsuru/bs/config"
	"github.com/tsuru/bs/log"
	"github.com/tsuru/bs/metric"
	_ "github.com/tsuru/bs/metric/logstash"
	"github.com/tsuru/bs/status"
)

const (
	version = "v1.8"
)

var printVersion bool

type StopWaiter interface {
	Stop()
	Wait()
}

func init() {
	flag.BoolVar(&printVersion, "version", false, "Print version and exit")
}

func startSignalHandler(callback func(os.Signal), signals ...os.Signal) {
	sigChan := make(chan os.Signal, 4)
	go func() {
		if signal, ok := <-sigChan; ok {
			callback(signal)
		}
	}()
	signal.Notify(sigChan, signals...)
}

func onSignalDebugGoroutines(signal os.Signal) {
	var buf []byte
	var written int
	currLen := 1024
	for written == len(buf) {
		buf = make([]byte, currLen)
		written = runtime.Stack(buf, true)
		currLen *= 2
	}
	fmt.Print(string(buf[:written]))
	startSignalHandler(onSignalDebugGoroutines, syscall.SIGUSR1)
}

func onSignalDebugProfile(signal os.Signal) {
	profFileName := "memprofile.out"
	file, err := os.OpenFile(profFileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0660)
	if err != nil {
		bslog.Warnf("Error trying to open profile file %q: %s", profFileName, err)
		return
	}
	err = pprof.WriteHeapProfile(file)
	if err != nil {
		bslog.Warnf("Error trying to write mem profile: %s", err)
	}
	bslog.Warnf("Wrote mem profile to %s", profFileName)
	file.Close()
	profFileName = "cpuprofile.out"
	bslog.Warnf("Starting cpu profile, writing output to %s", profFileName)
	defer bslog.Warnf("Finished cpu profile, see %s", profFileName)
	file, err = os.OpenFile(profFileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0660)
	if err != nil {
		bslog.Warnf("Error trying to open profile file %q: %s", profFileName, err)
	}
	defer file.Close()
	err = pprof.StartCPUProfile(file)
	if err != nil {
		bslog.Warnf("Error trying to start cpu profile: %s", err)
	}
	defer pprof.StopCPUProfile()
	time.Sleep(30 * time.Second)
	startSignalHandler(onSignalDebugProfile, syscall.SIGUSR2)
}

func main() {
	startSignalHandler(onSignalDebugGoroutines, syscall.SIGUSR1)
	startSignalHandler(onSignalDebugProfile, syscall.SIGUSR2)
	flag.Parse()
	if printVersion {
		fmt.Printf("bs version %s\n", version)
		return
	}
	lf := log.LogForwarder{
		BindAddress:     config.Config.SyslogListenAddress,
		DockerEndpoint:  config.Config.DockerEndpoint,
		EnabledBackends: config.Config.LogBackends,
	}
	err := lf.Start()
	if err != nil {
		bslog.Fatalf("Unable to initialize log forwarder: %s\n", err)
	}
	mRunner := metric.NewRunner(config.Config.DockerEndpoint, config.Config.MetricsInterval,
		config.Config.MetricsBackend)
	err = mRunner.Start()
	if err != nil {
		bslog.Warnf("Unable to initialize metrics runner: %s\n", err)
	}
	reporter, err := status.NewReporter(&status.ReporterConfig{
		TsuruEndpoint:  config.Config.TsuruEndpoint,
		TsuruToken:     config.Config.TsuruToken,
		DockerEndpoint: config.Config.DockerEndpoint,
		Interval:       config.Config.StatusInterval,
	})
	if err != nil {
		bslog.Warnf("Unable to initialize status reporter: %s\n", err)
	}
	monitorEl := []StopWaiter{&lf, mRunner}
	if reporter != nil {
		monitorEl = append(monitorEl, reporter)
	}
	var signaled bool
	startSignalHandler(func(signal os.Signal) {
		signaled = true
		for _, m := range monitorEl {
			go m.Stop()
		}
	}, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
	for _, m := range monitorEl {
		m.Wait()
	}
	if !signaled {
		bslog.Fatalf("Exiting bs because no service could be initialized.")
	}
}
<commit_msg>add lock profile on USR2 signal<commit_after>// Copyright 2016 bs authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/tsuru/bs/bslog"
	"github.com/tsuru/bs/config"
	"github.com/tsuru/bs/log"
	"github.com/tsuru/bs/metric"
	_ "github.com/tsuru/bs/metric/logstash"
	"github.com/tsuru/bs/status"
)

const (
	version = "v1.8"
)

var printVersion bool

type StopWaiter interface {
	Stop()
	Wait()
}

func init() {
	flag.BoolVar(&printVersion, "version", false, "Print version and exit")
}

func startSignalHandler(callback func(os.Signal), signals ...os.Signal) {
	sigChan := make(chan os.Signal, 4)
	go func() {
		if signal, ok := <-sigChan; ok {
			callback(signal)
		}
	}()
	signal.Notify(sigChan, signals...)
}

func onSignalDebugGoroutines(signal os.Signal) {
	var buf []byte
	var written int
	currLen := 1024
	for written == len(buf) {
		buf = make([]byte, currLen)
		written = runtime.Stack(buf, true)
		currLen *= 2
	}
	fmt.Print(string(buf[:written]))
	startSignalHandler(onSignalDebugGoroutines, syscall.SIGUSR1)
}

func onSignalDebugProfile(signal os.Signal) {
	cpufile, err := os.OpenFile("./cpuprofile.out", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
	if err != nil {
		bslog.Warnf("Error trying to open profile file: %s", err)
		return
	}
	memfile, err := os.OpenFile("./memprofile.out", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
	if err != nil {
		bslog.Warnf("Error trying to open profile file: %s", err)
		return
	}
	lockfile, err := os.OpenFile("./lockprofile.out", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
	if err != nil {
		bslog.Warnf("Error trying to open profile file: %s", err)
		return
	}
	bslog.Warnf("Starting profile...")
	defer bslog.Warnf("Profile done, files written: %s, %s, %s", cpufile.Name(), memfile.Name(), lockfile.Name())
	runtime.GC()
	pprof.WriteHeapProfile(memfile)
	memfile.Close()
	runtime.SetBlockProfileRate(1)
	time.Sleep(30 * time.Second)
	pprof.Lookup("block").WriteTo(lockfile, 0)
	runtime.SetBlockProfileRate(0)
	lockfile.Close()
	pprof.StartCPUProfile(cpufile)
	time.Sleep(30 * time.Second)
	pprof.StopCPUProfile()
	cpufile.Close()
	startSignalHandler(onSignalDebugProfile, syscall.SIGUSR2)
}

func main() {
	startSignalHandler(onSignalDebugGoroutines, syscall.SIGUSR1)
	startSignalHandler(onSignalDebugProfile, syscall.SIGUSR2)
	flag.Parse()
	if printVersion {
		fmt.Printf("bs version %s\n", version)
		return
	}
	lf := log.LogForwarder{
		BindAddress:     config.Config.SyslogListenAddress,
		DockerEndpoint:  config.Config.DockerEndpoint,
		EnabledBackends: config.Config.LogBackends,
	}
	err := lf.Start()
	if err != nil {
		bslog.Fatalf("Unable to initialize log forwarder: %s\n", err)
	}
	mRunner := metric.NewRunner(config.Config.DockerEndpoint, config.Config.MetricsInterval,
		config.Config.MetricsBackend)
	err = mRunner.Start()
	if err != nil {
		bslog.Warnf("Unable to initialize metrics runner: %s\n", err)
	}
	reporter, err := status.NewReporter(&status.ReporterConfig{
		TsuruEndpoint:  config.Config.TsuruEndpoint,
		TsuruToken:     config.Config.TsuruToken,
		DockerEndpoint: config.Config.DockerEndpoint,
		Interval:       config.Config.StatusInterval,
	})
	if err != nil {
		bslog.Warnf("Unable to initialize status reporter: %s\n", err)
	}
	monitorEl := []StopWaiter{&lf, mRunner}
	if reporter != nil {
		monitorEl = append(monitorEl, reporter)
	}
	var signaled bool
	startSignalHandler(func(signal os.Signal) {
		signaled = true
		for _, m := range monitorEl {
			go m.Stop()
		}
	}, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
	for _, m := range monitorEl {
		m.Wait()
	}
	if !signaled {
		bslog.Fatalf("Exiting bs because no service could be initialized.")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/nzai/stockrecorder/config"
	"github.com/nzai/stockrecorder/task"
)

const (
	configFileName           = "config.ini"
	configLogSection         = "path"
	configLogKey             = "logpath"
	configLogDefaultFileName = "main.log"
)

func main() {
	//	当前目录
	root := filepath.Dir(os.Args[0])
	filename := filepath.Join(root, configFileName)

	//	读取配置文件
	err := config.SetConfigFile(filename)
	if err != nil {
		log.Fatal(err)
		return
	}

	//	日志文件路径
	logPath := config.GetString(configLogSection, configLogKey, configLogDefaultFileName)
	logDir := filepath.Dir(logPath)
	_, err = os.Stat(logDir)
	if os.IsNotExist(err) {
		err = os.Mkdir(logDir, 0x777)
		if err != nil {
			log.Fatal(err)
			return
		}
	}

	file, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0x777)
	if err != nil {
		log.Fatal(err)
		return
	}
	defer file.Close()

	//	设置日志输出文件
	log.SetOutput(file)

	//	启动任务
	err = task.StartTasks()
	if err != nil {
		log.Fatal(err)
		return
	}
}
<commit_msg>分离了日志文件的逻辑，并增加阻塞保证程序一直运行<commit_after>package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/nzai/stockrecorder/config"
	"github.com/nzai/stockrecorder/task"
)

const (
	configFileName           = "config.ini"
	configLogSection         = "path"
	configLogKey             = "logpath"
	configLogDefaultFileName = "main.log"
)

func main() {
	//	当前目录
	root := filepath.Dir(os.Args[0])
	filename := filepath.Join(root, configFileName)

	//	读取配置文件
	err := config.SetConfigFile(filename)
	if err != nil {
		log.Fatal(err)
		return
	}

	//	打开日志文件
	file, err := openLogFile()
	if err != nil {
		log.Fatal(err)
		return
	}
	defer file.Close()

	//	设置日志输出文件
	log.SetOutput(file)

	//	启动任务
	err = task.StartTasks()
	if err != nil {
		log.Fatal(err)
		return
	}

	//	阻塞，一直运行
	channel := make(chan int)
	<-channel
}

//	打开日志文件
func openLogFile() (*os.File, error) {
	//	日志文件路径
	logPath := config.GetString(configLogSection, configLogKey, configLogDefaultFileName)
	logDir := filepath.Dir(logPath)
	_, err := os.Stat(logDir)
	if os.IsNotExist(err) {
		err = os.Mkdir(logDir, 0x644)
		if err != nil {
			return nil, err
		}
	}

	return os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0x644)
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
//
// 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
//
//      http://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.

// Program gcping pings GCP regions and reports about the latency.
package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"sort"
	"text/tabwriter"
	"time"
)

// TODO(jbd): Add more zones.
var endpoints = map[string]string{
	"global":                  "35.186.221.153",
	"asia-east1":              "104.155.201.52",
	"asia-east2":              "35.220.162.209",
	"asia-northeast1":         "104.198.86.148",
	"asia-northeast2":         "34.97.196.51",
	"asia-south1":             "35.200.186.152",
	"asia-southeast1":         "35.185.179.198",
	"australia-southeast1":    "35.189.6.113",
	"europe-north1":           "35.228.170.201",
	"europe-west1":            "104.199.82.109",
	"europe-west2":            "35.189.67.146",
	"europe-west3":            "35.198.78.172",
	"europe-west4":            "35.204.93.82",
	"europe-west6":            "34.65.3.254",
	"northamerica-northeast1": "35.203.57.164",
	"southamerica-east1":      "35.198.10.68",
	"us-central1":             "104.197.165.8",
	"us-east1":                "104.196.161.21",
	"us-east4":                "35.186.168.152",
	"us-west1":                "104.199.116.74",
	"us-west2":                "35.236.45.25",
}

var (
	top         bool
	number      int // number of requests for each region
	concurrency int
	timeout     time.Duration
	csv         bool
	verbose     bool
	// TODO(jbd): Add payload options such as body size.

	client  *http.Client // TODO(jbd): One client per worker?
	inputs  chan input
	outputs chan output
)

func main() {
	flag.BoolVar(&top, "top", false, "")
	flag.IntVar(&number, "n", 10, "")
	flag.IntVar(&concurrency, "c", 10, "")
	flag.DurationVar(&timeout, "t", time.Duration(0), "")
	flag.BoolVar(&verbose, "v", false, "")
	flag.BoolVar(&csv, "csv", false, "")

	flag.Usage = usage
	flag.Parse()

	if number < 0 || concurrency <= 0 {
		usage()
	}
	if csv {
		verbose = false // if output is CSV, no need for verbose output
	}

	client = &http.Client{
		Timeout: timeout,
	}

	go start()
	inputs = make(chan input, concurrency)
	outputs = make(chan output, number*len(endpoints))
	for i := 0; i < number; i++ {
		for r, e := range endpoints {
			inputs <- input{region: r, endpoint: e}
		}
	}
	close(inputs)
	report()
}

func start() {
	for worker := 0; worker < concurrency; worker++ {
		go func() {
			for m := range inputs {
				m.HTTP()
			}
		}()
	}
}

func report() {
	m := make(map[string]output)
	for i := 0; i < number*len(endpoints); i++ {
		o := <-outputs

		a := m[o.region]

		a.region = o.region
		a.durations = append(a.durations, o.durations[0])
		a.errors += o.errors

		m[o.region] = a
	}
	all := make([]output, 0, len(m))
	for _, t := range m {
		all = append(all, t)
	}

	// sort all by median duration.
	sort.Slice(all, func(i, j int) bool {
		return all[i].median() < all[j].median()
	})

	if top {
		t := averages[0].region
		if t == "global" {
			t = averages[1].region
		}
		fmt.Print(t)
		return
	}

	tr := tabwriter.NewWriter(os.Stdout, 3, 2, 2, ' ', 0)
	for i, a := range all {
		fmt.Fprintf(tr, "%2d.\t[%v]\t%v", i+1, a.region, a.median())
		if a.errors > 0 {
			fmt.Fprintf(tr, "\t(%d errors)", a.errors)
		}
		fmt.Fprintln(tr)
	}
	tr.Flush()
}

func usage() {
	fmt.Println(usageText)
	os.Exit(0)
}

var usageText = `gcping [options...]

Options:
-n   Number of requests to be made to each region.
     By default 10; can't be negative.
-c   Max number of requests to be made at any time.
     By default 10; can't be negative or zero.
-t   Timeout. By default, no timeout.
     Examples: "500ms", "1s", "1s500ms".
-top If true, only the top (non-global) region is printed.

-csv CSV output; disables verbose output.
-v   Verbose output.

Need a website version? See gcping.com
`
<commit_msg>fix build breakage caused by #13 and #14 (#17)<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
//
// 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
//
//      http://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.

// Program gcping pings GCP regions and reports about the latency.
package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"sort"
	"text/tabwriter"
	"time"
)

// TODO(jbd): Add more zones.
var endpoints = map[string]string{
	"global":                  "35.186.221.153",
	"asia-east1":              "104.155.201.52",
	"asia-east2":              "35.220.162.209",
	"asia-northeast1":         "104.198.86.148",
	"asia-northeast2":         "34.97.196.51",
	"asia-south1":             "35.200.186.152",
	"asia-southeast1":         "35.185.179.198",
	"australia-southeast1":    "35.189.6.113",
	"europe-north1":           "35.228.170.201",
	"europe-west1":            "104.199.82.109",
	"europe-west2":            "35.189.67.146",
	"europe-west3":            "35.198.78.172",
	"europe-west4":            "35.204.93.82",
	"europe-west6":            "34.65.3.254",
	"northamerica-northeast1": "35.203.57.164",
	"southamerica-east1":      "35.198.10.68",
	"us-central1":             "104.197.165.8",
	"us-east1":                "104.196.161.21",
	"us-east4":                "35.186.168.152",
	"us-west1":                "104.199.116.74",
	"us-west2":                "35.236.45.25",
}

var (
	top         bool
	number      int // number of requests for each region
	concurrency int
	timeout     time.Duration
	csv         bool
	verbose     bool
	// TODO(jbd): Add payload options such as body size.

	client  *http.Client // TODO(jbd): One client per worker?
	inputs  chan input
	outputs chan output
)

func main() {
	flag.BoolVar(&top, "top", false, "")
	flag.IntVar(&number, "n", 10, "")
	flag.IntVar(&concurrency, "c", 10, "")
	flag.DurationVar(&timeout, "t", time.Duration(0), "")
	flag.BoolVar(&verbose, "v", false, "")
	flag.BoolVar(&csv, "csv", false, "")

	flag.Usage = usage
	flag.Parse()

	if number < 0 || concurrency <= 0 {
		usage()
	}
	if csv {
		verbose = false // if output is CSV, no need for verbose output
	}

	client = &http.Client{
		Timeout: timeout,
	}

	go start()
	inputs = make(chan input, concurrency)
	outputs = make(chan output, number*len(endpoints))
	for i := 0; i < number; i++ {
		for r, e := range endpoints {
			inputs <- input{region: r, endpoint: e}
		}
	}
	close(inputs)
	report()
}

func start() {
	for worker := 0; worker < concurrency; worker++ {
		go func() {
			for m := range inputs {
				m.HTTP()
			}
		}()
	}
}

func report() {
	m := make(map[string]output)
	for i := 0; i < number*len(endpoints); i++ {
		o := <-outputs

		a := m[o.region]

		a.region = o.region
		a.durations = append(a.durations, o.durations[0])
		a.errors += o.errors

		m[o.region] = a
	}
	all := make([]output, 0, len(m))
	for _, t := range m {
		all = append(all, t)
	}

	// sort all by median duration.
	sort.Slice(all, func(i, j int) bool {
		return all[i].median() < all[j].median()
	})

	if top {
		t := all[0].region
		if t == "global" {
			t = all[1].region
		}
		fmt.Print(t)
		return
	}

	tr := tabwriter.NewWriter(os.Stdout, 3, 2, 2, ' ', 0)
	for i, a := range all {
		fmt.Fprintf(tr, "%2d.\t[%v]\t%v", i+1, a.region, a.median())
		if a.errors > 0 {
			fmt.Fprintf(tr, "\t(%d errors)", a.errors)
		}
		fmt.Fprintln(tr)
	}
	tr.Flush()
}

func usage() {
	fmt.Println(usageText)
	os.Exit(0)
}

var usageText = `gcping [options...]

Options:
-n   Number of requests to be made to each region.
     By default 10; can't be negative.
-c   Max number of requests to be made at any time.
     By default 10; can't be negative or zero.
-t   Timeout. By default, no timeout.
     Examples: "500ms", "1s", "1s500ms".
-top If true, only the top (non-global) region is printed.

-csv CSV output; disables verbose output.
-v   Verbose output.

Need a website version? See gcping.com
`
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/mattn/go-runewidth"
)

func usage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Align FILE(s), or standard input.

Options:
  -m, --margin=FORMAT      join line by FORMAT (default: 1:1)
  -r, --regexp             DELIM is a regular expression
  -d, --delimiter=DELIM    use DELIM to separate line (default: /\s+/)
  --help                   show this help message
  --version                print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
v0.1.0
`[1:])
}

var (
	DIGIT_ONLY             = regexp.MustCompile(`^\d+$`)
	COLON_SEPARATED_DIGITS = regexp.MustCompile(`^(\d+):(\d+)$`)
)

type Margin struct {
	left  int
	right int
}

func NewMargin() *Margin {
	return &Margin{
		left:  1,
		right: 1,
	}
}

func (m *Margin) String() string {
	return fmt.Sprint(*m)
}

func (m *Margin) Set(format string) error {
	switch {
	case DIGIT_ONLY.MatchString(format):
		n, err := strconv.Atoi(format)
		if err != nil {
			return err
		}
		m.left, m.right = n, n
	case COLON_SEPARATED_DIGITS.MatchString(format):
		a := COLON_SEPARATED_DIGITS.FindAllStringSubmatch(format, -1)
		left, err := strconv.Atoi(a[0][1])
		if err != nil {
			return err
		}
		right, err := strconv.Atoi(a[0][2])
		if err != nil {
			return err
		}
		m.left, m.right = left, right
	default:
		return fmt.Errorf("margin:", "invalid format:", format)
	}
	return nil
}

func (m *Margin) Join(a []string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := (m.left + m.right) * (len(a) / 2)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}
	lm, rm := strings.Repeat(" ", m.left), strings.Repeat(" ", m.right)

	b := make([]byte, n)
	bp := copy(b, a[0])
	for i := 2; i <= len(a); i += 2 {
		bp += copy(b[bp:], lm)
		bp += copy(b[bp:], a[i-1])
		if i != len(a) {
			bp += copy(b[bp:], rm)
			bp += copy(b[bp:], a[i])
		}
	}
	return string(b)
}

var SPACES = regexp.MustCompile(`\s+`)

type Delimiter struct {
	re        *regexp.Regexp
	UseRegexp bool
}

func NewDelimiter() *Delimiter {
	return &Delimiter{}
}

func (d *Delimiter) String() string {
	return fmt.Sprint(*d)
}

func (d *Delimiter) Set(expr string) error {
	if !d.UseRegexp {
		expr = regexp.QuoteMeta(expr)
	}
	re, err := regexp.Compile(expr)
	if err != nil {
		return err
	}
	d.re = re
	return nil
}

func (d *Delimiter) Split(a string) []string {
	if d.re == nil {
		return SPACES.Split(a, -1)
	}

	matches := d.re.FindAllStringIndex(a, -1)
	if len(matches) == 0 {
		return []string{a}
	}

	sls := make([]string, 0, len(matches)*2+1)
	beg, end := 0, 0
	for _, match := range matches {
		end = match[0]
		sls = append(sls, a[beg:end])
		beg, end = match[0], match[1]
		sls = append(sls, a[beg:end])
		beg = match[1]
	}
	sls = append(sls, a[beg:])
	for i := 0; i < len(sls); i++ {
		sls[i] = strings.TrimSpace(sls[i])
	}
	return sls
}

type Aligner struct {
	w      io.Writer
	Margin *Margin
	Delim  *Delimiter
	lines  [][]string
	width  []int
}

func NewAligner(w io.Writer) *Aligner {
	return &Aligner{
		w:      w,
		Margin: NewMargin(),
		Delim:  NewDelimiter(),
	}
}

func (a *Aligner) appendLine(s string) {
	sp := a.Delim.Split(s)
	a.lines = append(a.lines, sp)
	if len(sp) == 1 {
		return
	}
	for i, cell := range sp {
		if i == len(a.width) {
			a.width = append(a.width, 0)
		}

		w := runewidth.StringWidth(cell)
		if w > a.width[i] {
			a.width[i] = w
		}
	}
}

func (a *Aligner) ReadAll(r io.Reader) error {
	s := bufio.NewScanner(r)
	for s.Scan() {
		a.appendLine(s.Text())
	}
	return s.Err()
}

func (a *Aligner) format(l []string) string {
	if len(l) == 1 {
		return l[0]
	}
	for i := 0; i < len(l); i++ {
		l[i] = l[i] + strings.Repeat(" ", a.width[i]-runewidth.StringWidth(l[i]))
	}
	return strings.TrimSpace(a.Margin.Join(l))
}

func (a *Aligner) Flush() error {
	for _, l := range a.lines {
		_, err := fmt.Fprintln(a.w, a.format(l))
		if err != nil {
			return err
		}
	}
	return nil
}

func do(a *Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	return a.Flush()
}

func _main() error {
	isHelp := flag.Bool("help", false, "")
	isVersion := flag.Bool("version", false, "")

	a := NewAligner(os.Stdout)
	flag.Var(a.Margin, "m", "")
	flag.Var(a.Margin, "margin", "")
	flag.Var(a.Delim, "d", "")
	flag.Var(a.Delim, "delimiter", "")
	flag.BoolVar(&a.Delim.UseRegexp, "r", false, "")
	flag.BoolVar(&a.Delim.UseRegexp, "regexp", false, "")

	flag.Usage = usage
	flag.Parse()
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "alita:", err)
		os.Exit(1)
	}
}
<commit_msg>Refactoring Margin.Set<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/mattn/go-runewidth"
)

func usage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Align FILE(s), or standard input.

Options:
  -m, --margin=FORMAT      join line by FORMAT (default: 1:1)
  -r, --regexp             DELIM is a regular expression
  -d, --delimiter=DELIM    use DELIM to separate line (default: /\s+/)
  --help                   show this help message
  --version                print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
v0.1.0
`[1:])
}

var (
	DIGIT_ONLY             = regexp.MustCompile(`^\d+$`)
	COLON_SEPARATED_DIGITS = regexp.MustCompile(`^(\d+):(\d+)$`)
)

type Margin struct {
	left  int
	right int
}

func NewMargin() *Margin {
	return &Margin{
		left:  1,
		right: 1,
	}
}

func (m *Margin) String() string {
	return fmt.Sprint(*m)
}

func (m *Margin) Set(format string) error {
	if DIGIT_ONLY.MatchString(format) {
		n, err := strconv.Atoi(format)
		if err != nil {
			return err
		}
		m.left, m.right = n, n
		return nil
	}
	if COLON_SEPARATED_DIGITS.MatchString(format) {
		a := COLON_SEPARATED_DIGITS.FindAllStringSubmatch(format, -1)
		left, err := strconv.Atoi(a[0][1])
		if err != nil {
			return err
		}
		right, err := strconv.Atoi(a[0][2])
		if err != nil {
			return err
		}
		m.left, m.right = left, right
		return nil
	}
	return fmt.Errorf("margin:", "invalid format:", format)
}

func (m *Margin) Join(a []string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := (m.left + m.right) * (len(a) / 2)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}
	lm, rm := strings.Repeat(" ", m.left), strings.Repeat(" ", m.right)

	b := make([]byte, n)
	bp := copy(b, a[0])
	for i := 2; i <= len(a); i += 2 {
		bp += copy(b[bp:], lm)
		bp += copy(b[bp:], a[i-1])
		if i != len(a) {
			bp += copy(b[bp:], rm)
			bp += copy(b[bp:], a[i])
		}
	}
	return string(b)
}

var SPACES = regexp.MustCompile(`\s+`)

type Delimiter struct {
	re        *regexp.Regexp
	UseRegexp bool
}

func NewDelimiter() *Delimiter {
	return &Delimiter{}
}

func (d *Delimiter) String() string {
	return fmt.Sprint(*d)
}

func (d *Delimiter) Set(expr string) error {
	if !d.UseRegexp {
		expr = regexp.QuoteMeta(expr)
	}
	re, err := regexp.Compile(expr)
	if err != nil {
		return err
	}
	d.re = re
	return nil
}

func (d *Delimiter) Split(a string) []string {
	if d.re == nil {
		return SPACES.Split(a, -1)
	}

	matches := d.re.FindAllStringIndex(a, -1)
	if len(matches) == 0 {
		return []string{a}
	}

	sls := make([]string, 0, len(matches)*2+1)
	beg, end := 0, 0
	for _, match := range matches {
		end = match[0]
		sls = append(sls, a[beg:end])
		beg, end = match[0], match[1]
		sls = append(sls, a[beg:end])
		beg = match[1]
	}
	sls = append(sls, a[beg:])
	for i := 0; i < len(sls); i++ {
		sls[i] = strings.TrimSpace(sls[i])
	}
	return sls
}

type Aligner struct {
	w      io.Writer
	Margin *Margin
	Delim  *Delimiter
	lines  [][]string
	width  []int
}

func NewAligner(w io.Writer) *Aligner {
	return &Aligner{
		w:      w,
		Margin: NewMargin(),
		Delim:  NewDelimiter(),
	}
}

func (a *Aligner) appendLine(s string) {
	sp := a.Delim.Split(s)
	a.lines = append(a.lines, sp)
	if len(sp) == 1 {
		return
	}
	for i, cell := range sp {
		if i == len(a.width) {
			a.width = append(a.width, 0)
		}

		w := runewidth.StringWidth(cell)
		if w > a.width[i] {
			a.width[i] = w
		}
	}
}

func (a *Aligner) ReadAll(r io.Reader) error {
	s := bufio.NewScanner(r)
	for s.Scan() {
		a.appendLine(s.Text())
	}
	return s.Err()
}

func (a *Aligner) format(l []string) string {
	if len(l) == 1 {
		return l[0]
	}
	for i := 0; i < len(l); i++ {
		l[i] = l[i] + strings.Repeat(" ", a.width[i]-runewidth.StringWidth(l[i]))
	}
	return strings.TrimSpace(a.Margin.Join(l))
}

func (a *Aligner) Flush() error {
	for _, l := range a.lines {
		_, err := fmt.Fprintln(a.w, a.format(l))
		if err != nil {
			return err
		}
	}
	return nil
}

func do(a *Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	return a.Flush()
}

func _main() error {
	isHelp := flag.Bool("help", false, "")
	isVersion := flag.Bool("version", false, "")

	a := NewAligner(os.Stdout)
	flag.Var(a.Margin, "m", "")
	flag.Var(a.Margin, "margin", "")
	flag.Var(a.Delim, "d", "")
	flag.Var(a.Delim, "delimiter", "")
	flag.BoolVar(&a.Delim.UseRegexp, "r", false, "")
	flag.BoolVar(&a.Delim.UseRegexp, "regexp", false, "")

	flag.Usage = usage
	flag.Parse()
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "alita:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	cryptorand "crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"github.com/Sirupsen/logrus"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"time"
	"encoding/pem"
	"crypto/ecdsa"
)

const (
	LETSENCRYPT_CREATE_CERTIFICATE_TIMEOUT = time.Minute
	LETSENCRYPT_PRODUCTION_API_URL         = "https://acme-v01.api.letsencrypt.org/directory"
	LETSENCRYPT_STAGING_API_URL            = "https://acme-staging.api.letsencrypt.org/directory"
	PRIVATE_KEY_BITS                       = 2048
	TRY_COUNT                              = 10
	RETRY_SLEEP                            = time.Second
)

var (
	bindTo            = flag.String("bind-to", ":443", "")
	targetPort        = flag.Int("target-port", 80, "")
	targetConnTimeout = flag.Duration("target-conn-timeout", time.Second, "")
	acmeApiUrl        = flag.String("acme-server", LETSENCRYPT_PRODUCTION_API_URL, "")
	acmeTestServer    = flag.Bool("test", false, "Use test lets encrypt server instead of <acme-server>")
	certDir           = flag.String("cert-dir", "certs", `Directory for save cached certificates. Set cert-dir="" for disable save certs`)
)

var (
	localIPs    []net.IP
	acmeService *acmeStruct
)

type stateStruct struct {
	PrivateKey *rsa.PrivateKey
}

func main() {
	var err error

	flag.Parse()

	// Init
	logrus.SetLevel(logrus.DebugLevel)
	localIPs = getLocalIPs()
	acmeService = &acmeStruct{}

	// init service
	acmeService = &acmeStruct{}
	if *acmeTestServer {
		acmeService.serverAddress = LETSENCRYPT_STAGING_API_URL
	} else {
		acmeService.serverAddress = *acmeApiUrl
	}
	logrus.Info("Generate private keys")
	acmeService.privateKey, err = rsa.GenerateKey(cryptorand.Reader, PRIVATE_KEY_BITS)
	if err != nil {
		logrus.Panic("Can't generate private key")
	}
	acmeService.Init()
	acmeService.RegisterEnsure(context.TODO())

	// Start listen
	tcpAddr, err := net.ResolveTCPAddr("tcp", *bindTo)
	if err != nil {
		logrus.Panicf("Can't resolve bind-to address '%v': %v", *bindTo, err)
	}
	logrus.Errorf("Start listen: %v", tcpAddr)

	listener, err := net.ListenTCP("tcp", tcpAddr)
	logrus.Debug(listener.Addr())
	if err != nil {
		panic(err)
	}
	for {
		tcpConn, err := listener.AcceptTCP()
		if err != nil {
			panic(err)
		}
		go handleTcpConnection(tcpConn)
	}
}

func certificateCacheGet(domain string) *tls.Certificate {
	if *certDir == "" {
		logrus.Debugf("Skip certificateCacheGet becouse certDir is empty")
		return nil
	}
	keyPath := filepath.Join(*certDir, domain+".key")
	certPath := filepath.Join(*certDir, domain+"crt")
	cert, err := tls.LoadX509KeyPair(certPath, keyPath)

	switch {
	case err == nil:
		logrus.Debugf("Certificate files readed for domain '%v'", domain)
	case os.IsNotExist(err):
		logrus.Infof("Have no certificate/key in cert-dir for domain '%v'", domain)
		return nil
	default:
		logrus.Errorf("Can't certificate/key load from file for domain '%v': %v", domain)
		return nil
	}

	if len(cert.Certificate) == 0 {
		logrus.Errorf("No certificates in file for domain '%v', file '%v'", domain, certPath)
		return nil
	}
	cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
	if err == nil {
		logrus.Debugf("Certificate parsed for domain '%v'")
		return &cert
	} else {
		logrus.Errorf("Can't parse certificate for domain '%v': %v", domain, err)
		return nil
	}
}

func certificateCachePut(domain string, cert *tls.Certificate) {
	if *certDir == "" {
		logrus.Debugf("Skip certificateCachePut becouse certDir is empty")
		return
	}
	err := os.MkdirAll(*certDir, 0600)
	if err != nil {
		logrus.Errorf("Can't create dir for save cached cert '%v':%v", *certDir, err)
		return
	}

	keyPath := filepath.Join(*certDir, domain+".key")
	certPath := filepath.Join(*certDir, domain+".crt")

	keyFile, err := os.Create(keyPath)
	if keyFile != nil {
		defer keyFile.Close()
	}
	if err != nil {
		logrus.Errorf("Can't open file for save key '%v':%v", keyPath, err)
		return
	}

	switch key := cert.PrivateKey.(type) {
	case *rsa.PrivateKey:
		keyBytes := x509.MarshalPKCS1PrivateKey(key)
		pemBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}
		err = pem.Encode(keyFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Error while write bytes to rsa-key file '%v': %v", keyPath, err)
			return
		}
	case *ecdsa.PrivateKey:
		keyBytes, err := x509.MarshalECPrivateKey(key)
		if err != nil {
			logrus.Errorf("Error while marshal ecdsa-key for domain '%v': %v", domain, err)
			return
		}
		pemBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}
		err = pem.Encode(keyFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Error while write bytes to ecdsa-key file '%v': %v", keyPath, err)
			return
		}
	}

	certFile, err := os.Create(certPath)
	if certFile != nil {
		defer certFile.Close()
	}
	if err != nil {
		logrus.Errorf("Can't open file for write certificate '%v': %v", certPath, err)
		return
	}
	for _, certBytes := range cert.Certificate {
		pemBlock := pem.Block{Type:"CERTIFICATE", Bytes:certBytes}
		err = pem.Encode(certFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Can't write pem block to certificate '%v': %v", certPath, err)
			return
		}
	}

	logrus.Infof("Save certificate for domain '%v' to files: %v, %v", domain, keyPath, certPath)
}

func certificateGet(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
	domain := strings.ToLower(clientHello.ServerName)
	if logrus.GetLevel() >= logrus.DebugLevel {
		logrus.Debugf("Required certificate for domain '%v'", domain)
	}

	if strings.HasSuffix(domain, ACME_DOMAIN_SUFFIX) {
		// force generate new certificate, without caching.
		return acmeService.CreateCertificate(domain)
	}

	cert = certificateCacheGet(domain)
	if cert != nil && cert.Leaf.NotAfter.Before(time.Now()) {
		logrus.Warnf("Expired certificate got from cache for domain '%v'", domain)
		return cert, nil
	}

	cert, err = acmeService.CreateCertificate(domain)
	if err == nil {
		certificateCachePut(domain, cert)
	}
	return cert, err
}

func handleTcpConnection(in *net.TCPConn) {
	target, err := getTargetConn(in)
	if err != nil {
		logrus.Errorf("Can't get target IP/port for '%v': %v", target.String(), err)
		return
	}

	// handle ssl
	tlsConfig := tls.Config{
		GetCertificate: certificateGet,
		MinVersion:     tls.VersionSSL30,
	}
	tlsConn := tls.Server(in, &tlsConfig)
	err = tlsConn.Handshake()
	logrus.Debug("tls ciper:", tlsConn.ConnectionState().CipherSuite)
	if err == nil {
		logrus.Debug("Handshake for incoming:", tlsConn.RemoteAddr().String())
	} else {
		logrus.Infof("Error in tls handshake from '%v':%v", tlsConn.RemoteAddr(), err)
	}

	startProxy(target, tlsConn)
}

func getLocalIPs() (res []net.IP) {
	bindAddr, _ := net.ResolveTCPAddr("tcp", *bindTo)
	if bindAddr.IP.IsUnspecified() || len(bindAddr.IP) == 0 {
		addresses, err := net.InterfaceAddrs()
		if err != nil {
			log.Panic("Can't get local ip addresses:", err)
		}
		res = make([]net.IP, 0, len(addresses))
		for _, addr := range addresses {
			logrus.Debug("Local ip:", addr.String())
			ip, _, err := net.ParseCIDR(addr.String())
			if err == nil {
				res = append(res, ip)
			} else {
				logrus.Errorf("Can't parse local ip '%v': %v", addr.String(), err)
			}
		}
	} else {
		res = []net.IP{bindAddr.IP}
	}
	if logrus.GetLevel() >= logrus.InfoLevel {
		ipStrings := make([]string, len(res))
		for i, addr := range res {
			ipStrings[i] = addr.String()
		}
		logrus.Info("Local ip:", ipStrings)
	}
	return res
}

func getTargetConn(in *net.TCPConn) (net.TCPAddr, error) {
	targetAddrP, err := net.ResolveTCPAddr("tcp", in.LocalAddr().String())
	if err != nil {
		logrus.Errorf("Can't resolve local addr '%v': %v", in.LocalAddr().String(), err)
		return net.TCPAddr{}, err
	}
	targetAddrP.Port = *targetPort
	return *targetAddrP, nil
}

func startProxy(targetAddr net.TCPAddr, in net.Conn) {
	logrus.Infof("Start proxy connection from '%v' to'%v'", in.RemoteAddr().String(), targetAddr.String())

	targetConnCommon, err := net.DialTimeout("tcp", targetAddr.String(), *targetConnTimeout)
	if err != nil {
		logrus.Warnf("Can't connect to target '%v': %v", targetAddr.String(), err)
		return
	}

	targetConn := targetConnCommon.(*net.TCPConn)
	go func() {
		io.Copy(in, targetConn)
		in.Close()
		targetConn.Close()
	}()
	go func() {
		io.Copy(targetConn, in)
		in.Close()
		targetConn.Close()
	}()
}
<commit_msg>fix cert caching<commit_after>package main

import (
	"context"
	cryptorand "crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"github.com/Sirupsen/logrus"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"time"
	"encoding/pem"
	"crypto/ecdsa"
)

const (
	LETSENCRYPT_CREATE_CERTIFICATE_TIMEOUT = time.Minute
	LETSENCRYPT_PRODUCTION_API_URL         = "https://acme-v01.api.letsencrypt.org/directory"
	LETSENCRYPT_STAGING_API_URL            = "https://acme-staging.api.letsencrypt.org/directory"
	PRIVATE_KEY_BITS                       = 2048
	TRY_COUNT                              = 10
	RETRY_SLEEP                            = time.Second
)

var (
	bindTo            = flag.String("bind-to", ":443", "")
	targetPort        = flag.Int("target-port", 80, "")
	targetConnTimeout = flag.Duration("target-conn-timeout", time.Second, "")
	acmeApiUrl        = flag.String("acme-server", LETSENCRYPT_PRODUCTION_API_URL, "")
	acmeTestServer    = flag.Bool("test", false, "Use test lets encrypt server instead of <acme-server>")
	certDir           = flag.String("cert-dir", "certs", `Directory for save cached certificates. Set cert-dir="" for disable save certs`)
)

var (
	localIPs    []net.IP
	acmeService *acmeStruct
)

type stateStruct struct {
	PrivateKey *rsa.PrivateKey
}

func main() {
	var err error

	flag.Parse()

	// Init
	logrus.SetLevel(logrus.DebugLevel)
	localIPs = getLocalIPs()
	acmeService = &acmeStruct{}

	// init service
	acmeService = &acmeStruct{}
	if *acmeTestServer {
		acmeService.serverAddress = LETSENCRYPT_STAGING_API_URL
	} else {
		acmeService.serverAddress = *acmeApiUrl
	}
	logrus.Info("Generate private keys")
	acmeService.privateKey, err = rsa.GenerateKey(cryptorand.Reader, PRIVATE_KEY_BITS)
	if err != nil {
		logrus.Panic("Can't generate private key")
	}
	acmeService.Init()
	acmeService.RegisterEnsure(context.TODO())

	// Start listen
	tcpAddr, err := net.ResolveTCPAddr("tcp", *bindTo)
	if err != nil {
		logrus.Panicf("Can't resolve bind-to address '%v': %v", *bindTo, err)
	}
	logrus.Errorf("Start listen: %v", tcpAddr)

	listener, err := net.ListenTCP("tcp", tcpAddr)
	logrus.Debug(listener.Addr())
	if err != nil {
		panic(err)
	}
	for {
		tcpConn, err := listener.AcceptTCP()
		if err != nil {
			panic(err)
		}
		go handleTcpConnection(tcpConn)
	}
}

func certificateCacheGet(domain string) *tls.Certificate {
	if *certDir == "" {
		logrus.Debugf("Skip certificateCacheGet becouse certDir is empty")
		return nil
	}
	keyPath := filepath.Join(*certDir, domain+".key")
	certPath := filepath.Join(*certDir, domain+".crt")
	cert, err := tls.LoadX509KeyPair(certPath, keyPath)

	switch {
	case err == nil:
		logrus.Debugf("Certificate files readed for domain '%v'", domain)
	case os.IsNotExist(err):
		logrus.Debugf("Certificate cache path key: '%v', cert: '%v'", keyPath, certPath)
		logrus.Infof("Have no certificate/key in cert-dir for domain '%v'", domain)
		return nil
	default:
		logrus.Errorf("Can't certificate/key load from file for domain '%v': %v", domain)
		return nil
	}

	if len(cert.Certificate) == 0 {
		logrus.Errorf("No certificates in file for domain '%v', file '%v'", domain, certPath)
		return nil
	}
	cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
	if err == nil {
		logrus.Debugf("Certificate parsed for domain '%v'", domain)
		return &cert
	} else {
		logrus.Errorf("Can't parse certificate for domain '%v': %v", domain, err)
		return nil
	}
}

func certificateCachePut(domain string, cert *tls.Certificate) {
	logrus.Infof("Certificate put to cache for domain '%v'", domain)
	if *certDir == "" {
		logrus.Debugf("Skip certificateCachePut becouse certDir is empty")
		return
	}
	err := os.MkdirAll(*certDir, 0600)
	if err != nil {
		logrus.Errorf("Can't create dir for save cached cert '%v':%v", *certDir, err)
		return
	}

	keyPath := filepath.Join(*certDir, domain+".key")
	certPath := filepath.Join(*certDir, domain+".crt")

	keyFile, err := os.Create(keyPath)
	if keyFile != nil {
		defer keyFile.Close()
	}
	if err != nil {
		logrus.Errorf("Can't open file for save key '%v':%v", keyPath, err)
		return
	}

	switch key := cert.PrivateKey.(type) {
	case *rsa.PrivateKey:
		keyBytes := x509.MarshalPKCS1PrivateKey(key)
		pemBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}
		err = pem.Encode(keyFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Error while write bytes to rsa-key file '%v': %v", keyPath, err)
			return
		}
	case *ecdsa.PrivateKey:
		keyBytes, err := x509.MarshalECPrivateKey(key)
		if err != nil {
			logrus.Errorf("Error while marshal ecdsa-key for domain '%v': %v", domain, err)
			return
		}
		pemBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}
		err = pem.Encode(keyFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Error while write bytes to ecdsa-key file '%v': %v", keyPath, err)
			return
		}
	}

	certFile, err := os.Create(certPath)
	if certFile != nil {
		defer certFile.Close()
	}
	if err != nil {
		logrus.Errorf("Can't open file for write certificate '%v': %v", certPath, err)
		return
	}
	for _, certBytes := range cert.Certificate {
		pemBlock := pem.Block{Type:"CERTIFICATE", Bytes:certBytes}
		err = pem.Encode(certFile, &pemBlock)
		if err != nil {
			logrus.Errorf("Can't write pem block to certificate '%v': %v", certPath, err)
			return
		}
	}

	logrus.Infof("Save certificate for domain '%v' to files: %v, %v", domain, keyPath, certPath)
}

func certificateGet(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
	domain := strings.ToLower(clientHello.ServerName)
	if logrus.GetLevel() >= logrus.DebugLevel {
		logrus.Debugf("Required certificate for domain '%v'", domain)
	}

	if strings.HasSuffix(domain, ACME_DOMAIN_SUFFIX) {
		// force generate new certificate, without caching.
		return acmeService.CreateCertificate(domain)
	}

	cert = certificateCacheGet(domain)

	switch {
	case cert != nil && cert.Leaf.NotAfter.Before(time.Now()):
		logrus.Warnf("Expired certificate got from cache for domain '%v'", domain)
		// pass to create new certificate.
	case cert != nil:
		return cert, nil
	default:
		// pass
	}

	cert, err = acmeService.CreateCertificate(domain)
	if err == nil {
		certificateCachePut(domain, cert)
	}
	return cert, err
}

func handleTcpConnection(in *net.TCPConn) {
	target, err := getTargetConn(in)
	if err != nil {
		logrus.Errorf("Can't get target IP/port for '%v': %v", target.String(), err)
		return
	}

	// handle ssl
	tlsConfig := tls.Config{
		GetCertificate: certificateGet,
		MinVersion:     tls.VersionSSL30,
	}
	tlsConn := tls.Server(in, &tlsConfig)
	err = tlsConn.Handshake()
	logrus.Debug("tls ciper:", tlsConn.ConnectionState().CipherSuite)
	if err == nil {
		logrus.Debug("Handshake for incoming:", tlsConn.RemoteAddr().String())
	} else {
		logrus.Infof("Error in tls handshake from '%v':%v", tlsConn.RemoteAddr(), err)
	}

	startProxy(target, tlsConn)
}

func getLocalIPs() (res []net.IP) {
	bindAddr, _ := net.ResolveTCPAddr("tcp", *bindTo)
	if bindAddr.IP.IsUnspecified() || len(bindAddr.IP) == 0 {
		addresses, err := net.InterfaceAddrs()
		if err != nil {
			log.Panic("Can't get local ip addresses:", err)
		}
		res = make([]net.IP, 0, len(addresses))
		for _, addr := range addresses {
			logrus.Debug("Local ip:", addr.String())
			ip, _, err := net.ParseCIDR(addr.String())
			if err == nil {
				res = append(res, ip)
			} else {
				logrus.Errorf("Can't parse local ip '%v': %v", addr.String(), err)
			}
		}
	} else {
		res = []net.IP{bindAddr.IP}
	}
	if logrus.GetLevel() >= logrus.InfoLevel {
		ipStrings := make([]string, len(res))
		for i, addr := range res {
			ipStrings[i] = addr.String()
		}
		logrus.Info("Local ip:", ipStrings)
	}
	return res
}

func getTargetConn(in *net.TCPConn) (net.TCPAddr, error) {
	targetAddrP, err := net.ResolveTCPAddr("tcp", in.LocalAddr().String())
	if err != nil {
		logrus.Errorf("Can't resolve local addr '%v': %v", in.LocalAddr().String(), err)
		return net.TCPAddr{}, err
	}
	targetAddrP.Port = *targetPort
	return *targetAddrP, nil
}

func startProxy(targetAddr net.TCPAddr, in net.Conn) {
	logrus.Infof("Start proxy connection from '%v' to'%v'", in.RemoteAddr().String(), targetAddr.String())

	targetConnCommon, err := net.DialTimeout("tcp", targetAddr.String(), *targetConnTimeout)
	if err != nil {
		logrus.Warnf("Can't connect to target '%v': %v", targetAddr.String(), err)
		return
	}

	targetConn := targetConnCommon.(*net.TCPConn)
	go func() {
		io.Copy(in, targetConn)
		in.Close()
		targetConn.Close()
	}()
	go func() {
		io.Copy(targetConn, in)
		in.Close()
		targetConn.Close()
	}()
}
<|endoftext|>


<commit_before>// Copyright © 2016 Jacob Dearing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"

	_ "net/http/pprof"

	"github.com/dearing/havoc"
	"github.com/julienschmidt/httprouter"
)

var NAME = GetRandomName(0)

func main() {

	procs := runtime.NumCPU()
	runtime.GOMAXPROCS(procs)

	router := httprouter.New()
	router.GET("/", HandleIndex)
	router.GET("/kill", HandleKill)

	router.GET("/data/reset", HandleDataReset)
	router.GET("/data/set/:value", HandleDataSet)
	router.GET("/data/fill", HandleDataFill)
	router.GET("/data/fill/zero", HandleDataFillZero)
	router.GET("/data/fill/crypto", HandleDataFillCrypto)

	router.GET("/procs/:value", HandleProcs)

	log.Printf("%s : starting.\n", NAME)

	go func() {
		log.Println(http.ListenAndServe(":8081", nil))
	}()

	log.Fatal(http.ListenAndServe(":8080", router))
}

// HANDLES

func HandleIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "My name is %s.\n\n", NAME)
	fmt.Fprint(w, base64.StdEncoding.EncodeToString(havoc.Data))
}

func HandleKill(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "%s: I hardly knew thee.\n", NAME)
	os.Exit(0)
}

// HANDLES - DATA

func HandleDataSet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	size, err := strconv.Atoi(ps.ByName("value"))
	if err != nil {
		fmt.Fprintf(w, "%s: error in parse: %s\n", NAME, err)
		return
	}

	go func() {
		havoc.DataSet(size)
	}()

	fmt.Fprintf(w, "%s: %d indices set.\n", NAME, size)

}

func HandleDataReset(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataReset()
	fmt.Fprintf(w, "%s: Reset.\n", NAME)
}

func HandleDataFill(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFill()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with ones.\n", len(havoc.Data), NAME)
}

func HandleDataFillZero(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFillZero()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with zeroes.\n", len(havoc.Data), NAME)
}

func HandleDataFillCrypto(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFillCrypto()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with random data.\n", len(havoc.Data), NAME)
}

// HANDLES - CPU

func HandleProcs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

	procs, err := strconv.Atoi(ps.ByName("value"))
	if err != nil {
		fmt.Fprintf(w, "%s: error in parse: %s\n", NAME, err)
		return
	}

	for i := 0; i < procs; i++ {
		go func() {
			havoc.Forever()
		}()
	}

	fmt.Fprintf(w, "%s: %d of %d processors engaged.\n", NAME, procs, runtime.NumCPU())
}
<commit_msg>fix ordering for data fill response<commit_after>// Copyright © 2016 Jacob Dearing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"

	_ "net/http/pprof"

	"github.com/dearing/havoc"
	"github.com/julienschmidt/httprouter"
)

var NAME = GetRandomName(0)

func main() {

	procs := runtime.NumCPU()
	runtime.GOMAXPROCS(procs)

	router := httprouter.New()
	router.GET("/", HandleIndex)
	router.GET("/kill", HandleKill)

	router.GET("/data/reset", HandleDataReset)
	router.GET("/data/set/:value", HandleDataSet)
	router.GET("/data/fill", HandleDataFill)
	router.GET("/data/fill/zero", HandleDataFillZero)
	router.GET("/data/fill/crypto", HandleDataFillCrypto)

	router.GET("/procs/:value", HandleProcs)

	log.Printf("%s : starting.\n", NAME)

	go func() {
		log.Println(http.ListenAndServe(":8081", nil))
	}()

	log.Fatal(http.ListenAndServe(":8080", router))
}

// HANDLES

func HandleIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "My name is %s.\n\n", NAME)
	fmt.Fprint(w, base64.StdEncoding.EncodeToString(havoc.Data))
}

func HandleKill(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprintf(w, "%s: I hardly knew thee.\n", NAME)
	os.Exit(0)
}

// HANDLES - DATA

func HandleDataSet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	size, err := strconv.Atoi(ps.ByName("value"))
	if err != nil {
		fmt.Fprintf(w, "%s: error in parse: %s\n", NAME, err)
		return
	}

	go func() {
		havoc.DataSet(size)
	}()

	fmt.Fprintf(w, "%s: %d indices set.\n", NAME, size)

}

func HandleDataReset(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataReset()
	fmt.Fprintf(w, "%s: Reset.\n", NAME)
}

func HandleDataFill(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFill()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with ones.\n", NAME, len(havoc.Data))
}

func HandleDataFillZero(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFillZero()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with zeroes.\n", NAME, len(havoc.Data))
}

func HandleDataFillCrypto(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	havoc.DataFillCrypto()
	fmt.Fprintf(w, "%s: Filling Data, (%d) bytes, with random data.\n", NAME, len(havoc.Data))
}

// HANDLES - CPU

func HandleProcs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

	procs, err := strconv.Atoi(ps.ByName("value"))
	if err != nil {
		fmt.Fprintf(w, "%s: error in parse: %s\n", NAME, err)
		return
	}

	for i := 0; i < procs; i++ {
		go func() {
			havoc.Forever()
		}()
	}

	fmt.Fprintf(w, "%s: %d of %d processors engaged.\n", NAME, procs, runtime.NumCPU())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"path"

	"web_apps/news_aggregator/modules/newsGetter"

	"web_apps/news_aggregator/modules/config"
	"web_apps/news_aggregator/modules/database"
	_ "web_apps/news_aggregator/modules/utils"
)

var (
	serverPort = ":3000"
)

// handleAssets serve all file assets
func handleAssets(assets ...string) {
	fmt.Println("called")
	for _, asset := range assets {
		assetDir := path.Join("public", asset)
		assetURLPath := fmt.Sprintf("/%s/", asset)
		//asset_dir := fmt.Sprintf("public/%s", asset)
		http.Handle(assetURLPath, http.StripPrefix(assetURLPath, http.FileServer(http.Dir(assetDir))))
	}
}

// main entrypoint and main func for the app
func main() {
	go func() {
		config.StartEtcd()
		go database.MongodbStart()

		startRoutes()

		assetsToHandle := []string{"images", "css", "js", "fonts"}
		handleAssets(assetsToHandle...)

		// news getter initializers
		go newsGetter.StartHackerNews()
		go newsGetter.StartGoogleNews()

	}()

	log.Println("now servering to port: ...", serverPort)
	http.ListenAndServe(serverPort, nil)
}
<commit_msg>added comment in main.go for news crawlers<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"path"

	"web_apps/news_aggregator/modules/newsGetter"

	"web_apps/news_aggregator/modules/config"
	"web_apps/news_aggregator/modules/database"
	_ "web_apps/news_aggregator/modules/utils"
)

var (
	serverPort = ":3000"
)

// handleAssets serve all file assets
func handleAssets(assets ...string) {
	fmt.Println("called")
	for _, asset := range assets {
		assetDir := path.Join("public", asset)
		assetURLPath := fmt.Sprintf("/%s/", asset)
		//asset_dir := fmt.Sprintf("public/%s", asset)
		http.Handle(assetURLPath, http.StripPrefix(assetURLPath, http.FileServer(http.Dir(assetDir))))
	}
}

// main entrypoint and main func for the app
func main() {
	go func() {
		config.StartEtcd()
		go database.MongodbStart()

		startRoutes()

		assetsToHandle := []string{"images", "css", "js", "fonts"}
		handleAssets(assetsToHandle...)

		// news getter initializers
		// should set in admin page
		go newsGetter.StartHackerNews()
		go newsGetter.StartGoogleNews()

	}()

	log.Println("now servering to port: ...", serverPort)
	http.ListenAndServe(serverPort, nil)
}
<|endoftext|>


<commit_before>//go:generate go-bindata -pkg main -o credits.go vendor/CREDITS
package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/pkg/errors"

	"github.com/yuuki/binrep/pkg/command"
)

const (
	defaultKeepReleases    int = 5
	defaultSyncConcurrency int = 4
)

var (
	creditsText = string(MustAsset("vendor/CREDITS"))
)

// CLI is the command line object.
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

func main() {
	cli := &CLI{outStream: os.Stdout, errStream: os.Stderr}
	os.Exit(cli.Run(os.Args))
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {
	if len(args) <= 1 {
		fmt.Fprint(cli.errStream, helpText)
		return 2
	}

	var err error

	switch cmd := args[1]; cmd {
	case "list":
		err = cli.doList(args[2:])
	case "show":
		err = cli.doShow(args[2:])
	case "push":
		err = cli.doPush(args[2:])
	case "pull":
		err = cli.doPull(args[2:])
	case "sync":
		err = cli.doSync(args[2:])
	case "-v", "--version":
		fmt.Fprintf(cli.errStream, "%s version %s, build %s, date %s \n", name, version, commit, date)
		return 0
	case "--credits":
		fmt.Println(creditsText)
		return 0
	case "-h", "--help":
		fmt.Fprint(cli.errStream, helpText)
	default:
		fmt.Fprintf(cli.errStream, "%s is undefined subcommand or option", cmd)
		fmt.Fprint(cli.errStream, helpText)
		return 1
	}

	if err != nil {
		fmt.Fprintln(cli.errStream, err)
		return 2
	}

	return 0
}

var helpText = `
Usage: binrep [options]

  The static binary repository manager.

Commands:
  list		show releases on remote repository
  show          show binary information.
  push		push binary.
  pull		pull binary.
  sync          sync remote repository to local directory.

Options:
  --version, -v		print version
  --help, -h            print help
`

func (cli *CLI) prepareFlags(help string) *flag.FlagSet {
	flags := flag.NewFlagSet(name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprint(cli.errStream, help)
	}
	return flags
}

var listHelpText = `
Usage: binrep list [options]

show releases on remote repository

Options:
  --endpoint, -e   s3 URI
`

func (cli *CLI) doList(args []string) error {
	var param command.ListParam
	flags := cli.prepareFlags(listHelpText)
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, listHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) != 0 {
		fmt.Fprint(cli.errStream, listHelpText)
		return errors.Errorf("extra arguments")
	}
	return command.List(&param)
}

var showHelpText = `
Usage: binrep show [options] <host>/<user>/<project>

show binary information.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
`

func (cli *CLI) doShow(args []string) error {
	var param command.ShowParam
	flags := cli.prepareFlags(showHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, showHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) < 1 {
		fmt.Fprint(cli.errStream, showHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Show(&param, flags.Arg(0))
}

var pushHelpText = `
Usage: binrep push [options] <host>/<user>/<project> /path/to/binary ...

push binary.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
  --keep-releases, -k	the number of releases that it keeps (default: 5)
`

func (cli *CLI) doPush(args []string) error {
	var param command.PushParam
	flags := cli.prepareFlags(pushHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.IntVar(&param.KeepReleases, "k", defaultKeepReleases, "")
	flags.IntVar(&param.KeepReleases, "keep-releases", defaultKeepReleases, "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, pushHelpText)
		return errors.Errorf("--endpoint required")
	}
	argLen := len(flags.Args())
	if argLen < 2 {
		fmt.Fprint(cli.errStream, pushHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Push(&param, flags.Arg(0), flags.Args()[1:argLen])
}

var pullHelpText = `
Usage: binrep pull [options] <host>/<user>/<project> /path/to/binary

pull binary.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
`

func (cli *CLI) doPull(args []string) error {
	var param command.PullParam
	flags := cli.prepareFlags(pullHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, pullHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) != 2 {
		fmt.Fprint(cli.errStream, pullHelpText)
		return errors.Errorf("too few or many arguments")
	}
	return command.Pull(&param, flags.Arg(0), flags.Arg(1))
}

var syncHelpText = `
Usage: binrep sync [options] DEST_DIR

pull binary.

Options:
  --endpoint, -e	s3 uri
  --concurrency, -c     number of multiple release fetchers to make at a time
  --max-bandwidth, -bw	max bandwidth for download binaries (Bytes/sec) eg. '1 MB', '1024 KB'
`

func (cli *CLI) doSync(args []string) error {
	var param command.SyncParam
	flags := cli.prepareFlags(syncHelpText)
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	flags.IntVar(&param.Concurrency, "c", defaultSyncConcurrency, "")
	flags.IntVar(&param.Concurrency, "concurrency", defaultSyncConcurrency, "")
	flags.StringVar(&param.MaxBandWidth, "bw", "", "")
	flags.StringVar(&param.MaxBandWidth, "max-bandwidth", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, syncHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) < 1 {
		fmt.Fprint(cli.errStream, syncHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Sync(&param, flags.Arg(0))
}
<commit_msg>Omit '-v' option<commit_after>//go:generate go-bindata -pkg main -o credits.go vendor/CREDITS
package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/pkg/errors"

	"github.com/yuuki/binrep/pkg/command"
)

const (
	defaultKeepReleases    int = 5
	defaultSyncConcurrency int = 4
)

var (
	creditsText = string(MustAsset("vendor/CREDITS"))
)

// CLI is the command line object.
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

func main() {
	cli := &CLI{outStream: os.Stdout, errStream: os.Stderr}
	os.Exit(cli.Run(os.Args))
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {
	if len(args) <= 1 {
		fmt.Fprint(cli.errStream, helpText)
		return 2
	}

	var err error

	switch cmd := args[1]; cmd {
	case "list":
		err = cli.doList(args[2:])
	case "show":
		err = cli.doShow(args[2:])
	case "push":
		err = cli.doPush(args[2:])
	case "pull":
		err = cli.doPull(args[2:])
	case "sync":
		err = cli.doSync(args[2:])
	case "--version":
		fmt.Fprintf(cli.errStream, "%s version %s, build %s, date %s \n", name, version, commit, date)
		return 0
	case "--credits":
		fmt.Println(creditsText)
		return 0
	case "-h", "--help":
		fmt.Fprint(cli.errStream, helpText)
	default:
		fmt.Fprintf(cli.errStream, "%s is undefined subcommand or option", cmd)
		fmt.Fprint(cli.errStream, helpText)
		return 1
	}

	if err != nil {
		fmt.Fprintln(cli.errStream, err)
		return 2
	}

	return 0
}

var helpText = `
Usage: binrep [options]

  The static binary repository manager.

Commands:
  list		show releases on remote repository
  show          show binary information.
  push		push binary.
  pull		pull binary.
  sync          sync remote repository to local directory.

Options:
  --version, -v		print version
  --help, -h            print help
`

func (cli *CLI) prepareFlags(help string) *flag.FlagSet {
	flags := flag.NewFlagSet(name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprint(cli.errStream, help)
	}
	return flags
}

var listHelpText = `
Usage: binrep list [options]

show releases on remote repository

Options:
  --endpoint, -e   s3 URI
`

func (cli *CLI) doList(args []string) error {
	var param command.ListParam
	flags := cli.prepareFlags(listHelpText)
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, listHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) != 0 {
		fmt.Fprint(cli.errStream, listHelpText)
		return errors.Errorf("extra arguments")
	}
	return command.List(&param)
}

var showHelpText = `
Usage: binrep show [options] <host>/<user>/<project>

show binary information.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
`

func (cli *CLI) doShow(args []string) error {
	var param command.ShowParam
	flags := cli.prepareFlags(showHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, showHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) < 1 {
		fmt.Fprint(cli.errStream, showHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Show(&param, flags.Arg(0))
}

var pushHelpText = `
Usage: binrep push [options] <host>/<user>/<project> /path/to/binary ...

push binary.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
  --keep-releases, -k	the number of releases that it keeps (default: 5)
`

func (cli *CLI) doPush(args []string) error {
	var param command.PushParam
	flags := cli.prepareFlags(pushHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.IntVar(&param.KeepReleases, "k", defaultKeepReleases, "")
	flags.IntVar(&param.KeepReleases, "keep-releases", defaultKeepReleases, "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, pushHelpText)
		return errors.Errorf("--endpoint required")
	}
	argLen := len(flags.Args())
	if argLen < 2 {
		fmt.Fprint(cli.errStream, pushHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Push(&param, flags.Arg(0), flags.Args()[1:argLen])
}

var pullHelpText = `
Usage: binrep pull [options] <host>/<user>/<project> /path/to/binary

pull binary.

Options:
  --endpoint, -e	s3 uri
  --timestamp, -t       binary timestamp
`

func (cli *CLI) doPull(args []string) error {
	var param command.PullParam
	flags := cli.prepareFlags(pullHelpText)
	flags.StringVar(&param.Timestamp, "t", "", "")
	flags.StringVar(&param.Timestamp, "timestamp", "", "")
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, pullHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) != 2 {
		fmt.Fprint(cli.errStream, pullHelpText)
		return errors.Errorf("too few or many arguments")
	}
	return command.Pull(&param, flags.Arg(0), flags.Arg(1))
}

var syncHelpText = `
Usage: binrep sync [options] DEST_DIR

pull binary.

Options:
  --endpoint, -e	s3 uri
  --concurrency, -c     number of multiple release fetchers to make at a time
  --max-bandwidth, -bw	max bandwidth for download binaries (Bytes/sec) eg. '1 MB', '1024 KB'
`

func (cli *CLI) doSync(args []string) error {
	var param command.SyncParam
	flags := cli.prepareFlags(syncHelpText)
	flags.StringVar(&param.Endpoint, "e", "", "")
	flags.StringVar(&param.Endpoint, "endpoint", "", "")
	flags.IntVar(&param.Concurrency, "c", defaultSyncConcurrency, "")
	flags.IntVar(&param.Concurrency, "concurrency", defaultSyncConcurrency, "")
	flags.StringVar(&param.MaxBandWidth, "bw", "", "")
	flags.StringVar(&param.MaxBandWidth, "max-bandwidth", "", "")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if param.Endpoint == "" {
		fmt.Fprint(cli.errStream, syncHelpText)
		return errors.Errorf("--endpoint required")
	}
	if len(flags.Args()) < 1 {
		fmt.Fprint(cli.errStream, syncHelpText)
		return errors.Errorf("too few arguments")
	}
	return command.Sync(&param, flags.Arg(0))
}
<|endoftext|>


<commit_before>package main

import (
	_ "expvar"
	"net/http"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/pat"
	"github.com/meatballhat/negroni-logrus"
	"github.com/phyber/negroni-gzip/gzip"
	"gitlab.com/mattbostock/timeoff/handler"
)

var (
	addr = os.Getenv("TIMEOFF_ADDR")
	m    = pat.New()
	n    = negroni.New(negroni.NewRecovery(), negroni.NewStatic(http.Dir("assets")))
	l    = negronilogrus.NewMiddleware()
)

func init() {
	n.Use(gzip.Gzip(gzip.BestCompression))
	n.Use(l)
	n.UseHandler(m)
	handler.SetLogger(l.Logger)

	m.Add("GET", "/debug/vars", http.DefaultServeMux)

	if addr == "" {
		addr = ":3000"
	}
}

func main() {
	tlsCert := os.Getenv("TIMEOFF_TLS_CERT")
	tlsKey := os.Getenv("TIMEOFF_TLS_KEY")

	l.Logger.Infof("Listening on %s", addr)

	if tlsCert == "" && tlsKey == "" {
		l.Logger.Warningln(noTLSCertificateError)
		l.Logger.Fatal(http.ListenAndServe(addr, n))
	} else {
		l.Logger.Infoln("Listening with TLS")
		l.Logger.Fatal(http.ListenAndServeTLS(addr, tlsCert, tlsKey, n))
	}
}

const noTLSCertificateError = "No TLS certficiate supplied. Consider setting TIMEOFF_TLS_CERT " +
	"and TIMEOFF_TLS_KEY environment variables to enable TLS."
<commit_msg>Enable debug-level logging using env var<commit_after>package main

import (
	_ "expvar"
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/pat"
	"github.com/meatballhat/negroni-logrus"
	"github.com/phyber/negroni-gzip/gzip"
	"gitlab.com/mattbostock/timeoff/handler"
)

var (
	addr = os.Getenv("TIMEOFF_ADDR")
	m    = pat.New()
	n    = negroni.New(negroni.NewRecovery(), negroni.NewStatic(http.Dir("assets")))
	l    = negronilogrus.NewMiddleware()
)

func init() {
	n.Use(gzip.Gzip(gzip.BestCompression))
	n.Use(l)
	n.UseHandler(m)
	handler.SetLogger(l.Logger)

	if len(os.Getenv("TIMEOFF_DEBUG")) > 0 {
		l.Logger.Level = logrus.DebugLevel
	}

	m.Add("GET", "/debug/vars", http.DefaultServeMux)

	if addr == "" {
		addr = ":3000"
	}
}

func main() {
	tlsCert := os.Getenv("TIMEOFF_TLS_CERT")
	tlsKey := os.Getenv("TIMEOFF_TLS_KEY")

	l.Logger.Infof("Listening on %s", addr)

	if tlsCert == "" && tlsKey == "" {
		l.Logger.Warningln(noTLSCertificateError)
		l.Logger.Fatal(http.ListenAndServe(addr, n))
	} else {
		l.Logger.Infoln("Listening with TLS")
		l.Logger.Fatal(http.ListenAndServeTLS(addr, tlsCert, tlsKey, n))
	}
}

const noTLSCertificateError = "No TLS certficiate supplied. Consider setting TIMEOFF_TLS_CERT " +
	"and TIMEOFF_TLS_KEY environment variables to enable TLS."
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/fatih/color"
	"github.com/howeyc/fsnotify"
)

// parseArguments ...
func parseArguments(ev *fsnotify.FileEvent) (cmd string, args []string) {
	commandline := strings.Fields(flag.Args()[0])
	cmd = commandline[0]
	args = make([]string, len(commandline[1:]))

	// Do file name interpolation on the arguments if %f is in them
	for index, arg := range commandline[1:] {
		var err error
		if strings.Contains(arg, "%f") {
			arg, err = filepath.Abs(strings.Replace(arg, "%f", ev.Name, -1))
			if err != nil {
				log.Fatal("Could not get absolute path: ", err)
			}
		}
		args[index] = arg
	}

	return
}

func handle(ev *fsnotify.FileEvent) {
	command, args := parseArguments(ev)
	cmd := exec.Command(command, args...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal("stdout not gotten: ", err)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal("stderr not gotten: ", err)
	}

	// Clear the screen
	fmt.Print("\033[H\033[2J")

	yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
	magenta := color.New(color.FgMagenta, color.Bold).SprintfFunc()
	red := color.New(color.FgRed, color.Bold).SprintfFunc()
	green := color.New(color.FgGreen, color.Bold).SprintfFunc()

	// Print the command in nice colors
	out := fmt.Sprintf("Running %s %s...", yellow(command), magenta(strings.Join(args, " ")))

	log.Println(out)
	if err = cmd.Start(); err != nil {
		log.Fatal("Command failed to start: ", err)
	}

	outchan := make(chan string)
	errchan := make(chan string)
	outdonechan := make(chan bool)
	errdonechan := make(chan bool)
	outdone := false

	go loopOutput(outchan, outdonechan, stdout)
	go loopOutput(errchan, errdonechan, stderr)

	for outdone == false {
		select {
		case msg := <-outchan:
			fmt.Print(msg)
		case errmsg := <-errchan:
			fmt.Print(red(errmsg))
		case <-outdonechan:
			outdone = true
		}
	}

	// Print red error message or green success message
	if err = cmd.Wait(); err != nil {
		log.Println(red(err.Error()))
	} else {
		log.Println(green("Execution successful."))
	}
}

func loopOutput(c chan string, done chan bool, pipe io.ReadCloser) {
	buf := make([]byte, 1024)

	for {
		n, err := pipe.Read(buf)

		// Either if the pipe was empty or an EOF or other error was returned.
		if n == 0 && err == nil || err != nil {
			done <- true
			return
		}

		c <- string(buf[:n])
	}
}

func main() {
	dir := flag.String("d", ".", "directory to watch")
	flag.Parse()

	if flag.NArg() != 1 {
		log.Fatal("One command line argument sting required.")
	}

	watcher, err := fsnotify.NewWatcher()
	defer watcher.Close()

	if err != nil {
		log.Fatal("Unable to create fsnotify watcher: ", err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				handle(ev)

			case err := <-watcher.Error:
				log.Println("watcher error: ", err)

			}
		}
	}()

	log.Printf("Watching %s...", *dir)
	err = watcher.Watch(*dir)
	if err != nil {
		log.Fatal("Directory watching failed: ", err)
	}

	<-done
}
<commit_msg>Add handling of file starting errors<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/fatih/color"
	"github.com/howeyc/fsnotify"
)

// parseArguments ...
func parseArguments(ev *fsnotify.FileEvent) (cmd string, args []string) {
	commandline := strings.Fields(flag.Args()[0])
	cmd = commandline[0]
	args = make([]string, len(commandline[1:]))

	// Do file name interpolation on the arguments if %f is in them
	for index, arg := range commandline[1:] {
		var err error
		if strings.Contains(arg, "%f") {
			arg, err = filepath.Abs(strings.Replace(arg, "%f", ev.Name, -1))
			if err != nil {
				log.Fatal("Could not get absolute path: ", err)
			}
		}
		args[index] = arg
	}

	return
}

func handle(ev *fsnotify.FileEvent) {
	command, args := parseArguments(ev)
	cmd := exec.Command(command, args...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal("stdout not gotten: ", err)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal("stderr not gotten: ", err)
	}

	// Clear the screen
	fmt.Print("\033[H\033[2J")

	yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
	magenta := color.New(color.FgMagenta, color.Bold).SprintfFunc()
	red := color.New(color.FgRed, color.Bold).SprintfFunc()
	green := color.New(color.FgGreen, color.Bold).SprintfFunc()

	// Print the command in nice colors
	out := fmt.Sprintf("Running %s %s...", yellow(command), magenta(strings.Join(args, " ")))

	log.Println(out)

	// Repeatedly try to start the command.
	// There are cases in which this would fail, and just looping seems to fix it.
	// This is neither nice nor elegant, but hey, it works and if it can be kept
	// simple then it should be.
	for {
		err = cmd.Start()
		if err != nil {
			log.Print("Command failed to start: ", err)
		} else {
			break
		}
	}

	outchan := make(chan string)
	errchan := make(chan string)
	outdonechan := make(chan bool)
	errdonechan := make(chan bool)
	outdone := false

	go loopOutput(outchan, outdonechan, stdout)
	go loopOutput(errchan, errdonechan, stderr)

	for outdone == false {
		select {
		case msg := <-outchan:
			fmt.Print(msg)
		case errmsg := <-errchan:
			fmt.Print(red(errmsg))
		case <-outdonechan:
			outdone = true
		}
	}

	// Print red error message or green success message
	if err = cmd.Wait(); err != nil {
		log.Println(red(err.Error()))
	} else {
		log.Println(green("Execution successful."))
	}
}

func loopOutput(c chan string, done chan bool, pipe io.ReadCloser) {
	buf := make([]byte, 1024)

	for {
		n, err := pipe.Read(buf)

		// Either if the pipe was empty or an EOF or other error was returned.
		if n == 0 && err == nil || err != nil {
			done <- true
			return
		}

		c <- string(buf[:n])
	}
}

func main() {
	dir := flag.String("d", ".", "directory to watch")
	flag.Parse()

	if flag.NArg() != 1 {
		log.Fatal("One command line argument sting required.")
	}

	watcher, err := fsnotify.NewWatcher()
	defer watcher.Close()

	if err != nil {
		log.Fatal("Unable to create fsnotify watcher: ", err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				handle(ev)

			case err := <-watcher.Error:
				log.Println("watcher error: ", err)

			}
		}
	}()

	log.Printf("Watching %s...", *dir)
	err = watcher.Watch(*dir)
	if err != nil {
		log.Fatal("Directory watching failed: ", err)
	}

	<-done
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"

	msgpack "gopkg.in/vmihailenco/msgpack.v2"

	"github.com/go-redis/cache"
	"github.com/go-redis/redis"
	"github.com/gorilla/mux"
	"github.com/nuveo/gofn"
	"github.com/nuveo/gofn/provision"
	"github.com/urfave/negroni"
)

type Object struct {
	Cover string
}

func main2() {
	repo := flag.String("repo", "", "a string")
	flag.Parse()
	run("dockers/Golang", "Dockerfile", *repo)
}

func repoCover(repo string) (obj Object) {
	ring := redis.NewRing(&redis.RingOptions{
		Addrs: map[string]string{
			"server1": "redis:6379",
		},
	})
	codec := &cache.Codec{
		Redis: ring,

		Marshal: func(v interface{}) ([]byte, error) {
			return msgpack.Marshal(v)
		},
		Unmarshal: func(b []byte, v interface{}) error {
			return msgpack.Unmarshal(b, v)
		},
	}
	if err := codec.Get(repo, &obj); err != nil {
		StdOut, StdErr := run("dockers/Golang", "Dockerfile", repo)
		stdOut := strings.Trim(StdOut, " \n")
		if stdOut != "" {
			obj.Cover = stdOut
		} else {
			obj.Cover = StdErr
		}
		obj := &Object{
			Cover: obj.Cover,
		}
		codec.Set(&cache.Item{
			Key:        repo,
			Object:     obj,
			Expiration: time.Hour,
		})
	}
	return
}

func HandlerRepo(w http.ResponseWriter, r *http.Request) {
	Body := map[string]interface{}{}
	vars := mux.Vars(r)
	repo := vars["repo"]
	Body["Repo"] = repo
	obj := repoCover(repo)
	Body["Cover"] = obj.Cover
	t := template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/repo.tmpl"))
	t.Execute(w, Body)
	return

}

func Handler(w http.ResponseWriter, r *http.Request) {
	t := template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/home.tmpl"))
	t.Execute(w, nil)
	return
}

func main() {
	n := negroni.Classic()
	r := mux.NewRouter()
	r.HandleFunc("/", Handler)
	r.HandleFunc("/go/{repo:.*}", HandlerRepo)
	r.PathPrefix("/assets").Handler(
		http.StripPrefix("/assets", http.FileServer(http.Dir("./assets/"))))
	n.UseHandler(r)
	n.Run(":3000")
}

func run(contextDir, dockerFile, repo string) (StdOut, StdErr string) {
	buildOpts := &provision.BuildOptions{
		ContextDir: contextDir,
		Dockerfile: dockerFile,
		ImageName:  strings.ToLower(fmt.Sprintf("%s/%s", contextDir, dockerFile)),
		StdIN:      fmt.Sprintf("sh /run.sh %s", repo),
	}
	StdOut, StdErr, err := gofn.Run(
		buildOpts,
		&provision.VolumeOptions{})
	if err != nil {
		log.Println(err)
	}
	return
}
<commit_msg>added JSON handler<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"

	msgpack "gopkg.in/vmihailenco/msgpack.v2"

	"github.com/go-redis/cache"
	"github.com/go-redis/redis"
	"github.com/gorilla/mux"
	"github.com/nuveo/gofn"
	"github.com/nuveo/gofn/provision"
	"github.com/urfave/negroni"
)

type Object struct {
	Cover string
}

func main2() {
	repo := flag.String("repo", "", "a string")
	flag.Parse()
	run("dockers/Golang", "Dockerfile", *repo)
}

func repoCover(repo string) (obj Object) {
	ring := redis.NewRing(&redis.RingOptions{
		Addrs: map[string]string{
			"server1": "redis:6379",
		},
	})
	codec := &cache.Codec{
		Redis: ring,

		Marshal: func(v interface{}) ([]byte, error) {
			return msgpack.Marshal(v)
		},
		Unmarshal: func(b []byte, v interface{}) error {
			return msgpack.Unmarshal(b, v)
		},
	}
	if err := codec.Get(repo, &obj); err != nil {
		StdOut, StdErr := run("dockers/Golang", "Dockerfile", repo)
		stdOut := strings.Trim(StdOut, " \n")
		if stdOut != "" {
			obj.Cover = stdOut
		} else {
			obj.Cover = StdErr
		}
		obj := &Object{
			Cover: obj.Cover,
		}
		codec.Set(&cache.Item{
			Key:        repo,
			Object:     obj,
			Expiration: time.Hour,
		})
	}
	return
}

func HandlerRepoJSON(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	obj := repoCover(vars["repo"])
	json.NewEncoder(w).Encode(obj)
}

func HandlerRepo(w http.ResponseWriter, r *http.Request) {
	Body := map[string]interface{}{}
	vars := mux.Vars(r)
	repo := vars["repo"]
	Body["Repo"] = repo
	obj := repoCover(repo)
	Body["Cover"] = obj.Cover
	t := template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/repo.tmpl"))
	t.Execute(w, Body)
	return

}

func Handler(w http.ResponseWriter, r *http.Request) {
	t := template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/home.tmpl"))
	t.Execute(w, nil)
	return
}

func main() {
	n := negroni.Classic()
	r := mux.NewRouter()
	r.HandleFunc("/", Handler)
	r.HandleFunc("/go/{repo:.*}.json", HandlerRepoJSON)
	r.HandleFunc("/go/{repo:.*}", HandlerRepo)
	r.PathPrefix("/assets").Handler(
		http.StripPrefix("/assets", http.FileServer(http.Dir("./assets/"))))
	n.UseHandler(r)
	n.Run(":3000")
}

func run(contextDir, dockerFile, repo string) (StdOut, StdErr string) {
	buildOpts := &provision.BuildOptions{
		ContextDir: contextDir,
		Dockerfile: dockerFile,
		ImageName:  strings.ToLower(fmt.Sprintf("%s/%s", contextDir, dockerFile)),
		StdIN:      fmt.Sprintf("sh /run.sh %s", repo),
	}
	StdOut, StdErr, err := gofn.Run(
		buildOpts,
		&provision.VolumeOptions{})
	if err != nil {
		log.Println(err)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/ogier/pflag"
	"github.com/yuya-takeyama/argf"
)

var (
	name    = "csvp"
	version = "0.8.1"
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... [FILE]...
Print selected parts of CSV from each FILE to standard output.

Options:
  -i, --indexes=LIST
                 select only these indexes
  -h, --headers=LIST
                 select only these headers
  -t, --tsv
                 equivalent to -d'\t'
  -d, --delimiter=DELIM
                 use DELIM instead of comma for field delimiter
  -D, --output-delimiter=STRING
                 use STRING as the output delimiter (default: \t)
  --help
                 display this help text and exit
  --version
                 output version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", name)
}

type Option struct {
	IndexesList     string
	HeadersList     string
	IsTSV           bool
	Delimiter       string
	OutputDelimiter string
	IsHelp          bool
	IsVersion       bool
	Files           []string
}

func toDelimiter(s string) (r rune, err error) {
	s, err = strconv.Unquote(`"` + s + `"`)
	if err != nil {
		return 0, err
	}

	runes := []rune(s)
	if len(runes) != 1 {
		return 0, fmt.Errorf("the delimiter must be a single character")
	}
	return runes[0], nil
}

func do(c *CSVScanner) error {
	for c.Scan() {
		fmt.Println(c.Text())
	}
	return c.Err()
}

func _main() int {
	flag := pflag.NewFlagSet(name, pflag.ContinueOnError)
	flag.SetOutput(ioutil.Discard)

	opt := &Option{}
	flag.StringVarP(&opt.IndexesList, "indexes", "i", "", "")
	flag.StringVarP(&opt.HeadersList, "headers", "h", "", "")
	flag.BoolVarP(&opt.IsTSV, "tsv", "t", false, "")
	flag.StringVarP(&opt.Delimiter, "delimiter", "d", ",", "")
	flag.StringVarP(&opt.OutputDelimiter, "output-delimiter", "D", "\t", "")
	flag.BoolVarP(&opt.IsHelp, "help", "", false, "")
	flag.BoolVarP(&opt.IsVersion, "version", "", false, "")

	if err := flag.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	switch {
	case opt.IsHelp:
		printUsage()
		return 0
	case opt.IsVersion:
		printVersion()
		return 0
	}
	opt.Files = flag.Args()

	var selector Selector
	switch {
	case opt.IndexesList != "" && opt.HeadersList != "":
		printErr(fmt.Errorf("only one type of list may be specified"))
		guideToHelp()
		return 2
	case opt.IndexesList != "":
		selector = NewIndexes(opt.IndexesList)
	case opt.HeadersList != "":
		selector = NewHeaders(opt.HeadersList)
	default:
		selector = NewAll()
	}

	r, err := argf.From(opt.Files)
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}

	c := NewCSVScanner(selector, r)
	c.SetOutputDelimiter(opt.OutputDelimiter)
	switch {
	case opt.IsTSV:
		c.SetDelimiter('\t')
	default:
		ch, err := toDelimiter(opt.Delimiter)
		if err != nil {
			printErr(err)
			guideToHelp()
			return 2
		}
		c.SetDelimiter(ch)
	}

	if err = do(c); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<commit_msg>Extract flag<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/ogier/pflag"
	"github.com/yuya-takeyama/argf"
)

var (
	name    = "csvp"
	version = "0.8.1"

	flag            = pflag.NewFlagSet(name, pflag.ContinueOnError)
	indexesList     = flag.StringP("indexes", "i", "", "")
	headersList     = flag.StringP("headers", "h", "", "")
	isTSV           = flag.BoolP("tsv", "t", false, "")
	delimiter       = flag.StringP("delimiter", "d", ",", "")
	outputDelimiter = flag.StringP("output-delimiter", "D", "\t", "")
	isHelp          = flag.BoolP("help", "", false, "")
	isVersion       = flag.BoolP("version", "", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... [FILE]...
Print selected parts of CSV from each FILE to standard output.

Options:
  -i, --indexes=LIST
                 select only these indexes
  -h, --headers=LIST
                 select only these headers
  -t, --tsv
                 equivalent to -d'\t'
  -d, --delimiter=DELIM
                 use DELIM instead of comma for field delimiter
  -D, --output-delimiter=STRING
                 use STRING as the output delimiter (default: \t)
  --help
                 display this help text and exit
  --version
                 output version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", name)
}

type Option struct {
	IndexesList     string
	HeadersList     string
	IsTSV           bool
	Delimiter       string
	OutputDelimiter string
	IsHelp          bool
	IsVersion       bool
	Files           []string
}

func toDelimiter(s string) (r rune, err error) {
	s, err = strconv.Unquote(`"` + s + `"`)
	if err != nil {
		return 0, err
	}

	runes := []rune(s)
	if len(runes) != 1 {
		return 0, fmt.Errorf("the delimiter must be a single character")
	}
	return runes[0], nil
}

func do(c *CSVScanner) error {
	for c.Scan() {
		fmt.Println(c.Text())
	}
	return c.Err()
}

func _main() int {
	flag.SetOutput(ioutil.Discard)
	if err := flag.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	switch {
	case *isHelp:
		printUsage()
		return 0
	case *isVersion:
		printVersion()
		return 0
	}

	var selector Selector
	switch {
	case *indexesList != "" && *headersList != "":
		printErr(fmt.Errorf("only one type of list may be specified"))
		guideToHelp()
		return 2
	case *indexesList != "":
		selector = NewIndexes(*indexesList)
	case *headersList != "":
		selector = NewHeaders(*headersList)
	default:
		selector = NewAll()
	}

	r, err := argf.From(flag.Args())
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}

	c := NewCSVScanner(selector, r)
	c.SetOutputDelimiter(*outputDelimiter)
	switch {
	case *isTSV:
		c.SetDelimiter('\t')
	default:
		ch, err := toDelimiter(*delimiter)
		if err != nil {
			printErr(err)
			guideToHelp()
			return 2
		}
		c.SetDelimiter(ch)
	}

	if err = do(c); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

func main() {
	contents, err := ioutil.ReadFile("vendor.json")
	if err != nil {
		fmt.Println("failed to read vendor.json", err)
		os.Exit(1)
	}
	var data map[string]interface{}

	if err := json.Unmarshal(contents, &data); err != nil {
		fmt.Println("Invalid vendor.json", err)
		os.Exit(1)
	}
	os.Mkdir(".vendor", 0700)
	for name, config := range data {
		if err := vendor(name, config.(map[string]interface{})); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
	files, _  := ioutil.ReadDir(".vendor")
	for _, file := range files {
		if file.IsDir() {
			if _, valid := data[file.Name()]; valid == false {
				fmt.Println("removing", file.Name())
				os.RemoveAll(".vendor/" + file.Name())
			}
		}
	}
	os.Exit(0)
}

func vendor(name string, config map[string]interface{}) error {
	url, ok := config["url"].(string)
	if ok == false {
		return fmt.Errorf("%s missing url field", name)
	}
	root, err := os.Getwd()
	if err != nil {
		return err
	}
	root += "/.vendor/"
	path := root + name
	if exists(path) == false {
		fmt.Println("cloning", url)
		if err := gitRun(root, "clone", url, name); err != nil {
			return err
		}
	}
	revision, ok := config["revision"].(string)
	if ok == false {
		revision = "master"
	}
	fmt.Println("fetching", name)
	return gitReset(path, revision, true)
}

func gitReset(path, revision string, first bool) error {
	if first == false {
		if err := gitRun(path, "fetch", "--all"); err != nil {
			return err
		}
	}
	if err := gitRun(path, "reset", "--hard", revision); err != nil {
		if first {
			return gitReset(path, revision, false)
		}
		return err
	}
	return nil
}

func gitRun(dir string, args ...string) error {
	var out bytes.Buffer
	cmd := exec.Command("git", args...)
	cmd.Dir = dir
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("error running git %s:\n  %s", strings.Join(args, " "), out.String())
	}
	return nil
}

func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}
<commit_msg>recursive fetch<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

func main() {
	root, err := os.Getwd()
	if err != nil {
		fmt.Println("failed to get wordering directory", err)
		os.Exit(1)
	}
	install(root)
}

func install(root string) {
	config := readConfig(root)
	root = root + "/.vendor"
	os.Mkdir(root, 0700)
	for name, c := range config {
		vendor(root, name, c.(map[string]interface{}))
	}
	// files, _  := ioutil.ReadDir(root)
	// for _, file := range files {
	// 	if file.IsDir() {
	// 		if _, valid := data[file.Name()]; valid == false {
	// 			fmt.Println("removing", file.Name())
	// 			os.RemoveAll(root + file.Name())
	// 		}
	// 	}
	// }
	// os.Exit(0)
}

func readConfig(root string) map[string]interface{} {
	file := root + "/vendor.json"
	contents, err := ioutil.ReadFile(file)
	if err != nil {
		if os.IsNotExist(err) {
			os.Exit(0)
		}
		fmt.Printf("failed to read %s %v\n", file, err)
		os.Exit(1)
	}
	var config map[string]interface{}
	if err := json.Unmarshal(contents, &config); err != nil {
		fmt.Printf("invalid %s %v\n", file, err)
		os.Exit(1)
	}
	return config
}

func vendor(root string, name string, config map[string]interface{}) {
	url, ok := config["url"].(string)
	if ok == false {
		fmt.Printf("%s missing url field in %s/.vendor\n", name, root)
		os.Exit(1)
	}

	target := root + "/" + name
	if exists(target) == false {
		fmt.Println("cloning", url)
		if err := gitRun(root, "clone", url, name); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
	revision, ok := config["revision"].(string)
	if ok == false {
		revision = "master"
	}
	fmt.Println("fetching", name)
	if err := gitReset(target, revision, true); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	install(target)
}

func gitReset(path, revision string, first bool) error {
	if first == false {
		if err := gitRun(path, "fetch", "--all"); err != nil {
			return err
		}
	}
	if err := gitRun(path, "reset", "--hard", revision); err != nil {
		if first {
			return gitReset(path, revision, false)
		}
		return err
	}
	return nil
}

func gitRun(dir string, args ...string) error {
	var out bytes.Buffer
	cmd := exec.Command("git", args...)
	cmd.Dir = dir
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("error running git %s\n  %s", strings.Join(args, " "), out.String())
	}
	return nil
}

func exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/AlekSi/roll2push/rollbar"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

func hook(rw http.ResponseWriter, req *http.Request) {
	l := log.New(os.Stderr, req.RemoteAddr+" at ", log.Ldate|log.Lmicroseconds)
	var err error
	defer func() {
		if err == nil {
			rw.WriteHeader(204)
		} else {
			l.Print(err)
			rw.WriteHeader(500)
		}
	}()

	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return
	}

	var event rollbar.Event
	err = json.Unmarshal(b, &event)
	if err != nil {
		return
	}

	switch event.EventName {
	case "test":
		var test string
		err = json.Unmarshal(event.Data["message"], &test)
		if err != nil {
			return
		}

		l.Print(test)

	case "deploy":
		l.Printf("event is not handled yet: %s", event.EventName)

	default:
		if strings.HasSuffix(event.EventName, "_item") {
			var item rollbar.ItemEvent
			err = json.Unmarshal(event.Data["item"], &item)
			if err != nil {
				return
			}

			l.Printf("%+v", item)

		} else {
			l.Printf("unexpected event: %s", event.EventName)
		}
	}

	return
}

func main() {
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	http.HandleFunc("/", hook)

	addr := ":8080"
	log.Printf("Waiting for Rollbar events on %s.", addr)
	log.Fatal(http.ListenAndServe(addr, nil))
}
<commit_msg>Send messages to pushover.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"github.com/AlekSi/pushover"
	"github.com/AlekSi/roll2push/rollbar"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var (
	User string
)

func hook(rw http.ResponseWriter, req *http.Request) {
	l := log.New(os.Stderr, req.RemoteAddr+" at ", log.Ldate|log.Lmicroseconds)
	var err error
	defer func() {
		if err == nil {
			rw.WriteHeader(204)
		} else {
			l.Print(err)
			rw.WriteHeader(500)
		}
	}()

	b, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return
	}

	var event rollbar.Event
	err = json.Unmarshal(b, &event)
	if err != nil {
		return
	}

	switch event.EventName {
	case "test":
		var test string
		err = json.Unmarshal(event.Data["message"], &test)
		if err != nil {
			return
		}

		l.Print(test)
		pushover.SendMessage(User, "test", test)

	case "deploy":
		l.Printf("event is not handled yet: %s", event.EventName)

	default:
		if strings.HasSuffix(event.EventName, "_item") {
			var item rollbar.ItemEvent
			err = json.Unmarshal(event.Data["item"], &item)
			if err != nil {
				return
			}

			l.Printf("%+v", item)
			pushover.SendMessage(User, item.Environment, item.Title)

		} else {
			l.Printf("unexpected event: %s", event.EventName)
		}
	}

	return
}

func main() {
	log.SetFlags(log.Ldate | log.Lmicroseconds)

	token := flag.String("pushover-token", "", "")
	flag.StringVar(&User, "pushover-user", "", "")
	flag.Parse()

	pushover.DefaultClient.Token = *token

	http.HandleFunc("/", hook)

	addr := ":8080"
	log.Printf("Waiting for Rollbar events on %s.", addr)
	log.Fatal(http.ListenAndServe(addr, nil))
}
<|endoftext|>