<commit_before>package golog

import "testing"

func TestFacts (t *testing.T) {
    m := NewMachine().Consult(`
        father(michael).
        father(marc).

        mother(gail).

        parent(X) :-
            father(X).
        parent(X) :-
            mother(X).
    `)
    t.Logf("%s\n", m.String())

    // these should be provably true
    if !m.CanProve(`father(michael).`) {
        t.Errorf("Couldn't prove father(michael)")
    }
    if !m.CanProve(`father(marc).`) {
        t.Errorf("Couldn't prove father(marc)")
    }
    if !m.CanProve(`parent(michael).`) {
        t.Errorf("Couldn't prove parent(michael)")
    }
    if !m.CanProve(`parent(marc).`) {
        t.Errorf("Couldn't prove parent(marc)")
    }

    // these should not be provable
    if m.CanProve(`father(sue).`) {
        t.Errorf("Proved father(sue)")
    }
    if m.CanProve(`father(michael,marc).`) {
        t.Errorf("Proved father(michael, marc)")
    }
    if m.CanProve(`mother(michael).`) {
        t.Errorf("Proved mother(michael)")
    }
    if m.CanProve(`parent(sue).`) {
        t.Errorf("Proved parent(sue)")
    }

    // trivial predicate with multiple solutions
    solutions := m.ProveAll(`father(X).`)
    if len(solutions) != 2 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(solutions))
    }
    if x := solutions[0].ByName_("X").String(); x != "michael" {
        t.Errorf("Wrong first solution: %s", x)
    }
    if x := solutions[1].ByName_("X").String(); x != "marc" {
        t.Errorf("Wrong second solution: %s", x)
    }

    // simple predicate with multiple solutions
    solutions = m.ProveAll(`parent(Name).`)
    if len(solutions) != 3 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(solutions))
    }
    if x := solutions[0].ByName_("Name").String(); x != "michael" {
        t.Errorf("Wrong first solution: %s", x)
    }
    if x := solutions[1].ByName_("Name").String(); x != "marc" {
        t.Errorf("Wrong second solution: %s", x)
    }
    if x := solutions[2].ByName_("Name").String(); x != "gail" {
        t.Errorf("Wrong third solution: %s", x)
    }
}

func TestConjunction(t *testing.T) {
    m := NewMachine().Consult(`
        floor_wax(briwax).
        floor_wax(shimmer).
        floor_wax(minwax).

        dessert(shimmer).
        dessert(cake).
        dessert(pie).

        verb(glimmer).
        verb(shimmer).

        snl(Item) :-
            floor_wax(Item),
            dessert(Item).

        three(Item) :-
            verb(Item),
            dessert(Item),
            floor_wax(Item).
    `)

    skits := m.ProveAll(`snl(X).`)
    if len(skits) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(skits))
    }
    if x := skits[0].ByName_("X").String(); x != "shimmer" {
        t.Errorf("Wrong solution: %s vs shimmer", x)
    }

    skits = m.ProveAll(`three(W).`)
    if len(skits) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(skits))
    }
    if x := skits[0].ByName_("W").String(); x != "shimmer" {
        t.Errorf("Wrong solution: %s vs shimmer", x)
    }
}

func TestCut(t *testing.T) {
    m := NewMachine().Consult(`
        single(foo) :-
            !.
        single(bar).

        twice(X) :-
            single(X).  % cut inside here doesn't cut twice/1
        twice(bar).
    `)

    proofs := m.ProveAll(`single(X).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("X").String(); x != "foo" {
        t.Errorf("Wrong solution: %s vs foo", x)
    }

    proofs = m.ProveAll(`twice(X).`)
    if len(proofs) != 2 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(proofs))
    }
    if x := proofs[0].ByName_("X").String(); x != "foo" {
        t.Errorf("Wrong solution: %s vs foo", x)
    }
    if x := proofs[1].ByName_("X").String(); x != "bar" {
        t.Errorf("Wrong solution: %s vs bar", x)
    }
}

func TestAppend(t *testing.T) {
    m := NewMachine().Consult(`
        append([], A, A).   % test same variable name as other clauses
        append([A|B], C, [A|D]) :-
            append(B, C, D).
    `)

    proofs := m.ProveAll(`append([a], [b], List).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of answers: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("List").String(); x != "'.'(a, '.'(b, []))" {
        t.Errorf("Wrong solution: %s vs '.'(a, '.'(b, []))", x)
    }

    proofs = m.ProveAll(`append([a,b,c], [d,e], List).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of answers: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("List").String(); x != "'.'(a, '.'(b, '.'(c, '.'(d, '.'(e, [])))))" {
        t.Errorf("Wrong solution: %s", x)
    }
}
<commit_msg>Implement a couple benchmarks<commit_after>package golog

import "testing"

func TestFacts (t *testing.T) {
    m := NewMachine().Consult(`
        father(michael).
        father(marc).

        mother(gail).

        parent(X) :-
            father(X).
        parent(X) :-
            mother(X).
    `)
    t.Logf("%s\n", m.String())

    // these should be provably true
    if !m.CanProve(`father(michael).`) {
        t.Errorf("Couldn't prove father(michael)")
    }
    if !m.CanProve(`father(marc).`) {
        t.Errorf("Couldn't prove father(marc)")
    }
    if !m.CanProve(`parent(michael).`) {
        t.Errorf("Couldn't prove parent(michael)")
    }
    if !m.CanProve(`parent(marc).`) {
        t.Errorf("Couldn't prove parent(marc)")
    }

    // these should not be provable
    if m.CanProve(`father(sue).`) {
        t.Errorf("Proved father(sue)")
    }
    if m.CanProve(`father(michael,marc).`) {
        t.Errorf("Proved father(michael, marc)")
    }
    if m.CanProve(`mother(michael).`) {
        t.Errorf("Proved mother(michael)")
    }
    if m.CanProve(`parent(sue).`) {
        t.Errorf("Proved parent(sue)")
    }

    // trivial predicate with multiple solutions
    solutions := m.ProveAll(`father(X).`)
    if len(solutions) != 2 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(solutions))
    }
    if x := solutions[0].ByName_("X").String(); x != "michael" {
        t.Errorf("Wrong first solution: %s", x)
    }
    if x := solutions[1].ByName_("X").String(); x != "marc" {
        t.Errorf("Wrong second solution: %s", x)
    }

    // simple predicate with multiple solutions
    solutions = m.ProveAll(`parent(Name).`)
    if len(solutions) != 3 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(solutions))
    }
    if x := solutions[0].ByName_("Name").String(); x != "michael" {
        t.Errorf("Wrong first solution: %s", x)
    }
    if x := solutions[1].ByName_("Name").String(); x != "marc" {
        t.Errorf("Wrong second solution: %s", x)
    }
    if x := solutions[2].ByName_("Name").String(); x != "gail" {
        t.Errorf("Wrong third solution: %s", x)
    }
}

func TestConjunction(t *testing.T) {
    m := NewMachine().Consult(`
        floor_wax(briwax).
        floor_wax(shimmer).
        floor_wax(minwax).

        dessert(shimmer).
        dessert(cake).
        dessert(pie).

        verb(glimmer).
        verb(shimmer).

        snl(Item) :-
            floor_wax(Item),
            dessert(Item).

        three(Item) :-
            verb(Item),
            dessert(Item),
            floor_wax(Item).
    `)

    skits := m.ProveAll(`snl(X).`)
    if len(skits) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(skits))
    }
    if x := skits[0].ByName_("X").String(); x != "shimmer" {
        t.Errorf("Wrong solution: %s vs shimmer", x)
    }

    skits = m.ProveAll(`three(W).`)
    if len(skits) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(skits))
    }
    if x := skits[0].ByName_("W").String(); x != "shimmer" {
        t.Errorf("Wrong solution: %s vs shimmer", x)
    }
}

func TestCut(t *testing.T) {
    m := NewMachine().Consult(`
        single(foo) :-
            !.
        single(bar).

        twice(X) :-
            single(X).  % cut inside here doesn't cut twice/1
        twice(bar).
    `)

    proofs := m.ProveAll(`single(X).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of solutions: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("X").String(); x != "foo" {
        t.Errorf("Wrong solution: %s vs foo", x)
    }

    proofs = m.ProveAll(`twice(X).`)
    if len(proofs) != 2 {
        t.Errorf("Wrong number of solutions: %d vs 2", len(proofs))
    }
    if x := proofs[0].ByName_("X").String(); x != "foo" {
        t.Errorf("Wrong solution: %s vs foo", x)
    }
    if x := proofs[1].ByName_("X").String(); x != "bar" {
        t.Errorf("Wrong solution: %s vs bar", x)
    }
}

func TestAppend(t *testing.T) {
    m := NewMachine().Consult(`
        append([], A, A).   % test same variable name as other clauses
        append([A|B], C, [A|D]) :-
            append(B, C, D).
    `)

    proofs := m.ProveAll(`append([a], [b], List).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of answers: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("List").String(); x != "'.'(a, '.'(b, []))" {
        t.Errorf("Wrong solution: %s vs '.'(a, '.'(b, []))", x)
    }

    proofs = m.ProveAll(`append([a,b,c], [d,e], List).`)
    if len(proofs) != 1 {
        t.Errorf("Wrong number of answers: %d vs 1", len(proofs))
    }
    if x := proofs[0].ByName_("List").String(); x != "'.'(a, '.'(b, '.'(c, '.'(d, '.'(e, [])))))" {
        t.Errorf("Wrong solution: %s", x)
    }
}

func BenchmarkTrue(b *testing.B) {
    m := NewMachine()
    for i := 0; i < b.N; i++ {
        _ = m.ProveAll(`true.`)
    }
}

func BenchmarkAppend(b *testing.B) {
    m := NewMachine().Consult(`
        append([], A, A).   % test same variable name as other clauses
        append([A|B], C, [A|D]) :-
            append(B, C, D).
    `)

    for i := 0; i < b.N; i++ {
        _ = m.ProveAll(`append([a,b,c], [d,e], List).`)
    }
}
<|endoftext|>


<commit_before>package keg

import (
	"time"
	"net"
	"bytes"
	"encoding/binary"
	. "github.com/AspenWare/ardrinko-server/config"
)

type KegStatus struct {
	Temperature float32
	CurrentFlow int32
	Capacity uint32
	Available uint32
	LastUpdate time.Time
	Connection* net.UDPConn
}

func Initialize(config *Config) (KegStatus, error) {
	status := KegStatus {}
	socket, err := net.ListenUDP("udp4", &net.UDPAddr {
		IP: net.ParseIP(config.UDP.Endpoint),
		Port: config.UDP.Port,
	})
	if err != nil {
		return status, err
	}
	status.Connection = socket
	return status, nil
}

func Monitor(status *KegStatus, eventPipe chan int) {
	buffer := make([]byte, 512)
	for {
		length, _, err := status.Connection.ReadFromUDP(buffer[:])
		if err != nil {
			return // Drop packet
		}
		reader := bytes.NewReader(buffer[:length])
		var temp int32
		err = binary.Read(reader, binary.LittleEndian, &temp)
		status.Temperature = float32(temp) / 100
		if err != nil {
			return // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.CurrentFlow)
		if err != nil {
			return // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.Capacity)
		if err != nil {
			return // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.Available)
		if err != nil {
			return // Drop packet
		}
		status.LastUpdate = time.Now()
		eventPipe <- 1
	}
}
<commit_msg>Log temp data over UDP<commit_after>package keg

import (
	"time"
	"net"
	"bytes"
	"encoding/binary"
	. "github.com/AspenWare/ardrinko-server/config"
)

type KegStatus struct {
	Temperature float32
	CurrentFlow int32
	Capacity uint32
	Available uint32
	LastUpdate time.Time
	Connection* net.UDPConn
}

func Initialize(config *Config) (KegStatus, error) {
	status := KegStatus {}
	socket, err := net.ListenUDP("udp4", &net.UDPAddr {
		IP: net.ParseIP(config.UDP.Endpoint),
		Port: config.UDP.Port,
	})
	if err != nil {
		return status, err
	}
	status.Connection = socket
	return status, nil
}

func Monitor(status *KegStatus, eventPipe chan int) {
	buffer := make([]byte, 512)
	for {
		length, _, err := status.Connection.ReadFromUDP(buffer[:])
		if err != nil {
			return // Drop packet
		}
		reader := bytes.NewReader(buffer[:length])
		var temp int32
		err = binary.Read(reader, binary.LittleEndian, &temp)
		status.Temperature = float32(temp) / 100
		if err != nil {
			continue // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.CurrentFlow)
		if err != nil {
			continue // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.Capacity)
		if err != nil {
			continue // Drop packet
		}
		err = binary.Read(reader, binary.LittleEndian, &status.Available)
		if err != nil {
			continue // Drop packet
		}
		status.LastUpdate = time.Now()
		eventPipe <- 1
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"testing"

	"github.com/exercism/cli/config"
	"github.com/stretchr/testify/assert"
)

type testCase struct {
	desc           string
	args           []string
	existingUsrCfg *config.UserConfig
	expectedUsrCfg *config.UserConfig
	existingAPICfg *config.APIConfig
	expectedAPICfg *config.APIConfig
}

func TestConfigure(t *testing.T) {
	testCases := []testCase{
		testCase{
			desc:           "It writes the flags when there is no config file.",
			args:           []string{"fakeapp", "configure", "--token", "a", "--workspace", "/a", "--api", "http://example.com"},
			existingUsrCfg: nil,
			expectedUsrCfg: &config.UserConfig{Token: "a", Workspace: "/a"},
			existingAPICfg: nil,
			expectedAPICfg: &config.APIConfig{BaseURL: "http://example.com"},
		},
		testCase{
			desc:           "It overwrites the flags in the config file.",
			args:           []string{"fakeapp", "configure", "--token", "b", "--workspace", "/b", "--api", "http://example.com/v2"},
			existingUsrCfg: &config.UserConfig{Token: "token-b", Workspace: "/workspace-b"},
			expectedUsrCfg: &config.UserConfig{Token: "b", Workspace: "/b"},
			existingAPICfg: &config.APIConfig{BaseURL: "http://example.com/v1"},
			expectedAPICfg: &config.APIConfig{BaseURL: "http://example.com/v2"},
		},
		testCase{
			desc:           "It overwrites the flags that are passed, without losing the ones that are not.",
			args:           []string{"fakeapp", "configure", "--token", "c"},
			existingUsrCfg: &config.UserConfig{Token: "token-c", Workspace: "/workspace-c"},
			expectedUsrCfg: &config.UserConfig{Token: "c", Workspace: "/workspace-c"},
		},
		testCase{
			desc:           "It gets the default API base URL.",
			args:           []string{"fakeapp", "configure"},
			existingAPICfg: &config.APIConfig{},
			expectedAPICfg: &config.APIConfig{BaseURL: "https://v2.exercism.io/api/v1"},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.desc, makeTest(tc))
	}
}

func makeTest(tc testCase) func(*testing.T) {

	return func(t *testing.T) {
		cmdTest := &CommandTest{
			Cmd:    configureCmd,
			InitFn: initConfigureCmd,
			Args:   tc.args,
		}
		cmdTest.Setup(t)
		defer cmdTest.Teardown(t)

		if tc.existingUsrCfg != nil {
			// Write a fake config.
			cfg := config.NewEmptyUserConfig()
			cfg.Token = tc.existingUsrCfg.Token
			cfg.Workspace = tc.existingUsrCfg.Workspace
			err := cfg.Write()
			assert.NoError(t, err, tc.desc)
		}

		cmdTest.App.Execute()

		if tc.expectedUsrCfg != nil {
			usrCfg, err := config.NewUserConfig()
			assert.NoError(t, err, tc.desc)
			assert.Equal(t, tc.expectedUsrCfg.Token, usrCfg.Token, tc.desc)
			assert.Equal(t, tc.expectedUsrCfg.Workspace, usrCfg.Workspace, tc.desc)
		}

		if tc.expectedAPICfg != nil {
			apiCfg, err := config.NewAPIConfig()
			assert.NoError(t, err, tc.desc)
			assert.Equal(t, tc.expectedAPICfg.BaseURL, apiCfg.BaseURL, tc.desc)
		}
	}
}
<commit_msg>Calls Normalize() on expected result in configure_test so tests passes on windows.<commit_after>package cmd

import (
	"runtime"
	"testing"

	"github.com/exercism/cli/config"
	"github.com/stretchr/testify/assert"
)

type testCase struct {
	desc           string
	args           []string
	existingUsrCfg *config.UserConfig
	expectedUsrCfg *config.UserConfig
	existingAPICfg *config.APIConfig
	expectedAPICfg *config.APIConfig
}

func TestConfigure(t *testing.T) {
	testCases := []testCase{
		testCase{
			desc:           "It writes the flags when there is no config file.",
			args:           []string{"fakeapp", "configure", "--token", "a", "--workspace", "/a", "--api", "http://example.com"},
			existingUsrCfg: nil,
			expectedUsrCfg: &config.UserConfig{Token: "a", Workspace: "/a"},
			existingAPICfg: nil,
			expectedAPICfg: &config.APIConfig{BaseURL: "http://example.com"},
		},
		testCase{
			desc:           "It overwrites the flags in the config file.",
			args:           []string{"fakeapp", "configure", "--token", "b", "--workspace", "/b", "--api", "http://example.com/v2"},
			existingUsrCfg: &config.UserConfig{Token: "token-b", Workspace: "/workspace-b"},
			expectedUsrCfg: &config.UserConfig{Token: "b", Workspace: "/b"},
			existingAPICfg: &config.APIConfig{BaseURL: "http://example.com/v1"},
			expectedAPICfg: &config.APIConfig{BaseURL: "http://example.com/v2"},
		},
		testCase{
			desc:           "It overwrites the flags that are passed, without losing the ones that are not.",
			args:           []string{"fakeapp", "configure", "--token", "c"},
			existingUsrCfg: &config.UserConfig{Token: "token-c", Workspace: "/workspace-c"},
			expectedUsrCfg: &config.UserConfig{Token: "c", Workspace: "/workspace-c"},
		},
		testCase{
			desc:           "It gets the default API base URL.",
			args:           []string{"fakeapp", "configure"},
			existingAPICfg: &config.APIConfig{},
			expectedAPICfg: &config.APIConfig{BaseURL: "https://v2.exercism.io/api/v1"},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.desc, makeTest(tc))
	}
}

func makeTest(tc testCase) func(*testing.T) {

	return func(t *testing.T) {
		cmdTest := &CommandTest{
			Cmd:    configureCmd,
			InitFn: initConfigureCmd,
			Args:   tc.args,
		}
		cmdTest.Setup(t)
		defer cmdTest.Teardown(t)

		if tc.existingUsrCfg != nil {
			// Write a fake config.
			cfg := config.NewEmptyUserConfig()
			cfg.Token = tc.existingUsrCfg.Token
			cfg.Workspace = tc.existingUsrCfg.Workspace
			err := cfg.Write()
			assert.NoError(t, err, tc.desc)
		}

		cmdTest.App.Execute()

		if tc.expectedUsrCfg != nil {
			if runtime.GOOS == "windows" {
				tc.expectedUsrCfg.Normalize()
			}

			usrCfg, err := config.NewUserConfig()

			assert.NoError(t, err, tc.desc)
			assert.Equal(t, tc.expectedUsrCfg.Token, usrCfg.Token, tc.desc)
			assert.Equal(t, tc.expectedUsrCfg.Workspace, usrCfg.Workspace, tc.desc)
		}

		if tc.expectedAPICfg != nil {
			apiCfg, err := config.NewAPIConfig()
			assert.NoError(t, err, tc.desc)
			assert.Equal(t, tc.expectedAPICfg.BaseURL, apiCfg.BaseURL, tc.desc)
		}
	}
}
<|endoftext|>


<commit_before>/*
Package key contains a single Key interface. The key package was
created to prevent cicular dependencies between "github.com/lleo/go-hamt" and
either "github.com/lleo/go-hamt/hamt32" or "github.com/lleo/go-hamt/hamt64".

Additionally, the github.com/lleo/go-hamt/key provides a Base structure.
The Base structure if added to a derivative key type will provide the
Hamt30() and Hamt60() methods. Base needs to be populated by the derivative
key constructor calling the Initialize([]byte) method.

Any key created using the Key interface must be read only after construction.

The key package is used by the functional HAMT variation in
"github.com/lleo/go-hamt-functional".
*/
package key

import (
	"fmt"
	"hash/fnv"
	"strings"
)

// KeyVal is a simple struct used to transfer lists ([]KeyVal) from one
// function to another.
type KeyVal struct {
	Key Key
	Val interface{}
}

func (kv KeyVal) String() string {
	return fmt.Sprintf("KeyVal{%s, %v}", kv.Key, kv.Val)
}

// Key interface descibes the methods any struct needs to implement to be used
// in either the github.com/lleo/go-hamt or github.com/lleo/go-hamt-functional
// packages.
type Key interface {
	Hash30() uint32
	Hash60() uint64
	Equals(Key) bool
	String() string
	String30() string
	String60() string
	Index30(depth uint) uint
	Index60(depth uint) uint
	HashPathString30(depth uint) string
	HashPathString60(depth uint) string
}

type HashVal30 uint32
type HashVal60 uint64

// Base struct is intended to be the base struct of all structs that satisfy
// Key interface. It caches the calculated hash30 and hash60 generated when
// the method Initialize([]byte) is called.
type Base struct {
	hash30 uint32
	hash60 uint64
}

const BitsPerLevel30 uint = 5
const BitsPerLevel60 uint = 6

const MaxDepth30 uint = 5
const MaxDepth60 uint = 9

// Index30() will return a 5bit (aka BitsPerLevel30) value 'depth' number
// of 5bits from the beginning of the uint32 kb.base30 value.
func (kb Base) Index30(depth uint) uint {
	var idxMask = indexMask30(depth)
	var idx = uint(kb.hash30&idxMask) >> (depth * BitsPerLevel30)
	return idx
}

func indexMask30(depth uint) uint32 {
	return uint32((1<<BitsPerLevel30)-1) << (depth * BitsPerLevel30)
}

// Index60() will return a 6bit (aka BitsPerLevel60) value 'depth' number
// of 6bits from the beginning of the uint64 h60 value.
func (kb Base) Index60(depth uint) uint {
	var idxMask = indexMask60(depth)
	var idx = uint(kb.hash60&idxMask) >> (depth * BitsPerLevel60)
	return idx
}

func indexMask60(depth uint) uint64 {
	return uint64((1<<BitsPerLevel60)-1) << (depth * BitsPerLevel60)
}

// HashPathString30() returns a string representation of the index path of
// a hash30 30 bit value; that is depth number of zero padded numbers between
// "00" and "63" separated by "/" characters.
// Warning: It will panic() if depth > MaxDepth30.
// Example: "/00/24/46/17" for depth=4 of a hash30 value represented
//       by "/00/24/46/17/34/08".
func (kb Base) HashPathString30(depth uint) string {
	if depth > MaxDepth30 {
		panic(fmt.Sprintf("HashPathString30: depth,%d > MaxDepth30,%d\n", depth, MaxDepth30))
	}

	if depth == 0 {
		return "/"
	}

	var strs = make([]string, depth)

	for d := uint(0); d < depth; d++ {
		var idx = kb.Index30(d)
		strs[d] = fmt.Sprintf("%02d", idx)
	}

	return "/" + strings.Join(strs, "/")
}

// HashPathString60() returns a string representation of the index path of
// a hash60 60 bit value; that is depth number of zero padded numbers between
// "00" and "63" separated by "/" characters.
// Warning: It will panic() if depth > MaxDepth60.
// Example: "/00/24/46/17/34/08/54" for depth=7 of a hash60 value represented
//       by "/00/24/46/17/34/08/54/28/59/51".
func (kb Base) HashPathString60(depth uint) string {
	if depth > MaxDepth60 {
		panic(fmt.Sprintf("PathString60: depth,%d > MaxDepth60,%d\n", depth, MaxDepth60))
	}

	if depth == 0 {
		return "/"
	}

	var strs = make([]string, depth)

	for d := uint(0); d < depth; d++ {
		var idx = kb.Index60(d)
		strs[d] = fmt.Sprintf("%02d", idx)
	}

	return "/" + strings.Join(strs, "/")
}

// String() provides a human readable form of the Base's hash30 and hash60
// values. Both in raw integer and slash '/' separated integers of the 5 and
// 6 bit path values; for hash30 and hash60 respectively.
func (kb Base) String() string {
	return fmt.Sprintf("Base{%s, %s}", kb.String30(), kb.String60())
}

// String30() returns a string representation of the kb.hash30 value. This
// is MaxDepth30+1(6) two digit numbers (zero padded) between "00" and "31"
// seperated by '/' characters.
// Example: "/08/14/28/20/00/31"
func (kb Base) String30() string {
	return kb.HashPathString30(MaxDepth30)
}

// String60() returns a string representation of the kb.hash60 value. This
// is MaxDepth60+1(10) two digit numbers (zero padded) between "00" and "63"
// seperated by '/' characters.
// Example: "/08/14/28/20/00/31/56/01/24/63"
func (kb Base) String60() string {
	return kb.HashPathString60(MaxDepth60)
}

//
// Calculate Hash of byte slice functions
//

const mask30 = uint32(1<<30) - 1

// fold30 folds the top 2 bits into the bottom 30 to get 30bits of hash
// from: http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold
func fold30(h32 uint32) uint32 {
	return h32>>30 ^ h32&mask30
}

// hash64 calculates the 64bit hash value of a byte string using hash/fnv.
func hash32(bs []byte) uint32 {
	var h = fnv.New32()
	h.Write(bs)
	return h.Sum32()
}

const mask60 = uint64(1<<60) - 1

// fold60 folds the top 4 bits into the bottom 60 to get 60bits of hash
// from: http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold
func fold60(h64 uint64) uint64 {
	return h64>>60 ^ h64&mask60
}

// hash64 calculates the 64bit hash value of a byte string using hash/fnv.
func hash64(bs []byte) uint64 {
	var h = fnv.New64()
	h.Write(bs)
	return h.Sum64()
}

// Initialize the calculates the Base part of any struct that has the Base
// struct embedded. It will be called by the New() function of any descendant
// class.
//     k.Initialize(bs)
// where k is interpreted as a *Base and bs is a unique []byte to calculate
// the 30bit and 60bit hash values from.
func (kb *Base) Initialize(bs []byte) {
	kb.hash30 = fold30(hash32(bs))
	kb.hash60 = fold60(hash64(bs))
}

// Hash30 returns the uint32 that contains the 30bit hash value.
func (kb Base) Hash30() uint32 {
	return kb.hash30
}

// Hash60 returns the uint32 that contains the 60bit hash value.
func (kb Base) Hash60() uint64 {
	return kb.hash60
}
<commit_msg>fixed off-by-one bug in Base.HashPathString() where the path string was one depth short<commit_after>/*
Package key contains a single Key interface. The key package was
created to prevent cicular dependencies between "github.com/lleo/go-hamt" and
either "github.com/lleo/go-hamt/hamt32" or "github.com/lleo/go-hamt/hamt64".

Additionally, the github.com/lleo/go-hamt/key provides a Base structure.
The Base structure if added to a derivative key type will provide the
Hamt30() and Hamt60() methods. Base needs to be populated by the derivative
key constructor calling the Initialize([]byte) method.

Any key created using the Key interface must be read only after construction.

The key package is used by the functional HAMT variation in
"github.com/lleo/go-hamt-functional".
*/
package key

import (
	"fmt"
	"hash/fnv"
	"strings"
)

// KeyVal is a simple struct used to transfer lists ([]KeyVal) from one
// function to another.
type KeyVal struct {
	Key Key
	Val interface{}
}

func (kv KeyVal) String() string {
	return fmt.Sprintf("KeyVal{%s, %v}", kv.Key, kv.Val)
}

// Key interface descibes the methods any struct needs to implement to be used
// in either the github.com/lleo/go-hamt or github.com/lleo/go-hamt-functional
// packages.
type Key interface {
	Hash30() uint32
	Hash60() uint64
	Equals(Key) bool
	String() string
	String30() string
	String60() string
	Index30(depth uint) uint
	Index60(depth uint) uint
	HashPathString30(depth uint) string
	HashPathString60(depth uint) string
}

type HashVal30 uint32
type HashVal60 uint64

// Base struct is intended to be the base struct of all structs that satisfy
// Key interface. It caches the calculated hash30 and hash60 generated when
// the method Initialize([]byte) is called.
type Base struct {
	hash30 uint32
	hash60 uint64
}

const BitsPerLevel30 uint = 5
const BitsPerLevel60 uint = 6

const MaxDepth30 uint = 5
const MaxDepth60 uint = 9

// Index30() will return a 5bit (aka BitsPerLevel30) value 'depth' number
// of 5bits from the beginning of the uint32 kb.base30 value.
func (kb Base) Index30(depth uint) uint {
	var idxMask = indexMask30(depth)
	var idx = uint(kb.hash30&idxMask) >> (depth * BitsPerLevel30)
	return idx
}

func indexMask30(depth uint) uint32 {
	return uint32((1<<BitsPerLevel30)-1) << (depth * BitsPerLevel30)
}

// Index60() will return a 6bit (aka BitsPerLevel60) value 'depth' number
// of 6bits from the beginning of the uint64 h60 value.
func (kb Base) Index60(depth uint) uint {
	var idxMask = indexMask60(depth)
	var idx = uint(kb.hash60&idxMask) >> (depth * BitsPerLevel60)
	return idx
}

func indexMask60(depth uint) uint64 {
	return uint64((1<<BitsPerLevel60)-1) << (depth * BitsPerLevel60)
}

// HashPathString30() returns a string representation of the index path of
// a hash30 30 bit value; that is depth number of zero padded numbers between
// "00" and "63" separated by "/" characters.
// Warning: It will panic() if depth > MaxDepth30.
// Example: "/00/24/46/17" for depth=4 of a hash30 value represented
//       by "/00/24/46/17/34/08".
func (kb Base) HashPathString30(depth uint) string {
	if depth > MaxDepth30 {
		panic(fmt.Sprintf("HashPathString30: depth,%d > MaxDepth30,%d\n", depth, MaxDepth30))
	}

	if depth == 0 {
		return "/"
	}

	var strs = make([]string, depth+1)

	for d := uint(0); d <= depth; d++ {
		var idx = kb.Index30(d)
		strs[d] = fmt.Sprintf("%02d", idx)
	}

	return "/" + strings.Join(strs, "/")
}

// HashPathString60() returns a string representation of the index path of
// a hash60 60 bit value; that is depth number of zero padded numbers between
// "00" and "63" separated by "/" characters.
// Warning: It will panic() if depth > MaxDepth60.
// Example: "/00/24/46/17/34/08/54" for depth=7 of a hash60 value represented
//       by "/00/24/46/17/34/08/54/28/59/51".
func (kb Base) HashPathString60(depth uint) string {
	if depth > MaxDepth60 {
		panic(fmt.Sprintf("PathString60: depth,%d > MaxDepth60,%d\n", depth, MaxDepth60))
	}

	if depth == 0 {
		return "/"
	}

	var strs = make([]string, depth+1)

	for d := uint(0); d <= depth; d++ {
		var idx = kb.Index60(d)
		strs[d] = fmt.Sprintf("%02d", idx)
	}

	return "/" + strings.Join(strs, "/")
}

// String() provides a human readable form of the Base's hash30 and hash60
// values. Both in raw integer and slash '/' separated integers of the 5 and
// 6 bit path values; for hash30 and hash60 respectively.
func (kb Base) String() string {
	return fmt.Sprintf("Base{%s, %s}", kb.String30(), kb.String60())
}

// String30() returns a string representation of the kb.hash30 value. This
// is MaxDepth30+1(6) two digit numbers (zero padded) between "00" and "31"
// seperated by '/' characters.
// Example: "/08/14/28/20/00/31"
func (kb Base) String30() string {
	return kb.HashPathString30(MaxDepth30)
}

// String60() returns a string representation of the kb.hash60 value. This
// is MaxDepth60+1(10) two digit numbers (zero padded) between "00" and "63"
// seperated by '/' characters.
// Example: "/08/14/28/20/00/31/56/01/24/63"
func (kb Base) String60() string {
	return kb.HashPathString60(MaxDepth60)
}

//
// Calculate Hash of byte slice functions
//

const mask30 = uint32(1<<30) - 1

// fold30 folds the top 2 bits into the bottom 30 to get 30bits of hash
// from: http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold
func fold30(h32 uint32) uint32 {
	return h32>>30 ^ h32&mask30
}

// hash64 calculates the 64bit hash value of a byte string using hash/fnv.
func hash32(bs []byte) uint32 {
	var h = fnv.New32()
	h.Write(bs)
	return h.Sum32()
}

const mask60 = uint64(1<<60) - 1

// fold60 folds the top 4 bits into the bottom 60 to get 60bits of hash
// from: http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold
func fold60(h64 uint64) uint64 {
	return h64>>60 ^ h64&mask60
}

// hash64 calculates the 64bit hash value of a byte string using hash/fnv.
func hash64(bs []byte) uint64 {
	var h = fnv.New64()
	h.Write(bs)
	return h.Sum64()
}

// Initialize the calculates the Base part of any struct that has the Base
// struct embedded. It will be called by the New() function of any descendant
// class.
//     k.Initialize(bs)
// where k is interpreted as a *Base and bs is a unique []byte to calculate
// the 30bit and 60bit hash values from.
func (kb *Base) Initialize(bs []byte) {
	kb.hash30 = fold30(hash32(bs))
	kb.hash60 = fold60(hash64(bs))
}

// Hash30 returns the uint32 that contains the 30bit hash value.
func (kb Base) Hash30() uint32 {
	return kb.hash30
}

// Hash60 returns the uint32 that contains the 60bit hash value.
func (kb Base) Hash60() uint64 {
	return kb.hash60
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"

	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/missinggo"
	"github.com/anacrolix/missinggo/filecache"
	"github.com/anacrolix/tagflag"
	"github.com/dustin/go-humanize"
)

var c *filecache.Cache

func handleNewData(w http.ResponseWriter, path string, offset int64, r io.Reader) (served bool) {
	f, err := c.OpenFile(path, os.O_CREATE|os.O_WRONLY)
	if err != nil {
		log.Print(err)
		http.Error(w, "couldn't open file", http.StatusInternalServerError)
		return true
	}
	defer f.Close()
	f.Seek(offset, os.SEEK_SET)
	_, err = io.Copy(f, r)
	if err != nil {
		log.Print(err)
		f.Remove()
		http.Error(w, "didn't complete", http.StatusInternalServerError)
		return true
	}
	return
}

// Parses out the first byte from a Content-Range header. Returns 0 if it
// isn't found, which is what is implied if there is no header.
func parseContentRangeFirstByte(s string) int64 {
	matches := regexp.MustCompile(`(\d+)-`).FindStringSubmatch(s)
	if matches == nil {
		return 0
	}
	ret, _ := strconv.ParseInt(matches[1], 0, 64)
	return ret
}

func handleDelete(w http.ResponseWriter, path string) {
	err := c.Remove(path)
	if err != nil {
		log.Print(err)
		http.Error(w, "didn't work", http.StatusInternalServerError)
		return
	}
}

func main() {
	log.SetFlags(log.Flags() | log.Lshortfile)
	args := struct {
		Capacity tagflag.Bytes `short:"c"`
		Addr     string
	}{
		Capacity: -1,
		Addr:     "localhost:2076",
	}
	tagflag.Parse(&args)
	root, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("cache root at %q", root)
	c, err = filecache.NewCache(root)
	if err != nil {
		log.Fatalf("error creating cache: %s", err)
	}
	if args.Capacity < 0 {
		log.Printf("no capacity set, no evictions will occur")
	} else {
		c.SetCapacity(args.Capacity.Int64())
		log.Printf("setting capacity to %s bytes", humanize.Comma(args.Capacity.Int64()))
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		p := r.URL.Path[1:]
		switch r.Method {
		case "DELETE":
			log.Printf("%s %s", r.Method, r.RequestURI)
			handleDelete(w, p)
			return
		case "PUT", "PATCH", "POST":
			contentRange := r.Header.Get("Content-Range")
			firstByte := parseContentRangeFirstByte(contentRange)
			log.Printf("%s (%d-) %s", r.Method, firstByte, r.RequestURI)
			if handleNewData(w, p, firstByte, r.Body) {
				return
			}
			if contentRange != "" {
				w.WriteHeader(206)
				return
			}
			return
		}
		log.Printf("%s %s %s", r.Method, r.Header.Get("Range"), r.RequestURI)
		f, err := c.OpenFile(p, os.O_RDONLY)
		if os.IsNotExist(err) {
			http.NotFound(w, r)
			return
		}
		if err != nil {
			log.Printf("couldn't open requested file: %s", err)
			http.Error(w, "couldn't open file", http.StatusInternalServerError)
			return
		}
		defer func() {
			go f.Close()
		}()
		info, _ := f.Stat()
		http.ServeContent(w, r, p, info.ModTime(), f)
	})
	http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		info := c.Info()
		fmt.Fprintf(w, "Capacity: %d\n", info.Capacity)
		fmt.Fprintf(w, "Current Size: %d\n", info.Filled)
		fmt.Fprintf(w, "Item Count: %d\n", info.NumItems)
	})
	http.HandleFunc("/lru", func(w http.ResponseWriter, r *http.Request) {
		c.WalkItems(func(item filecache.ItemInfo) {
			fmt.Fprintf(w, "%s\t%d\t%s\n", item.Accessed, item.Size, item.Path)
		})
	})
	cert, err := missinggo.NewSelfSignedCertificate()
	if err != nil {
		log.Fatal(err)
	}
	srv := http.Server{
		Addr: args.Addr,
		TLSConfig: &tls.Config{
			Certificates: []tls.Certificate{cert},
		},
	}
	log.Fatal(srv.ListenAndServeTLS("", ""))
}
<commit_msg>cmd/filecache: Don't return 206 for partial requests<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"

	_ "github.com/anacrolix/envpprof"
	"github.com/anacrolix/tagflag"
	"github.com/dustin/go-humanize"

	"github.com/anacrolix/missinggo"
	"github.com/anacrolix/missinggo/filecache"
)

var c *filecache.Cache

func handleNewData(w http.ResponseWriter, path string, offset int64, r io.Reader) (served bool) {
	f, err := c.OpenFile(path, os.O_CREATE|os.O_WRONLY)
	if err != nil {
		log.Print(err)
		http.Error(w, "couldn't open file", http.StatusInternalServerError)
		return true
	}
	defer f.Close()
	f.Seek(offset, os.SEEK_SET)
	_, err = io.Copy(f, r)
	if err != nil {
		log.Print(err)
		f.Remove()
		http.Error(w, "didn't complete", http.StatusInternalServerError)
		return true
	}
	return
}

// Parses out the first byte from a Content-Range header. Returns 0 if it
// isn't found, which is what is implied if there is no header.
func parseContentRangeFirstByte(s string) int64 {
	matches := regexp.MustCompile(`(\d+)-`).FindStringSubmatch(s)
	if matches == nil {
		return 0
	}
	ret, _ := strconv.ParseInt(matches[1], 0, 64)
	return ret
}

func handleDelete(w http.ResponseWriter, path string) {
	err := c.Remove(path)
	if err != nil {
		log.Print(err)
		http.Error(w, "didn't work", http.StatusInternalServerError)
		return
	}
}

func main() {
	log.SetFlags(log.Flags() | log.Lshortfile)
	args := struct {
		Capacity tagflag.Bytes `short:"c"`
		Addr     string
	}{
		Capacity: -1,
		Addr:     "localhost:2076",
	}
	tagflag.Parse(&args)
	root, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("cache root at %q", root)
	c, err = filecache.NewCache(root)
	if err != nil {
		log.Fatalf("error creating cache: %s", err)
	}
	if args.Capacity < 0 {
		log.Printf("no capacity set, no evictions will occur")
	} else {
		c.SetCapacity(args.Capacity.Int64())
		log.Printf("setting capacity to %s bytes", humanize.Comma(args.Capacity.Int64()))
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		p := r.URL.Path[1:]
		switch r.Method {
		case "DELETE":
			log.Printf("%s %s", r.Method, r.RequestURI)
			handleDelete(w, p)
			return
		case "PUT", "PATCH", "POST":
			contentRange := r.Header.Get("Content-Range")
			firstByte := parseContentRangeFirstByte(contentRange)
			log.Printf("%s (%d-) %s", r.Method, firstByte, r.RequestURI)
			handleNewData(w, p, firstByte, r.Body)
		}
		log.Printf("%s %s %s", r.Method, r.Header.Get("Range"), r.RequestURI)
		f, err := c.OpenFile(p, os.O_RDONLY)
		if os.IsNotExist(err) {
			http.NotFound(w, r)
			return
		}
		if err != nil {
			log.Printf("couldn't open requested file: %s", err)
			http.Error(w, "couldn't open file", http.StatusInternalServerError)
			return
		}
		defer func() {
			go f.Close()
		}()
		info, _ := f.Stat()
		http.ServeContent(w, r, p, info.ModTime(), f)
	})
	http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		info := c.Info()
		fmt.Fprintf(w, "Capacity: %d\n", info.Capacity)
		fmt.Fprintf(w, "Current Size: %d\n", info.Filled)
		fmt.Fprintf(w, "Item Count: %d\n", info.NumItems)
	})
	http.HandleFunc("/lru", func(w http.ResponseWriter, r *http.Request) {
		c.WalkItems(func(item filecache.ItemInfo) {
			fmt.Fprintf(w, "%s\t%d\t%s\n", item.Accessed, item.Size, item.Path)
		})
	})
	cert, err := missinggo.NewSelfSignedCertificate()
	if err != nil {
		log.Fatal(err)
	}
	srv := http.Server{
		Addr: args.Addr,
		TLSConfig: &tls.Config{
			Certificates: []tls.Certificate{cert},
		},
	}
	log.Fatal(srv.ListenAndServeTLS("", ""))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"errors"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/bmizerany/lpx"
	"github.com/heroku/authenticater"
	metrics "github.com/rcrowley/go-metrics"
	log "github.com/sirupsen/logrus"
)

type payload struct {
	SourceAddr string
	RequestID  string
	Body       []byte
	WaitCh     chan struct{}
}

func NewPayload(sa string, ri string, b []byte) payload {
	return payload{
		SourceAddr: sa,
		RequestID:  ri,
		Body:       b,
		WaitCh:     make(chan struct{}, 1),
	}
}

type FixerFunc func(io.Reader, string, string) ([]byte, error)

type httpServer struct {
	Config         IssConfig
	FixerFunc      FixerFunc
	shutdownCh     shutdownCh
	deliverer      deliverer
	isShuttingDown bool
	auth           authenticater.Authenticater
	posts          metrics.Timer   // tracks metrics about posts
	healthChecks   metrics.Timer   // tracks metrics about health checks
	pErrors        metrics.Counter // tracks the count of post errors
	pSuccesses     metrics.Counter // tracks the number of post successes
	pAuthErrors    metrics.Counter // tracks the count of auth errors
	pAuthSuccesses metrics.Counter // tracks the number of auth successes
	sync.WaitGroup
}

func newHTTPServer(config IssConfig, auth authenticater.Authenticater, fixerFunc FixerFunc, deliverer deliverer) *httpServer {
	return &httpServer{
		auth:           auth,
		Config:         config,
		FixerFunc:      fixerFunc,
		deliverer:      deliverer,
		shutdownCh:     make(shutdownCh),
		posts:          metrics.GetOrRegisterTimer("log-iss.http.logs", config.MetricsRegistry),
		healthChecks:   metrics.GetOrRegisterTimer("log-iss.http.healthchecks", config.MetricsRegistry),
		pErrors:        metrics.GetOrRegisterCounter("log-iss.http.logs.errors", config.MetricsRegistry),
		pSuccesses:     metrics.GetOrRegisterCounter("log-iss.http.logs.successes", config.MetricsRegistry),
		pAuthErrors:    metrics.GetOrRegisterCounter("log-iss.auth.errors", config.MetricsRegistry),
		pAuthSuccesses: metrics.GetOrRegisterCounter("log-iss.auth.successes", config.MetricsRegistry),
		isShuttingDown: false,
	}
}

func (s *httpServer) handleHTTPError(w http.ResponseWriter, errMsg string, errCode int, fields ...log.Fields) {
	ff := log.Fields{"post.code": errCode}
	for _, f := range fields {
		for k, v := range f {
			ff[k] = v
		}
	}

	s.pErrors.Inc(1)
	log.WithFields(ff).Error(errMsg)
	http.Error(w, errMsg, errCode)
}

func extractRemoteAddr(r *http.Request) string {
	remoteAddr := r.Header.Get("X-Forwarded-For")
	if remoteAddr == "" {
		remoteAddrParts := strings.Split(r.RemoteAddr, ":")
		remoteAddr = strings.Join(remoteAddrParts[:len(remoteAddrParts)-1], ":")
	}
	return remoteAddr
}

func (s *httpServer) Run() error {
	go s.awaitShutdown()

	//FXME: check outlet depth?
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		defer s.healthChecks.UpdateSince(time.Now())
		if s.isShuttingDown {
			http.Error(w, "Shutting down", 503)
			return
		}

	})

	http.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
		defer s.posts.UpdateSince(time.Now())

		if s.Config.EnforceSsl && r.Header.Get("X-Forwarded-Proto") != "https" {
			s.handleHTTPError(w, "Only SSL requests accepted", 400)
			return
		}

		if s.isShuttingDown {
			s.handleHTTPError(w, "Shutting down", 503)
			return
		}

		if r.Method != "POST" {
			s.handleHTTPError(w, "Only POST is accepted", 400)
			return
		}

		if r.Header.Get("Content-Type") != "application/logplex-1" {
			s.handleHTTPError(w, "Only Content-Type application/logplex-1 is accepted", 400)
			return
		}

		if !s.auth.Authenticate(r) {
			s.pAuthErrors.Inc(1)
			s.handleHTTPError(w, "Unable to authenticate request", 401)
			return
		} else {
			s.pAuthSuccesses.Inc(1)
		}

		remoteAddr := extractRemoteAddr(r)
		requestID := r.Header.Get("X-Request-Id")
		logplexDrainToken := r.Header.Get("Logplex-Drain-Token")

		body := r.Body
		var err error

		if r.Header.Get("Content-Encoding") == "gzip" {
			body, err = gzip.NewReader(r.Body)
			if err != nil {
				s.handleHTTPError(w, "Could not decode gzip request", 500)
				return
			}
			defer body.Close()
		}

		var buf bytes.Buffer
		// This should only be reached if authentication information is valid.
		authUser, _, ok := r.BasicAuth()
		if ok && s.Config.LogAuthUser(authUser, rand.Intn(99)+1) {
			// tee body to buffer
			body = ioutil.NopCloser(io.TeeReader(body, &buf))
		}

		if err, status := s.process(body, remoteAddr, requestID, logplexDrainToken); err != nil {
			s.handleHTTPError(
				w, err.Error(), status,
				log.Fields{"remote_addr": remoteAddr, "requestId": requestID, "logdrain_token": logplexDrainToken},
			)
			return
		}

		if buf.Len() > 0 {
			lp := lpx.NewReader(bufio.NewReader(bytes.NewReader(buf.Bytes())))

			// Don't travers, but get the first entry.
			if lp.Next() {
				h := lp.Header()

				log.WithFields(log.Fields{
					"log_iss_user": authUser,
					"hostname":     string(h.Hostname),
					"procid":       string(h.Procid),
					"msgid":        string(h.Msgid),
				}).Info()
			}
		}

		s.pSuccesses.Inc(1)
	})

	return http.ListenAndServe(":"+s.Config.HttpPort, nil)
}

func (s *httpServer) awaitShutdown() {
	<-s.shutdownCh
	s.isShuttingDown = true
	log.WithFields(log.Fields{"ns": "http", "at": "shutdown"}).Info()
}

func (s *httpServer) process(r io.Reader, remoteAddr string, requestID string, logplexDrainToken string) (error, int) {
	s.Add(1)
	defer s.Done()

	fixedBody, err := s.FixerFunc(r, remoteAddr, logplexDrainToken)
	if err != nil {
		return errors.New("Problem fixing body: " + err.Error()), http.StatusBadRequest
	}

	payload := NewPayload(remoteAddr, requestID, fixedBody)
	if err := s.deliverer.Deliver(payload); err != nil {
		return errors.New("Problem delivering body: " + err.Error()), http.StatusGatewayTimeout
	}

	return nil, 200
}
<commit_msg>tweaking what to log<commit_after>package main

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"errors"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/bmizerany/lpx"
	"github.com/heroku/authenticater"
	metrics "github.com/rcrowley/go-metrics"
	log "github.com/sirupsen/logrus"
)

type payload struct {
	SourceAddr string
	RequestID  string
	Body       []byte
	WaitCh     chan struct{}
}

func NewPayload(sa string, ri string, b []byte) payload {
	return payload{
		SourceAddr: sa,
		RequestID:  ri,
		Body:       b,
		WaitCh:     make(chan struct{}, 1),
	}
}

type FixerFunc func(io.Reader, string, string) ([]byte, error)

type httpServer struct {
	Config         IssConfig
	FixerFunc      FixerFunc
	shutdownCh     shutdownCh
	deliverer      deliverer
	isShuttingDown bool
	auth           authenticater.Authenticater
	posts          metrics.Timer   // tracks metrics about posts
	healthChecks   metrics.Timer   // tracks metrics about health checks
	pErrors        metrics.Counter // tracks the count of post errors
	pSuccesses     metrics.Counter // tracks the number of post successes
	pAuthErrors    metrics.Counter // tracks the count of auth errors
	pAuthSuccesses metrics.Counter // tracks the number of auth successes
	sync.WaitGroup
}

func newHTTPServer(config IssConfig, auth authenticater.Authenticater, fixerFunc FixerFunc, deliverer deliverer) *httpServer {
	return &httpServer{
		auth:           auth,
		Config:         config,
		FixerFunc:      fixerFunc,
		deliverer:      deliverer,
		shutdownCh:     make(shutdownCh),
		posts:          metrics.GetOrRegisterTimer("log-iss.http.logs", config.MetricsRegistry),
		healthChecks:   metrics.GetOrRegisterTimer("log-iss.http.healthchecks", config.MetricsRegistry),
		pErrors:        metrics.GetOrRegisterCounter("log-iss.http.logs.errors", config.MetricsRegistry),
		pSuccesses:     metrics.GetOrRegisterCounter("log-iss.http.logs.successes", config.MetricsRegistry),
		pAuthErrors:    metrics.GetOrRegisterCounter("log-iss.auth.errors", config.MetricsRegistry),
		pAuthSuccesses: metrics.GetOrRegisterCounter("log-iss.auth.successes", config.MetricsRegistry),
		isShuttingDown: false,
	}
}

func (s *httpServer) handleHTTPError(w http.ResponseWriter, errMsg string, errCode int, fields ...log.Fields) {
	ff := log.Fields{"post.code": errCode}
	for _, f := range fields {
		for k, v := range f {
			ff[k] = v
		}
	}

	s.pErrors.Inc(1)
	log.WithFields(ff).Error(errMsg)
	http.Error(w, errMsg, errCode)
}

func extractRemoteAddr(r *http.Request) string {
	remoteAddr := r.Header.Get("X-Forwarded-For")
	if remoteAddr == "" {
		remoteAddrParts := strings.Split(r.RemoteAddr, ":")
		remoteAddr = strings.Join(remoteAddrParts[:len(remoteAddrParts)-1], ":")
	}
	return remoteAddr
}

func (s *httpServer) Run() error {
	go s.awaitShutdown()

	//FXME: check outlet depth?
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		defer s.healthChecks.UpdateSince(time.Now())
		if s.isShuttingDown {
			http.Error(w, "Shutting down", 503)
			return
		}

	})

	http.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
		defer s.posts.UpdateSince(time.Now())

		if s.Config.EnforceSsl && r.Header.Get("X-Forwarded-Proto") != "https" {
			s.handleHTTPError(w, "Only SSL requests accepted", 400)
			return
		}

		if s.isShuttingDown {
			s.handleHTTPError(w, "Shutting down", 503)
			return
		}

		if r.Method != "POST" {
			s.handleHTTPError(w, "Only POST is accepted", 400)
			return
		}

		if r.Header.Get("Content-Type") != "application/logplex-1" {
			s.handleHTTPError(w, "Only Content-Type application/logplex-1 is accepted", 400)
			return
		}

		if !s.auth.Authenticate(r) {
			s.pAuthErrors.Inc(1)
			s.handleHTTPError(w, "Unable to authenticate request", 401)
			return
		} else {
			s.pAuthSuccesses.Inc(1)
		}

		remoteAddr := extractRemoteAddr(r)
		requestID := r.Header.Get("X-Request-Id")
		logplexDrainToken := r.Header.Get("Logplex-Drain-Token")

		body := r.Body
		var err error

		if r.Header.Get("Content-Encoding") == "gzip" {
			body, err = gzip.NewReader(r.Body)
			if err != nil {
				s.handleHTTPError(w, "Could not decode gzip request", 500)
				return
			}
			defer body.Close()
		}

		var buf bytes.Buffer
		// This should only be reached if authentication information is valid.
		authUser, _, ok := r.BasicAuth()
		if ok && s.Config.LogAuthUser(authUser, rand.Intn(99)+1) {
			// tee body to buffer
			body = ioutil.NopCloser(io.TeeReader(body, &buf))
		}

		if err, status := s.process(body, remoteAddr, requestID, logplexDrainToken); err != nil {
			s.handleHTTPError(
				w, err.Error(), status,
				log.Fields{"remote_addr": remoteAddr, "requestId": requestID, "logdrain_token": logplexDrainToken},
			)
			return
		}

		if buf.Len() > 0 {
			lp := lpx.NewReader(bufio.NewReader(bytes.NewReader(buf.Bytes())))

			// Don't travers, but get the first entry.
			if lp.Next() {
				h := lp.Header()

				host := string(h.Hostname)
				if hostname == "host" {
					hostname = logplexDrainToken
				}

				log.WithFields(log.Fields{
					"log_iss_user": hauthUser,
					"hostname":     hostname,
					"procid":       string(h.Procid),
					"request_id":   requestID,
					"remote_addr":  remoteAddr,
				}).Info()
			}
		}

		s.pSuccesses.Inc(1)
	})

	return http.ListenAndServe(":"+s.Config.HttpPort, nil)
}

func (s *httpServer) awaitShutdown() {
	<-s.shutdownCh
	s.isShuttingDown = true
	log.WithFields(log.Fields{"ns": "http", "at": "shutdown"}).Info()
}

func (s *httpServer) process(r io.Reader, remoteAddr string, requestID string, logplexDrainToken string) (error, int) {
	s.Add(1)
	defer s.Done()

	fixedBody, err := s.FixerFunc(r, remoteAddr, logplexDrainToken)
	if err != nil {
		return errors.New("Problem fixing body: " + err.Error()), http.StatusBadRequest
	}

	payload := NewPayload(remoteAddr, requestID, fixedBody)
	if err := s.deliverer.Deliver(payload); err != nil {
		return errors.New("Problem delivering body: " + err.Error()), http.StatusGatewayTimeout
	}

	return nil, 200
}
<|endoftext|>


<commit_before>package scene

import (
	"image"
	"math"

	"github.com/pankona/gomo-simra/examples/sample2/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

type CtrlTrial struct {
	ball     simra.Sprite
	ctrlup   simra.Sprite
	ctrldown simra.Sprite
}

func (self *CtrlTrial) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)

	// initialize sprites
	self.initSprites()

	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initSprites() {
	self.initBall()
	self.initCtrlDown()
	self.initCtrlUp()
}

func (self *CtrlTrial) initBall() {
	// set size of ball
	self.ball.W = float32(48)
	self.ball.H = float32(48)

	// put center of screen at start
	self.ball.X = config.SCREEN_WIDTH / 2
	self.ball.Y = config.SCREEN_HEIGHT / 2

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(self.ball.W), int(self.ball.H)),
		&self.ball)
}

const (
	CTRL_MARGIN_LEFT    = 10
	CTRL_MARGIN_BOTTOM  = 10
	CTRL_MARGIN_BETWEEN = 10
)

// CtrlUp
type CtrlUpTouchListener struct {
}

func (self *CtrlUpTouchListener) OnTouchBegin(x, y float32) {
	simra.LogDebug("[IN] CtrlUp Begin!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlUpTouchListener) OnTouchMove(x, y float32) {
	simra.LogDebug("[IN] CtrlUp Move!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlUpTouchListener) OnTouchEnd(x, y float32) {
	simra.LogDebug("[IN] CtrlUp End")
	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initCtrlUp() {
	// set size of CtrlUp
	self.ctrlup.W = float32(120)
	self.ctrlup.H = float32(120)

	// put CtrlUp on left bottom
	self.ctrlup.X = (self.ctrlup.W / 2) + CTRL_MARGIN_LEFT
	self.ctrlup.Y = CTRL_MARGIN_BOTTOM + self.ctrldown.H + CTRL_MARGIN_BETWEEN + (self.ctrlup.H / 2)

	// add sprite to glpeer
	simra.GetInstance().AddSprite("arrow.png",
		image.Rect(0, 0, int(self.ctrlup.W), int(self.ctrlup.H)),
		&self.ctrlup)

	// add touch listener for sprite
	self.ctrlup.AddTouchListener(&CtrlUpTouchListener{})
}

// CtrlDown
type CtrlDownTouchListener struct {
}

func (self *CtrlDownTouchListener) OnTouchBegin(x, y float32) {
	simra.LogDebug("[IN] CtrlDown Begin!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlDownTouchListener) OnTouchMove(x, y float32) {
	simra.LogDebug("[IN] CtrlDown Move!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlDownTouchListener) OnTouchEnd(x, y float32) {
	simra.LogDebug("[IN] CtrlDown End")
	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initCtrlDown() {
	// set size of CtrlDown
	self.ctrldown.W = float32(120)
	self.ctrldown.H = float32(120)

	// put CtrlDown on left bottom
	self.ctrldown.X = (self.ctrldown.W / 2) + CTRL_MARGIN_LEFT
	self.ctrldown.Y = CTRL_MARGIN_BOTTOM + (self.ctrldown.H / 2)

	// rotate arrow to indicate down control
	self.ctrldown.R = math.Pi

	// add sprite to glpeer
	simra.GetInstance().AddSprite("arrow.png",
		image.Rect(0, 0, int(self.ctrldown.W), int(self.ctrldown.H)),
		&self.ctrldown)

	// add touch listener for sprite
	self.ctrldown.AddTouchListener(&CtrlDownTouchListener{})
}

var degree float32 = 0

func (self *CtrlTrial) Drive() {
	degree += 1
	if degree >= 360 {
		degree = 0
	}
	self.ball.R = float32(degree) * math.Pi / 180
}
<commit_msg>[#23] define buttonState variable to represent which button is pressed<commit_after>package scene

import (
	"image"
	"math"

	"github.com/pankona/gomo-simra/examples/sample2/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

type CtrlTrial struct {
	ball     simra.Sprite
	ctrlup   simra.Sprite
	ctrldown simra.Sprite

	// buttonState represents which ctrl is pressed (or no ctrl pressed)
	buttonState int
}

const (
	CTRL_NOP = iota
	CTRL_UP
	CTRL_DOWN
)

func (self *CtrlTrial) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)

	// initialize sprites
	self.initSprites()

	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initSprites() {
	self.initBall()
	self.initCtrlDown()
	self.initCtrlUp()
}

func (self *CtrlTrial) initBall() {
	// set size of ball
	self.ball.W = float32(48)
	self.ball.H = float32(48)

	// put center of screen at start
	self.ball.X = config.SCREEN_WIDTH / 2
	self.ball.Y = config.SCREEN_HEIGHT / 2

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(self.ball.W), int(self.ball.H)),
		&self.ball)
}

const (
	CTRL_MARGIN_LEFT    = 10
	CTRL_MARGIN_BOTTOM  = 10
	CTRL_MARGIN_BETWEEN = 10
)

// CtrlUp
type CtrlUpTouchListener struct {
	parent *CtrlTrial
}

func (self *CtrlUpTouchListener) OnTouchBegin(x, y float32) {
	simra.LogDebug("[IN] CtrlUp Begin!")

	// TODO: update buttonState
	//ctrl := self.parent

	simra.LogDebug("[OUT]")
}

func (self *CtrlUpTouchListener) OnTouchMove(x, y float32) {
	simra.LogDebug("[IN] CtrlUp Move!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlUpTouchListener) OnTouchEnd(x, y float32) {
	simra.LogDebug("[IN] CtrlUp End")

	// TODO: update buttonState
	//ctrl := self.parent

	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initCtrlUp() {
	// set size of CtrlUp
	self.ctrlup.W = float32(120)
	self.ctrlup.H = float32(120)

	// put CtrlUp on left bottom
	self.ctrlup.X = (self.ctrlup.W / 2) + CTRL_MARGIN_LEFT
	self.ctrlup.Y = CTRL_MARGIN_BOTTOM + self.ctrldown.H + CTRL_MARGIN_BETWEEN + (self.ctrlup.H / 2)

	// add sprite to glpeer
	simra.GetInstance().AddSprite("arrow.png",
		image.Rect(0, 0, int(self.ctrlup.W), int(self.ctrlup.H)),
		&self.ctrlup)

	// add touch listener for sprite
	ctrlup := &CtrlUpTouchListener{}
	self.ctrlup.AddTouchListener(ctrlup)
	ctrlup.parent = self
}

// CtrlDown
type CtrlDownTouchListener struct {
	parent *CtrlTrial
}

func (self *CtrlDownTouchListener) OnTouchBegin(x, y float32) {
	simra.LogDebug("[IN] CtrlDown Begin!")

	// TODO: update buttonState
	//ctrl := self.parent

	simra.LogDebug("[OUT]")
}

func (self *CtrlDownTouchListener) OnTouchMove(x, y float32) {
	simra.LogDebug("[IN] CtrlDown Move!")
	simra.LogDebug("[OUT]")
}

func (self *CtrlDownTouchListener) OnTouchEnd(x, y float32) {
	simra.LogDebug("[IN] CtrlDown End")

	// TODO: update buttonState
	//ctrl := self.parent

	simra.LogDebug("[OUT]")
}

func (self *CtrlTrial) initCtrlDown() {
	// set size of CtrlDown
	self.ctrldown.W = float32(120)
	self.ctrldown.H = float32(120)

	// put CtrlDown on left bottom
	self.ctrldown.X = (self.ctrldown.W / 2) + CTRL_MARGIN_LEFT
	self.ctrldown.Y = CTRL_MARGIN_BOTTOM + (self.ctrldown.H / 2)

	// rotate arrow to indicate down control
	self.ctrldown.R = math.Pi

	// add sprite to glpeer
	simra.GetInstance().AddSprite("arrow.png",
		image.Rect(0, 0, int(self.ctrldown.W), int(self.ctrldown.H)),
		&self.ctrldown)

	// add touch listener for sprite
	ctrldown := &CtrlDownTouchListener{}
	self.ctrldown.AddTouchListener(ctrldown)
	ctrldown.parent = self
}

var degree float32 = 0

func (self *CtrlTrial) Drive() {
	degree += 1
	if degree >= 360 {
		degree = 0
	}

	// TODO: move ball according to buttonState

	self.ball.R = float32(degree) * math.Pi / 180
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// GitPodsRunner builds, runs, stops and restarts GitPods.
type GitPodsRunner struct {
	name    string
	env     []string
	cmd     *exec.Cmd
	restart chan bool
}

func NewGitPodsRunner(name string, env []string) *GitPodsRunner {
	return &GitPodsRunner{
		name:    name,
		env:     env,
		restart: make(chan bool, 16),
	}
}

func (r *GitPodsRunner) Name() string {
	return r.name
}

func (r *GitPodsRunner) Run() error {
	if err := r.Build(); err == nil {
		r.restart <- true
	}

	for {
		_, more := <-r.restart
		if more {
			if r.cmd != nil {
				r.Stop()
			}

			go func() {
				r.cmd = exec.Command("./dev/" + r.name)
				r.cmd.Env = r.env
				r.cmd.Stdin = os.Stdin
				r.cmd.Stdout = os.Stdout
				r.cmd.Stderr = os.Stderr
				r.cmd.Run()
			}()
		} else {
			return nil
		}
	}
	return nil
}

func (r *GitPodsRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

func (r *GitPodsRunner) Build() error {
	cmd := exec.Command("go", "build", "-v", "-i", "-o", "./dev/"+r.name, "./cmd/"+r.name)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	fmt.Println(strings.Join(cmd.Args, " "))

	return cmd.Run()
}

func (r *GitPodsRunner) Restart() {
	r.restart <- true
}

func (r *GitPodsRunner) Shutdown() {
	close(r.restart)
	r.Stop()
}

// CaddyRunner runs caddy
type CaddyRunner struct {
	cmd *exec.Cmd
}

func (r *CaddyRunner) Run() error {
	r.cmd = exec.Command(filepath.Join(".", "dev", "caddy"), "-conf", "./dev/Caddyfile")
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *CaddyRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}
<commit_msg>Compile statically with gitpods dev and without -i flag now<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// GitPodsRunner builds, runs, stops and restarts GitPods.
type GitPodsRunner struct {
	name    string
	env     []string
	cmd     *exec.Cmd
	restart chan bool
}

func NewGitPodsRunner(name string, env []string) *GitPodsRunner {
	return &GitPodsRunner{
		name:    name,
		env:     env,
		restart: make(chan bool, 16),
	}
}

func (r *GitPodsRunner) Name() string {
	return r.name
}

func (r *GitPodsRunner) Run() error {
	if err := r.Build(); err == nil {
		r.restart <- true
	}

	for {
		_, more := <-r.restart
		if more {
			if r.cmd != nil {
				r.Stop()
			}

			go func() {
				r.cmd = exec.Command("./dev/" + r.name)
				r.cmd.Env = r.env
				r.cmd.Stdin = os.Stdin
				r.cmd.Stdout = os.Stdout
				r.cmd.Stderr = os.Stderr
				r.cmd.Run()
			}()
		} else {
			return nil
		}
	}
	return nil
}

func (r *GitPodsRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}

func (r *GitPodsRunner) Build() error {
	cmd := exec.Command("go", "build", "-v", "-ldflags", "-w -extldflags '-static'", "-o", "./dev/"+r.name, "./cmd/"+r.name)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	fmt.Println(strings.Join(cmd.Args, " "))

	return cmd.Run()
}

func (r *GitPodsRunner) Restart() {
	r.restart <- true
}

func (r *GitPodsRunner) Shutdown() {
	close(r.restart)
	r.Stop()
}

// CaddyRunner runs caddy
type CaddyRunner struct {
	cmd *exec.Cmd
}

func (r *CaddyRunner) Run() error {
	r.cmd = exec.Command(filepath.Join(".", "dev", "caddy"), "-conf", "./dev/Caddyfile")
	r.cmd.Stdin = os.Stdin
	r.cmd.Stdout = os.Stdout
	r.cmd.Stderr = os.Stderr

	return r.cmd.Run()
}

func (r *CaddyRunner) Stop() {
	if r.cmd == nil || r.cmd.Process == nil {
		return
	}
	r.cmd.Process.Kill()
}
<|endoftext|>


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

// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
// files named $GOROOT/doc/codewalk/*.xml.
// For an example and a description of the format, see
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
// and see http://localhost:6060/doc/codewalk/codewalk .
// That page is itself a codewalk; the source code for it is
// $GOROOT/doc/codewalk/codewalk.xml.

package main

import (
	"log"
	"net/http"
	"text/template"

	"code.google.com/p/go.tools/godoc"
	"code.google.com/p/go.tools/godoc/vfs"
)

var (
	pres *godoc.Presentation
	fs   = vfs.NameSpace{}
)

func registerHandlers(pres *godoc.Presentation) {
	if pres == nil {
		panic("nil Presentation")
	}
	http.HandleFunc("/doc/codewalk/", codewalk)
	http.Handle("/doc/play/", pres.FileServer())
	http.Handle("/robots.txt", pres.FileServer())
	http.Handle("/", pres)
}

func readTemplate(name string) *template.Template {
	if pres == nil {
		panic("no global Presentation set yet")
	}
	path := "lib/godoc/" + name

	// use underlying file system fs to read the template file
	// (cannot use template ParseFile functions directly)
	data, err := vfs.ReadFile(fs, path)
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	// be explicit with errors (for app engine use)
	t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	return t
}

func readTemplates(p *godoc.Presentation) {
	// have to delay until after flags processing since paths depend on goroot
	codewalkHTML = readTemplate("codewalk.html")
	codewalkdirHTML = readTemplate("codewalkdir.html")
	p.DirlistHTML = readTemplate("dirlist.html")
	p.ErrorHTML = readTemplate("error.html")
	p.ExampleHTML = readTemplate("example.html")
	p.GodocHTML = readTemplate("godoc.html")
	p.PackageHTML = readTemplate("package.html")
	p.PackageText = readTemplate("package.txt")
	p.SearchHTML = readTemplate("search.html")
	p.SearchText = readTemplate("search.txt")
	p.SearchDescXML = readTemplate("opensearch.xml")
}
<commit_msg>go.tools/cmd/godoc: redirect old pkg/cmd paths<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
// files named $GOROOT/doc/codewalk/*.xml.
// For an example and a description of the format, see
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
// and see http://localhost:6060/doc/codewalk/codewalk .
// That page is itself a codewalk; the source code for it is
// $GOROOT/doc/codewalk/codewalk.xml.

package main

import (
	"log"
	"net/http"
	"text/template"

	"code.google.com/p/go.tools/godoc"
	"code.google.com/p/go.tools/godoc/vfs"
)

var (
	pres *godoc.Presentation
	fs   = vfs.NameSpace{}
)

func registerHandlers(pres *godoc.Presentation) {
	if pres == nil {
		panic("nil Presentation")
	}
	http.HandleFunc("/doc/codewalk/", codewalk)
	http.Handle("/doc/play/", pres.FileServer())
	http.Handle("/robots.txt", pres.FileServer())
	http.Handle("/", pres)
	handlePathRedirects(pkgRedirects, "/pkg/")
	handlePathRedirects(cmdRedirects, "/cmd/")
}

func readTemplate(name string) *template.Template {
	if pres == nil {
		panic("no global Presentation set yet")
	}
	path := "lib/godoc/" + name

	// use underlying file system fs to read the template file
	// (cannot use template ParseFile functions directly)
	data, err := vfs.ReadFile(fs, path)
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	// be explicit with errors (for app engine use)
	t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
	if err != nil {
		log.Fatal("readTemplate: ", err)
	}
	return t
}

func readTemplates(p *godoc.Presentation) {
	// have to delay until after flags processing since paths depend on goroot
	codewalkHTML = readTemplate("codewalk.html")
	codewalkdirHTML = readTemplate("codewalkdir.html")
	p.DirlistHTML = readTemplate("dirlist.html")
	p.ErrorHTML = readTemplate("error.html")
	p.ExampleHTML = readTemplate("example.html")
	p.GodocHTML = readTemplate("godoc.html")
	p.PackageHTML = readTemplate("package.html")
	p.PackageText = readTemplate("package.txt")
	p.SearchHTML = readTemplate("search.html")
	p.SearchText = readTemplate("search.txt")
	p.SearchDescXML = readTemplate("opensearch.xml")
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"govet":     "vet",
	"goyacc":    "yacc",
}

func handlePathRedirects(redirects map[string]string, prefix string) {
	for source, target := range pkgRedirects {
		h := makeRedirectHandler(prefix + target + "/")
		p := prefix + source
		http.HandleFunc(p, h)
		http.HandleFunc(p+"/", h)
	}
}

func makeRedirectHandler(target string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The hgo 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 (
	"archive/tar"
	"archive/zip"
	"bytes"
	"compress/gzip"
	"io"
	"os"
	"strings"
	"time"

	"github.com/beyang/hgo/changelog"
	"github.com/beyang/hgo/revlog"
	"github.com/beyang/hgo/store"
)

var cmdArchive = &Command{
	UsageLine: "archive [-R dir] [-r rev] [-t type] [dest]",
	Short:     "extract all files of the project at a certain revision",
	Long:      ``,
}

var archiveType = cmdArchive.Flag.String("t", "files", "type of archive to be created")

const archTemplate = `repo: {{(.Index.Record 0).Id.Node}}
node: {{.Id}}
branch: {{if .Branch}}{{.Branch}}{{else}}default{{end}}
{{with .LatestTag (tags)}}{{range .Names}}latesttag: {{.}}
{{end}}latesttagdistance: {{.Distance}}
{{end}}`

func init() {
	addStdFlags(cmdArchive)
	addRevFlag(cmdArchive)
	cmdArchive.Run = runArchive
}

type archiver interface {
	createFile(name string, mode int, sz int64, mTime time.Time) (io.Writer, error)
	symlink(name, target string, mTime time.Time) error
	Close() error
}

var amap = map[string]func(dest string) (archiver, string, error){
	"tar": newTarArchiver,
	"tgz": newTarGzipArchiver,
	"zip": newZipArchiver,
}

func runArchive(cmd *Command, w io.Writer, args []string) {
	openRepository(args)
	rs := getRevisionSpec()
	b := revlog.NewFileBuilder()
	c, err := getChangeset(rs, b)
	if err != nil {
		fatalf("%s", err)
	}

	var ent *store.ManifestEnt
	link := revlog.NewLinkRevSpec(int(c.Linkrev))
	link.FindPresent = func(rlist []*revlog.Rec) (index int, err error) {
		index, err = findPresentByNodeId(ent, rlist)
		return
	}

	mm, err := getManifest(link.Rev, c.ManifestNode, b)
	if err != nil {
		fatalf("%s", err)
	}
	st := repo.NewStore()

	fileArg := getFileArg(args)

	newArchive, ok := amap[*archiveType]
	if !ok {
		fatalf("unknown archive type: %s", *archiveType)
	}
	a, pathPfx, err := newArchive(fileArg)
	if err != nil {
		fatalf("%s", err)
	}

	err = createArchivalTxt(a, pathPfx, c)
	if err != nil {
		fatalf("%s", err)
	}
	pathPfx += "/"

	for i := range mm {
		ent = &mm[i]

		f, err := st.OpenRevlog(ent.FileName)
		if err != nil {
			fatalf("%s", err)
		}
		r, err := link.Lookup(f)
		if err != nil {
			fatalf("%s", err)
		}

		name := pathPfx + ent.FileName
		if ent.IsLink() {
			buf, err := b.Build(r)
			if err != nil {
				fatalf("%s", err)
			}
			err = a.symlink(name, string(buf), c.Date)
			if err != nil {
				fatalf("%s", err)
			}
		} else {
			var mode int
			if ent.IsExecutable() {
				mode = 0755
			} else {
				mode = 0644
			}
			p, err := b.PreparePatch(r)
			if err != nil {
				fatalf("%s", err)
			}

			w, err := a.createFile(name, mode, int64(r.FileLength)-int64(len(p.MetaData)), c.Date)
			if err != nil {
				fatalf("%s", err)
			}
			err = p.Apply(w)
			if err != nil {
				fatalf("%s", err)
			}
		}
	}
	err = a.Close()
	if err != nil {
		fatalf("%s", err)
	}
}

func createArchivalTxt(a archiver, pathPrefix string, c *changelog.Entry) (err error) {
	t, err := setupLogTemplate(archTemplate, globalTags.ById)
	if err != nil {
		return
	}
	var b bytes.Buffer
	err = t.Execute(&b, c)
	if err != nil {
		return
	}
	w, err := a.createFile(pathPrefix+"/.hg_archival.txt", 0644, int64(b.Len()), c.Date)
	if err != nil {
		return
	}
	_, err = b.WriteTo(w)
	return
}

type tarArchiver struct {
	*tar.Writer
	file io.WriteCloser
	h    tar.Header
}

func newTarArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	a = &tarArchiver{Writer: tar.NewWriter(f), file: f}
	pathPfx = stripExt(dest, ".tar")
	return
}

func (a *tarArchiver) createFile(name string, mode int, sz int64, mTime time.Time) (w io.Writer, err error) {
	hdr := a.initHeader(name, mode, mTime)
	hdr.Typeflag = tar.TypeReg
	hdr.Size = sz
	w = a.Writer
	err = a.WriteHeader(hdr)
	return
}

func (a *tarArchiver) symlink(name, target string, mTime time.Time) (err error) {
	hdr := a.initHeader(name, 0777, mTime)
	hdr.Typeflag = tar.TypeSymlink
	hdr.Linkname = target
	err = a.WriteHeader(hdr)
	return
}

func (a *tarArchiver) initHeader(name string, mode int, mTime time.Time) (hdr *tar.Header) {
	a.h = tar.Header{ /*Uname: "root", Gname: "root"*/}
	hdr = &a.h
	hdr.Name = name
	hdr.ModTime = mTime
	hdr.Mode = int64(mode)
	return
}

func (a *tarArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.file.Close()
	}
	return
}

type tarGzipArchiver struct {
	tarArchiver
	zf io.Closer
}

func newTarGzipArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	zf := gzip.NewWriter(f)
	a = &tarGzipArchiver{tarArchiver: tarArchiver{Writer: tar.NewWriter(zf), file: f}, zf: zf}
	pathPfx = stripExt(dest, ".tar.gz")
	pathPfx = stripExt(pathPfx, ".tgz")
	return
}

func (a *tarGzipArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.zf.Close()
		if err == nil {
			err = a.file.Close()
		}
	}
	return
}

type zipArchiver struct {
	*zip.Writer
	file io.WriteCloser
	h    zip.FileHeader
}

func newZipArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	a = &zipArchiver{Writer: zip.NewWriter(f), file: f}
	pathPfx = stripExt(dest, ".zip")
	return
}

func (a *zipArchiver) createFile(name string, mode int, sz int64, mTime time.Time) (w io.Writer, err error) {
	hdr := a.initHeader(name, os.FileMode(mode), mTime)
	hdr.UncompressedSize64 = uint64(sz)
	w, err = a.CreateHeader(hdr)
	return
}

func (a *zipArchiver) symlink(name, target string, mTime time.Time) (err error) {
	hdr := a.initHeader(name, 0777|os.ModeSymlink, mTime)
	w, err := a.CreateHeader(hdr)
	if err != nil {
		return
	}
	w.Write([]byte(target))
	return
}

func (a *zipArchiver) initHeader(name string, mode os.FileMode, mTime time.Time) (hdr *zip.FileHeader) {
	hdr = new(zip.FileHeader)
	hdr.Name = name
	hdr.SetModTime(mTime)
	hdr.SetMode(os.FileMode(mode))
	hdr.Method = zip.Deflate
	return
}

func (a *zipArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.file.Close()
	}
	return
}

func stripExt(fileName, ext string) (baseName string) {
	if strings.HasSuffix(fileName, ext) {
		baseName = fileName[:len(fileName)-len(ext)]
	} else {
		baseName = fileName
	}
	return
}
<commit_msg>Fix gofmt formatting.<commit_after>// Copyright 2013 The hgo 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 (
	"archive/tar"
	"archive/zip"
	"bytes"
	"compress/gzip"
	"io"
	"os"
	"strings"
	"time"

	"github.com/beyang/hgo/changelog"
	"github.com/beyang/hgo/revlog"
	"github.com/beyang/hgo/store"
)

var cmdArchive = &Command{
	UsageLine: "archive [-R dir] [-r rev] [-t type] [dest]",
	Short:     "extract all files of the project at a certain revision",
	Long:      ``,
}

var archiveType = cmdArchive.Flag.String("t", "files", "type of archive to be created")

const archTemplate = `repo: {{(.Index.Record 0).Id.Node}}
node: {{.Id}}
branch: {{if .Branch}}{{.Branch}}{{else}}default{{end}}
{{with .LatestTag (tags)}}{{range .Names}}latesttag: {{.}}
{{end}}latesttagdistance: {{.Distance}}
{{end}}`

func init() {
	addStdFlags(cmdArchive)
	addRevFlag(cmdArchive)
	cmdArchive.Run = runArchive
}

type archiver interface {
	createFile(name string, mode int, sz int64, mTime time.Time) (io.Writer, error)
	symlink(name, target string, mTime time.Time) error
	Close() error
}

var amap = map[string]func(dest string) (archiver, string, error){
	"tar": newTarArchiver,
	"tgz": newTarGzipArchiver,
	"zip": newZipArchiver,
}

func runArchive(cmd *Command, w io.Writer, args []string) {
	openRepository(args)
	rs := getRevisionSpec()
	b := revlog.NewFileBuilder()
	c, err := getChangeset(rs, b)
	if err != nil {
		fatalf("%s", err)
	}

	var ent *store.ManifestEnt
	link := revlog.NewLinkRevSpec(int(c.Linkrev))
	link.FindPresent = func(rlist []*revlog.Rec) (index int, err error) {
		index, err = findPresentByNodeId(ent, rlist)
		return
	}

	mm, err := getManifest(link.Rev, c.ManifestNode, b)
	if err != nil {
		fatalf("%s", err)
	}
	st := repo.NewStore()

	fileArg := getFileArg(args)

	newArchive, ok := amap[*archiveType]
	if !ok {
		fatalf("unknown archive type: %s", *archiveType)
	}
	a, pathPfx, err := newArchive(fileArg)
	if err != nil {
		fatalf("%s", err)
	}

	err = createArchivalTxt(a, pathPfx, c)
	if err != nil {
		fatalf("%s", err)
	}
	pathPfx += "/"

	for i := range mm {
		ent = &mm[i]

		f, err := st.OpenRevlog(ent.FileName)
		if err != nil {
			fatalf("%s", err)
		}
		r, err := link.Lookup(f)
		if err != nil {
			fatalf("%s", err)
		}

		name := pathPfx + ent.FileName
		if ent.IsLink() {
			buf, err := b.Build(r)
			if err != nil {
				fatalf("%s", err)
			}
			err = a.symlink(name, string(buf), c.Date)
			if err != nil {
				fatalf("%s", err)
			}
		} else {
			var mode int
			if ent.IsExecutable() {
				mode = 0755
			} else {
				mode = 0644
			}
			p, err := b.PreparePatch(r)
			if err != nil {
				fatalf("%s", err)
			}

			w, err := a.createFile(name, mode, int64(r.FileLength)-int64(len(p.MetaData)), c.Date)
			if err != nil {
				fatalf("%s", err)
			}
			err = p.Apply(w)
			if err != nil {
				fatalf("%s", err)
			}
		}
	}
	err = a.Close()
	if err != nil {
		fatalf("%s", err)
	}
}

func createArchivalTxt(a archiver, pathPrefix string, c *changelog.Entry) (err error) {
	t, err := setupLogTemplate(archTemplate, globalTags.ById)
	if err != nil {
		return
	}
	var b bytes.Buffer
	err = t.Execute(&b, c)
	if err != nil {
		return
	}
	w, err := a.createFile(pathPrefix+"/.hg_archival.txt", 0644, int64(b.Len()), c.Date)
	if err != nil {
		return
	}
	_, err = b.WriteTo(w)
	return
}

type tarArchiver struct {
	*tar.Writer
	file io.WriteCloser
	h    tar.Header
}

func newTarArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	a = &tarArchiver{Writer: tar.NewWriter(f), file: f}
	pathPfx = stripExt(dest, ".tar")
	return
}

func (a *tarArchiver) createFile(name string, mode int, sz int64, mTime time.Time) (w io.Writer, err error) {
	hdr := a.initHeader(name, mode, mTime)
	hdr.Typeflag = tar.TypeReg
	hdr.Size = sz
	w = a.Writer
	err = a.WriteHeader(hdr)
	return
}

func (a *tarArchiver) symlink(name, target string, mTime time.Time) (err error) {
	hdr := a.initHeader(name, 0777, mTime)
	hdr.Typeflag = tar.TypeSymlink
	hdr.Linkname = target
	err = a.WriteHeader(hdr)
	return
}

func (a *tarArchiver) initHeader(name string, mode int, mTime time.Time) (hdr *tar.Header) {
	a.h = tar.Header{ /*Uname: "root", Gname: "root"*/ }
	hdr = &a.h
	hdr.Name = name
	hdr.ModTime = mTime
	hdr.Mode = int64(mode)
	return
}

func (a *tarArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.file.Close()
	}
	return
}

type tarGzipArchiver struct {
	tarArchiver
	zf io.Closer
}

func newTarGzipArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	zf := gzip.NewWriter(f)
	a = &tarGzipArchiver{tarArchiver: tarArchiver{Writer: tar.NewWriter(zf), file: f}, zf: zf}
	pathPfx = stripExt(dest, ".tar.gz")
	pathPfx = stripExt(pathPfx, ".tgz")
	return
}

func (a *tarGzipArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.zf.Close()
		if err == nil {
			err = a.file.Close()
		}
	}
	return
}

type zipArchiver struct {
	*zip.Writer
	file io.WriteCloser
	h    zip.FileHeader
}

func newZipArchiver(dest string) (a archiver, pathPfx string, err error) {
	f, err := os.Create(dest)
	if err != nil {
		return
	}
	a = &zipArchiver{Writer: zip.NewWriter(f), file: f}
	pathPfx = stripExt(dest, ".zip")
	return
}

func (a *zipArchiver) createFile(name string, mode int, sz int64, mTime time.Time) (w io.Writer, err error) {
	hdr := a.initHeader(name, os.FileMode(mode), mTime)
	hdr.UncompressedSize64 = uint64(sz)
	w, err = a.CreateHeader(hdr)
	return
}

func (a *zipArchiver) symlink(name, target string, mTime time.Time) (err error) {
	hdr := a.initHeader(name, 0777|os.ModeSymlink, mTime)
	w, err := a.CreateHeader(hdr)
	if err != nil {
		return
	}
	w.Write([]byte(target))
	return
}

func (a *zipArchiver) initHeader(name string, mode os.FileMode, mTime time.Time) (hdr *zip.FileHeader) {
	hdr = new(zip.FileHeader)
	hdr.Name = name
	hdr.SetModTime(mTime)
	hdr.SetMode(os.FileMode(mode))
	hdr.Method = zip.Deflate
	return
}

func (a *zipArchiver) close() (err error) {
	err = a.Writer.Close()
	if err == nil {
		err = a.file.Close()
	}
	return
}

func stripExt(fileName, ext string) (baseName string) {
	if strings.HasSuffix(fileName, ext) {
		baseName = fileName[:len(fileName)-len(ext)]
	} else {
		baseName = fileName
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct {
	testing.FakeHomeSuite
}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHomeEnvKey+"="+osenv.JujuHome())
	output, err := ps.CombinedOutput()
	c.Logf("command output: %q", output)
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// osenv.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
'
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := osenv.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return `cannot parse "[^"]*": YAML error.*`
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"authorised-keys",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-machine",  // alias for destroy-machine
	"remove-relation", // alias for destroy-relation
	"remove-service",  // alias for destroy-service
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"run",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"unset",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"azure-provider",
	"basics",
	"commands",
	"constraints",
	"ec2-provider",
	"global-options",
	"glossary",
	"hpcloud-provider",
	"local-provider",
	"logging",
	"openstack-provider",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-file .*",
	"--logging-config .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<commit_msg>Add quiet flag to the test.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	stdtesting "testing"

	"launchpad.net/gnuflag"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/juju/osenv"
	_ "launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
)

func TestPackage(t *stdtesting.T) {
	testing.MgoTestPackage(t)
}

type MainSuite struct {
	testing.FakeHomeSuite
}

var _ = gc.Suite(&MainSuite{})

var (
	flagRunMain = flag.Bool("run-main", false, "Run the application's main function for recursive testing")
)

// Reentrancy point for testing (something as close as possible to) the juju
// tool itself.
func TestRunMain(t *stdtesting.T) {
	if *flagRunMain {
		Main(flag.Args())
	}
}

func badrun(c *gc.C, exit int, args ...string) string {
	localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--", "juju"}, args...)
	ps := exec.Command(os.Args[0], localArgs...)
	ps.Env = append(os.Environ(), osenv.JujuHomeEnvKey+"="+osenv.JujuHome())
	output, err := ps.CombinedOutput()
	c.Logf("command output: %q", output)
	if exit != 0 {
		c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit))
	}
	return string(output)
}

func helpText(command cmd.Command, name string) string {
	buff := &bytes.Buffer{}
	info := command.Info()
	info.Name = name
	f := gnuflag.NewFlagSet(info.Name, gnuflag.ContinueOnError)
	command.SetFlags(f)
	buff.Write(info.Help(f))
	return buff.String()
}

func deployHelpText() string {
	return helpText(&DeployCommand{}, "juju deploy")
}

func syncToolsHelpText() string {
	return helpText(&SyncToolsCommand{}, "juju sync-tools")
}

func (s *MainSuite) TestRunMain(c *gc.C) {
	defer testing.MakeSampleHome(c).Restore()
	// The test array structure needs to be inline here as some of the
	// expected values below use deployHelpText().  This constructs the deploy
	// command and runs gets the help for it.  When the deploy command is
	// setting the flags (which is needed for the help text) it is accessing
	// osenv.JujuHome(), which panics if SetJujuHome has not been called.
	// The FakeHome from testing does this.
	for i, t := range []struct {
		summary string
		args    []string
		code    int
		out     string
	}{{
		summary: "no params shows help",
		args:    []string{},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help is the same as juju",
		args:    []string{"help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju --help works too",
		args:    []string{"--help"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help basics is the same as juju",
		args:    []string{"help", "basics"},
		code:    0,
		out:     strings.TrimLeft(helpBasics, "\n"),
	}, {
		summary: "juju help foo doesn't exist",
		args:    []string{"help", "foo"},
		code:    1,
		out:     "ERROR unknown command or topic for foo\n",
	}, {
		summary: "juju help deploy shows the default help without global options",
		args:    []string{"help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju --help deploy shows the same help as 'help deploy'",
		args:    []string{"--help", "deploy"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "juju deploy --help shows the same help as 'help deploy'",
		args:    []string{"deploy", "--help"},
		code:    0,
		out:     deployHelpText(),
	}, {
		summary: "unknown command",
		args:    []string{"discombobulate"},
		code:    1,
		out:     "ERROR unrecognized command: juju discombobulate\n",
	}, {
		summary: "unknown option before command",
		args:    []string{"--cheese", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "unknown option after command",
		args:    []string{"bootstrap", "--cheese"},
		code:    2,
		out:     "error: flag provided but not defined: --cheese\n",
	}, {
		summary: "known option, but specified before command",
		args:    []string{"--environment", "blah", "bootstrap"},
		code:    2,
		out:     "error: flag provided but not defined: --environment\n",
	}, {
		summary: "juju sync-tools registered properly",
		args:    []string{"sync-tools", "--help"},
		code:    0,
		out:     syncToolsHelpText(),
	}, {
		summary: "check version command registered properly",
		args:    []string{"version"},
		code:    0,
		out:     version.Current.String() + "\n",
	},
	} {
		c.Logf("test %d: %s", i, t.summary)
		out := badrun(c, t.code, t.args...)
		c.Assert(out, gc.Equals, t.out)
	}
}

var brokenConfig = `
'
`

// breakJuju writes a dummy environment with incomplete configuration.
// environMethod is called.
func breakJuju(c *gc.C, environMethod string) (msg string) {
	path := osenv.JujuHomePath("environments.yaml")
	err := ioutil.WriteFile(path, []byte(brokenConfig), 0666)
	c.Assert(err, gc.IsNil)
	return `cannot parse "[^"]*": YAML error.*`
}

func (s *MainSuite) TestActualRunJujuArgsBeforeCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified before command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "--log-file", logpath, "bootstrap")
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

func (s *MainSuite) TestActualRunJujuArgsAfterCommand(c *gc.C) {
	c.Skip("breaks test isolation: lp:1233601")
	defer testing.MakeFakeHomeNoEnvironments(c, "one").Restore()
	// Check global args work when specified after command
	msg := breakJuju(c, "Bootstrap")
	logpath := filepath.Join(c.MkDir(), "log")
	out := badrun(c, 1, "bootstrap", "--log-file", logpath)
	fullmsg := fmt.Sprintf(`(.|\n)*ERROR .*%s\n`, msg)
	c.Assert(out, gc.Matches, fullmsg)
	content, err := ioutil.ReadFile(logpath)
	c.Assert(err, gc.IsNil)
	c.Assert(string(content), gc.Matches, fullmsg)
}

var commandNames = []string{
	"add-machine",
	"add-relation",
	"add-unit",
	"api-endpoints",
	"authorised-keys",
	"bootstrap",
	"debug-hooks",
	"debug-log",
	"deploy",
	"destroy-environment",
	"destroy-machine",
	"destroy-relation",
	"destroy-service",
	"destroy-unit",
	"env", // alias for switch
	"expose",
	"generate-config", // alias for init
	"get",
	"get-constraints",
	"get-env", // alias for get-environment
	"get-environment",
	"help",
	"help-tool",
	"init",
	"publish",
	"remove-machine",  // alias for destroy-machine
	"remove-relation", // alias for destroy-relation
	"remove-service",  // alias for destroy-service
	"remove-unit",     // alias for destroy-unit
	"resolved",
	"run",
	"scp",
	"set",
	"set-constraints",
	"set-env", // alias for set-environment
	"set-environment",
	"ssh",
	"stat", // alias for status
	"status",
	"switch",
	"sync-tools",
	"terminate-machine", // alias for destroy-machine
	"unexpose",
	"unset",
	"upgrade-charm",
	"upgrade-juju",
	"version",
}

func (s *MainSuite) TestHelpCommands(c *gc.C) {
	// Check that we have correctly registered all the commands
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "commands")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, commandNames)
}

var topicNames = []string{
	"azure-provider",
	"basics",
	"commands",
	"constraints",
	"ec2-provider",
	"global-options",
	"glossary",
	"hpcloud-provider",
	"local-provider",
	"logging",
	"openstack-provider",
	"plugins",
	"topics",
}

func (s *MainSuite) TestHelpTopics(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "topics")
	lines := strings.Split(out, "\n")
	var names []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 {
			continue
		}
		names = append(names, f[0])
	}
	// The names should be output in alphabetical order, so don't sort.
	c.Assert(names, gc.DeepEquals, topicNames)
}

var globalFlags = []string{
	"--debug .*",
	"--description .*",
	"-h, --help .*",
	"--log-file .*",
	"--logging-config .*",
	"-q, --quiet .*",
	"--show-log .*",
	"-v, --verbose .*",
}

func (s *MainSuite) TestHelpGlobalOptions(c *gc.C) {
	// Check that we have correctly registered all the topics
	// by checking the help output.
	defer osenv.SetJujuHome(osenv.SetJujuHome(c.MkDir()))
	out := badrun(c, 0, "help", "global-options")
	c.Assert(out, gc.Matches, `Global Options

These options may be used with any command, and may appear in front of any
command\.(.|\n)*`)
	lines := strings.Split(out, "\n")
	var flags []string
	for _, line := range lines {
		f := strings.Fields(line)
		if len(f) == 0 || line[0] != '-' {
			continue
		}
		flags = append(flags, line)
	}
	c.Assert(len(flags), gc.Equals, len(globalFlags))
	for i, line := range flags {
		c.Assert(line, gc.Matches, globalFlags[i])
	}
}
<|endoftext|>