<commit_before>package main

import (
	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	sdk "github.com/dysolution/espsdk"
)

// A Release wraps the verbs provided by the ESP API for Releases,
// legal agreements for property owners or models to be associated
// with Submission Batches.
type Release struct{ context *cli.Context }

// Index requests a list of all Releases associated with the specified
// Submission Batch.
func (r Release) Index() { get(childPath("releases", r.context, "")) }

// Get requests the metadata for a specific Release.
func (r Release) Get() sdk.Release { return r.Unmarshal(get(r.path())) }

// Create associates a new Release with the specified Submission Batch.
func (r Release) Create() sdk.Release {
	return r.Unmarshal(post(r.build(r.context), batchPath(r.context)+"/releases"))
}

// Delete destroys a specific Release.
func (r Release) Delete()      { _delete(r.path()) }
func (r Release) id() string   { return getRequiredValue(r.context, "release-id") }
func (r Release) path() string { return childPath("releases", r.context, r.id()) }

func (r Release) build(c *cli.Context) sdk.Release {
	return sdk.Release{
		SubmissionBatchID:    c.Int("submission-batch-id"),
		FileName:             c.String("file-name"),
		FilePath:             c.String("file-path"),
		ExternalFileLocation: c.String("external-file-location"),
		ReleaseType:          c.String("release-type"),
		ModelDateOfBirth:     c.String("model-date-of-birth"),
		ModelEthnicities:     c.StringSlice("model-ethnicities"),
		ModelGender:          c.String("model-gender"),
	}
}

// Unmarshal attempts to deserialize the provided JSON payload into a
// Release object as defined by the SDK.
func (r Release) Unmarshal(payload []byte) sdk.Release {
	var release sdk.Release
	if err := json.Unmarshal(payload, &release); err != nil {
		log.Fatal(err)
	}
	return release
}
<commit_msg>refactor<commit_after>package main

import (
	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	sdk "github.com/dysolution/espsdk"
)

// A Release wraps the verbs provided by the ESP API for Releases,
// legal agreements for property owners or models to be associated
// with Submission Batches.
type Release struct{ context *cli.Context }

// Index requests a list of all Releases associated with the specified
// Submission Batch.
func (r Release) Index() { get(childPath("releases", r.context, "")) }

// Get requests the metadata for a specific Release.
func (r Release) Get() sdk.Release { return r.Unmarshal(r.get()) }

// Create associates a new Release with the specified Submission Batch.
func (r Release) Create() sdk.Release { return r.Unmarshal(r.post()) }

// Delete destroys a specific Release.
func (r Release) Delete() { _delete(r.path()) }

func (r Release) id() string   { return getRequiredValue(r.context, "release-id") }
func (r Release) path() string { return childPath("releases", r.context, r.id()) }
func (r Release) get() []byte  { return get(r.path()) }
func (r Release) post() []byte { return post(r.build(), batchPath(r.context)+"/releases") }

func (r Release) build() sdk.Release {
	return sdk.Release{
		ExternalFileLocation: r.context.String("external-file-location"),
		FileName:             r.context.String("file-name"),
		FilePath:             r.context.String("file-path"),
		ModelDateOfBirth:     r.context.String("model-date-of-birth"),
		ModelEthnicities:     r.context.StringSlice("model-ethnicities"),
		ModelGender:          r.context.String("model-gender"),
		ReleaseType:          r.context.String("release-type"),
		SubmissionBatchID:    r.context.Int("submission-batch-id"),
	}
}

// Unmarshal attempts to deserialize the provided JSON payload into a
// Release object as defined by the SDK.
func (r Release) Unmarshal(payload []byte) sdk.Release {
	var release sdk.Release
	if err := json.Unmarshal(payload, &release); err != nil {
		log.Fatal(err)
	}
	return release
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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.
*/

// Package memcache provides a client for the memcached cache server.
package memcache

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"
)

const testServer = "localhost:11211"

func setup(t *testing.T) bool {
	c, err := net.Dial("tcp", testServer)
	if err != nil {
		t.Logf("skipping test; no server running at %s", testServer)
		return false
	}
	c.Write([]byte("flush_all\r\n"))
	c.Close()
	return true
}

func TestLocalhost(t *testing.T) {
	if !setup(t) {
		return
	}
	testWithClient(t, New(testServer))
}

// Run the memcached binary as a child process and connect to its unix socket.
func TestUnixSocket(t *testing.T) {
	sock := fmt.Sprintf("/tmp/test-gomemcache-%d.sock", os.Getpid())
	cmd := exec.Command("memcached", "-s", sock)
	if err := cmd.Start(); err != nil {
		t.Logf("skipping test; couldn't find memcached")
		return
	}
	defer cmd.Wait()
	defer cmd.Process.Kill()

	// Wait a bit for the socket to appear.
	for i := 0; i < 10; i++ {
		if _, err := os.Stat(sock); err == nil {
			break
		}
		time.Sleep(time.Duration(25*i) * time.Millisecond)
	}

	testWithClient(t, New(sock))
}

func testWithClient(t *testing.T, c *Client) {
	checkErr := func(err error, format string, args ...interface{}) {
		if err != nil {
			t.Fatalf(format, args...)
		}
	}

	mustSet := func(it *Item) {
		if err := c.Set(it); err != nil {
			t.Fatalf("failed to Set %#v: %v", *it, err)
		}
	}

	// Set
	foo := &Item{Key: "foo", Value: []byte("fooval"), Flags: 123}
	err := c.Set(foo)
	checkErr(err, "first set(foo): %v", err)
	err = c.Set(foo)
	checkErr(err, "second set(foo): %v", err)

	// Get
	it, err := c.Get("foo")
	checkErr(err, "get(foo): %v", err)
	if it.Key != "foo" {
		t.Errorf("get(foo) Key = %q, want foo", it.Key)
	}
	if string(it.Value) != "fooval" {
		t.Errorf("get(foo) Value = %q, want fooval", string(it.Value))
	}
	if it.Flags != 123 {
		t.Errorf("get(foo) Flags = %v, want 123", it.Flags)
	}

	// Add
	bar := &Item{Key: "bar", Value: []byte("barval")}
	err = c.Add(bar)
	checkErr(err, "first add(foo): %v", err)
	if err := c.Add(bar); err != ErrNotStored {
		t.Fatalf("second add(foo) want ErrNotStored, got %v", err)
	}

	// GetMulti
	m, err := c.GetMulti([]string{"foo", "bar"})
	checkErr(err, "GetMulti: %v", err)
	if g, e := len(m), 2; g != e {
		t.Errorf("GetMulti: got len(map) = %d, want = %d", g, e)
	}
	if _, ok := m["foo"]; !ok {
		t.Fatalf("GetMulti: didn't get key 'foo'")
	}
	if _, ok := m["bar"]; !ok {
		t.Fatalf("GetMulti: didn't get key 'bar'")
	}
	if g, e := string(m["foo"].Value), "fooval"; g != e {
		t.Errorf("GetMulti: foo: got %q, want %q", g, e)
	}
	if g, e := string(m["bar"].Value), "barval"; g != e {
		t.Errorf("GetMulti: bar: got %q, want %q", g, e)
	}

	// Delete
	err = c.Delete("foo")
	checkErr(err, "Delete: %v", err)
	it, err = c.Get("foo")
	if err != ErrCacheMiss {
		t.Errorf("post-Delete want ErrCacheMiss, got %v", err)
	}

	// Incr/Decr
	mustSet(&Item{Key: "num", Value: []byte("42")})
	n, err := c.Increment("num", 8)
	checkErr(err, "Increment num + 8: %v", err)
	if n != 50 {
		t.Fatalf("Increment num + 8: want=50, got=%d", n)
	}
	n, err = c.Decrement("num", 49)
	checkErr(err, "Decrement: %v", err)
	if n != 1 {
		t.Fatalf("Decrement 49: want=1, got=%d", n)
	}
	err = c.Delete("num")
	checkErr(err, "delete num: %v", err)
	n, err = c.Increment("num", 1)
	if err != ErrCacheMiss {
		t.Fatalf("increment post-delete: want ErrCacheMiss, got %v", err)
	}
	mustSet(&Item{Key: "num", Value: []byte("not-numeric")})
	n, err = c.Increment("num", 1)
	if err == nil || !strings.Contains(err.Error(), "client error") {
		t.Fatalf("increment non-number: want client error, got %v", err)
	}

}
<commit_msg>use Skipf<commit_after>/*
Copyright 2011 Google Inc.

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.
*/

// Package memcache provides a client for the memcached cache server.
package memcache

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"
)

const testServer = "localhost:11211"

func setup(t *testing.T) bool {
	c, err := net.Dial("tcp", testServer)
	if err != nil {
		t.Skipf("skipping test; no server running at %s", testServer)
	}
	c.Write([]byte("flush_all\r\n"))
	c.Close()
	return true
}

func TestLocalhost(t *testing.T) {
	if !setup(t) {
		return
	}
	testWithClient(t, New(testServer))
}

// Run the memcached binary as a child process and connect to its unix socket.
func TestUnixSocket(t *testing.T) {
	sock := fmt.Sprintf("/tmp/test-gomemcache-%d.sock", os.Getpid())
	cmd := exec.Command("memcached", "-s", sock)
	if err := cmd.Start(); err != nil {
		t.Skipf("skipping test; couldn't find memcached")
		return
	}
	defer cmd.Wait()
	defer cmd.Process.Kill()

	// Wait a bit for the socket to appear.
	for i := 0; i < 10; i++ {
		if _, err := os.Stat(sock); err == nil {
			break
		}
		time.Sleep(time.Duration(25*i) * time.Millisecond)
	}

	testWithClient(t, New(sock))
}

func testWithClient(t *testing.T, c *Client) {
	checkErr := func(err error, format string, args ...interface{}) {
		if err != nil {
			t.Fatalf(format, args...)
		}
	}

	mustSet := func(it *Item) {
		if err := c.Set(it); err != nil {
			t.Fatalf("failed to Set %#v: %v", *it, err)
		}
	}

	// Set
	foo := &Item{Key: "foo", Value: []byte("fooval"), Flags: 123}
	err := c.Set(foo)
	checkErr(err, "first set(foo): %v", err)
	err = c.Set(foo)
	checkErr(err, "second set(foo): %v", err)

	// Get
	it, err := c.Get("foo")
	checkErr(err, "get(foo): %v", err)
	if it.Key != "foo" {
		t.Errorf("get(foo) Key = %q, want foo", it.Key)
	}
	if string(it.Value) != "fooval" {
		t.Errorf("get(foo) Value = %q, want fooval", string(it.Value))
	}
	if it.Flags != 123 {
		t.Errorf("get(foo) Flags = %v, want 123", it.Flags)
	}

	// Add
	bar := &Item{Key: "bar", Value: []byte("barval")}
	err = c.Add(bar)
	checkErr(err, "first add(foo): %v", err)
	if err := c.Add(bar); err != ErrNotStored {
		t.Fatalf("second add(foo) want ErrNotStored, got %v", err)
	}

	// GetMulti
	m, err := c.GetMulti([]string{"foo", "bar"})
	checkErr(err, "GetMulti: %v", err)
	if g, e := len(m), 2; g != e {
		t.Errorf("GetMulti: got len(map) = %d, want = %d", g, e)
	}
	if _, ok := m["foo"]; !ok {
		t.Fatalf("GetMulti: didn't get key 'foo'")
	}
	if _, ok := m["bar"]; !ok {
		t.Fatalf("GetMulti: didn't get key 'bar'")
	}
	if g, e := string(m["foo"].Value), "fooval"; g != e {
		t.Errorf("GetMulti: foo: got %q, want %q", g, e)
	}
	if g, e := string(m["bar"].Value), "barval"; g != e {
		t.Errorf("GetMulti: bar: got %q, want %q", g, e)
	}

	// Delete
	err = c.Delete("foo")
	checkErr(err, "Delete: %v", err)
	it, err = c.Get("foo")
	if err != ErrCacheMiss {
		t.Errorf("post-Delete want ErrCacheMiss, got %v", err)
	}

	// Incr/Decr
	mustSet(&Item{Key: "num", Value: []byte("42")})
	n, err := c.Increment("num", 8)
	checkErr(err, "Increment num + 8: %v", err)
	if n != 50 {
		t.Fatalf("Increment num + 8: want=50, got=%d", n)
	}
	n, err = c.Decrement("num", 49)
	checkErr(err, "Decrement: %v", err)
	if n != 1 {
		t.Fatalf("Decrement 49: want=1, got=%d", n)
	}
	err = c.Delete("num")
	checkErr(err, "delete num: %v", err)
	n, err = c.Increment("num", 1)
	if err != ErrCacheMiss {
		t.Fatalf("increment post-delete: want ErrCacheMiss, got %v", err)
	}
	mustSet(&Item{Key: "num", Value: []byte("not-numeric")})
	n, err = c.Increment("num", 1)
	if err == nil || !strings.Contains(err.Error(), "client error") {
		t.Fatalf("increment non-number: want client error, got %v", err)
	}

}
<|endoftext|>


<commit_before><commit_msg>Refactor createServer into smaller parts<commit_after><|endoftext|>


<commit_before><commit_msg>basically, the client tracing feature is done, under test<commit_after><|endoftext|>


<commit_before><commit_msg>add more useful help on manifest export<commit_after><|endoftext|>


<commit_before><commit_msg>Fix Virtlet DB path (again)<commit_after><|endoftext|>


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

package main

import (
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"labix.org/v2/mgo/bson"
)

func update(units []provision.Unit) {
	log.Print("updating status from provisioner")
	for _, unit := range units {
		a := app.App{Name: unit.AppName}
		err := a.Get()
		if err != nil {
			log.Printf("collector: app %s not found. Skipping.\n", unit.AppName)
			continue
		}
		u := app.Unit{}
		u.Name = unit.Name
		u.Type = unit.Type
		u.Machine = unit.Machine
		u.Ip = unit.Ip
		u.State = string(unit.Status)
		a.State = string(unit.Status)
		a.AddUnit(&u)
		db.Session.Apps().Update(bson.M{"name": a.Name}, a)
	}
}
<commit_msg>collector: set app's ip to one of its unit<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"labix.org/v2/mgo/bson"
)

func update(units []provision.Unit) {
	log.Print("updating status from provisioner")
	for _, unit := range units {
		a := app.App{Name: unit.AppName}
		err := a.Get()
		if err != nil {
			log.Printf("collector: app %s not found. Skipping.\n", unit.AppName)
			continue
		}
		u := app.Unit{}
		u.Name = unit.Name
		u.Type = unit.Type
		u.Machine = unit.Machine
		u.Ip = unit.Ip
		u.State = string(unit.Status)
		a.State = string(unit.Status)
		a.Ip = unit.Ip
		a.AddUnit(&u)
		db.Session.Apps().Update(bson.M{"name": a.Name}, a)
	}
}
<|endoftext|>


<commit_before><commit_msg>add archetype to local state<commit_after><|endoftext|>


<commit_before>// Copyright 2016 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.

package merkle

import (
	"fmt"
	"testing"

	"github.com/google/trillian/merkle/compact"
)

type auditPathTestData struct {
	treeSize     int64
	leafIndex    int64
	expectedPath []NodeFetch
}

type consistencyProofTestData struct {
	priorTreeSize int64
	treeSize      int64
	expectedProof []NodeFetch
}

var lastNodeWrittenVec = []struct {
	ts     int64
	result string
}{
	{3, "101"},
	{5, "1001"},
	{11, "10101"},
	{14, "11011"},
	{15, "11101"},
}

// For the path test tests at tree sizes up to this value
const testUpToTreeSize = 99

// Expected inclusion proof paths built by examination of the example 7 leaf tree in RFC 6962:
//
//                hash              <== Level 3
//               /    \
//              /      \
//             /        \
//            /          \
//           /            \
//          k              l        <== Level 2
//         / \            / \
//        /   \          /   \
//       /     \        /     \
//      g       h      i      [ ]   <== Level 1
//     / \     / \    / \    /
//     a b     c d    e f    j      <== Level 0
//     | |     | |    | |    |
//     d0 d1   d2 d3  d4 d5  d6
//
// When comparing with the document remember that our storage node layers are always
// populated from the bottom up, hence the gap at level 1, index 3 in the above picture.

var expectedPathSize7Index0 = []NodeFetch{ // from a
	NodeFetchForTreeCoords(0, 1, false), // b
	NodeFetchForTreeCoords(1, 1, false), // h
	NodeFetchForTreeCoords(2, 1, false), // l
}
var expectedPathSize7Index3 = []NodeFetch{ // from d
	NodeFetchForTreeCoords(0, 2, false), // c
	NodeFetchForTreeCoords(1, 0, false), // g
	NodeFetchForTreeCoords(2, 1, false), // l
}
var expectedPathSize7Index4 = []NodeFetch{ // from e
	NodeFetchForTreeCoords(0, 5, false), // f
	NodeFetchForTreeCoords(0, 6, false), // j
	NodeFetchForTreeCoords(2, 0, false), // k
}
var expectedPathSize7Index6 = []NodeFetch{ // from j
	NodeFetchForTreeCoords(1, 2, false), // i
	NodeFetchForTreeCoords(2, 0, false), // k
}

// Expected consistency proofs built from the examples in RFC 6962. Again, in our implementation
// node layers are filled from the bottom upwards.
var expectedConsistencyProofFromSize1To2 = []NodeFetch{
	//                     hash1=g
	//                          / \
	//  hash0=a      =>         a b
	//        |                 | |
	//        d0               d0 d1
	NodeFetchForTreeCoords(0, 1, false), // b
}
var expectedConsistencyProofFromSize1To4 = []NodeFetch{
	//
	//
	//  hash0=a      =>           hash1=k
	//        |                  /   \
	//        d0                /     \
	//                         /      \
	//                         /       \
	//                         g       h
	//                        / \     / \
	//                        a b     c d
	//                        | |     | |
	//                       d0 d1   d2 d3
	//
	//
	NodeFetchForTreeCoords(0, 1, false), // b
	NodeFetchForTreeCoords(1, 1, false), // h
}
var expectedConsistencyProofFromSize3To7 = []NodeFetch{
	//                                             hash
	//                                            /    \
	//                                           /      \
	//                                          /        \
	//                                         /          \
	//                            =>          /            \
	//       hash0                           k              l
	//       / \                            / \            / \
	//      /   \                          /   \          /   \
	//     /     \                        /     \        /     \
	//     g     [ ]                     g       h      i      [ ]
	//    / \    /                      / \     / \    / \    /
	//    a b    c                      a b     c d    e f    j
	//    | |    |                      | |     | |    | |    |
	//   d0 d1   d2                     d0 d1   d2 d3  d4 d5  d6
	NodeFetchForTreeCoords(0, 2, false), // c
	NodeFetchForTreeCoords(0, 3, false), // d
	NodeFetchForTreeCoords(1, 0, false), // g
	NodeFetchForTreeCoords(2, 1, false), // l
}
var expectedConsistencyProofFromSize4To7 = []NodeFetch{
	//                                             hash
	//                                            /    \
	//                                           /      \
	//                                          /        \
	//                                         /          \
	//                            =>          /            \
	//     hash1=k                           k              l
	//       /  \                           / \            / \
	//      /    \                         /   \          /   \
	//     /      \                       /     \        /     \
	//     g       h                     g       h      i      [ ]
	//    / \     / \                   / \     / \    / \    /
	//    a b     c d                   a b     c d    e f    j
	//    | |     | |                   | |     | |    | |    |
	//   d0 d1   d2 d3                  d0 d1   d2 d3  d4 d5  d6
	NodeFetchForTreeCoords(2, 1, false), // l
}
var expectedConsistencyProofFromSize6To7 = []NodeFetch{
	//             hash2                           hash
	//             /  \                           /    \
	//            /    \                         /      \
	//           /      \                       /        \
	//          /        \                     /          \
	//         /          \       =>          /            \
	//        k            [ ]               k              l
	//       / \           /                / \            / \
	//      /   \         /                /   \          /   \
	//     /     \        |               /     \        /     \
	//    g       h       i              g       h      i      [ ]
	//   / \     / \     / \            / \     / \    / \    /
	//   a b     c d     e f            a b     c d    e f    j
	//   | |     | |     | |            | |     | |    | |    |
	//   d0 d1   d2 d3  d4 d5           d0 d1   d2 d3  d4 d5  d6
	NodeFetchForTreeCoords(1, 2, false), // i
	NodeFetchForTreeCoords(0, 6, false), // j
	NodeFetchForTreeCoords(2, 0, false), // k
}
var expectedConsistencyProofFromSize2To8 = []NodeFetch{
	//                               hash8
	//                              /    \
	//                             /      \
	//                            /        \
	//                           /          \
	//              =>          /            \
	//                         k              l
	//                        / \            / \
	//                       /   \          /   \
	//  hash2=              /     \        /     \
	//     g               g       h      i      n
	//    / \             / \     / \    / \    / \
	//    a b             a b     c d    e f    j m
	//    | |             | |     | |    | |    | |
	//   d0 d1            d0 d1   d2 d3  d4 d5 d6 d7
	NodeFetchForTreeCoords(1, 1, false), // h
	NodeFetchForTreeCoords(2, 1, false), // l
}

// These should all successfully compute the expected path
var pathTests = []auditPathTestData{
	{1, 0, []NodeFetch{}},
	{7, 3, expectedPathSize7Index3},
	{7, 6, expectedPathSize7Index6},
	{7, 0, expectedPathSize7Index0},
	{7, 4, expectedPathSize7Index4},
}

// These should all fail
var pathTestBad = []auditPathTestData{
	{0, 1, []NodeFetch{}},
	{1, 2, []NodeFetch{}},
	{0, 3, []NodeFetch{}},
	{-1, 3, []NodeFetch{}},
	{7, -1, []NodeFetch{}},
	{7, 8, []NodeFetch{}},
}

// These should compute the expected consistency proofs
var consistencyTests = []consistencyProofTestData{
	{1, 2, expectedConsistencyProofFromSize1To2},
	{1, 4, expectedConsistencyProofFromSize1To4},
	{6, 7, expectedConsistencyProofFromSize6To7},
	{3, 7, expectedConsistencyProofFromSize3To7},
	{4, 7, expectedConsistencyProofFromSize4To7},
	{2, 8, expectedConsistencyProofFromSize2To8},
	{1, 1, []NodeFetch{}},
	{2, 2, []NodeFetch{}},
	{3, 3, []NodeFetch{}},
	{4, 4, []NodeFetch{}},
	{5, 5, []NodeFetch{}},
	{7, 7, []NodeFetch{}},
	{8, 8, []NodeFetch{}},
}

// These should all fail to provide proofs
var consistencyTestsBad = []consistencyProofTestData{
	{0, -1, []NodeFetch{}},
	{-10, 0, []NodeFetch{}},
	{-1, -1, []NodeFetch{}},
	{0, 0, []NodeFetch{}},
	{9, 8, []NodeFetch{}},
}

func TestCalcInclusionProofNodeAddresses(t *testing.T) {
	for _, testCase := range pathTests {
		path, err := CalcInclusionProofNodeAddresses(testCase.treeSize, testCase.leafIndex, testCase.treeSize)

		if err != nil {
			t.Fatalf("unexpected error calculating path %v: %v", testCase, err)
		}

		comparePaths(t, fmt.Sprintf("i(%d,%d)", testCase.leafIndex, testCase.treeSize), path, testCase.expectedPath)
	}
}

func TestCalcInclusionProofNodeAddressesBadRanges(t *testing.T) {
	for _, testCase := range pathTestBad {
		_, err := CalcInclusionProofNodeAddresses(testCase.treeSize, testCase.leafIndex, testCase.treeSize)

		if err == nil {
			t.Fatalf("incorrectly accepted bad params: %v", testCase)
		}
	}
}

func TestCalcConsistencyProofNodeAddresses(t *testing.T) {
	for _, testCase := range consistencyTests {
		proof, err := CalcConsistencyProofNodeAddresses(testCase.priorTreeSize, testCase.treeSize, testCase.treeSize)

		if err != nil {
			t.Fatalf("failed to calculate consistency proof from %d to %d: %v", testCase.priorTreeSize, testCase.treeSize, err)
		}

		comparePaths(t, fmt.Sprintf("c(%d, %d)", testCase.priorTreeSize, testCase.treeSize), proof, testCase.expectedProof)
	}
}

func TestCalcConsistencyProofNodeAddressesBadInputs(t *testing.T) {
	for _, testCase := range consistencyTestsBad {
		_, err := CalcConsistencyProofNodeAddresses(testCase.priorTreeSize, testCase.treeSize, testCase.treeSize)

		if err == nil {
			t.Fatalf("consistency path calculation accepted bad input: %v", testCase)
		}
	}
}

func comparePaths(t *testing.T, desc string, got, expected []NodeFetch) {
	if len(expected) != len(got) {
		t.Fatalf("%s: expected %d nodes in path but got %d: %v", desc, len(expected), len(got), got)
	}

	for i := 0; i < len(expected); i++ {
		if expected[i] != got[i] {
			t.Fatalf("%s: expected node %+v at position %d but got %+v", desc, expected[i], i, got[i])
		}
	}
}

func TestLastNodeWritten(t *testing.T) {
	for _, testCase := range lastNodeWrittenVec {
		str := ""
		for d := int64(len(testCase.result) - 1); d >= 0; d-- {
			if lastNodePresent(d, testCase.ts) {
				str += "1"
			} else {
				str += "0"
			}
		}

		if got, want := str, testCase.result; got != want {
			t.Errorf("lastNodeWritten(%d) got: %s, want: %s", testCase.ts, got, want)
		}
	}
}

func TestInclusionSucceedsUpToTreeSize(t *testing.T) {
	for ts := 1; ts < testUpToTreeSize; ts++ {
		for i := ts; i < ts; i++ {
			if _, err := CalcInclusionProofNodeAddresses(int64(ts), int64(i), int64(ts)); err != nil {
				t.Errorf("CalcInclusionProofNodeAddresses(ts:%d, i:%d) = %v", ts, i, err)
			}
		}
	}
}

func TestConsistencySucceedsUpToTreeSize(t *testing.T) {
	for s1 := 1; s1 < testUpToTreeSize; s1++ {
		for s2 := s1 + 1; s2 < testUpToTreeSize; s2++ {
			if _, err := CalcConsistencyProofNodeAddresses(int64(s1), int64(s2), int64(s2)); err != nil {
				t.Errorf("CalcConsistencyProofNodeAddresses(%d, %d) = %v", s1, s2, err)
			}
		}
	}
}

func NodeFetchForTreeCoords(depth, index int64, rehash bool) NodeFetch {
	n := compact.NewNodeID(uint(depth), uint64(index))
	return NodeFetch{ID: n, Rehash: rehash}
}
<commit_msg>Refactor log_proofs tests (#2144)<commit_after>// Copyright 2016 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.

package merkle

import (
	"fmt"
	"testing"

	"github.com/google/trillian/merkle/compact"
)

// Expected inclusion proof paths built by examination of the example 7 leaf tree in RFC 6962:
//
//                hash              <== Level 3
//               /    \
//              /      \
//             /        \
//            /          \
//           /            \
//          k              l        <== Level 2
//         / \            / \
//        /   \          /   \
//       /     \        /     \
//      g       h      i      [ ]   <== Level 1
//     / \     / \    / \    /
//     a b     c d    e f    j      <== Level 0
//     | |     | |    | |    |
//     d0 d1   d2 d3  d4 d5  d6
//
// When comparing with the document remember that our storage node layers are always
// populated from the bottom up, hence the gap at level 1, index 3 in the above picture.
var (
	expectedPathSize7Index0 = []NodeFetch{ // from a
		newNodeFetch(0, 1, false), // b
		newNodeFetch(1, 1, false), // h
		newNodeFetch(2, 1, false), // l
	}
	expectedPathSize7Index3 = []NodeFetch{ // from d
		newNodeFetch(0, 2, false), // c
		newNodeFetch(1, 0, false), // g
		newNodeFetch(2, 1, false), // l
	}
	expectedPathSize7Index4 = []NodeFetch{ // from e
		newNodeFetch(0, 5, false), // f
		newNodeFetch(0, 6, false), // j
		newNodeFetch(2, 0, false), // k
	}
	expectedPathSize7Index6 = []NodeFetch{ // from j
		newNodeFetch(1, 2, false), // i
		newNodeFetch(2, 0, false), // k
	}
)

// Expected consistency proofs built from the examples in RFC 6962. Again, in our implementation
// node layers are filled from the bottom upwards.
var (
	//                     hash1=g
	//                          / \
	//  hash0=a      =>         a b
	//        |                 | |
	//        d0               d0 d1
	expectedConsistencyProofFromSize1To2 = []NodeFetch{
		newNodeFetch(0, 1, false), // b
	}

	//  hash0=a      =>           hash1=k
	//        |                  /   \
	//        d0                /     \
	//                         /      \
	//                         /       \
	//                         g       h
	//                        / \     / \
	//                        a b     c d
	//                        | |     | |
	//                       d0 d1   d2 d3
	expectedConsistencyProofFromSize1To4 = []NodeFetch{
		newNodeFetch(0, 1, false), // b
		newNodeFetch(1, 1, false), // h
	}

	//                                             hash
	//                                            /    \
	//                                           /      \
	//                                          /        \
	//                                         /          \
	//                            =>          /            \
	//       hash0                           k              l
	//       / \                            / \            / \
	//      /   \                          /   \          /   \
	//     /     \                        /     \        /     \
	//     g     [ ]                     g       h      i      [ ]
	//    / \    /                      / \     / \    / \    /
	//    a b    c                      a b     c d    e f    j
	//    | |    |                      | |     | |    | |    |
	//   d0 d1   d2                     d0 d1   d2 d3  d4 d5  d6
	expectedConsistencyProofFromSize3To7 = []NodeFetch{
		newNodeFetch(0, 2, false), // c
		newNodeFetch(0, 3, false), // d
		newNodeFetch(1, 0, false), // g
		newNodeFetch(2, 1, false), // l
	}

	//                                             hash
	//                                            /    \
	//                                           /      \
	//                                          /        \
	//                                         /          \
	//                            =>          /            \
	//     hash1=k                           k              l
	//       /  \                           / \            / \
	//      /    \                         /   \          /   \
	//     /      \                       /     \        /     \
	//     g       h                     g       h      i      [ ]
	//    / \     / \                   / \     / \    / \    /
	//    a b     c d                   a b     c d    e f    j
	//    | |     | |                   | |     | |    | |    |
	//   d0 d1   d2 d3                  d0 d1   d2 d3  d4 d5  d6
	expectedConsistencyProofFromSize4To7 = []NodeFetch{
		newNodeFetch(2, 1, false), // l
	}

	//             hash2                           hash
	//             /  \                           /    \
	//            /    \                         /      \
	//           /      \                       /        \
	//          /        \                     /          \
	//         /          \       =>          /            \
	//        k            [ ]               k              l
	//       / \           /                / \            / \
	//      /   \         /                /   \          /   \
	//     /     \        |               /     \        /     \
	//    g       h       i              g       h      i      [ ]
	//   / \     / \     / \            / \     / \    / \    /
	//   a b     c d     e f            a b     c d    e f    j
	//   | |     | |     | |            | |     | |    | |    |
	//   d0 d1   d2 d3  d4 d5           d0 d1   d2 d3  d4 d5  d6
	expectedConsistencyProofFromSize6To7 = []NodeFetch{
		newNodeFetch(1, 2, false), // i
		newNodeFetch(0, 6, false), // j
		newNodeFetch(2, 0, false), // k
	}

	//                               hash8
	//                              /    \
	//                             /      \
	//                            /        \
	//                           /          \
	//              =>          /            \
	//                         k              l
	//                        / \            / \
	//                       /   \          /   \
	//  hash2=              /     \        /     \
	//     g               g       h      i      n
	//    / \             / \     / \    / \    / \
	//    a b             a b     c d    e f    j m
	//    | |             | |     | |    | |    | |
	//   d0 d1            d0 d1   d2 d3  d4 d5 d6 d7
	expectedConsistencyProofFromSize2To8 = []NodeFetch{
		newNodeFetch(1, 1, false), // h
		newNodeFetch(2, 1, false), // l
	}
)

func TestCalcInclusionProofNodeAddresses(t *testing.T) {
	// These should all successfully compute the expected path.
	for _, testCase := range []struct {
		treeSize     int64
		leafIndex    int64
		expectedPath []NodeFetch
	}{
		{1, 0, []NodeFetch{}},
		{7, 3, expectedPathSize7Index3},
		{7, 6, expectedPathSize7Index6},
		{7, 0, expectedPathSize7Index0},
		{7, 4, expectedPathSize7Index4},
	} {
		path, err := CalcInclusionProofNodeAddresses(testCase.treeSize, testCase.leafIndex, testCase.treeSize)

		if err != nil {
			t.Fatalf("unexpected error calculating path %v: %v", testCase, err)
		}

		comparePaths(t, fmt.Sprintf("i(%d,%d)", testCase.leafIndex, testCase.treeSize), path, testCase.expectedPath)
	}
}

func TestCalcInclusionProofNodeAddressesBadRanges(t *testing.T) {
	// These should all fail.
	for _, testCase := range []struct {
		treeSize  int64
		leafIndex int64
	}{
		{0, 1},
		{1, 2},
		{0, 3},
		{-1, 3},
		{7, -1},
		{7, 8},
	} {
		_, err := CalcInclusionProofNodeAddresses(testCase.treeSize, testCase.leafIndex, testCase.treeSize)

		if err == nil {
			t.Fatalf("incorrectly accepted bad params: %v", testCase)
		}
	}
}

func TestCalcConsistencyProofNodeAddresses(t *testing.T) {
	// These should compute the expected consistency proofs.
	for _, testCase := range []struct {
		priorTreeSize int64
		treeSize      int64
		expectedProof []NodeFetch
	}{
		{1, 2, expectedConsistencyProofFromSize1To2},
		{1, 4, expectedConsistencyProofFromSize1To4},
		{6, 7, expectedConsistencyProofFromSize6To7},
		{3, 7, expectedConsistencyProofFromSize3To7},
		{4, 7, expectedConsistencyProofFromSize4To7},
		{2, 8, expectedConsistencyProofFromSize2To8},
		{1, 1, []NodeFetch{}},
		{2, 2, []NodeFetch{}},
		{3, 3, []NodeFetch{}},
		{4, 4, []NodeFetch{}},
		{5, 5, []NodeFetch{}},
		{7, 7, []NodeFetch{}},
		{8, 8, []NodeFetch{}},
	} {
		proof, err := CalcConsistencyProofNodeAddresses(testCase.priorTreeSize, testCase.treeSize, testCase.treeSize)

		if err != nil {
			t.Fatalf("failed to calculate consistency proof from %d to %d: %v", testCase.priorTreeSize, testCase.treeSize, err)
		}

		comparePaths(t, fmt.Sprintf("c(%d, %d)", testCase.priorTreeSize, testCase.treeSize), proof, testCase.expectedProof)
	}
}

func TestCalcConsistencyProofNodeAddressesBadInputs(t *testing.T) {
	// These should all fail to provide proofs.
	for _, testCase := range []struct {
		priorTreeSize int64
		treeSize      int64
	}{
		{0, -1},
		{-10, 0},
		{-1, -1},
		{0, 0},
		{9, 8},
	} {
		_, err := CalcConsistencyProofNodeAddresses(testCase.priorTreeSize, testCase.treeSize, testCase.treeSize)

		if err == nil {
			t.Fatalf("consistency path calculation accepted bad input: %v", testCase)
		}
	}
}

func comparePaths(t *testing.T, desc string, got, expected []NodeFetch) {
	if len(expected) != len(got) {
		t.Fatalf("%s: expected %d nodes in path but got %d: %v", desc, len(expected), len(got), got)
	}

	for i := 0; i < len(expected); i++ {
		if expected[i] != got[i] {
			t.Fatalf("%s: expected node %+v at position %d but got %+v", desc, expected[i], i, got[i])
		}
	}
}

func TestLastNodeWritten(t *testing.T) {
	for _, testCase := range []struct {
		ts     int64
		result string
	}{
		{3, "101"},
		{5, "1001"},
		{11, "10101"},
		{14, "11011"},
		{15, "11101"},
	} {
		str := ""
		for d := int64(len(testCase.result) - 1); d >= 0; d-- {
			if lastNodePresent(d, testCase.ts) {
				str += "1"
			} else {
				str += "0"
			}
		}

		if got, want := str, testCase.result; got != want {
			t.Errorf("lastNodeWritten(%d) got: %s, want: %s", testCase.ts, got, want)
		}
	}
}

func TestInclusionSucceedsUpToTreeSize(t *testing.T) {
	const maxSize = 555
	for ts := 1; ts <= maxSize; ts++ {
		for i := ts; i < ts; i++ {
			if _, err := CalcInclusionProofNodeAddresses(int64(ts), int64(i), int64(ts)); err != nil {
				t.Errorf("CalcInclusionProofNodeAddresses(ts:%d, i:%d) = %v", ts, i, err)
			}
		}
	}
}

func TestConsistencySucceedsUpToTreeSize(t *testing.T) {
	const maxSize = 100
	for s1 := 1; s1 < maxSize; s1++ {
		for s2 := s1 + 1; s2 <= maxSize; s2++ {
			if _, err := CalcConsistencyProofNodeAddresses(int64(s1), int64(s2), int64(s2)); err != nil {
				t.Errorf("CalcConsistencyProofNodeAddresses(%d, %d) = %v", s1, s2, err)
			}
		}
	}
}

func newNodeFetch(level uint, index uint64, rehash bool) NodeFetch {
	return NodeFetch{ID: compact.NewNodeID(level, index), Rehash: rehash}
}
<|endoftext|>


<commit_before>package main

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

// Global Vars
var verbose = false

type header struct {
	name string
	value string
	points int
}

func (h *header) SetPoints(points int) {
    h.points = points
}

func main(){

    headersPresent := []header{}
    hostPtr := flag.String("t", "", "Target host.")
    redirPtr := flag.Bool("r", true, "Follow redirects.") // Not really used yet.
    flag.BoolVar(&verbose, "v", false, "Increase the number of status messages.")
    flag.Parse()

    if verbose {
        fmt.Println("Beginning operations......")
    }

    // This is our map of all point-valued standard HTTP headers.
    var stdHeaders = map[string]int {
        "access-control-allow-origin": 2,
        "cache-control": 2,
        "content-security-policy": 10,
        "pragma": 2,
        "public-key-pins": 10,
        "strict-transport-security": 6,
        "tsv": 2,
        "x-content-type-options": 2,
        "x-frame-options": 4,
        "x-xss-protection": 2,
        "via": -2,
        "warning": -1,
        "www-authenticate": -4,
        "x-content-security-policy": -5,
        "x-powered-by": -2,
        "x-ua-compatible": -2,
        "x-webkit-csp": -5,
    }

    if *hostPtr == "" {
        fmt.Println("No target host was specified.")
        return
    }

    // Here is where we start reaching out to the target.
    headersPresent, err := testTarget(*hostPtr, *redirPtr)

    if err != nil {
        fmt.Println("We have encountered an error, exiting...")
        return
    }

    // Now we compare the retrieved headers with our standard list.
    for _, p := range headersPresent {
        for k, v := range stdHeaders{
            fmt.Printf("%v:%v:%v\n", strings.ToLower(p.name),k,v)
            if strings.ToLower(p.name) == k {
                fmt.Printf("***hit***: %v\n", v)
                p.SetPoints(v)
            }
        }
    }

    for _, p := range headersPresent {
        fmt.Println(p)
    }
}

// This method is used to perform a basic HTTP request to the target host.
func testTarget(url string, redir bool) (h []header, err error) {

    client := &http.Client {
        Timeout: 10 * time.Second,
    }

    request, err := http.NewRequest("GET", url, nil)

    // Make the HTTP request to the target URL.
    response, err := client.Do(request)

    if err != nil {
        fmt.Printf("Error message: %v \n", err)
    }

    if verbose { fmt.Printf("Target %v responded.\n", url)}
    if response.StatusCode != http.StatusOK {
                fmt.Printf("Server return non-200 status: %v\n", response.Status)
        }

    // Let's print some pretty stuff.
    fmt.Printf("\n\n")
    fmt.Println("**************************************************")
    fmt.Println("*")
    fmt.Println("* Headers present")
    fmt.Println("*")
    fmt.Println("**************************************************")
    fmt.Printf("\n\n")

    // titles := []interface{}{"Header","Value",0}
    // headerList := []interface{}(titles)

    // header := []interface{}{"h","v",10}
    // header2 := []interface{}{"x","y",5}
    // headerList = append(header)
    // headerList = append(header2)

    // for v := range headerList {
    //     fmt.Println(headerList[v])
    // }

    headers := []header{}

    // Print out all headers.
    for k, v := range response.Header {
        //fmt.Println("Header:", k, "Value:", v)
        temp := header{k,v[0],0}
        //fmt.Println(temp)
        headers = append(headers, temp)
    }

    // Let's print some more pretty stuff.
    fmt.Printf("\n\n")
    fmt.Println("**************************************************")
    fmt.Println("*")
    fmt.Println("**************************************************")

    return headers, err
}<commit_msg>Fixed scoring on main slice.<commit_after>package main

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

// Global Vars
var verbose = false

type header struct {
	name string
	value string
	points int
}

func (h *header) SetPoints(points int) {
    h.points = points
}

func main(){

    headersPresent := []header{}
    hostPtr := flag.String("t", "", "Target host.")
    redirPtr := flag.Bool("r", true, "Follow redirects.") // Not really used yet.
    flag.BoolVar(&verbose, "v", false, "Increase the number of status messages.")
    flag.Parse()

    if verbose {
        fmt.Printf("\nBeginning operations......\n")
    }

    // This is our map of all point-valued standard HTTP headers.
    var stdHeaders = map[string]int {
        "access-control-allow-origin": 2,
        "cache-control": 2,
        "content-security-policy": 10,
        "pragma": 2,
        "public-key-pins": 10,
        "strict-transport-security": 6,
        "tsv": 2,
        "x-content-type-options": 2,
        "x-frame-options": 4,
        "x-xss-protection": 2,
        "via": -2,
        "warning": -1,
        "www-authenticate": -4,
        "x-content-security-policy": -5,
        "x-powered-by": -2,
        "x-ua-compatible": -2,
        "x-webkit-csp": -5,
    }

    if *hostPtr == "" {
        fmt.Println("No target host was specified.")
        return
    }

    // Here is where we start reaching out to the target.
    headersPresent, err := testTarget(*hostPtr, *redirPtr)

    if err != nil {
        fmt.Println("We have encountered an error, exiting...")
        return
    }

    // We compare the headers retrieved from the target to the standard
    // header list to start scoring.
    for i := range headersPresent {
        for k, v := range stdHeaders{
            if strings.ToLower(headersPresent[i].name) == k {
                headersPresent[i].points = v
            }
        }
    }

    // Let's print some pretty stuff.
    fmt.Printf("\n\n")
    fmt.Println("**************************************************")
    fmt.Println("*")
    fmt.Println("* Headers present")
    fmt.Println("*")
    fmt.Println("**************************************************")
    fmt.Printf("\n\n")

    for _, p := range headersPresent {
        fmt.Println(p)
    }

    // Let's print some more pretty stuff.
    fmt.Printf("\n\n")
    fmt.Println("**************************************************")
    fmt.Println("*")
    fmt.Println("**************************************************")
}

// This method is used to perform a basic HTTP request to the target host.
func testTarget(url string, redir bool) (h []header, err error) {

    client := &http.Client {
        Timeout: 10 * time.Second,
    }

    request, err := http.NewRequest("GET", url, nil)

    // Make the HTTP request to the target URL.
    response, err := client.Do(request)

    if err != nil {
        fmt.Printf("Error message: %v \n", err)
    }

    if verbose { fmt.Printf("Target %v responded.\n", url)}
    if response.StatusCode != http.StatusOK {
                fmt.Printf("Server return non-200 status: %v\n", response.Status)
        }

    headers := []header{}

    // Print out all headers.
    for k, v := range response.Header {
        //fmt.Println("Header:", k, "Value:", v)
        temp := header{k,v[0],0}
        //fmt.Println(temp)
        headers = append(headers, temp)
    }

    return headers, err
}<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"sync"
	"sync/atomic"
	"time"

	term "github.com/nsf/termbox-go"
	terminal "github.com/wayneashleyberry/terminal-dimensions"
)

const (
	statsLines             = 3
	movingWindowsSize      = 10 // seconds
	screenRefreshFrequency = 10 // per second
	screenRefreshInterval  = time.Second / screenRefreshFrequency

	rateIncreaseStep = 100
	rateDecreaseStep = 100
)

var (
	requestsSent      counter
	responsesReceived counter
	responses         [1024]counter
	desiredRate       counter

	timingsOk  [][]counter
	timingsBad [][]counter

	terminalWidth  uint
	terminalHeight uint

	// plotting vars
	plotWidth  uint
	plotHeight uint
	buckets    uint
	logBase    float64
	minY, maxY float64
)

func resetStats() {
	requestsSent.Store(0)
	responsesReceived.Store(0)

	for _, ok := range timingsOk {
		for i := 0; i < len(ok); i++ {
			ok[i].Store(0)
		}
	}

	for _, bad := range timingsBad {
		for i := 0; i < len(bad); i++ {
			bad[i].Store(0)
		}
	}

	for i := 0; i < len(responses); i++ {
		responses[i].Store(0)
	}
}

type counter int64

func (c *counter) Add(v int64) int64 { return atomic.AddInt64((*int64)(c), v) }
func (c *counter) Load() int64       { return atomic.LoadInt64((*int64)(c)) }
func (c *counter) Store(v int64)     { atomic.StoreInt64((*int64)(c), v) }

type targeter struct {
	idx      counter
	requests []struct {
		method string
		url    string
		body   []byte
	}
}

func newTargeter(targets string) (*targeter, error) {
	var reader *bufio.Reader
	if targets == "stdin" {
		reader = bufio.NewReader(os.Stdin)
	} else {
		f, err := os.Open(targets)
		if err != nil {
			return nil, err
		}

		reader = bufio.NewReader(f)
		defer f.Close()
	}

	trgt := &targeter{}

	// syntax
	// GET <url>\n
	// $ <body>\n
	// \n

	for {
		var method string
		var url, body []byte

		b, err := reader.ReadBytes('\n')
		if err != nil {
			break
		}

		b = bytes.Trim(b, " \t\n")
		if !bytes.HasPrefix(b, []byte("GET")) {
			continue
		}

		method = http.MethodGet
		url = bytes.TrimLeft(b[3:], " \t\n")

		b, err = reader.ReadBytes('\n')
		if err != nil {
			break
		}

		b = bytes.Trim(b, " \t\n")
		if len(b) == 0 {
			b = []byte("")
		} else if bytes.HasPrefix(b, []byte("$ ")) {
			body = b[2:]

			b, err = reader.ReadBytes('\n')
			if err != nil {
				break
			}

			if b = bytes.Trim(b, " \t\n"); len(b) != 0 {
				continue
			}
		}

		trgt.requests = append(trgt.requests, struct {
			method string
			url    string
			body   []byte
		}{
			method: method,
			url:    string(url),
			body:   body,
		})
	}

	return trgt, nil
}

func (t *targeter) nextRequest() (*http.Request, error) {
	if len(t.requests) == 0 {
		return nil, errors.New("no requests")
	}

	idx := int(t.idx.Add(1))
	st := t.requests[idx%len(t.requests)]
	return http.NewRequest(
		st.method,
		string(st.url),
		bytes.NewReader(st.body),
	)
}

func attack(trgt *targeter, timeout time.Duration, ch <-chan time.Time, quit <-chan struct{}) {
	tr := &http.Transport{
		DisableKeepAlives:   false,
		DisableCompression:  true,
		MaxIdleConnsPerHost: 100,
		IdleConnTimeout:     30 * time.Second,
	}

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

	for {
		select {
		case <-ch:
			if request, err := trgt.nextRequest(); err == nil {
				requestsSent.Add(1)

				start := time.Now()
				response, err := client.Do(request)
				if err == nil {
					_, err = ioutil.ReadAll(response.Body)
					response.Body.Close()
				}
				now := time.Now()

				tOk, tBad := getTimingsSlot(now)

				elapsed := now.Sub(start)
				elapsedMs := float64(elapsed) / float64(time.Millisecond)
				elapsedBucket := int(math.Log(elapsedMs) / math.Log(logBase))
				if elapsedBucket >= len(tOk) {
					elapsedBucket = len(tOk) - 1
				} else if elapsedBucket < 0 {
					elapsedBucket = 0
				}

				responsesReceived.Add(1)

				status := 0
				if err == nil {
					status = response.StatusCode
				}

				responses[status].Add(1)
				if status >= 200 && status < 300 {
					tOk[elapsedBucket].Add(1)
				} else {
					tBad[elapsedBucket].Add(1)
				}
			}
		case <-quit:
			return
		}
	}
}

func reporter(quit <-chan struct{}) {
	fmt.Print("\033[H")
	for i := 0; i < int(terminalHeight); i++ {
		fmt.Println(string(bytes.Repeat([]byte(" "), int(terminalWidth)-1)))
	}

	var currentRate counter
	go func() {
		var lastSent int64
		for _ = range time.Tick(time.Second) {
			curr := requestsSent.Load()
			currentRate.Store(curr - lastSent)
			lastSent = curr
		}
	}()

	colors := []string{
		"\033[38;5;46m", "\033[38;5;47m", "\033[38;5;48m", "\033[38;5;49m", // green
		"\033[38;5;149m", "\033[38;5;148m", "\033[38;5;179m", "\033[38;5;176m", // yellow
		"\033[38;5;169m", "\033[38;5;168m", "\033[38;5;197m", "\033[38;5;196m", // red
	}

	colorMultiplier := float64(len(colors)) / float64(buckets)
	barWidth := int(plotWidth) - 40 // reserve some space on right and left

	ticker := time.Tick(screenRefreshInterval)
	for {
		select {
		case <-ticker:
			// scratch arrays
			tOk := make([]int64, len(timingsOk))
			tBad := make([]int64, len(timingsBad))

			// need to understand how long in longest bar,
			// also take a change to copy arrays to have consistent view

			max := int64(1)
			for i := 0; i < len(timingsOk); i++ {
				ok := timingsOk[i]
				bad := timingsBad[i]

				for j := 0; j < len(ok); j++ {
					tOk[j] += ok[j].Load()
					tBad[j] += bad[j].Load()
					if sum := tOk[j] + tBad[j]; sum > max {
						max = sum
					}
				}
			}

			sent := requestsSent.Load()
			recv := responsesReceived.Load()
			fmt.Print("\033[H") // clean screen
			fmt.Printf("sent: %-6d ", sent)
			fmt.Printf("in-flight: %-2d ", sent-recv)
			fmt.Printf("\033[96mrate: %4d/%d RPS\033[0m ", currentRate.Load(), desiredRate.Load())

			fmt.Print("responses: ")
			for status, counter := range responses {
				if c := counter.Load(); c > 0 {
					if status >= 200 && status < 300 {
						fmt.Printf("\033[32m[%d]: %-6d\033[0m ", status, c)
					} else {
						fmt.Printf("\033[31m[%d]: %-6d\033[0m ", status, c)
					}
				}
			}
			fmt.Print("\r\n\r\n")

			width := float64(barWidth) / float64(max)
			for bkt := uint(0); bkt < buckets; bkt++ {
				startMs := math.Pow(logBase, float64(bkt))
				endMs := math.Pow(logBase, float64(bkt)+1)

				var label string
				if bkt == buckets-1 {
					label = fmt.Sprintf("%3.0f+", startMs)
				} else if endMs > 10 {
					label = fmt.Sprintf("%3.0f-%3.0f", startMs, endMs)
				} else {
					label = fmt.Sprintf("%.1f-%.1f", startMs, endMs)
				}

				widthOk := int(float64(tOk[bkt]) * width)
				widthBad := int(float64(tBad[bkt]) * width)
				widthLeft := barWidth - widthOk - widthBad

				fmt.Printf("%10s ms: [%s%6d%s/%s%6d%s] %s%s%s%s%s \r\n",
					label,
					"\033[32m",
					tOk[bkt],
					"\033[0m",
					"\033[31m",
					tBad[bkt],
					"\033[0m",
					colors[int(float64(bkt)*colorMultiplier)],
					bytes.Repeat([]byte("E"), widthBad),
					bytes.Repeat([]byte("*"), widthOk),
					bytes.Repeat([]byte(" "), widthLeft),
					"\033[0m")
			}
		case <-quit:
			return
		}
	}
}

func keyPressListener(increase, decrease chan<- int) {
	// start keyPress listener
	err := term.Init()
	if err != nil {
		panic(err)
	}

	defer term.Close()

keyPressListenerLoop:
	for {
		switch ev := term.PollEvent(); ev.Type {
		case term.EventKey:
			switch ev.Key {
			case term.KeyCtrlC:
				break keyPressListenerLoop
			default:
				switch ev.Ch {
				case 'q':
					break keyPressListenerLoop
				case 'r':
					resetStats()
				case 'k': // up
					increase <- rateIncreaseStep
				case 'j':
					decrease <- rateDecreaseStep
				}
			}
		case term.EventError:
			panic(ev.Err)
		}
	}
}

func ticker(rate int, quit <-chan struct{}) (<-chan time.Time, chan<- int, chan<- int) {
	ticker := make(chan time.Time, 1)
	increase := make(chan int, 1)
	decrease := make(chan int, 1)

	// start main workers
	go func() {
		desiredRate.Store(int64(rate))
		tck := time.Tick(time.Duration(1e9 / desiredRate.Load()))

		for {
			select {
			case v := <-increase:
				desiredRate.Add(int64(v))
				tck = time.Tick(time.Duration(1e9 / desiredRate.Load()))
			case v := <-decrease:
				desiredRate.Add(int64(-v))
				tck = time.Tick(time.Duration(1e9 / desiredRate.Load()))
			case t := <-tck:
				ticker <- t
			case <-quit:
				return
			}
		}
	}()

	return ticker, increase, decrease
}

func getTimingsSlot(now time.Time) ([]counter, []counter) {
	n := int(now.UnixNano() / 100000000)
	slot := n % len(timingsOk)
	return timingsOk[slot], timingsBad[slot]
}

func initializeTimingsBucket(buckets uint) {
	timingsOk = make([][]counter, movingWindowsSize*screenRefreshFrequency)
	for i := 0; i < len(timingsOk); i++ {
		timingsOk[i] = make([]counter, buckets)
	}

	timingsBad = make([][]counter, movingWindowsSize*screenRefreshFrequency)
	for i := 0; i < len(timingsBad); i++ {
		timingsBad[i] = make([]counter, buckets)
	}

	go func() {
		for now := range time.Tick(screenRefreshInterval) {
			// TODO account for missing ticks
			// clean next timing slot which is last one in ring buffer
			next := now.Add(screenRefreshInterval)
			tOk, tBad := getTimingsSlot(next)
			for i := 0; i < len(tOk); i++ {
				tOk[i].Store(0)
			}

			for i := 0; i < len(tBad); i++ {
				tBad[i].Store(0)
			}
		}
	}()
}

func main() {
	workers := flag.Int("workers", 8, "Number of workers")
	timeout := flag.Duration("timeout", 30*time.Second, "Requests timeout")
	targets := flag.String("targets", "stdin", "Targets file")
	rate := flag.Int("rate", 50, "Requests per second")
	miY := flag.Duration("minY", 0, "min on Y axe (default 0ms)")
	maY := flag.Duration("maxY", 100*time.Millisecond, "max on Y axe")
	flag.Parse()

	terminalWidth, _ = terminal.Width()
	terminalHeight, _ = terminal.Height()

	plotWidth = terminalWidth
	plotHeight = terminalHeight - statsLines

	minY, maxY = float64(*miY/time.Millisecond), float64(*maY/time.Millisecond)
	deltaY := maxY - minY
	buckets = plotHeight
	logBase = math.Pow(deltaY, 1/float64(buckets))

	initializeTimingsBucket(buckets)

	quit := make(chan struct{}, 1)
	ticker, increase, decrease := ticker(*rate, quit)

	trgt, err := newTargeter(*targets)
	if err != nil {
		panic(err)
	}

	// start attackers
	var wg sync.WaitGroup
	for i := 0; i < *workers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			attack(trgt, *timeout, ticker, quit)
		}()
	}

	// start reporter
	wg.Add(1)
	go func() {
		defer wg.Done()
		reporter(quit)
	}()

	keyPressListener(increase, decrease)

	// bye
	close(quit)
	wg.Wait()
}
<commit_msg>-workers is uint<commit_after>package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"sync"
	"sync/atomic"
	"time"

	term "github.com/nsf/termbox-go"
	terminal "github.com/wayneashleyberry/terminal-dimensions"
)

const (
	statsLines             = 3
	movingWindowsSize      = 10 // seconds
	screenRefreshFrequency = 10 // per second
	screenRefreshInterval  = time.Second / screenRefreshFrequency

	rateIncreaseStep = 100
	rateDecreaseStep = 100
)

var (
	requestsSent      counter
	responsesReceived counter
	responses         [1024]counter
	desiredRate       counter

	timingsOk  [][]counter
	timingsBad [][]counter

	terminalWidth  uint
	terminalHeight uint

	// plotting vars
	plotWidth  uint
	plotHeight uint
	buckets    uint
	logBase    float64
	minY, maxY float64
)

func resetStats() {
	requestsSent.Store(0)
	responsesReceived.Store(0)

	for _, ok := range timingsOk {
		for i := 0; i < len(ok); i++ {
			ok[i].Store(0)
		}
	}

	for _, bad := range timingsBad {
		for i := 0; i < len(bad); i++ {
			bad[i].Store(0)
		}
	}

	for i := 0; i < len(responses); i++ {
		responses[i].Store(0)
	}
}

type counter int64

func (c *counter) Add(v int64) int64 { return atomic.AddInt64((*int64)(c), v) }
func (c *counter) Load() int64       { return atomic.LoadInt64((*int64)(c)) }
func (c *counter) Store(v int64)     { atomic.StoreInt64((*int64)(c), v) }

type targeter struct {
	idx      counter
	requests []struct {
		method string
		url    string
		body   []byte
	}
}

func newTargeter(targets string) (*targeter, error) {
	var reader *bufio.Reader
	if targets == "stdin" {
		reader = bufio.NewReader(os.Stdin)
	} else {
		f, err := os.Open(targets)
		if err != nil {
			return nil, err
		}

		reader = bufio.NewReader(f)
		defer f.Close()
	}

	trgt := &targeter{}

	// syntax
	// GET <url>\n
	// $ <body>\n
	// \n

	for {
		var method string
		var url, body []byte

		b, err := reader.ReadBytes('\n')
		if err != nil {
			break
		}

		b = bytes.Trim(b, " \t\n")
		if !bytes.HasPrefix(b, []byte("GET")) {
			continue
		}

		method = http.MethodGet
		url = bytes.TrimLeft(b[3:], " \t\n")

		b, err = reader.ReadBytes('\n')
		if err != nil {
			break
		}

		b = bytes.Trim(b, " \t\n")
		if len(b) == 0 {
			b = []byte("")
		} else if bytes.HasPrefix(b, []byte("$ ")) {
			body = b[2:]

			b, err = reader.ReadBytes('\n')
			if err != nil {
				break
			}

			if b = bytes.Trim(b, " \t\n"); len(b) != 0 {
				continue
			}
		}

		trgt.requests = append(trgt.requests, struct {
			method string
			url    string
			body   []byte
		}{
			method: method,
			url:    string(url),
			body:   body,
		})
	}

	return trgt, nil
}

func (t *targeter) nextRequest() (*http.Request, error) {
	if len(t.requests) == 0 {
		return nil, errors.New("no requests")
	}

	idx := int(t.idx.Add(1))
	st := t.requests[idx%len(t.requests)]
	return http.NewRequest(
		st.method,
		string(st.url),
		bytes.NewReader(st.body),
	)
}

func attack(trgt *targeter, timeout time.Duration, ch <-chan time.Time, quit <-chan struct{}) {
	tr := &http.Transport{
		DisableKeepAlives:   false,
		DisableCompression:  true,
		MaxIdleConnsPerHost: 100,
		IdleConnTimeout:     30 * time.Second,
	}

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

	for {
		select {
		case <-ch:
			if request, err := trgt.nextRequest(); err == nil {
				requestsSent.Add(1)

				start := time.Now()
				response, err := client.Do(request)
				if err == nil {
					_, err = ioutil.ReadAll(response.Body)
					response.Body.Close()
				}
				now := time.Now()

				tOk, tBad := getTimingsSlot(now)

				elapsed := now.Sub(start)
				elapsedMs := float64(elapsed) / float64(time.Millisecond)
				elapsedBucket := int(math.Log(elapsedMs) / math.Log(logBase))
				if elapsedBucket >= len(tOk) {
					elapsedBucket = len(tOk) - 1
				} else if elapsedBucket < 0 {
					elapsedBucket = 0
				}

				responsesReceived.Add(1)

				status := 0
				if err == nil {
					status = response.StatusCode
				}

				responses[status].Add(1)
				if status >= 200 && status < 300 {
					tOk[elapsedBucket].Add(1)
				} else {
					tBad[elapsedBucket].Add(1)
				}
			}
		case <-quit:
			return
		}
	}
}

func reporter(quit <-chan struct{}) {
	fmt.Print("\033[H")
	for i := 0; i < int(terminalHeight); i++ {
		fmt.Println(string(bytes.Repeat([]byte(" "), int(terminalWidth)-1)))
	}

	var currentRate counter
	go func() {
		var lastSent int64
		for _ = range time.Tick(time.Second) {
			curr := requestsSent.Load()
			currentRate.Store(curr - lastSent)
			lastSent = curr
		}
	}()

	colors := []string{
		"\033[38;5;46m", "\033[38;5;47m", "\033[38;5;48m", "\033[38;5;49m", // green
		"\033[38;5;149m", "\033[38;5;148m", "\033[38;5;179m", "\033[38;5;176m", // yellow
		"\033[38;5;169m", "\033[38;5;168m", "\033[38;5;197m", "\033[38;5;196m", // red
	}

	colorMultiplier := float64(len(colors)) / float64(buckets)
	barWidth := int(plotWidth) - 40 // reserve some space on right and left

	ticker := time.Tick(screenRefreshInterval)
	for {
		select {
		case <-ticker:
			// scratch arrays
			tOk := make([]int64, len(timingsOk))
			tBad := make([]int64, len(timingsBad))

			// need to understand how long in longest bar,
			// also take a change to copy arrays to have consistent view

			max := int64(1)
			for i := 0; i < len(timingsOk); i++ {
				ok := timingsOk[i]
				bad := timingsBad[i]

				for j := 0; j < len(ok); j++ {
					tOk[j] += ok[j].Load()
					tBad[j] += bad[j].Load()
					if sum := tOk[j] + tBad[j]; sum > max {
						max = sum
					}
				}
			}

			sent := requestsSent.Load()
			recv := responsesReceived.Load()
			fmt.Print("\033[H") // clean screen
			fmt.Printf("sent: %-6d ", sent)
			fmt.Printf("in-flight: %-2d ", sent-recv)
			fmt.Printf("\033[96mrate: %4d/%d RPS\033[0m ", currentRate.Load(), desiredRate.Load())

			fmt.Print("responses: ")
			for status, counter := range responses {
				if c := counter.Load(); c > 0 {
					if status >= 200 && status < 300 {
						fmt.Printf("\033[32m[%d]: %-6d\033[0m ", status, c)
					} else {
						fmt.Printf("\033[31m[%d]: %-6d\033[0m ", status, c)
					}
				}
			}
			fmt.Print("\r\n\r\n")

			width := float64(barWidth) / float64(max)
			for bkt := uint(0); bkt < buckets; bkt++ {
				startMs := math.Pow(logBase, float64(bkt))
				endMs := math.Pow(logBase, float64(bkt)+1)

				var label string
				if bkt == buckets-1 {
					label = fmt.Sprintf("%3.0f+", startMs)
				} else if endMs > 10 {
					label = fmt.Sprintf("%3.0f-%3.0f", startMs, endMs)
				} else {
					label = fmt.Sprintf("%.1f-%.1f", startMs, endMs)
				}

				widthOk := int(float64(tOk[bkt]) * width)
				widthBad := int(float64(tBad[bkt]) * width)
				widthLeft := barWidth - widthOk - widthBad

				fmt.Printf("%10s ms: [%s%6d%s/%s%6d%s] %s%s%s%s%s \r\n",
					label,
					"\033[32m",
					tOk[bkt],
					"\033[0m",
					"\033[31m",
					tBad[bkt],
					"\033[0m",
					colors[int(float64(bkt)*colorMultiplier)],
					bytes.Repeat([]byte("E"), widthBad),
					bytes.Repeat([]byte("*"), widthOk),
					bytes.Repeat([]byte(" "), widthLeft),
					"\033[0m")
			}
		case <-quit:
			return
		}
	}
}

func keyPressListener(increase, decrease chan<- int) {
	// start keyPress listener
	err := term.Init()
	if err != nil {
		panic(err)
	}

	defer term.Close()

keyPressListenerLoop:
	for {
		switch ev := term.PollEvent(); ev.Type {
		case term.EventKey:
			switch ev.Key {
			case term.KeyCtrlC:
				break keyPressListenerLoop
			default:
				switch ev.Ch {
				case 'q':
					break keyPressListenerLoop
				case 'r':
					resetStats()
				case 'k': // up
					increase <- rateIncreaseStep
				case 'j':
					decrease <- rateDecreaseStep
				}
			}
		case term.EventError:
			panic(ev.Err)
		}
	}
}

func ticker(rate int, quit <-chan struct{}) (<-chan time.Time, chan<- int, chan<- int) {
	ticker := make(chan time.Time, 1)
	increase := make(chan int, 1)
	decrease := make(chan int, 1)

	// start main workers
	go func() {
		desiredRate.Store(int64(rate))
		tck := time.Tick(time.Duration(1e9 / desiredRate.Load()))

		for {
			select {
			case v := <-increase:
				desiredRate.Add(int64(v))
				tck = time.Tick(time.Duration(1e9 / desiredRate.Load()))
			case v := <-decrease:
				desiredRate.Add(int64(-v))
				tck = time.Tick(time.Duration(1e9 / desiredRate.Load()))
			case t := <-tck:
				ticker <- t
			case <-quit:
				return
			}
		}
	}()

	return ticker, increase, decrease
}

func getTimingsSlot(now time.Time) ([]counter, []counter) {
	n := int(now.UnixNano() / 100000000)
	slot := n % len(timingsOk)
	return timingsOk[slot], timingsBad[slot]
}

func initializeTimingsBucket(buckets uint) {
	timingsOk = make([][]counter, movingWindowsSize*screenRefreshFrequency)
	for i := 0; i < len(timingsOk); i++ {
		timingsOk[i] = make([]counter, buckets)
	}

	timingsBad = make([][]counter, movingWindowsSize*screenRefreshFrequency)
	for i := 0; i < len(timingsBad); i++ {
		timingsBad[i] = make([]counter, buckets)
	}

	go func() {
		for now := range time.Tick(screenRefreshInterval) {
			// TODO account for missing ticks
			// clean next timing slot which is last one in ring buffer
			next := now.Add(screenRefreshInterval)
			tOk, tBad := getTimingsSlot(next)
			for i := 0; i < len(tOk); i++ {
				tOk[i].Store(0)
			}

			for i := 0; i < len(tBad); i++ {
				tBad[i].Store(0)
			}
		}
	}()
}

func main() {
	workers := flag.Uint("workers", 8, "Number of workers")
	timeout := flag.Duration("timeout", 30*time.Second, "Requests timeout")
	targets := flag.String("targets", "stdin", "Targets file")
	rate := flag.Int("rate", 50, "Requests per second")
	miY := flag.Duration("minY", 0, "min on Y axe (default 0ms)")
	maY := flag.Duration("maxY", 100*time.Millisecond, "max on Y axe")
	flag.Parse()

	terminalWidth, _ = terminal.Width()
	terminalHeight, _ = terminal.Height()

	plotWidth = terminalWidth
	plotHeight = terminalHeight - statsLines

	minY, maxY = float64(*miY/time.Millisecond), float64(*maY/time.Millisecond)
	deltaY := maxY - minY
	buckets = plotHeight
	logBase = math.Pow(deltaY, 1/float64(buckets))

	initializeTimingsBucket(buckets)

	quit := make(chan struct{}, 1)
	ticker, increase, decrease := ticker(*rate, quit)

	trgt, err := newTargeter(*targets)
	if err != nil {
		panic(err)
	}

	// start attackers
	var wg sync.WaitGroup
	for i := uint(0); i < *workers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			attack(trgt, *timeout, ticker, quit)
		}()
	}

	// start reporter
	wg.Add(1)
	go func() {
		defer wg.Done()
		reporter(quit)
	}()

	keyPressListener(increase, decrease)

	// bye
	close(quit)
	wg.Wait()
}
<|endoftext|>


<commit_before><commit_msg>smarter bulk price fetches<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/big"
)

/*

The series, 1^1 + 2^2 + 3^3 + ... + 10^10 = 10405071317.

Find the last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000.

*/

func pow(n, p int) *big.Int {
	constNum := big.NewInt(int64(n))
	result := big.NewInt(1)
	for i := 0; i < p; i++ {
		result.Mul(result, constNum)
	}
	return result
}

func main() {
	result := new(big.Int)
	for i := 1; i <= 1000; i++ {
		result.Add(result, pow(i, i))
	}
	fmt.Println(result.String()[len(result.String())-10:]) //outputs: 9110846700
}
<commit_msg>Ouput change to problem 48<commit_after>package main

import (
	"fmt"
	"math/big"
)

/*

The series, 1^1 + 2^2 + 3^3 + ... + 10^10 = 10405071317.

Find the last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000.

*/

func pow(n, p int) *big.Int {
	constNum := big.NewInt(int64(n))
	result := big.NewInt(1)
	for i := 0; i < p; i++ {
		result.Mul(result, constNum)
	}
	return result
}

func main() {
	result := new(big.Int)
	for i := 1; i <= 1000; i++ {
		result.Add(result, pow(i, i))
	}
	fmt.Printf("Result = %s\n", result.String()[len(result.String())-10:]) //outputs: 9110846700
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"time"

	"github.com/hashicorp/vault/api"
)

const (
	// DefaultVaultGrace is the default grace period before which to read a new
	// secret from Vault. If a lease is due to expire in 15 seconds, Consul
	// Template will read a new secret at that time minus this value.
	DefaultVaultGrace = 15 * time.Second

	// DefaultVaultRenewToken is the default value for if the Vault token should
	// be renewed.
	DefaultVaultRenewToken = true

	// DefaultVaultUnwrapToken is the default value for if the Vault token should
	// be unwrapped.
	DefaultVaultUnwrapToken = false

	// DefaultVaultRetryBase is the default value for the base time to use for
	// exponential backoff.
	DefaultVaultRetryBase = 250 * time.Millisecond

	// DefaultVaultRetryMaxAttempts is the default maximum number of attempts to
	// retry before quitting.
	DefaultVaultRetryMaxAttempts = 5
)

// VaultConfig is the configuration for connecting to a vault server.
type VaultConfig struct {
	// Address is the URI to the Vault server.
	Address *string `mapstructure:"address"`

	// Enabled controls whether the Vault integration is active.
	Enabled *bool `mapstructure:"enabled"`

	// Grace is the amount of time before a lease is about to expire to force a
	// new secret to be read.
	Grace *time.Duration `mapstructure:"grace"`

	// Namespace is the Vault namespace to use for reading/writing secrets. This can
	// also be set via the VAULT_NAMESPACE environment variable.
	Namespace *string `mapstructure:"namespace"`

	// RenewToken renews the Vault token.
	RenewToken *bool `mapstructure:"renew_token"`

	// Retry is the configuration for specifying how to behave on failure.
	Retry *RetryConfig `mapstructure:"retry"`

	// SSL indicates we should use a secure connection while talking to Vault.
	SSL *SSLConfig `mapstructure:"ssl"`

	// Token is the Vault token to communicate with for requests. It may be
	// a wrapped token or a real token. This can also be set via the VAULT_TOKEN
	// environment variable, or via the VaultAgentTokenFile.
	Token *string `mapstructure:"token" json:"-"`

	// VaultAgentTokenFile is the path of file that contains a Vault Agent token.
	// If vault_agent_token_file is specified:
	//   - Consul Template will not try to renew the Vault token.
	//   - Consul Template will periodically stat the file and update the token if it has
	// changed.
	VaultAgentTokenFile *string `mapstructure:"vault_agent_token_file" json:"-"`

	// Transport configures the low-level network connection details.
	Transport *TransportConfig `mapstructure:"transport"`

	// UnwrapToken unwraps the provided Vault token as a wrapped token.
	UnwrapToken *bool `mapstructure:"unwrap_token"`
}

// DefaultVaultConfig returns a configuration that is populated with the
// default values.
func DefaultVaultConfig() *VaultConfig {
	v := &VaultConfig{
		Retry:     DefaultRetryConfig(),
		SSL:       DefaultSSLConfig(),
		Transport: DefaultTransportConfig(),
	}

	// Force SSL when communicating with Vault.
	v.SSL.Enabled = Bool(true)

	return v
}

// Copy returns a deep copy of this configuration.
func (c *VaultConfig) Copy() *VaultConfig {
	if c == nil {
		return nil
	}

	var o VaultConfig
	o.Address = c.Address

	o.Enabled = c.Enabled

	o.Grace = c.Grace

	o.Namespace = c.Namespace

	o.RenewToken = c.RenewToken

	if c.Retry != nil {
		o.Retry = c.Retry.Copy()
	}

	if c.SSL != nil {
		o.SSL = c.SSL.Copy()
	}

	o.Token = c.Token

	o.VaultAgentTokenFile = c.VaultAgentTokenFile

	if c.Transport != nil {
		o.Transport = c.Transport.Copy()
	}

	o.UnwrapToken = c.UnwrapToken

	return &o
}

// Merge combines all values in this configuration with the values in the other
// configuration, with values in the other configuration taking precedence.
// Maps and slices are merged, most other values are overwritten. Complex
// structs define their own merge functionality.
func (c *VaultConfig) Merge(o *VaultConfig) *VaultConfig {
	if c == nil {
		if o == nil {
			return nil
		}
		return o.Copy()
	}

	if o == nil {
		return c.Copy()
	}

	r := c.Copy()

	if o.Address != nil {
		r.Address = o.Address
	}

	if o.Enabled != nil {
		r.Enabled = o.Enabled
	}

	if o.Grace != nil {
		r.Grace = o.Grace
	}

	if o.Namespace != nil {
		r.Namespace = o.Namespace
	}

	if o.RenewToken != nil {
		r.RenewToken = o.RenewToken
	}

	if o.Retry != nil {
		r.Retry = r.Retry.Merge(o.Retry)
	}

	if o.SSL != nil {
		r.SSL = r.SSL.Merge(o.SSL)
	}

	if o.Token != nil {
		r.Token = o.Token
	}

	if o.VaultAgentTokenFile != nil {
		r.VaultAgentTokenFile = o.VaultAgentTokenFile
	}

	if o.Transport != nil {
		r.Transport = r.Transport.Merge(o.Transport)
	}

	if o.UnwrapToken != nil {
		r.UnwrapToken = o.UnwrapToken
	}

	return r
}

// Finalize ensures there no nil pointers.
func (c *VaultConfig) Finalize() {
	if c.Address == nil {
		c.Address = stringFromEnv([]string{
			api.EnvVaultAddress,
		}, "")
	}

	if c.Grace == nil {
		c.Grace = TimeDuration(DefaultVaultGrace)
	}

	if c.Namespace == nil {
		c.Namespace = stringFromEnv([]string{"VAULT_NAMESPACE"}, "")
	}

	if c.RenewToken == nil {
		c.RenewToken = boolFromEnv([]string{
			"VAULT_RENEW_TOKEN",
		}, DefaultVaultRenewToken)
	}

	if c.Retry == nil {
		c.Retry = DefaultRetryConfig()
	}
	c.Retry.Finalize()

	// Vault has custom SSL settings
	if c.SSL == nil {
		c.SSL = DefaultSSLConfig()
	}
	if c.SSL.Enabled == nil {
		c.SSL.Enabled = Bool(true)
	}
	if c.SSL.CaCert == nil {
		c.SSL.CaCert = stringFromEnv([]string{api.EnvVaultCACert}, "")
	}
	if c.SSL.CaPath == nil {
		c.SSL.CaPath = stringFromEnv([]string{api.EnvVaultCAPath}, "")
	}
	if c.SSL.Cert == nil {
		c.SSL.Cert = stringFromEnv([]string{api.EnvVaultClientCert}, "")
	}
	if c.SSL.Key == nil {
		c.SSL.Key = stringFromEnv([]string{api.EnvVaultClientKey}, "")
	}
	if c.SSL.ServerName == nil {
		c.SSL.ServerName = stringFromEnv([]string{api.EnvVaultTLSServerName}, "")
	}
	if c.SSL.Verify == nil {
		c.SSL.Verify = antiboolFromEnv([]string{api.EnvVaultInsecure}, true)
	}
	c.SSL.Finalize()

	// Order of precedence
	// 1. `vault_agent_token_file` configuration value
	// 2. `token` configuration value`
	// 3. `VAULT_TOKEN` environment variable
	if c.Token == nil {
		c.Token = stringFromEnv([]string{
			"VAULT_TOKEN",
		}, "")
	}

	if c.VaultAgentTokenFile != nil {
		c.Token = stringFromFile([]string{*c.VaultAgentTokenFile}, "")
		c.RenewToken = Bool(false)
	}

	if c.Transport == nil {
		c.Transport = DefaultTransportConfig()
	}
	c.Transport.Finalize()

	if c.UnwrapToken == nil {
		c.UnwrapToken = boolFromEnv([]string{
			"VAULT_UNWRAP_TOKEN",
		}, DefaultVaultUnwrapToken)
	}

	if c.Enabled == nil {
		c.Enabled = Bool(StringPresent(c.Address))
	}
}

// GoString defines the printable version of this struct.
func (c *VaultConfig) GoString() string {
	if c == nil {
		return "(*VaultConfig)(nil)"
	}

	return fmt.Sprintf("&VaultConfig{"+
		"Address:%s, "+
		"Enabled:%s, "+
		"Grace:%s, "+
		"Namespace:%s,"+
		"RenewToken:%s, "+
		"Retry:%#v, "+
		"SSL:%#v, "+
		"Token:%t, "+
		"VaultAgentTokenFile:%t, "+
		"Transport:%#v, "+
		"UnwrapToken:%s"+
		"}",
		StringGoString(c.Address),
		BoolGoString(c.Enabled),
		TimeDurationGoString(c.Grace),
		StringGoString(c.Namespace),
		BoolGoString(c.RenewToken),
		c.Retry,
		c.SSL,
		StringPresent(c.Token),
		StringPresent(c.VaultAgentTokenFile),
		c.Transport,
		BoolGoString(c.UnwrapToken),
	)
}
<commit_msg>fix: by default, if a token is found in Vaults /.vault-token, use this and renew when necessary<commit_after>package config

import (
	"fmt"
	"time"

	"github.com/hashicorp/vault/api"
)

const (
	// DefaultVaultGrace is the default grace period before which to read a new
	// secret from Vault. If a lease is due to expire in 15 seconds, Consul
	// Template will read a new secret at that time minus this value.
	DefaultVaultGrace = 15 * time.Second

	// DefaultVaultRenewToken is the default value for if the Vault token should
	// be renewed.
	DefaultVaultRenewToken = true

	// DefaultVaultUnwrapToken is the default value for if the Vault token should
	// be unwrapped.
	DefaultVaultUnwrapToken = false

	// DefaultVaultRetryBase is the default value for the base time to use for
	// exponential backoff.
	DefaultVaultRetryBase = 250 * time.Millisecond

	// DefaultVaultRetryMaxAttempts is the default maximum number of attempts to
	// retry before quitting.
	DefaultVaultRetryMaxAttempts = 5
)

// VaultConfig is the configuration for connecting to a vault server.
type VaultConfig struct {
	// Address is the URI to the Vault server.
	Address *string `mapstructure:"address"`

	// Enabled controls whether the Vault integration is active.
	Enabled *bool `mapstructure:"enabled"`

	// Grace is the amount of time before a lease is about to expire to force a
	// new secret to be read.
	Grace *time.Duration `mapstructure:"grace"`

	// Namespace is the Vault namespace to use for reading/writing secrets. This can
	// also be set via the VAULT_NAMESPACE environment variable.
	Namespace *string `mapstructure:"namespace"`

	// RenewToken renews the Vault token.
	RenewToken *bool `mapstructure:"renew_token"`

	// Retry is the configuration for specifying how to behave on failure.
	Retry *RetryConfig `mapstructure:"retry"`

	// SSL indicates we should use a secure connection while talking to Vault.
	SSL *SSLConfig `mapstructure:"ssl"`

	// Token is the Vault token to communicate with for requests. It may be
	// a wrapped token or a real token. This can also be set via the VAULT_TOKEN
	// environment variable, or via the VaultAgentTokenFile.
	Token *string `mapstructure:"token" json:"-"`

	// VaultAgentTokenFile is the path of file that contains a Vault Agent token.
	// If vault_agent_token_file is specified:
	//   - Consul Template will not try to renew the Vault token.
	//   - Consul Template will periodically stat the file and update the token if it has
	// changed.
	VaultAgentTokenFile *string `mapstructure:"vault_agent_token_file" json:"-"`

	// Transport configures the low-level network connection details.
	Transport *TransportConfig `mapstructure:"transport"`

	// UnwrapToken unwraps the provided Vault token as a wrapped token.
	UnwrapToken *bool `mapstructure:"unwrap_token"`
}

// DefaultVaultConfig returns a configuration that is populated with the
// default values.
func DefaultVaultConfig() *VaultConfig {
	v := &VaultConfig{
		Retry:     DefaultRetryConfig(),
		SSL:       DefaultSSLConfig(),
		Transport: DefaultTransportConfig(),
	}

	// Force SSL when communicating with Vault.
	v.SSL.Enabled = Bool(true)

	return v
}

// Copy returns a deep copy of this configuration.
func (c *VaultConfig) Copy() *VaultConfig {
	if c == nil {
		return nil
	}

	var o VaultConfig
	o.Address = c.Address

	o.Enabled = c.Enabled

	o.Grace = c.Grace

	o.Namespace = c.Namespace

	o.RenewToken = c.RenewToken

	if c.Retry != nil {
		o.Retry = c.Retry.Copy()
	}

	if c.SSL != nil {
		o.SSL = c.SSL.Copy()
	}

	o.Token = c.Token

	o.VaultAgentTokenFile = c.VaultAgentTokenFile

	if c.Transport != nil {
		o.Transport = c.Transport.Copy()
	}

	o.UnwrapToken = c.UnwrapToken

	return &o
}

// Merge combines all values in this configuration with the values in the other
// configuration, with values in the other configuration taking precedence.
// Maps and slices are merged, most other values are overwritten. Complex
// structs define their own merge functionality.
func (c *VaultConfig) Merge(o *VaultConfig) *VaultConfig {
	if c == nil {
		if o == nil {
			return nil
		}
		return o.Copy()
	}

	if o == nil {
		return c.Copy()
	}

	r := c.Copy()

	if o.Address != nil {
		r.Address = o.Address
	}

	if o.Enabled != nil {
		r.Enabled = o.Enabled
	}

	if o.Grace != nil {
		r.Grace = o.Grace
	}

	if o.Namespace != nil {
		r.Namespace = o.Namespace
	}

	if o.RenewToken != nil {
		r.RenewToken = o.RenewToken
	}

	if o.Retry != nil {
		r.Retry = r.Retry.Merge(o.Retry)
	}

	if o.SSL != nil {
		r.SSL = r.SSL.Merge(o.SSL)
	}

	if o.Token != nil {
		r.Token = o.Token
	}

	if o.VaultAgentTokenFile != nil {
		r.VaultAgentTokenFile = o.VaultAgentTokenFile
	}

	if o.Transport != nil {
		r.Transport = r.Transport.Merge(o.Transport)
	}

	if o.UnwrapToken != nil {
		r.UnwrapToken = o.UnwrapToken
	}

	return r
}

// Finalize ensures there no nil pointers.
func (c *VaultConfig) Finalize() {
	if c.Address == nil {
		c.Address = stringFromEnv([]string{
			api.EnvVaultAddress,
		}, "")
	}

	if c.Grace == nil {
		c.Grace = TimeDuration(DefaultVaultGrace)
	}

	if c.Namespace == nil {
		c.Namespace = stringFromEnv([]string{"VAULT_NAMESPACE"}, "")
	}

	if c.RenewToken == nil {
		c.RenewToken = boolFromEnv([]string{
			"VAULT_RENEW_TOKEN",
		}, DefaultVaultRenewToken)
	}

	if c.Retry == nil {
		c.Retry = DefaultRetryConfig()
	}
	c.Retry.Finalize()

	// Vault has custom SSL settings
	if c.SSL == nil {
		c.SSL = DefaultSSLConfig()
	}
	if c.SSL.Enabled == nil {
		c.SSL.Enabled = Bool(true)
	}
	if c.SSL.CaCert == nil {
		c.SSL.CaCert = stringFromEnv([]string{api.EnvVaultCACert}, "")
	}
	if c.SSL.CaPath == nil {
		c.SSL.CaPath = stringFromEnv([]string{api.EnvVaultCAPath}, "")
	}
	if c.SSL.Cert == nil {
		c.SSL.Cert = stringFromEnv([]string{api.EnvVaultClientCert}, "")
	}
	if c.SSL.Key == nil {
		c.SSL.Key = stringFromEnv([]string{api.EnvVaultClientKey}, "")
	}
	if c.SSL.ServerName == nil {
		c.SSL.ServerName = stringFromEnv([]string{api.EnvVaultTLSServerName}, "")
	}
	if c.SSL.Verify == nil {
		c.SSL.Verify = antiboolFromEnv([]string{api.EnvVaultInsecure}, true)
	}
	c.SSL.Finalize()

	// Order of precedence
	// 1. `vault_agent_token_file` configuration value
	// 2. `token` configuration value`
	// 3. `VAULT_TOKEN` environment variable
	if c.Token == nil {
		c.Token = stringFromEnv([]string{
			"VAULT_TOKEN",
		}, "")
	}

	if c.VaultAgentTokenFile == nil {
		if StringVal(c.Token) == "" {
			if homePath != "" {
				c.Token = stringFromFile([]string{
					homePath + "/.vault-token",
				}, "")
			}
		}
	} else {
		c.Token = stringFromFile([]string{*c.VaultAgentTokenFile}, "")
		c.RenewToken = Bool(false)
	}

	if c.Transport == nil {
		c.Transport = DefaultTransportConfig()
	}
	c.Transport.Finalize()

	if c.UnwrapToken == nil {
		c.UnwrapToken = boolFromEnv([]string{
			"VAULT_UNWRAP_TOKEN",
		}, DefaultVaultUnwrapToken)
	}

	if c.Enabled == nil {
		c.Enabled = Bool(StringPresent(c.Address))
	}
}

// GoString defines the printable version of this struct.
func (c *VaultConfig) GoString() string {
	if c == nil {
		return "(*VaultConfig)(nil)"
	}

	return fmt.Sprintf("&VaultConfig{"+
		"Address:%s, "+
		"Enabled:%s, "+
		"Grace:%s, "+
		"Namespace:%s,"+
		"RenewToken:%s, "+
		"Retry:%#v, "+
		"SSL:%#v, "+
		"Token:%t, "+
		"VaultAgentTokenFile:%t, "+
		"Transport:%#v, "+
		"UnwrapToken:%s"+
		"}",
		StringGoString(c.Address),
		BoolGoString(c.Enabled),
		TimeDurationGoString(c.Grace),
		StringGoString(c.Namespace),
		BoolGoString(c.RenewToken),
		c.Retry,
		c.SSL,
		StringPresent(c.Token),
		StringPresent(c.VaultAgentTokenFile),
		c.Transport,
		BoolGoString(c.UnwrapToken),
	)
}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// 一个简单的Go语言热编译工具
package main

import (
	"flag"
	"fmt"
	"github.com/issue9/term/colors"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"gopkg.in/fsnotify.v1"
)

// 当前程序的版本号
const version = "0.1.1.150605"

const usage = `gobuild 用于热编译Go程序。

用法:
 gobuild [options] [dependents]

 options:
  -h 显示当前帮助信息；
  -v 显示gobuild和go程序的版本信息；
  -o 执行编译后的可执行文件名。
  -main 指定需要编译的文件，默认为""。

 dependents
  指定其它依赖的目录，只能出现在命令的尾部。

常见用法:

 - gobuild
   监视当前目录，若有变动，则重新编译当前目录下的*.go文件；

 - gobuild -main=main.go
   监视当前目录，若有变动，则重新编译当前目录下的main.go文件；

 - gobuild dir1 dir2
   监视当前目录及dir1和dir2，若有变动，则重新编译当前目录下的*.go文件；
`

var (
	showHelp    = false
	showVersion = false
	mainFiles   = ""
	outputName  = ""

	watcher *fsnotify.Watcher

	wd string // 当前工作目录

	// outputName的命令
	cmd *exec.Cmd
)

func init() {
	// 基本环境检测
	gopath := os.Getenv("GOPATH")
	if len(gopath) == 0 {
		log(erro, "未设置环境变量GOPATH")
		os.Exit(2)
	}

	// 获取所有被监视的路径
	var err error
	wd, err = os.Getwd()
	if err != nil {
		log(erro, "获取当前工作目录时，发生以下错误:", err)
		os.Exit(2)
	}

	// 初始化flag相关设置
	flag.BoolVar(&showHelp, "h", false, "显示帮助信息")
	flag.BoolVar(&showVersion, "v", false, "显示版本号")
	flag.StringVar(&outputName, "o", "", "指定输出名称")
	flag.StringVar(&mainFiles, "main", "", "指定需要编译的文件")

	flag.Usage = func() {
		fmt.Println(usage)
	}

	// 初始化监视器
	if watcher, err = fsnotify.NewWatcher(); err != nil {
		log(erro, err)
	}
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log(info, "watcher:", event)
				autoBuild()
			case err := <-watcher.Errors:
				log(erro, err)
			}
		}
	}()
}

func main() {
	flag.Parse()

	if showHelp {
		flag.Usage()
		return
	}

	if showVersion {
		colors.Print(colors.Stdout, colors.Green, colors.Default, "gobuild: ")
		colors.Println(colors.Stdout, colors.Default, colors.Default, version)

		colors.Print(colors.Stdout, colors.Green, colors.Default, "Go: ")
		goVersion := runtime.Version() + " " + runtime.GOOS + "/" + runtime.GOARCH
		colors.Println(colors.Stdout, colors.Default, colors.Default, goVersion)

		return
	}

	// 确定编译后的文件名
	if len(outputName) == 0 {
		outputName = filepath.Base(wd)
	}
	if strings.IndexByte(outputName, '/') < 0 || strings.IndexByte(outputName, filepath.Separator) < 0 {
		outputName = wd + string(filepath.Separator) + outputName
	}
	if runtime.GOOS == "windows" {
		outputName += ".exe"
	}
	cmd = exec.Command(outputName)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	// 将可执行文件从监视器中删除
	if err := watcher.Remove(outputName); err != nil {
		log(erro, err)
		os.Exit(2)
	}

	// 监视的路径，必定包含当前工作目录
	paths := append(flag.Args(), wd)
	log(info, "初始化监视器...")
	log(info, "以下路径或是文件将被监视:", paths)
	for _, path := range paths {
		if err := watcher.Add(path); err != nil {
			log(erro, err)
			os.Exit(2)
		}
	}

	autoBuild()
	//watcher.Close()
}

func autoBuild() {
	log(info, "编译代码...")

	args := []string{"build"}
	if len(mainFiles) > 0 {
		args = append(args, mainFiles)
	}

	cmd := exec.Command("go", args...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	if err := cmd.Run(); err != nil {
		log(erro, "编译失败:", err)
		return
	}

	log(succ, "编译成功!")
	restart()
}

func kill() {
	log(info, "中止旧进程...")
	defer func() {
		if err := recover(); err != nil {
			log(erro, err)
		}
	}()

	if cmd != nil && cmd.Process != nil {
		if err := cmd.Process.Kill(); err != nil {
			log(erro, err)
		}
	}
}

func restart() {
	log(info, "重启进程...")

	kill()

	if err := cmd.Run(); err != nil {
		log(erro, err)
	}
}
<commit_msg>在编译成功之后，移除对被编译文件的监视<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// 一个简单的Go语言热编译工具
package main

import (
	"flag"
	"fmt"
	"github.com/issue9/term/colors"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"gopkg.in/fsnotify.v1"
)

// 当前程序的版本号
const version = "0.1.1.150605"

const usage = `gobuild 用于热编译Go程序。

用法:
 gobuild [options] [dependents]

 options:
  -h 显示当前帮助信息；
  -v 显示gobuild和go程序的版本信息；
  -o 执行编译后的可执行文件名。
  -main 指定需要编译的文件，默认为""。

 dependents
  指定其它依赖的目录，只能出现在命令的尾部。

常见用法:

 - gobuild
   监视当前目录，若有变动，则重新编译当前目录下的*.go文件；

 - gobuild -main=main.go
   监视当前目录，若有变动，则重新编译当前目录下的main.go文件；

 - gobuild dir1 dir2
   监视当前目录及dir1和dir2，若有变动，则重新编译当前目录下的*.go文件；
`

var (
	showHelp    = false
	showVersion = false
	mainFiles   = ""
	outputName  = ""

	watcher *fsnotify.Watcher

	wd string // 当前工作目录

	// outputName的命令
	cmd *exec.Cmd
)

func init() {
	// 基本环境检测
	gopath := os.Getenv("GOPATH")
	if len(gopath) == 0 {
		log(erro, "未设置环境变量GOPATH")
		os.Exit(2)
	}

	// 获取所有被监视的路径
	var err error
	wd, err = os.Getwd()
	if err != nil {
		log(erro, "获取当前工作目录时，发生以下错误:", err)
		os.Exit(2)
	}

	// 初始化flag相关设置
	flag.BoolVar(&showHelp, "h", false, "显示帮助信息")
	flag.BoolVar(&showVersion, "v", false, "显示版本号")
	flag.StringVar(&outputName, "o", "", "指定输出名称")
	flag.StringVar(&mainFiles, "main", "", "指定需要编译的文件")

	flag.Usage = func() {
		fmt.Println(usage)
	}

	// 初始化监视器
	if watcher, err = fsnotify.NewWatcher(); err != nil {
		log(erro, err)
	}
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log(info, "watcher:", event)
				autoBuild()
			case err := <-watcher.Errors:
				log(erro, err)
			}
		}
	}()
}

func main() {
	flag.Parse()

	if showHelp {
		flag.Usage()
		return
	}

	if showVersion {
		colors.Print(colors.Stdout, colors.Green, colors.Default, "gobuild: ")
		colors.Println(colors.Stdout, colors.Default, colors.Default, version)

		colors.Print(colors.Stdout, colors.Green, colors.Default, "Go: ")
		goVersion := runtime.Version() + " " + runtime.GOOS + "/" + runtime.GOARCH
		colors.Println(colors.Stdout, colors.Default, colors.Default, goVersion)

		return
	}

	// 确定编译后的文件名
	if len(outputName) == 0 {
		outputName = filepath.Base(wd)
	}
	if strings.IndexByte(outputName, '/') < 0 || strings.IndexByte(outputName, filepath.Separator) < 0 {
		outputName = wd + string(filepath.Separator) + outputName
	}
	if runtime.GOOS == "windows" {
		outputName += ".exe"
	}
	cmd = exec.Command(outputName)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	// 监视的路径，必定包含当前工作目录
	paths := append(flag.Args(), wd)
	log(info, "初始化监视器...")
	log(info, "以下路径或是文件将被监视:", paths)
	for _, path := range paths {
		if err := watcher.Add(path); err != nil {
			log(erro, err)
			os.Exit(2)
		}
	}

	autoBuild()
	//watcher.Close()
}

func autoBuild() {
	log(info, "编译代码...")

	args := []string{"build", "-o", outputName}
	if len(mainFiles) > 0 {
		args = append(args, mainFiles)
	}

	cmd := exec.Command("go", args...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	if err := cmd.Run(); err != nil {
		log(erro, "编译失败:", err)
		return
	}

	log(succ, "编译成功!")

	// 将可执行文件从监视器中删除
	if err := watcher.Remove(outputName); err != nil {
		log(erro, err)
		os.Exit(2)
	}

	restart()
}

func kill() {
	log(info, "中止旧进程...")
	defer func() {
		if err := recover(); err != nil {
			log(erro, err)
		}
	}()

	if cmd != nil && cmd.Process != nil {
		if err := cmd.Process.Kill(); err != nil {
			log(erro, err)
		}
	}
}

func restart() {
	log(info, "重启进程...")

	kill()

	if err := cmd.Run(); err != nil {
		log(erro, err)
	}
}
<|endoftext|>


<commit_before>package djangobot

import "testing"

func TestLogin(t *testing.T) {

	// Before running this test, make sure to set your username and password below.

	// Disqus
	bot := With("https://disqus.com/profile/login/").
		ForHost("disqus.com").
		SetUsername("").
		SetPassword("")

	if bot.Error != nil {
		panic(bot.Error)
	}

	_, err := bot.LoadCookies().
		Set("next", "https://disqus.com/"). // Set the next parameter
		X("csrfmiddlewaretoken", bot.Cookie("csrftoken").Value).
		X("username", bot.Username).
		X("password", bot.Password).
		Login()

	if err != nil {
		panic(err)
	}

	 sessionid := bot.Cookie("sessionid").Value
	 if sessionid == "" {
	 	t.Error("Authentication failed.")
	 }

	 t.Log(sessionid)

}
<commit_msg>Test password change feature.<commit_after>package djangobot

import (
	"testing"
)

func TestLogin(t *testing.T) {

	// Before running this test, make sure to set your username and password below.

	username := ""
	password := ""

	if username == "" && password == "" {
		t.Log("Cannot execute test. Please supply username and password.")
		return
	}

	// Disqus
	bot := With("https://disqus.com/profile/login/").
		ForHost("disqus.com").
		SetUsername(username).
		SetPassword(password)

	if bot.Error != nil {
		panic(bot.Error)
	}

	_, err := bot.LoadCookies().
		Set("next", "https://disqus.com/"). // Set the next parameter
		X("csrfmiddlewaretoken", bot.Cookie("csrftoken").Value).
		X("username", bot.Username).
		X("password", bot.Password).
		Login()

	if err != nil {
		panic(err)
	}

	sessionid := bot.Cookie("sessionid").Value
	if sessionid == "" {
		t.Error("Authentication failed.")
		return
	}

	t.Log("Authenticated with session id: ", sessionid)

	// Add details to the form data
	data := map[string]string{}

	//data := map[string]string{
	//	"email":        "",
	//	"old_password": "",
	//	"password":     "",
	//	"username":     "",
	//}

	if len(data) == 0 {
		t.Log("Cannot change password. Form data empty.")
		return
	}

	_, body, _ := bot.Requester("PUT", "https://disqus.com/users/self/account/").
		Client.
		Send(data).
		End()

	t.Log(body)

}
<|endoftext|>