<commit_before>package pagecache

import (
	"bytes"
	"net/http"
	"strings"

	"time"

	"github.com/herb-go/herb/cache"
)

var Debug bool

var PageCacheKeyHeader = "herbgo-debug-pagecache"

func New(c cache.Cacheable) *PageCache {
	p := PageCache{
		Cache:           c,
		KeyPrefix:       defaultKeyPrefix,
		StatusValidator: defualtStatusValidator,
	}
	return &p
}

type cachedPage struct {
	Status   int
	Header   map[string][]string
	Response []byte
}

type PageCache struct {
	Cache           cache.Cacheable
	KeyPrefix       string
	StatusValidator func(status int) bool
}

var defaultKeyPrefix = ""

func defualtStatusValidator(status int) bool {
	return status < 500
}
func (p *PageCache) ValidateStatus(status int) bool {
	if p.StatusValidator != nil {
		return p.StatusValidator(status)
	}
	return defualtStatusValidator(status)
}
func (p *PageCache) serve(key string, ttl time.Duration, w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	page := cachedPage{}
	err := p.Cache.Load(key, &page, ttl, func() (interface{}, error) {
		cw := cacheResponseWriter{
			writer: *(bytes.NewBuffer([]byte{})),
			header: http.Header{},
			status: 0,
		}
		next(&cw, r)
		page.Header = map[string][]string(cw.Header())
		page.Response = cw.writer.Bytes()
		page.Status = cw.status
		if p.ValidateStatus(cw.status) {
			return page, nil
		}
		return nil, cache.ErrNotCacheable
	})
	if err != nil {
		if err != cache.ErrEntryTooLarge && err != cache.ErrNotCacheable {
			panic(err)
		}
	}
	h := w.Header()
	for k, v := range page.Header {
		h[k] = v
	}
	if Debug {
		k, err := p.Cache.FinalKey(key)
		if err == nil {
			h.Set(PageCacheKeyHeader, strings.Replace(k, cache.KeyPrefix, " ", -1))
		}
	}
	if page.Status != 0 {
		w.WriteHeader(page.Status)
	}
	_, err = w.Write(page.Response)
	if err != nil {
		panic(err)
	}
}
func (p *PageCache) Middleware(keyGenerator func(r *http.Request) string, ttl time.Duration) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		key := keyGenerator(r)
		if key == "" {
			next(w, r)
			return
		}
		p.serve(p.KeyPrefix+key, ttl, w, r, next)
	}
}
func FieldMiddleware(FieldGenerator func(r *http.Request) *cache.Field, ttl time.Duration, statusValidator func(status int) bool) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		f := FieldGenerator(r)
		if f == nil {
			next(w, r)
			return
		}
		p := &PageCache{
			Cache: f.Cache,
		}
		p.serve(f.FieldName, ttl, w, r, next)
	}
}

type cacheResponseWriter struct {
	writer bytes.Buffer
	header http.Header
	status int
}

func (w *cacheResponseWriter) Write(data []byte) (int, error) {
	return w.writer.Write(data)
}
func (w *cacheResponseWriter) Header() http.Header {
	return w.header
}
func (w *cacheResponseWriter) WriteHeader(status int) {
	w.status = status
}
<commit_msg>update<commit_after>package pagecache

import (
	"bytes"
	"net/http"
	"strings"
	"sync"

	"time"

	"github.com/herb-go/herb/cache"
)

var Debug bool

var pagePool = sync.Pool{
	New: func() interface{} {
		return []byte{}
	},
}
var PageCacheKeyHeader = "herbgo-debug-pagecache"

func New(c cache.Cacheable) *PageCache {
	p := PageCache{
		Cache:           c,
		KeyPrefix:       defaultKeyPrefix,
		StatusValidator: defualtStatusValidator,
	}
	return &p
}

type cachedPage struct {
	Status   int
	Header   map[string][]string
	Response []byte
}

type PageCache struct {
	Cache           cache.Cacheable
	KeyPrefix       string
	StatusValidator func(status int) bool
}

var defaultKeyPrefix = ""

func defualtStatusValidator(status int) bool {
	return status < 500
}
func (p *PageCache) ValidateStatus(status int) bool {
	if p.StatusValidator != nil {
		return p.StatusValidator(status)
	}
	return defualtStatusValidator(status)
}
func (p *PageCache) serve(key string, ttl time.Duration, w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	page := cachedPage{
		Response: pagePool.Get().([]byte),
	}
	defer pagePool.Put(page.Response)
	err := p.Cache.Load(key, &page, ttl, func() (interface{}, error) {
		cw := cacheResponseWriter{
			writer: *(bytes.NewBuffer([]byte{})),
			header: http.Header{},
			status: 0,
		}
		next(&cw, r)
		page.Header = map[string][]string(cw.Header())
		page.Response = cw.writer.Bytes()
		page.Status = cw.status
		if p.ValidateStatus(cw.status) {
			return page, nil
		}
		return nil, cache.ErrNotCacheable
	})
	if err != nil {
		if err != cache.ErrEntryTooLarge && err != cache.ErrNotCacheable {
			panic(err)
		}
	}
	h := w.Header()
	for k, v := range page.Header {
		h[k] = v
	}
	if Debug {
		k, err := p.Cache.FinalKey(key)
		if err == nil {
			h.Set(PageCacheKeyHeader, strings.Replace(k, cache.KeyPrefix, " ", -1))
		}
	}
	if page.Status != 0 {
		w.WriteHeader(page.Status)
	}
	_, err = w.Write(page.Response)
	if err != nil {
		panic(err)
	}
}
func (p *PageCache) Middleware(keyGenerator func(r *http.Request) string, ttl time.Duration) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		key := keyGenerator(r)
		if key == "" {
			next(w, r)
			return
		}
		p.serve(p.KeyPrefix+key, ttl, w, r, next)
	}
}
func FieldMiddleware(FieldGenerator func(r *http.Request) *cache.Field, ttl time.Duration, statusValidator func(status int) bool) func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		f := FieldGenerator(r)
		if f == nil {
			next(w, r)
			return
		}
		p := &PageCache{
			Cache: f.Cache,
		}
		p.serve(f.FieldName, ttl, w, r, next)
	}
}

type cacheResponseWriter struct {
	writer bytes.Buffer
	header http.Header
	status int
}

func (w *cacheResponseWriter) Write(data []byte) (int, error) {
	return w.writer.Write(data)
}
func (w *cacheResponseWriter) Header() http.Header {
	return w.header
}
func (w *cacheResponseWriter) WriteHeader(status int) {
	w.status = status
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`testing`
)

// Initial position.
func TestEvaluate000(t *testing.T) {
	p := NewGame().Start()
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}

// After 1. e2-e4
func TestEvaluate010(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e7,f7,g7,h7`).Start(Black)
	score := p.Evaluate()
	expect(t, score, -73) // +73 for white.
}

// After 1. e2-e4 e7-e5
func TestEvaluate020(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}

// After 1. e2-e4 e7-e5 2. Ng1-f3
func TestEvaluate030(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(Black)
	score := p.Evaluate()
	expect(t, score, -74)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Ng8-f6
func TestEvaluate040(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Nf6,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, 22)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Nb8-c6
func TestEvaluate050(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nc6,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, -1)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Nb8-c6 3. Nb1-c3 Ng8-f6
func TestEvaluate060(t *testing.T) {
	p := NewGame(`Ra1,Nc3,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nc6,Bc8,Qd8,Ke8,Bf8,Nf6,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}
<commit_msg>Added opposite bishops tests<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`testing`
)

// Initial position.
func TestEvaluate000(t *testing.T) {
	p := NewGame().Start()
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}

// After 1. e2-e4
func TestEvaluate010(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e7,f7,g7,h7`).Start(Black)
	score := p.Evaluate()
	expect(t, score, -73) // +73 for white.
}

// After 1. e2-e4 e7-e5
func TestEvaluate020(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Ng1,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}

// After 1. e2-e4 e7-e5 2. Ng1-f3
func TestEvaluate030(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(Black)
	score := p.Evaluate()
	expect(t, score, -74)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Ng8-f6
func TestEvaluate040(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nb8,Bc8,Qd8,Ke8,Bf8,Nf6,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, 22)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Nb8-c6
func TestEvaluate050(t *testing.T) {
	p := NewGame(`Ra1,Nb1,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nc6,Bc8,Qd8,Ke8,Bf8,Ng8,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, -1)
}

// After 1. e2-e4 e7-e5 2. Ng1-f3 Nb8-c6 3. Nb1-c3 Ng8-f6
func TestEvaluate060(t *testing.T) {
	p := NewGame(`Ra1,Nc3,Bc1,Qd1,Ke1,Bf1,Nf3,Rh1,a2,b2,c2,d2,e4,f2,g2,h2`,
		`Ra8,Nc6,Bc8,Qd8,Ke8,Bf8,Nf6,Rh8,a7,b7,c7,d7,e5,f7,g7,h7`).Start(White)
	score := p.Evaluate()
	expect(t, score, rightToMove.midgame) // Right to move only.
}

// Opposite-colored bishops.
func TestEvaluate070(t *testing.T) {
	p := NewGame(`Ke1,Bc1`, `Ke8,Bc8`).Start(White)
	eval.init(p)
	expect(t, eval.oppositeBishops(), false)
}

func TestEvaluate080(t *testing.T) {
	p := NewGame(`Ke1,Bc1`, `Ke8,Bf8`).Start(White)
	eval.init(p)
	expect(t, eval.oppositeBishops(), true)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"os"
	"sync"
)

var factors_lock sync.RWMutex

// radix-2 factors
var factors = map[int][]complex128{
	4: {complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
}

// bluestein factors
var n2_factors = map[int][]complex128{}
var n2_inv_factors = map[int][]complex128{}

// Ensures the complex multiplication factors exist for an input array of length input_len.
func ensureFactors(input_len int) {
	var cos, sin float64

	factors_lock.Lock()

	for i, p := 8, 4; i <= input_len; i, p = i<<1, i {
		if factors[i] == nil {
			factors[i] = make([]complex128, i)

			for n, j := 0, 0; n < i; n, j = n+2, j+1 {
				factors[i][n] = factors[p][j]
			}

			for n := 1; n < i; n += 2 {
				sin, cos = math.Sincos(-2 * math.Pi / float64(i) * float64(n))
				factors[i][n] = complex(cos, sin)
			}
		}
	}

	if n2_factors[input_len] == nil {
		n2_factors[input_len] = make([]complex128, input_len)
		n2_inv_factors[input_len] = make([]complex128, input_len)

		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			n2_factors[input_len][i] = complex(cos, sin)
			n2_inv_factors[input_len][i] = complex(cos, -sin)
		}
	}

	factors_lock.Unlock()
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(toComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(toComplex(x))
}

// toComplex returns the complex equivalent of the real-valued slice.
func toComplex(x []float64) []complex128 {
	y := make([]complex128, len(x))
	for n, v := range x {
		y[n] = complex(v, 0)
	}
	return y
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) ([]complex128, os.Error) {
	if len(x) != len(y) {
		return []complex128{}, os.NewError("fft: input arrays are not of equal length")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r), nil
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if isPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	ensureFactors(lx)

	lx_2 := lx / 2
	r := make([]complex128, lx) // result
	t := make([]complex128, lx) // temp
	copy(r, x)

	// split into even and odd parts for each stage
	for block_sz := lx; block_sz > 1; block_sz >>= 1 {
		i := 0
		bs_2 := block_sz / 2
		for block := 0; block < lx/block_sz; block++ {
			for n := 0; n < bs_2; n++ {
				bn := block_sz*block + n
				t[bn] = r[i]
				i++
				t[bn+bs_2] = r[i]
				i++
			}
		}
		copy(r, t)
	}

	for stage := 2; stage <= lx; stage <<= 1 {
		if stage == 2 { // 2-point transforms
			for n := 0; n < lx_2; n++ {
				t[n*2] = r[n*2] + r[n*2+1]
				t[n*2+1] = r[n*2] - r[n*2+1]
			}
		} else { // >2-point transforms
			blocks := lx / stage
			s_2 := stage / 2

			for n := 0; n < blocks; n++ {
				nb := n * stage
				for j := 0; j < s_2; j++ {
					w_n := r[j+nb+s_2] * factors[stage][j]
					t[j+nb] = r[j+nb] + w_n
					t[j+nb+s_2] = r[j+nb] - w_n
				}
			}
		}

		copy(r, t)
	}

	return r
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := zeroPad(x, nextPowerOf2(lx*2-1))
	la := len(a)
	ensureFactors(lx)

	for n, v := range x {
		a[n] = v * n2_inv_factors[lx][n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = n2_factors[lx][i]

		if i != 0 {
			b[la-i] = n2_factors[lx][i]
		}
	}

	r, _ := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= n2_inv_factors[lx][i]
	}

	return r[:lx]
}

// isPowerOf2 returns true if x is a power of 2, else false.
func isPowerOf2(x int) bool {
	return x&(x-1) == 0
}

// nextPowerOf2 returns the next power of 2 >= x.
func nextPowerOf2(x int) int {
	if isPowerOf2(x) {
		return x
	}

	return int(math.Pow(2, math.Ceil(math.Log2(float64(x)))))
}

// zeroPad returns x with zeros appended to the end to the specified length.
// If len(x) == length, x is returned.
func zeroPad(x []complex128, length int) []complex128 {
	if len(x) == length {
		return x
	}

	r := make([]complex128, length)
	copy(r, x)
	return r
}

// zeroPad2 returns zeroPad of x, with the length as next power of 2 >= len(x).
func zeroPad2(x []complex128) []complex128 {
	return zeroPad(x, nextPowerOf2(len(x)))
}

// toComplex2 returns the complex equivalent of the real-valued matrix.
func toComplex2(x [][]float64) [][]complex128 {
	y := make([][]complex128, len(x))
	for n, v := range x {
		y[n] = toComplex(v)
	}
	return y
}

// FFT2Real returns the 2-dimensional, forward FFT of the real-valued matrix.
func FFT2Real(x [][]float64) ([][]complex128, os.Error) {
	return FFT2(toComplex2(x))
}

// FFT2 returns the 2-dimensional, forward FFT of the complex-valued matrix.
func FFT2(x [][]complex128) ([][]complex128, os.Error) {
	return computeFFT2(x, FFT)
}

// IFFT2Real returns the 2-dimensional, inverse FFT of the real-valued matrix.
func IFFT2Real(x [][]float64) ([][]complex128, os.Error) {
	return IFFT2(toComplex2(x))
}

// IFFT2 returns the 2-dimensional, inverse FFT of the complex-valued matrix.
func IFFT2(x [][]complex128) ([][]complex128, os.Error) {
	return computeFFT2(x, IFFT)
}

func computeFFT2(x [][]complex128, fftFunc func([]complex128) []complex128) ([][]complex128, os.Error) {
	rows := len(x)
	if rows == 0 {
		return nil, os.NewError("fft: empty input array")
	}

	cols := len(x[0])
	r := make([][]complex128, rows)
	for i := 0; i < rows; i++ {
		if len(x[i]) != cols {
			return nil, os.NewError("fft: input matrix must have identical row lengths")
		}
		r[i] = make([]complex128, cols)
	}

	for i := 0; i < cols; i++ {
		t := make([]complex128, rows)
		for j := 0; j < rows; j++ {
			t[j] = x[j][i]
		}

		for n, v := range fftFunc(t) {
			r[n][i] = v
		}
	}

	for n, v := range r {
		r[n] = fftFunc(v)
	}

	return r, nil
}
<commit_msg>Make factors maps thread-safe<commit_after>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"os"
	"sync"
)

var radix2Lock, bluesteinLock sync.RWMutex

// radix-2 factors
var radix2Factors = map[int][]complex128{
	4: {complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
}

// bluestein factors
var bluesteinFactors = map[int][]complex128{}
var bluesteinInvFactors = map[int][]complex128{}

func getRadix2Factors(input_len int) []complex128 {
	var cos, sin float64

	radix2Lock.RLock()

	if hasRadix2Factors(input_len) {
		defer radix2Lock.RUnlock()
		return radix2Factors[input_len]
	}

	radix2Lock.RUnlock()
	radix2Lock.Lock()
	defer radix2Lock.Unlock()

	if !hasRadix2Factors(input_len) {
		for i, p := 8, 4; i <= input_len; i, p = i<<1, i {
			if radix2Factors[i] == nil {
				radix2Factors[i] = make([]complex128, i)

				for n, j := 0, 0; n < i; n, j = n+2, j+1 {
					radix2Factors[i][n] = radix2Factors[p][j]
				}

				for n := 1; n < i; n += 2 {
					sin, cos = math.Sincos(-2 * math.Pi / float64(i) * float64(n))
					radix2Factors[i][n] = complex(cos, sin)
				}
			}
		}
	}

	return radix2Factors[input_len]
}

func hasRadix2Factors(idx int) bool {
	return radix2Factors[idx] != nil
}

func getBluesteinFactors(input_len int) ([]complex128, []complex128) {
	var cos, sin float64

	bluesteinLock.RLock()

	if hasBluesteinFactors(input_len) {
		defer bluesteinLock.RUnlock()
		return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
	}

	bluesteinLock.RUnlock()
	bluesteinLock.Lock()
	defer bluesteinLock.Unlock()

	if !hasBluesteinFactors(input_len) {
		bluesteinFactors[input_len] = make([]complex128, input_len)
		bluesteinInvFactors[input_len] = make([]complex128, input_len)

		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			bluesteinFactors[input_len][i] = complex(cos, sin)
			bluesteinInvFactors[input_len][i] = complex(cos, -sin)
		}
	}

	return bluesteinFactors[input_len], bluesteinInvFactors[input_len]
}

func hasBluesteinFactors(idx int) bool {
	return bluesteinFactors[idx] != nil
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(toComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(toComplex(x))
}

// toComplex returns the complex equivalent of the real-valued slice.
func toComplex(x []float64) []complex128 {
	y := make([]complex128, len(x))
	for n, v := range x {
		y[n] = complex(v, 0)
	}
	return y
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) ([]complex128, os.Error) {
	if len(x) != len(y) {
		return []complex128{}, os.NewError("fft: input arrays are not of equal length")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r), nil
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if isPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	factors := getRadix2Factors(lx)

	lx_2 := lx / 2
	r := make([]complex128, lx) // result
	t := make([]complex128, lx) // temp
	copy(r, x)

	// split into even and odd parts for each stage
	for block_sz := lx; block_sz > 1; block_sz >>= 1 {
		i := 0
		bs_2 := block_sz / 2
		for block := 0; block < lx/block_sz; block++ {
			for n := 0; n < bs_2; n++ {
				bn := block_sz*block + n
				t[bn] = r[i]
				i++
				t[bn+bs_2] = r[i]
				i++
			}
		}
		copy(r, t)
	}

	for stage := 2; stage <= lx; stage <<= 1 {
		if stage == 2 { // 2-point transforms
			for n := 0; n < lx_2; n++ {
				t[n*2] = r[n*2] + r[n*2+1]
				t[n*2+1] = r[n*2] - r[n*2+1]
			}
		} else { // >2-point transforms
			blocks := lx / stage
			s_2 := stage / 2

			for n := 0; n < blocks; n++ {
				nb := n * stage
				for j := 0; j < s_2; j++ {
					w_n := r[j+nb+s_2] * factors[blocks*j]
					t[j+nb] = r[j+nb] + w_n
					t[j+nb+s_2] = r[j+nb] - w_n
				}
			}
		}

		copy(r, t)
	}

	return r
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := zeroPad(x, nextPowerOf2(lx*2-1))
	la := len(a)
	factors, invFactors := getBluesteinFactors(lx)

	for n, v := range x {
		a[n] = v * invFactors[n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = factors[i]

		if i != 0 {
			b[la-i] = factors[i]
		}
	}

	r, _ := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= invFactors[i]
	}

	return r[:lx]
}

// isPowerOf2 returns true if x is a power of 2, else false.
func isPowerOf2(x int) bool {
	return x&(x-1) == 0
}

// nextPowerOf2 returns the next power of 2 >= x.
func nextPowerOf2(x int) int {
	if isPowerOf2(x) {
		return x
	}

	return int(math.Pow(2, math.Ceil(math.Log2(float64(x)))))
}

// zeroPad returns x with zeros appended to the end to the specified length.
// If len(x) == length, x is returned.
func zeroPad(x []complex128, length int) []complex128 {
	if len(x) == length {
		return x
	}

	r := make([]complex128, length)
	copy(r, x)
	return r
}

// zeroPad2 returns zeroPad of x, with the length as next power of 2 >= len(x).
func zeroPad2(x []complex128) []complex128 {
	return zeroPad(x, nextPowerOf2(len(x)))
}

// toComplex2 returns the complex equivalent of the real-valued matrix.
func toComplex2(x [][]float64) [][]complex128 {
	y := make([][]complex128, len(x))
	for n, v := range x {
		y[n] = toComplex(v)
	}
	return y
}

// FFT2Real returns the 2-dimensional, forward FFT of the real-valued matrix.
func FFT2Real(x [][]float64) ([][]complex128, os.Error) {
	return FFT2(toComplex2(x))
}

// FFT2 returns the 2-dimensional, forward FFT of the complex-valued matrix.
func FFT2(x [][]complex128) ([][]complex128, os.Error) {
	return computeFFT2(x, FFT)
}

// IFFT2Real returns the 2-dimensional, inverse FFT of the real-valued matrix.
func IFFT2Real(x [][]float64) ([][]complex128, os.Error) {
	return IFFT2(toComplex2(x))
}

// IFFT2 returns the 2-dimensional, inverse FFT of the complex-valued matrix.
func IFFT2(x [][]complex128) ([][]complex128, os.Error) {
	return computeFFT2(x, IFFT)
}

func computeFFT2(x [][]complex128, fftFunc func([]complex128) []complex128) ([][]complex128, os.Error) {
	rows := len(x)
	if rows == 0 {
		return nil, os.NewError("fft: empty input array")
	}

	cols := len(x[0])
	r := make([][]complex128, rows)
	for i := 0; i < rows; i++ {
		if len(x[i]) != cols {
			return nil, os.NewError("fft: input matrix must have identical row lengths")
		}
		r[i] = make([]complex128, cols)
	}

	for i := 0; i < cols; i++ {
		t := make([]complex128, rows)
		for j := 0; j < rows; j++ {
			t[j] = x[j][i]
		}

		for n, v := range fftFunc(t) {
			r[n][i] = v
		}
	}

	for n, v := range r {
		r[n] = fftFunc(v)
	}

	return r, nil
}
<|endoftext|>


<commit_before>// file.go
//
// Copyright (c) 2016, Ayke van Laethem
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Package file implements the file tree interface (tree.Entry) for local
// filesystems.
package file

// TODO: use the Linux system calls openat(), readdirat() etc.

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/aykevl/dtsync/tree"
)

// A prefix and suffix for files that are being copied.
const (
	TEMPPREFIX = ".usync-"
	TEMPSUFFIX = ".tmp"
)

// filesystem encapsulates the root path, so every Entry can know the root path.
type filesystem struct {
	path string
}

// Entry is one file or directory in the filesystem. It additionally contains
// it's name, parent, root, and stat() result.
type Entry struct {
	name   string
	root   *filesystem
	parent *Entry
	st     os.FileInfo
}

// NewRoot wraps a root directory in an Entry.
func NewRoot(rootPath string) (*Entry, error) {
	rootPath = filepath.Clean(rootPath)
	st, err := os.Stat(rootPath)
	if err != nil {
		return nil, err
	}
	return &Entry{
		root: &filesystem{
			path: rootPath,
		},
		st: st,
	}, nil
}

// NewTestRoot returns a new root in a temporary directory. It should be removed
// after use using root.Remove()
func NewTestRoot() (*Entry, error) {
	rootPath1, err := ioutil.TempDir("", "usync-test-")
	if err != nil {
		return nil, err
	}
	return NewRoot(rootPath1)
}

// String returns a string representation of this file, for debugging.
func (e *Entry) String() string {
	return "file.Entry(" + e.path() + ")"
}

// pathElements returns a list of path elements to be joined by filepath.Join.
func (e *Entry) pathElements() []string {
	if e.parent == nil {
		parts := make([]string, 1, 2)
		parts[0] = e.root.path
		return parts
	} else {
		return append(e.parent.pathElements(), e.name)
	}
}

// path returns the full path for this entry.
func (e *Entry) path() string {
	return filepath.Join(e.pathElements()...)
}

// AddRegular implements tree.TestEntry by adding a single file with the given
// name and contents.
func (e *Entry) AddRegular(name string, contents []byte) (tree.FileEntry, error) {
	if !tree.ValidName(name) {
		return nil, tree.ErrInvalidName
	}

	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}
	file, err := os.Create(child.path())
	if err != nil {
		return nil, err
	}
	defer file.Close()
	_, err = file.Write(contents)
	if err != nil {
		// "Write must return a non-nil error if it returns n < len(p)."
		return nil, err
	}
	err = file.Sync()
	if err != nil {
		return nil, err
	}
	child.st, err = file.Stat()
	if err != nil {
		return nil, err
	}
	return child, nil
}

// Type returns the file type (regular, directory, or unknown). More types may
// be added in the future.
func (e *Entry) Type() tree.Type {
	switch e.st.Mode() & os.ModeType {
	case 0:
		return tree.TYPE_REGULAR
	case os.ModeDir:
		return tree.TYPE_DIRECTORY
	default:
		return tree.TYPE_UNKNOWN
	}
}

// CreateDir adds a single child directory to this directory.
func (e *Entry) CreateDir(name string) (tree.Entry, error) {
	if !tree.ValidName(name) {
		return nil, tree.ErrInvalidName
	}
	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}
	err := os.Mkdir(child.path(), 0777)
	if err != nil {
		return nil, err
	}
	child.st, err = os.Stat(child.path())
	if err != nil {
		return nil, err
	}
	return child, nil
}

// GetContents returns an io.ReadCloser (that must be closed) with the contents
// of this entry.
func (e *Entry) GetContents() (io.ReadCloser, error) {
	return os.Open(e.path())
}

// GetFile returns an io.ReadCloser with the named file. The file must be closed
// after use.
func (e *Entry) GetFile(name string) (io.ReadCloser, error) {
	fp, err := os.Open(filepath.Join(e.path(), name))
	if err != nil {
		if os.IsNotExist(err) {
			return nil, tree.ErrNotFound
		} else {
			return nil, err
		}
	}
	return fp, nil
}

// List returns a directory listing, sorted by name.
func (e *Entry) List() ([]tree.Entry, error) {
	list, err := ioutil.ReadDir(e.path())
	if err != nil {
		return nil, err
	}
	listEntries := make([]tree.Entry, len(list))
	for i, st := range list {
		listEntries[i] = &Entry{
			st:     st,
			name:   st.Name(),
			parent: e,
			root:   e.root,
		}
	}
	return listEntries, nil
}

// ModTime returns the modification time from the (cached) stat() call.
func (e *Entry) ModTime() time.Time {
	return e.st.ModTime()
}

// Fingerprint returns a fingerprint calculated from the file's metadata.
func (e *Entry) Fingerprint() string {
	return tree.Fingerprint(e)
}

// Hash returns the blake2b hash of this file.
func (e *Entry) Hash() ([]byte, error) {
	hash := tree.NewHash()
	file, err := e.GetContents()
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(hash, file)
	if err != nil {
		return nil, err
	}
	return hash.Sum(nil), nil
}

// Name returns the filename.
func (e *Entry) Name() string {
	return e.name
}

func (e *Entry) RelativePath() string {
	return filepath.Join(e.pathElements()[1:]...)
}

// Remove removes this entry, recursively.
func (e *Entry) Remove() error {
	if e.Type() == tree.TYPE_DIRECTORY && e.parent != nil {
		// move to temporary location to provide atomicity in removing a
		// directory tree
		oldPath := e.path()
		tmpName := TEMPPREFIX + e.name + TEMPSUFFIX
		tmpPath := filepath.Join(e.parent.path(), tmpName)
		err := os.Rename(oldPath, tmpPath)
		if err != nil {
			return err
		}
		e.name = tmpName
	}
	return e.removeSelf()
}

func (e *Entry) removeSelf() error {
	if e.Type() == tree.TYPE_DIRECTORY {
		// remove children first
		list, err := e.List()
		if err != nil {
			return err
		}
		for _, child := range list {
			err = child.(*Entry).removeSelf()
			if err != nil {
				return err
			}
		}
	}

	// Actually remove the file or (empty) directory
	err := os.Remove(e.path())
	if err != nil {
		return err
	}

	// Update parent stat result
	if e.parent != nil {
		st, err := os.Stat(e.parent.path())
		if err != nil {
			return err
		}
		e.parent.st = st
	}
	return nil
}

func (e *Entry) SetFile(name string) (io.WriteCloser, error) {
	_, out, err := e.CreateFile(name, time.Time{})
	return out, err
}

// Size returns the filesize for regular files. For other file types, the result
// is undefined.
func (e *Entry) Size() int64 {
	return e.st.Size()
}

// CreateFile creates the child, implementing tree.FileEntry. This function is useful for CopyTo.
func (e *Entry) CreateFile(name string, modTime time.Time) (tree.Entry, io.WriteCloser, error) {
	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}

	writer, err := child.replaceFile(modTime)
	return child, writer, err
}

// UpdateFile replaces itself, to implement tree.FileEntry. This function is
// useful for UpdateOver.
func (e *Entry) UpdateFile(modTime time.Time) (io.WriteCloser, error) {
	if e.Type() != tree.TYPE_REGULAR {
		return nil, tree.ErrNoRegular
	}
	return e.replaceFile(modTime)
}

// replaceFile replaces the current file without checking for a type. Used by
// CreateFile and UpdateFile.
func (e *Entry) replaceFile(modTime time.Time) (io.WriteCloser, error) {
	tempPath := filepath.Join(e.parent.path(), TEMPPREFIX+e.name+TEMPSUFFIX)
	fp, err := os.Create(tempPath)
	if err != nil {
		return nil, err
	}
	return &fileWriter{
		fp: fp,
		closeCall: func() error {
			if !modTime.IsZero() {
				err = os.Chtimes(tempPath, modTime, modTime)
				if err != nil {
					return err
				}
			}
			err = os.Rename(tempPath, e.path())
			if err != nil {
				return err
			}
			e.st, err = os.Stat(e.path())

			// Update parent stat result
			st, err := os.Stat(e.parent.path())
			if err != nil {
				return err
			}
			e.parent.st = st

			return err
		},
	}, nil
}

// UpdateOver replaces this file with the contents and modtime of the other
// file.
func (e *Entry) UpdateOver(other tree.Entry) ([]byte, error) {
	file, ok := other.(tree.FileEntry)
	if !ok {
		return nil, tree.ErrNotImplemented
	}

	switch e.Type() {
	case tree.TYPE_REGULAR:
		out, err := file.UpdateFile(e.ModTime())
		if err != nil {
			return nil, err
		}

		in, err := os.Open(e.path())

		hasher := tree.NewHash()
		hashReader := io.TeeReader(in, hasher)

		_, err = io.Copy(out, hashReader)
		if err != nil {
			return nil, err
		}

		return hasher.Sum(nil), out.Close()

	default:
		return nil, tree.ErrNotImplemented
	}
}

// SetContents writes contents to this file, for testing.
func (e *Entry) SetContents(contents []byte) error {
	fp, err := os.Create(e.path())
	if err != nil {
		return err
	}
	defer fp.Close()
	_, err = fp.Write(contents)
	if err != nil {
		return err
	}
	now := time.Now()
	err = os.Chtimes(e.path(), now, now)
	if err != nil {
		// could not update
		return err
	}
	e.st, err = fp.Stat()
	if err != nil {
		return err
	}
	return fp.Sync()
}

// CopyTo copies this file into the otherParent. The latter must be a directory.
// Only implemented for regular files, not directories.
func (e *Entry) CopyTo(otherParent tree.Entry) (tree.Entry, []byte, error) {
	file, ok := otherParent.(tree.FileEntry)
	if !ok {
		return nil, nil, tree.ErrNotImplemented
	}

	switch e.Type() {
	case tree.TYPE_REGULAR:
		other, out, err := file.CreateFile(e.name, e.ModTime())
		if err != nil {
			return nil, nil, err
		}
		in, err := os.Open(e.path())
		if err != nil {
			return nil, nil, err
		}
		hasher := tree.NewHash()
		hashReader := io.TeeReader(in, hasher)
		_, err = io.Copy(out, hashReader)
		if err != nil {
			return nil, nil, err
		}
		// out.Close() does an fsync and rename
		err = out.Close()
		if err != nil {
			return nil, nil, err
		}
		return other, hasher.Sum(nil), nil

	default:
		return nil, nil, tree.ErrNotImplemented
	}
}
<commit_msg>tree/file: os.Stat → os.Lstat, we want to detect symlinks someday<commit_after>// file.go
//
// Copyright (c) 2016, Ayke van Laethem
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Package file implements the file tree interface (tree.Entry) for local
// filesystems.
package file

// TODO: use the Linux system calls openat(), readdirat() etc.

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/aykevl/dtsync/tree"
)

// A prefix and suffix for files that are being copied.
const (
	TEMPPREFIX = ".usync-"
	TEMPSUFFIX = ".tmp"
)

// filesystem encapsulates the root path, so every Entry can know the root path.
type filesystem struct {
	path string
}

// Entry is one file or directory in the filesystem. It additionally contains
// it's name, parent, root, and stat() result.
type Entry struct {
	name   string
	root   *filesystem
	parent *Entry
	st     os.FileInfo
}

// NewRoot wraps a root directory in an Entry.
func NewRoot(rootPath string) (*Entry, error) {
	rootPath = filepath.Clean(rootPath)
	st, err := os.Lstat(rootPath)
	if err != nil {
		return nil, err
	}
	return &Entry{
		root: &filesystem{
			path: rootPath,
		},
		st: st,
	}, nil
}

// NewTestRoot returns a new root in a temporary directory. It should be removed
// after use using root.Remove()
func NewTestRoot() (*Entry, error) {
	rootPath1, err := ioutil.TempDir("", "usync-test-")
	if err != nil {
		return nil, err
	}
	return NewRoot(rootPath1)
}

// String returns a string representation of this file, for debugging.
func (e *Entry) String() string {
	return "file.Entry(" + e.path() + ")"
}

// pathElements returns a list of path elements to be joined by filepath.Join.
func (e *Entry) pathElements() []string {
	if e.parent == nil {
		parts := make([]string, 1, 2)
		parts[0] = e.root.path
		return parts
	} else {
		return append(e.parent.pathElements(), e.name)
	}
}

// path returns the full path for this entry.
func (e *Entry) path() string {
	return filepath.Join(e.pathElements()...)
}

// AddRegular implements tree.TestEntry by adding a single file with the given
// name and contents.
func (e *Entry) AddRegular(name string, contents []byte) (tree.FileEntry, error) {
	if !tree.ValidName(name) {
		return nil, tree.ErrInvalidName
	}

	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}
	file, err := os.Create(child.path())
	if err != nil {
		return nil, err
	}
	defer file.Close()
	_, err = file.Write(contents)
	if err != nil {
		// "Write must return a non-nil error if it returns n < len(p)."
		return nil, err
	}
	err = file.Sync()
	if err != nil {
		return nil, err
	}
	child.st, err = file.Stat()
	if err != nil {
		return nil, err
	}
	return child, nil
}

// Type returns the file type (regular, directory, or unknown). More types may
// be added in the future.
func (e *Entry) Type() tree.Type {
	switch e.st.Mode() & os.ModeType {
	case 0:
		return tree.TYPE_REGULAR
	case os.ModeDir:
		return tree.TYPE_DIRECTORY
	default:
		return tree.TYPE_UNKNOWN
	}
}

// CreateDir adds a single child directory to this directory.
func (e *Entry) CreateDir(name string) (tree.Entry, error) {
	if !tree.ValidName(name) {
		return nil, tree.ErrInvalidName
	}
	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}
	err := os.Mkdir(child.path(), 0777)
	if err != nil {
		return nil, err
	}
	child.st, err = os.Lstat(child.path())
	if err != nil {
		return nil, err
	}
	return child, nil
}

// GetContents returns an io.ReadCloser (that must be closed) with the contents
// of this entry.
func (e *Entry) GetContents() (io.ReadCloser, error) {
	return os.Open(e.path())
}

// GetFile returns an io.ReadCloser with the named file. The file must be closed
// after use.
func (e *Entry) GetFile(name string) (io.ReadCloser, error) {
	fp, err := os.Open(filepath.Join(e.path(), name))
	if err != nil {
		if os.IsNotExist(err) {
			return nil, tree.ErrNotFound
		} else {
			return nil, err
		}
	}
	return fp, nil
}

// List returns a directory listing, sorted by name.
func (e *Entry) List() ([]tree.Entry, error) {
	list, err := ioutil.ReadDir(e.path())
	if err != nil {
		return nil, err
	}
	listEntries := make([]tree.Entry, len(list))
	for i, st := range list {
		listEntries[i] = &Entry{
			st:     st,
			name:   st.Name(),
			parent: e,
			root:   e.root,
		}
	}
	return listEntries, nil
}

// ModTime returns the modification time from the (cached) stat() call.
func (e *Entry) ModTime() time.Time {
	return e.st.ModTime()
}

// Fingerprint returns a fingerprint calculated from the file's metadata.
func (e *Entry) Fingerprint() string {
	return tree.Fingerprint(e)
}

// Hash returns the blake2b hash of this file.
func (e *Entry) Hash() ([]byte, error) {
	hash := tree.NewHash()
	file, err := e.GetContents()
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(hash, file)
	if err != nil {
		return nil, err
	}
	return hash.Sum(nil), nil
}

// Name returns the filename.
func (e *Entry) Name() string {
	return e.name
}

func (e *Entry) RelativePath() string {
	return filepath.Join(e.pathElements()[1:]...)
}

// Remove removes this entry, recursively.
func (e *Entry) Remove() error {
	if e.Type() == tree.TYPE_DIRECTORY && e.parent != nil {
		// move to temporary location to provide atomicity in removing a
		// directory tree
		oldPath := e.path()
		tmpName := TEMPPREFIX + e.name + TEMPSUFFIX
		tmpPath := filepath.Join(e.parent.path(), tmpName)
		err := os.Rename(oldPath, tmpPath)
		if err != nil {
			return err
		}
		e.name = tmpName
	}
	return e.removeSelf()
}

func (e *Entry) removeSelf() error {
	if e.Type() == tree.TYPE_DIRECTORY {
		// remove children first
		list, err := e.List()
		if err != nil {
			return err
		}
		for _, child := range list {
			err = child.(*Entry).removeSelf()
			if err != nil {
				return err
			}
		}
	}

	// Actually remove the file or (empty) directory
	err := os.Remove(e.path())
	if err != nil {
		return err
	}

	// Update parent stat result
	if e.parent != nil {
		st, err := os.Lstat(e.parent.path())
		if err != nil {
			return err
		}
		e.parent.st = st
	}
	return nil
}

func (e *Entry) SetFile(name string) (io.WriteCloser, error) {
	_, out, err := e.CreateFile(name, time.Time{})
	return out, err
}

// Size returns the filesize for regular files. For other file types, the result
// is undefined.
func (e *Entry) Size() int64 {
	return e.st.Size()
}

// CreateFile creates the child, implementing tree.FileEntry. This function is useful for CopyTo.
func (e *Entry) CreateFile(name string, modTime time.Time) (tree.Entry, io.WriteCloser, error) {
	child := &Entry{
		name:   name,
		parent: e,
		root:   e.root,
	}

	writer, err := child.replaceFile(modTime)
	return child, writer, err
}

// UpdateFile replaces itself, to implement tree.FileEntry. This function is
// useful for UpdateOver.
func (e *Entry) UpdateFile(modTime time.Time) (io.WriteCloser, error) {
	if e.Type() != tree.TYPE_REGULAR {
		return nil, tree.ErrNoRegular
	}
	return e.replaceFile(modTime)
}

// replaceFile replaces the current file without checking for a type. Used by
// CreateFile and UpdateFile.
func (e *Entry) replaceFile(modTime time.Time) (io.WriteCloser, error) {
	tempPath := filepath.Join(e.parent.path(), TEMPPREFIX+e.name+TEMPSUFFIX)
	fp, err := os.Create(tempPath)
	if err != nil {
		return nil, err
	}
	return &fileWriter{
		fp: fp,
		closeCall: func() error {
			if !modTime.IsZero() {
				err = os.Chtimes(tempPath, modTime, modTime)
				if err != nil {
					return err
				}
			}
			err = os.Rename(tempPath, e.path())
			if err != nil {
				return err
			}
			e.st, err = os.Lstat(e.path())

			// Update parent stat result
			st, err := os.Lstat(e.parent.path())
			if err != nil {
				return err
			}
			e.parent.st = st

			return err
		},
	}, nil
}

// UpdateOver replaces this file with the contents and modtime of the other
// file.
func (e *Entry) UpdateOver(other tree.Entry) ([]byte, error) {
	file, ok := other.(tree.FileEntry)
	if !ok {
		return nil, tree.ErrNotImplemented
	}

	switch e.Type() {
	case tree.TYPE_REGULAR:
		out, err := file.UpdateFile(e.ModTime())
		if err != nil {
			return nil, err
		}

		in, err := os.Open(e.path())

		hasher := tree.NewHash()
		hashReader := io.TeeReader(in, hasher)

		_, err = io.Copy(out, hashReader)
		if err != nil {
			return nil, err
		}

		return hasher.Sum(nil), out.Close()

	default:
		return nil, tree.ErrNotImplemented
	}
}

// SetContents writes contents to this file, for testing.
func (e *Entry) SetContents(contents []byte) error {
	fp, err := os.Create(e.path())
	if err != nil {
		return err
	}
	defer fp.Close()
	_, err = fp.Write(contents)
	if err != nil {
		return err
	}
	now := time.Now()
	err = os.Chtimes(e.path(), now, now)
	if err != nil {
		// could not update
		return err
	}
	e.st, err = fp.Stat()
	if err != nil {
		return err
	}
	return fp.Sync()
}

// CopyTo copies this file into the otherParent. The latter must be a directory.
// Only implemented for regular files, not directories.
func (e *Entry) CopyTo(otherParent tree.Entry) (tree.Entry, []byte, error) {
	file, ok := otherParent.(tree.FileEntry)
	if !ok {
		return nil, nil, tree.ErrNotImplemented
	}

	switch e.Type() {
	case tree.TYPE_REGULAR:
		other, out, err := file.CreateFile(e.name, e.ModTime())
		if err != nil {
			return nil, nil, err
		}
		in, err := os.Open(e.path())
		if err != nil {
			return nil, nil, err
		}
		hasher := tree.NewHash()
		hashReader := io.TeeReader(in, hasher)
		_, err = io.Copy(out, hashReader)
		if err != nil {
			return nil, nil, err
		}
		// out.Close() does an fsync and rename
		err = out.Close()
		if err != nil {
			return nil, nil, err
		}
		return other, hasher.Sum(nil), nil

	default:
		return nil, nil, tree.ErrNotImplemented
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by a BSD-style license.

// 2017-04-02 02:04
// package gxelasticsearch provides a Elasticsearch driver

package gxelasticsearch

import (
	"context"
	"fmt"
)

import (
	"encoding/json"
	"github.com/pkg/errors"
	es "gopkg.in/olivere/elastic.v3"
)

type EsClient struct {
	*es.Client
	bulk *es.BulkService
}

func CreateEsClient(hosts []string) (EsClient, error) {
	var esClient EsClient
	// Create a client
	// snif的作用是根据部分url获取整个集群的urls
	client, err := es.NewClient(es.SetURL(hosts[:]...), es.SetSniff(true), es.SetHealthcheck(true))
	if err == nil {
		esClient.Client = client
	}

	return esClient, err
}

// https://github.com/olivere/elastic/issues/457
func buildEsIndexSettings(shardNum int32, replicaNum int32, refreshInterval int32) string {
	return fmt.Sprintf(`{
		"settings" : {
			"number_of_shards": %d,
			"number_of_replicas": %d,
			"refresh_interval": "%ds"
		}
	}`, shardNum, replicaNum, refreshInterval)
}

func (ec EsClient) CreateEsIndex(index string, shardNum int32, replicaNum int32, refreshInterval int32) error {
	var (
		err    error
		exists bool
		body   string
		ctx    context.Context
	)

	ctx = context.Background()
	exists, err = ec.IndexExists(index).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "CreateRcIndex(index:%s, shardNum:%s, replicaNum:%d, refreshInterval:%d)",
			index, shardNum, replicaNum, refreshInterval)
	}
	if exists {
		return nil
	}

	body = buildEsIndexSettings(shardNum, replicaNum, refreshInterval)
	_, err = ec.CreateIndex(index).BodyString(body).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "CreateEsIndex(body:%s)", body)
	}

	return nil
}

func (ec EsClient) DeleteEsIndex(index string) error {
	var (
		err error
		ctx context.Context
	)

	ctx = context.Background()
	_, err = ec.DeleteIndex(index).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "DeleteEsIndex(index:%s)", index)
	}

	return nil
}

// InsertWithDocId 插入@msg
// !!! 如果@msg的类型是string 或者 []byte，则被当做Json String类型直接存进去
func (ec EsClient) Insert(index string, typ string, msg interface{}) error {
	var (
		err      error
		ok       bool
		msgBytes []byte
		ctx      context.Context
	)

	// https://github.com/olivere/elastic/issues/127
	// Elasticsearch can create an identifier for you, automatically.
	// _, err = ec.Index().Index(index).Type(typ).Id(1).BodyJson(msg).Do()
	ctx = context.Background()
	switch msg.(type) {
	case string:
		_, err = ec.Index().Index(index).Type(typ).BodyString(msg.(string)).DoC(ctx)
		if err != nil {
			return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%s)", index, typ, msg)
		}

	default:
		if msgBytes, ok = msg.([]byte); ok {
			_, err = ec.Index().Index(index).Type(typ).BodyString(string(msgBytes)).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%s)", index, typ, (string)(msgBytes))
			}
		} else {
			_, err = ec.Index().Index(index).Type(typ).BodyJson(msg).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%#v)", index, typ, msg)
			}
		}
	}

	return nil
}

// InsertWithDocId 插入@msg时候指定@docID
// !!! 如果@msg的类型是string 或者 []byte，则被当做Json String类型直接存进去
func (ec EsClient) InsertWithDocId(index string, typ string, docID string, msg interface{}) error {
	var (
		err      error
		ok       bool
		msgBytes []byte
		ctx      context.Context
	)

	ctx = context.Background()
	switch msg.(type) {
	case string:
		_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyString(msg.(string)).DoC(ctx)
		if err != nil {
			return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%s)", index, typ, docID, msg)
		}

	default:
		if msgBytes, ok = msg.([]byte); ok {
			_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyString(string(msgBytes)).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%s)", index, typ, docID, (string)(msgBytes))
			}
		} else {
			_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyJson(msg).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%#v)", index, typ, docID, msg)
			}
		}
	}

	return nil
}

// BulkInsert 批量插入@arr
// !!! 如果@arr[0]的类型是string 或者 []byte，则被当做Json String类型直接存进去
// https://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html
// A good place to start is with batches of 1,000 to 5,000 documents
func (ec EsClient) BulkInsert(index string, typ string, arr []interface{}) error {
	var (
		err  error
		ctx  context.Context
		bulk *es.BulkService
		rsp  *es.BulkResponse
	)

	if ec.bulk == nil {
		ec.bulk = ec.Bulk()
	}

	bulk = ec.bulk.Index(index).Type(typ)
	for _, e := range arr {
		switch e.(type) {
		case string:
			data := ([]byte)(e.(string))
			bulk.Add(es.NewBulkIndexRequest().Doc((*json.RawMessage)(&data)))
		default:
			if data, ok := e.([]byte); ok {
				bulk.Add(es.NewBulkIndexRequest().Doc((*json.RawMessage)(&data)))
			} else {
				bulk.Add(es.NewBulkIndexRequest().Doc(e))
				// bulk.Add(es.NewBulkIndexRequest().Index("1").Doc(e))
			}
		}
	}
	if bulk.NumberOfActions() <= 0 {
		return fmt.Errorf("bulk.NumberOfActions() = %d", bulk.NumberOfActions())
	}

	ctx = context.Background()
	rsp, err = bulk.DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "BulkInsert(@arr:%#v)", arr)
	}
	if rsp.Errors {
		return fmt.Errorf("BulkInsert(@arr:%#v) = error:%#v ", arr, rsp.Failed())
	}

	return nil
}

// Search
// Waiting for es5.x's future sql feature
<commit_msg>add fail reason for bulkinsert<commit_after>// Copyright 2017 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by a BSD-style license.

// 2017-04-02 02:04
// package gxelasticsearch provides a Elasticsearch driver
package gxelasticsearch

import (
	"context"
	"encoding/json"
	"fmt"
)

import (
	"github.com/pkg/errors"
	es "gopkg.in/olivere/elastic.v3"
)

type EsClient struct {
	*es.Client
	bulk *es.BulkService
}

func CreateEsClient(hosts []string) (EsClient, error) {
	var esClient EsClient
	// Create a client
	// snif的作用是根据部分url获取整个集群的urls
	client, err := es.NewClient(es.SetURL(hosts[:]...), es.SetSniff(true), es.SetHealthcheck(true))
	if err == nil {
		esClient.Client = client
	}

	return esClient, err
}

// https://github.com/olivere/elastic/issues/457
func buildEsIndexSettings(shardNum int32, replicaNum int32, refreshInterval int32) string {
	return fmt.Sprintf(`{
		"settings" : {
			"number_of_shards": %d,
			"number_of_replicas": %d,
			"refresh_interval": "%ds"
		}
	}`, shardNum, replicaNum, refreshInterval)
}

func (ec EsClient) CreateEsIndex(index string, shardNum int32, replicaNum int32, refreshInterval int32) error {
	var (
		err    error
		exists bool
		body   string
		ctx    context.Context
	)

	ctx = context.Background()
	exists, err = ec.IndexExists(index).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "CreateRcIndex(index:%s, shardNum:%s, replicaNum:%d, refreshInterval:%d)",
			index, shardNum, replicaNum, refreshInterval)
	}
	if exists {
		return nil
	}

	body = buildEsIndexSettings(shardNum, replicaNum, refreshInterval)
	_, err = ec.CreateIndex(index).BodyString(body).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "CreateEsIndex(body:%s)", body)
	}

	return nil
}

func (ec EsClient) DeleteEsIndex(index string) error {
	var (
		err error
		ctx context.Context
	)

	ctx = context.Background()
	_, err = ec.DeleteIndex(index).DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "DeleteEsIndex(index:%s)", index)
	}

	return nil
}

// InsertWithDocId 插入@msg
// !!! 如果@msg的类型是string 或者 []byte，则被当做Json String类型直接存进去
func (ec EsClient) Insert(index string, typ string, msg interface{}) error {
	var (
		err      error
		ok       bool
		msgBytes []byte
		ctx      context.Context
	)

	// https://github.com/olivere/elastic/issues/127
	// Elasticsearch can create an identifier for you, automatically.
	// _, err = ec.Index().Index(index).Type(typ).Id(1).BodyJson(msg).Do()
	ctx = context.Background()
	switch msg.(type) {
	case string:
		_, err = ec.Index().Index(index).Type(typ).BodyString(msg.(string)).DoC(ctx)
		if err != nil {
			return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%s)", index, typ, msg)
		}

	default:
		if msgBytes, ok = msg.([]byte); ok {
			_, err = ec.Index().Index(index).Type(typ).BodyString(string(msgBytes)).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%s)", index, typ, (string)(msgBytes))
			}
		} else {
			_, err = ec.Index().Index(index).Type(typ).BodyJson(msg).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "Insert(index:%s, type:%s, msg:%#v)", index, typ, msg)
			}
		}
	}

	return nil
}

// InsertWithDocId 插入@msg时候指定@docID
// !!! 如果@msg的类型是string 或者 []byte，则被当做Json String类型直接存进去
func (ec EsClient) InsertWithDocId(index string, typ string, docID string, msg interface{}) error {
	var (
		err      error
		ok       bool
		msgBytes []byte
		ctx      context.Context
	)

	ctx = context.Background()
	switch msg.(type) {
	case string:
		_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyString(msg.(string)).DoC(ctx)
		if err != nil {
			return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%s)", index, typ, docID, msg)
		}

	default:
		if msgBytes, ok = msg.([]byte); ok {
			_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyString(string(msgBytes)).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%s)", index, typ, docID, (string)(msgBytes))
			}
		} else {
			_, err = ec.Index().Index(index).Type(typ).Id(docID).BodyJson(msg).DoC(ctx)
			if err != nil {
				return errors.Wrapf(err, "InsertWithDocId(index:%s, type:%s, docID:%s, msg:%#v)", index, typ, docID, msg)
			}
		}
	}

	return nil
}

// BulkInsert 批量插入@arr
// !!! 如果@arr[0]的类型是string 或者 []byte，则被当做Json String类型直接存进去
// https://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html
// A good place to start is with batches of 1,000 to 5,000 documents
func (ec EsClient) BulkInsert(index string, typ string, arr []interface{}) error {
	var (
		err  error
		ctx  context.Context
		bulk *es.BulkService
		rsp  *es.BulkResponse
	)

	if ec.bulk == nil {
		ec.bulk = ec.Bulk()
	}

	bulk = ec.bulk.Index(index).Type(typ)
	for _, e := range arr {
		switch e.(type) {
		case string:
			data := ([]byte)(e.(string))
			bulk.Add(es.NewBulkIndexRequest().Doc((*json.RawMessage)(&data)))
		default:
			if data, ok := e.([]byte); ok {
				bulk.Add(es.NewBulkIndexRequest().Doc((*json.RawMessage)(&data)))
			} else {
				bulk.Add(es.NewBulkIndexRequest().Doc(e))
				// bulk.Add(es.NewBulkIndexRequest().Index("1").Doc(e))
			}
		}
	}
	if bulk.NumberOfActions() <= 0 {
		return fmt.Errorf("bulk.NumberOfActions() = %d", bulk.NumberOfActions())
	}

	ctx = context.Background()
	rsp, err = bulk.DoC(ctx)
	if err != nil {
		return errors.Wrapf(err, "BulkInsert(@arr len:%d)", len(arr))
	}
	if rsp.Errors {
		return fmt.Errorf("BulkInsert(@arr len:%d), failed number:%#v, first fail reason:%#v", len(arr), len(rsp.Failed()), rsp.Failed()[0])
	}

	return nil
}

// Search
// Waiting for es5.x's future sql feature
<|endoftext|>


<commit_before>package shell

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"
)

func TestCmdRun(t *testing.T) {
	output := Cmd("echo", "foobar").Run().String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestRun(t *testing.T) {
	output := Run("echo", "foobar").String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestPanic(t *testing.T) {
	defer func() {
		p := recover().(*Process).ExitStatus
		if p != 2 {
			t.Fatal("status not expected:", p)
		}
	}()
	Run("exit", "2")
}

func TestPipe(t *testing.T) {
	p := Cmd("echo", "foobar").Pipe("wc", "-c").Pipe("awk", "'{print $1}'").Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestSingleArg(t *testing.T) {
	p := Run("echo foobar | wc -c | awk '{print $1}'")
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestProcessAsArg(t *testing.T) {
	p := Cmd("echo", Run("echo foobar")).Pipe("wc", "-c").Pipe(Run("echo", "awk"), "'{print $1}'").Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestLastArgStdin(t *testing.T) {
	p := Cmd("awk '{print $1}'", Cmd("wc", "-c", Cmd("echo foobar"))).Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestCmdRunFunc(t *testing.T) {
	echo := Cmd("echo").ProcFn()
	output := echo("foobar").String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestPath(t *testing.T) {
	p := Path("/root", "part1/part2", "foobar")
	if p != "/root/part1/part2/foobar" {
		t.Fatal("path not expected:", p)
	}
}

func TestPathTemplate(t *testing.T) {
	tmpl := PathTemplate("/root", "%s/part2", "%s")
	p := tmpl("one", "two")
	if p != "/root/one/part2/two" {
		t.Fatal("path not expected:", p)
	}
}

func TestPrintlnStringer(t *testing.T) {
	var buf bytes.Buffer
	fmt.Fprintln(&buf, Run("echo foobar"))
	if buf.String() != "foobar\n" {
		t.Fatal("output not expected:", buf.String())
	}
}

func TestWrapPanicToErr(t *testing.T) {
	copy := func(src, dst string) (err error) {
		defer func() {
			if p := recover().(*Process); p != nil {
				err = p.Error()
			}
		}()
		Run("cp", src, dst)
		return
	}
	err := copy("", "")
	if !strings.HasPrefix(err.Error(), "[64] ") {
		t.Fatal("output not expected:", err)
	}
}

func TestCmdOutputFn(t *testing.T) {
	copy := Cmd("cp").OutputFn()
	echo := Cmd("echo").OutputFn()
	_, err := copy("", "")
	if !strings.HasPrefix(err.Error(), "[64] ") {
		t.Fatal("output not expected:", err)
	}
	out, err := echo("foobar")
	if err != nil {
		t.Fatal("unexpected error:", err)
	}
	if out != "foobar" {
		t.Fatal("output not expected:", out)
	}
}

func TestSetWorkDir(t *testing.T) {
	var (
		pwd      = os.Getenv("PWD")
		testPath = Path(pwd, "_goshell_unique")
	)
	defer func() {
		os.RemoveAll(Path(pwd, "testfile"))
		os.RemoveAll(testPath)
	}()
	if err := os.MkdirAll(testPath, os.ModePerm); err != nil {
		t.Fatal("unexpected error:", err)
	}

	p := Cmd("touch", "testfile").SetWorkDir(testPath).Run()
	if p.ExitStatus != 0 {
		t.Fatal("unexpected error:", p.Error())
	}

	_, err := os.Stat(testPath, "testfile")
	if err != nil {
		t.Errorf("expected touched file to be present in correct working dir but was not")
	}
}
<commit_msg>Fix improper use of os.Stat<commit_after>package shell

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"testing"
)

func TestCmdRun(t *testing.T) {
	output := Cmd("echo", "foobar").Run().String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestRun(t *testing.T) {
	output := Run("echo", "foobar").String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestPanic(t *testing.T) {
	defer func() {
		p := recover().(*Process).ExitStatus
		if p != 2 {
			t.Fatal("status not expected:", p)
		}
	}()
	Run("exit", "2")
}

func TestPipe(t *testing.T) {
	p := Cmd("echo", "foobar").Pipe("wc", "-c").Pipe("awk", "'{print $1}'").Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestSingleArg(t *testing.T) {
	p := Run("echo foobar | wc -c | awk '{print $1}'")
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestProcessAsArg(t *testing.T) {
	p := Cmd("echo", Run("echo foobar")).Pipe("wc", "-c").Pipe(Run("echo", "awk"), "'{print $1}'").Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestLastArgStdin(t *testing.T) {
	p := Cmd("awk '{print $1}'", Cmd("wc", "-c", Cmd("echo foobar"))).Run()
	if p.String() != "7" {
		t.Fatal("output not expected:", p.String())
	}
}

func TestCmdRunFunc(t *testing.T) {
	echo := Cmd("echo").ProcFn()
	output := echo("foobar").String()
	if output != "foobar" {
		t.Fatal("output not expected:", output)
	}
}

func TestPath(t *testing.T) {
	p := Path("/root", "part1/part2", "foobar")
	if p != "/root/part1/part2/foobar" {
		t.Fatal("path not expected:", p)
	}
}

func TestPathTemplate(t *testing.T) {
	tmpl := PathTemplate("/root", "%s/part2", "%s")
	p := tmpl("one", "two")
	if p != "/root/one/part2/two" {
		t.Fatal("path not expected:", p)
	}
}

func TestPrintlnStringer(t *testing.T) {
	var buf bytes.Buffer
	fmt.Fprintln(&buf, Run("echo foobar"))
	if buf.String() != "foobar\n" {
		t.Fatal("output not expected:", buf.String())
	}
}

func TestWrapPanicToErr(t *testing.T) {
	copy := func(src, dst string) (err error) {
		defer func() {
			if p := recover().(*Process); p != nil {
				err = p.Error()
			}
		}()
		Run("cp", src, dst)
		return
	}
	err := copy("", "")
	if !strings.HasPrefix(err.Error(), "[64] ") {
		t.Fatal("output not expected:", err)
	}
}

func TestCmdOutputFn(t *testing.T) {
	copy := Cmd("cp").OutputFn()
	echo := Cmd("echo").OutputFn()
	_, err := copy("", "")
	if !strings.HasPrefix(err.Error(), "[64] ") {
		t.Fatal("output not expected:", err)
	}
	out, err := echo("foobar")
	if err != nil {
		t.Fatal("unexpected error:", err)
	}
	if out != "foobar" {
		t.Fatal("output not expected:", out)
	}
}

func TestSetWorkDir(t *testing.T) {
	var (
		pwd      = os.Getenv("PWD")
		testPath = Path(pwd, "_goshell_unique")
	)
	defer func() {
		os.RemoveAll(Path(pwd, "testfile"))
		os.RemoveAll(testPath)
	}()
	if err := os.MkdirAll(testPath, os.ModePerm); err != nil {
		t.Fatal("unexpected error:", err)
	}

	p := Cmd("touch", "testfile").SetWorkDir(testPath).Run()
	if p.ExitStatus != 0 {
		t.Fatal("unexpected error:", p.Error())
	}

	_, err := os.Stat(Path(testPath, "testfile"))
	if err != nil {
		t.Errorf("expected touched file to be present in correct working dir but was not")
	}
}
<|endoftext|>


<commit_before>package main

import "testing"

func TestGir(t *testing.T) {
	return
}
<commit_msg>In TestGir(), load file test.gir<commit_after>package main

import (
	"bufio"
	"io"
	"os"
	"testing"

	"github.com/bjwbell/gir/config"
	"github.com/bjwbell/gir/exec"
	"github.com/bjwbell/gir/parse"
	"github.com/bjwbell/gir/run"
	"github.com/bjwbell/gir/scan"
	"github.com/bjwbell/gir/value"
)

func TestGir(t *testing.T) {
	var (
		conf    config.Config
		context value.Context
		fd      io.Reader
		err     error
	)
	context = exec.NewContext(&conf)
	file := "test.gir"
	fd, err = os.Open(file)
	if err != nil {
		t.Fatalf("gir: %s\n", err)
	}
	scanner := scan.New(context, file, bufio.NewReader(fd))
	parser := parse.NewParser(file, scanner, context)
	interactive := false
	ok := run.Run(parser, context, interactive)
	if !ok {
		t.Errorf("Error in run.Run")
	} else {
		t.Logf("parser: %#v\n", parser)
	}
	return
}
<|endoftext|>


<commit_before>package git

import (
	"testing"
)

func init() {
	runner = &fakeRunner{}
}

var (
	testingPath = "_testing/kamino-test"
	testingSha  = "97d2258b4a58d9bf07636d76c97a3eb09490cf70"
)

func TestRemoteAccountHTTP(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  http://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountHTTPS(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  https://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountSSH(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git@github.com:rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountGit(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountWithoutSuffix(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git://github.com/rafecolton/docker-builder (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestSha(t *testing.T) {
	runner.(*fakeRunner).sha = "abc123\n"
	actual := Sha("")
	expected := "abc123"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestBranch(t *testing.T) {
	runner.(*fakeRunner).branch = "asdf\n"
	actual := Branch("")
	expected := "asdf"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestBranchAlt(t *testing.T) {
	runner.(*fakeRunner).branch = "HEAD\n"
	runner.(*fakeRunner).branch2 = `  master
  move-mithril-to-quay
* update-loadbalancer-role
  using-mighril-from-quay-instead-of-docker-hub`
	actual := Branch("")
	expected := "master"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestCleanClean(t *testing.T) {
	if !IsClean("") {
		t.Errorf("expected cleanliness")
	}
}

func TestCleanDirty(t *testing.T) {
	runner.(*fakeRunner).clean = " 2 files changed, 139 insertions(+), 105 deletions(-)\n"
	if IsClean("") {
		t.Errorf("repo is dirty")
	}
}

func TestUpToDateDiverged(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "abc"
	runner.(*fakeRunner).upToDateRemote = "123"
	runner.(*fakeRunner).upToDateBase = "def"
	if UpToDate("") != StatusDiverged {
		t.Errorf("status should be StatusDiverged")
	}
}

func TestUpToDateUpToDate(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateRemote = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusUpToDate {
		t.Errorf("status should be StatusUpToDate")
	}
}

func TestUpToDateNeedToPush(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "f4c103a85141c59749ef24320a538ae7ed238909"
	runner.(*fakeRunner).upToDateRemote = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateBase = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusNeedToPush {
		t.Errorf("status should be StatusNeedToPush")
	}
}

func TestUpToDateNeedToPull(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateRemote = "f4c103a85141c59749ef24320a538ae7ed238909"
	runner.(*fakeRunner).upToDateBase = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusNeedToPull {
		t.Errorf("status should be StatusNeedToPull")
	}
}

func TestTag(t *testing.T) {
	runner.(*fakeRunner).tag = "foo-tag"
	if Tag("") != "foo-tag" {
		t.Errorf("expected foo-tag, got %s", Tag(""))
	}
}

func TestStatusString(t *testing.T) {
	assertStatusString(StatusUpToDate, "StatusUpToDate", t)
	assertStatusString(StatusNeedToPull, "StatusNeedToPull", t)
	assertStatusString(StatusNeedToPush, "StatusNeedToPush", t)
	assertStatusString(StatusDiverged, "StatusDiverged", t)
}

func assertStatusString(status Status, str string, t *testing.T) {
	if status.String() != str {
		t.Errorf("expected " + str + ", got " + status.String())
	}
}
<commit_msg>Adding test for panic behavior for attempting to print an invalid status<commit_after>package git

import (
	"testing"
)

func init() {
	runner = &fakeRunner{}
}

var (
	testingPath = "_testing/kamino-test"
	testingSha  = "97d2258b4a58d9bf07636d76c97a3eb09490cf70"
)

func TestRemoteAccountHTTP(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  http://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountHTTPS(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  https://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountSSH(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git@github.com:rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountGit(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git://github.com/rafecolton/docker-builder.git (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestRemoteAccountWithoutSuffix(t *testing.T) {
	runner.(*fakeRunner).remoteV = `origin  git://github.com/rafecolton/docker-builder (fetch)`
	expected := "rafecolton"
	actual := RemoteAccount("")
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestSha(t *testing.T) {
	runner.(*fakeRunner).sha = "abc123\n"
	actual := Sha("")
	expected := "abc123"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestBranch(t *testing.T) {
	runner.(*fakeRunner).branch = "asdf\n"
	actual := Branch("")
	expected := "asdf"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestBranchAlt(t *testing.T) {
	runner.(*fakeRunner).branch = "HEAD\n"
	runner.(*fakeRunner).branch2 = `  master
  move-mithril-to-quay
* update-loadbalancer-role
  using-mighril-from-quay-instead-of-docker-hub`
	actual := Branch("")
	expected := "master"
	if actual != expected {
		t.Errorf("expected %q, got %q", expected, actual)
	}
}

func TestCleanClean(t *testing.T) {
	if !IsClean("") {
		t.Errorf("expected cleanliness")
	}
}

func TestCleanDirty(t *testing.T) {
	runner.(*fakeRunner).clean = " 2 files changed, 139 insertions(+), 105 deletions(-)\n"
	if IsClean("") {
		t.Errorf("repo is dirty")
	}
}

func TestUpToDateDiverged(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "abc"
	runner.(*fakeRunner).upToDateRemote = "123"
	runner.(*fakeRunner).upToDateBase = "def"
	if UpToDate("") != StatusDiverged {
		t.Errorf("status should be StatusDiverged")
	}
}

func TestUpToDateUpToDate(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateRemote = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusUpToDate {
		t.Errorf("status should be StatusUpToDate")
	}
}

func TestUpToDateNeedToPush(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "f4c103a85141c59749ef24320a538ae7ed238909"
	runner.(*fakeRunner).upToDateRemote = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateBase = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusNeedToPush {
		t.Errorf("status should be StatusNeedToPush")
	}
}

func TestUpToDateNeedToPull(t *testing.T) {
	runner.(*fakeRunner).upToDateLocal = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	runner.(*fakeRunner).upToDateRemote = "f4c103a85141c59749ef24320a538ae7ed238909"
	runner.(*fakeRunner).upToDateBase = "50d1ab234ffa3df05162c8eae4dddef1d907faa8"
	if UpToDate("") != StatusNeedToPull {
		t.Errorf("status should be StatusNeedToPull")
	}
}

func TestTag(t *testing.T) {
	runner.(*fakeRunner).tag = "foo-tag"
	if Tag("") != "foo-tag" {
		t.Errorf("expected foo-tag, got %s", Tag(""))
	}
}

func TestStatusString(t *testing.T) {
	assertStatusString(StatusUpToDate, "StatusUpToDate", t)
	assertStatusString(StatusNeedToPull, "StatusNeedToPull", t)
	assertStatusString(StatusNeedToPush, "StatusNeedToPush", t)
	assertStatusString(StatusDiverged, "StatusDiverged", t)
}

func assertStatusString(status Status, str string, t *testing.T) {
	if status.String() != str {
		t.Errorf("expected " + str + ", got " + status.String())
	}
}

func TestPrintInvalidStatus(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			println("wheeeeee")
		}
	}()
	var invalid uint8 = 86
	assertStatusString(Status(invalid), "doesn't matter", t)
	t.Error("should not get here")
}
<|endoftext|>


<commit_before>package ec2

import (
	"io"
	"launchpad.net/goamz/ec2"
	"launchpad.net/goamz/s3"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/jujutest"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/trivial"
	"net/http"
)

type BootstrapState struct {
	StateInstances []state.InstanceId
}

func LoadState(e environs.Environ) (*BootstrapState, error) {
	s, err := e.(*environ).loadState()
	if err != nil {
		return nil, err
	}
	return &BootstrapState{s.StateInstances}, nil
}

func JujuGroupName(e environs.Environ) string {
	return e.(*environ).jujuGroupName()
}

func MachineGroupName(e environs.Environ, machineId string) string {
	return e.(*environ).machineGroupName(machineId)
}

func EnvironEC2(e environs.Environ) *ec2.EC2 {
	return e.(*environ).ec2()
}

func EnvironS3(e environs.Environ) *s3.S3 {
	return e.(*environ).s3()
}

func DeleteStorageContent(s environs.Storage) error {
	return s.(*storage).deleteAll()
}

func InstanceEC2(inst environs.Instance) *ec2.Instance {
	return inst.(*instance).Instance
}

// BucketStorage returns a storage instance addressing
// an arbitrary s3 bucket.
func BucketStorage(b *s3.Bucket) environs.Storage {
	return &storage{
		bucket: b,
	}
}

var testRoundTripper = &jujutest.ProxyRoundTripper{}

func init() {
	// Prepare mock http transport for overriding metadata and images output in tests
	http.DefaultTransport.(*http.Transport).RegisterProtocol("test", testRoundTripper)
}

var TestImagesContent = []jujutest.FileContent{
	{"/query/precise/server/released.current.txt", "" +
		"precise\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-20800c10\taki-98e26fa8\t\tparavirtual\n" +
		""},
	{"/query/quantal/server/released.current.txt", "" +
		"quantal\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
		""},
	{"/query/raring/server/released.current.txt", "" +
		"raring\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
		""},
}

// TODO: Apart from overriding different hardcoded hosts, these two test helpers are identical. Let's share.

var origImagesHost = imagesHost

func UseTestImageData(content []jujutest.FileContent) {
	if content != nil {
		testRoundTripper.Sub = jujutest.NewVirtualRoundTripper(content)
		imagesHost = "test:"
	} else {
		testRoundTripper.Sub = nil
		imagesHost = origImagesHost
	}
}

var origMetadataHost = metadataHost

func UseTestMetadata(content []jujutest.FileContent) {
	if content != nil {
		testRoundTripper.Sub = jujutest.NewVirtualRoundTripper(content)
		metadataHost = "test:"
	} else {
		testRoundTripper.Sub = nil
		metadataHost = origMetadataHost
	}
}

var originalShortAttempt = shortAttempt
var originalLongAttempt = longAttempt

// ShortTimeouts sets the timeouts to a short period as we
// know that the ec2test server doesn't get better with time,
// and this reduces the test time from 30s to 3s.
func ShortTimeouts(short bool) {
	if short {
		shortAttempt = trivial.AttemptStrategy{
			Total: 0.25e9,
			Delay: 0.01e9,
		}
		longAttempt = shortAttempt
	} else {
		shortAttempt = originalShortAttempt
		longAttempt = originalLongAttempt
	}
}

var ShortAttempt = &shortAttempt

func EC2ErrCode(err error) string {
	return ec2ErrCode(err)
}

// FabricateInstance creates a new fictitious instance
// given an existing instance and a new id.
func FabricateInstance(inst environs.Instance, newId string) environs.Instance {
	oldi := inst.(*instance)
	newi := &instance{oldi.e, &ec2.Instance{}}
	*newi.Instance = *oldi.Instance
	newi.InstanceId = newId
	return newi
}

// Access non exported methods on ec2.storage
type Storage interface {
	Put(file string, r io.Reader, length int64) error
	ResetMadeBucket()
}

func (s *storage) ResetMadeBucket() {
	s.Lock()
	defer s.Unlock()
	s.madeBucket = false
}

// WritablePublicStorage returns a Storage instance which is authorised to write to the PublicStorage bucket.
// It is used by tests which need to upload files.
func WritablePublicStorage(e environs.Environ) environs.Storage {
	// In the case of ec2, access to the public storage instance is created with the user's AWS credentials.
	// So write access is there implicitly, and we just need to cast to a writable storage instance.
	// This contrasts with the openstack case, where the public storage instance truly is read only and we need
	// to create a separate writable instance. If the ec2 case ever changes, the changes are confined to this method.
	return e.PublicStorage().(environs.Storage)
}
<commit_msg>Removed dummy whitespace.<commit_after>package ec2

import (
	"io"
	"launchpad.net/goamz/ec2"
	"launchpad.net/goamz/s3"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/jujutest"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/trivial"
	"net/http"
)

type BootstrapState struct {
	StateInstances []state.InstanceId
}

func LoadState(e environs.Environ) (*BootstrapState, error) {
	s, err := e.(*environ).loadState()
	if err != nil {
		return nil, err
	}
	return &BootstrapState{s.StateInstances}, nil
}

func JujuGroupName(e environs.Environ) string {
	return e.(*environ).jujuGroupName()
}

func MachineGroupName(e environs.Environ, machineId string) string {
	return e.(*environ).machineGroupName(machineId)
}

func EnvironEC2(e environs.Environ) *ec2.EC2 {
	return e.(*environ).ec2()
}

func EnvironS3(e environs.Environ) *s3.S3 {
	return e.(*environ).s3()
}

func DeleteStorageContent(s environs.Storage) error {
	return s.(*storage).deleteAll()
}

func InstanceEC2(inst environs.Instance) *ec2.Instance {
	return inst.(*instance).Instance
}

// BucketStorage returns a storage instance addressing
// an arbitrary s3 bucket.
func BucketStorage(b *s3.Bucket) environs.Storage {
	return &storage{
		bucket: b,
	}
}

var testRoundTripper = &jujutest.ProxyRoundTripper{}

func init() {
	// Prepare mock http transport for overriding metadata and images output in tests
	http.DefaultTransport.(*http.Transport).RegisterProtocol("test", testRoundTripper)
}

var TestImagesContent = []jujutest.FileContent{
	{"/query/precise/server/released.current.txt", "" +
		"precise\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-20800c10\taki-98e26fa8\t\tparavirtual\n" +
		""},
	{"/query/quantal/server/released.current.txt", "" +
		"quantal\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
		""},
	{"/query/raring/server/released.current.txt", "" +
		"raring\tserver\trelease\t20121017\tebs\tamd64\ttest\tami-40f97070\taki-98e26fa8\t\tparavirtual\n" +
		""},
}

// TODO: Apart from overriding different hardcoded hosts, these two test helpers are identical. Let's share.

var origImagesHost = imagesHost

func UseTestImageData(content []jujutest.FileContent) {
	if content != nil {
		testRoundTripper.Sub = jujutest.NewVirtualRoundTripper(content)
		imagesHost = "test:"
	} else {
		testRoundTripper.Sub = nil
		imagesHost = origImagesHost
	}
}

var origMetadataHost = metadataHost

func UseTestMetadata(content []jujutest.FileContent) {
	if content != nil {
		testRoundTripper.Sub = jujutest.NewVirtualRoundTripper(content)
		metadataHost = "test:"
	} else {
		testRoundTripper.Sub = nil
		metadataHost = origMetadataHost
	}
}

var originalShortAttempt = shortAttempt
var originalLongAttempt = longAttempt

// ShortTimeouts sets the timeouts to a short period as we
// know that the ec2test server doesn't get better with time,
// and this reduces the test time from 30s to 3s.
func ShortTimeouts(short bool) {
	if short {
		shortAttempt = trivial.AttemptStrategy{
			Total: 0.25e9,
			Delay: 0.01e9,
		}
		longAttempt = shortAttempt
	} else {
		shortAttempt = originalShortAttempt
		longAttempt = originalLongAttempt
	}
}

var ShortAttempt = &shortAttempt

func EC2ErrCode(err error) string {
	return ec2ErrCode(err)
}

// FabricateInstance creates a new fictitious instance
// given an existing instance and a new id.
func FabricateInstance(inst environs.Instance, newId string) environs.Instance {
	oldi := inst.(*instance)
	newi := &instance{oldi.e, &ec2.Instance{}}
	*newi.Instance = *oldi.Instance
	newi.InstanceId = newId
	return newi
}

// Access non exported methods on ec2.storage
type Storage interface {
	Put(file string, r io.Reader, length int64) error
	ResetMadeBucket()
}

func (s *storage) ResetMadeBucket() {
	s.Lock()
	defer s.Unlock()
	s.madeBucket = false
}

// WritablePublicStorage returns a Storage instance which is authorised to write to the PublicStorage bucket.
// It is used by tests which need to upload files.
func WritablePublicStorage(e environs.Environ) environs.Storage {
	// In the case of ec2, access to the public storage instance is created with the user's AWS credentials.
	// So write access is there implicitly, and we just need to cast to a writable storage instance.
	// This contrasts with the openstack case, where the public storage instance truly is read only and we need
	// to create a separate writable instance. If the ec2 case ever changes, the changes are confined to this method.
	return e.PublicStorage().(environs.Storage)
}
<|endoftext|>


<commit_before>package local

import (
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"io/ioutil"
	"os/exec"
	"strings"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// container represents an lxc container with the given name.
type container struct {
	name string
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) error {
	command := exec.Command(cmd, args...)
	out, err := command.CombinedOutput()
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	log.Print(string(out))
	return err
}

// ip returns the ip for the container.
func (c *container) ip() string {
	file, _ := filesystem().Open("/var/lib/misc/dnsmasq.leases")
	data, _ := ioutil.ReadAll(file)
	log.Print(data)
	for _, line := range strings.Split(string(data), "\n") {
		if strings.Index(line, c.name) != -1 {
			log.Printf("ip in %s", line)
			return strings.Split(line, " ")[2]
		}
	}
	return ""
}

// create creates a lxc container with ubuntu template by default.
func (c *container) create() error {
	return runCmd("sudo", "lxc-create", "-t", "ubuntu", "-n", c.name)
}

// start starts a lxc container.
func (c *container) start() error {
	return runCmd("sudo", "lxc-start", "--daemon", "-n", c.name)
}

// stop stops a lxc container.
func (c *container) stop() error {
	return runCmd("sudo", "lxc-stop", "-n", c.name)
}

// destroy destory a lxc container.
func (c *container) destroy() error {
	return runCmd("sudo", "lxc-destroy", "-n", c.name)
}
<commit_msg>provision/local: using a sleep before getting container ip.<commit_after>package local

import (
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"io/ioutil"
	"os/exec"
	"strings"
	"time"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// container represents an lxc container with the given name.
type container struct {
	name string
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) error {
	command := exec.Command(cmd, args...)
	out, err := command.CombinedOutput()
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	log.Print(string(out))
	return err
}

// ip returns the ip for the container.
func (c *container) ip() string {
	file, _ := filesystem().Open("/var/lib/misc/dnsmasq.leases")
	data, _ := ioutil.ReadAll(file)
	log.Print(string(data))
	time.Sleep(5 * time.Second)
	for _, line := range strings.Split(string(data), "\n") {
		if strings.Index(line, c.name) != -1 {
			log.Printf("ip in %s", line)
			return strings.Split(line, " ")[2]
		}
	}
	return ""
}

// create creates a lxc container with ubuntu template by default.
func (c *container) create() error {
	return runCmd("sudo", "lxc-create", "-t", "ubuntu", "-n", c.name)
}

// start starts a lxc container.
func (c *container) start() error {
	return runCmd("sudo", "lxc-start", "--daemon", "-n", c.name)
}

// stop stops a lxc container.
func (c *container) stop() error {
	return runCmd("sudo", "lxc-stop", "-n", c.name)
}

// destroy destory a lxc container.
func (c *container) destroy() error {
	return runCmd("sudo", "lxc-destroy", "-n", c.name)
}
<|endoftext|>


<commit_before>package types

type DatabaseConfig struct {
	Host     string `json:"host"`
	Port     uint   `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Database string `json:"database"`
	Driver   string `json:"driver"`
}
<commit_msg>added error var in types/database<commit_after>package types

import "github.com/pkg/errors"

var (
	ErrUnsupportedDriver = errors.New("Unsupported database driver")
)

type DatabaseConfig struct {
	Host     string `json:"host"`
	Port     uint   `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Database string `json:"database"`
	Driver   string `json:"driver"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/abh/geoip"
)

func main() {

	file6 := "../db/GeoIPv6.dat"

	gi6, err := geoip.Open(file6)
	if err != nil {
		fmt.Printf("Could not open GeoIPv6 database: %s\n", err)
	}

	gi, err := geoip.Open()
	if err != nil {
		fmt.Printf("Could not open GeoIP database: %s\n", err)
	}

	giasn, err := geoip.Open("../db/GeoIPASNum.dat")
	if err != nil {
		fmt.Printf("Could not open GeoIPASN database: %s\n", err)
	}

	giasn6, err := geoip.Open("../db/GeoIPASNumv6.dat")
	if err != nil {
		fmt.Printf("Could not open GeoIPASN database: %s\n", err)
	}

	if giasn != nil {
		ip := "207.171.7.51"
		asn, netmask := giasn.GetName(ip)
		fmt.Printf("%s: %s (netmask /%d)\n", ip, asn, netmask)

	}

	if gi != nil {
		test4(*gi, "207.171.7.51")
		test4(*gi, "127.0.0.1")
	}
	if gi6 != nil {
		ip := "2607:f238:2::5"
		country, netmask := gi6.GetCountry_v6(ip)
		var asn string
		var asn_netmask int
		if giasn6 != nil {
			asn, asn_netmask = giasn6.GetNameV6(ip)
		}
		fmt.Printf("%s: %s/%d %s/%d\n", ip, country, netmask, asn, asn_netmask)

	}

}

func test4(g geoip.GeoIP, ip string) {
	test(func(s string) (string, int) { return g.GetCountry(s) }, ip)
}

func test(f func(string) (string, int), ip string) {
	country, netmask := f(ip)
	fmt.Printf("ip: %s is [%s] (netmask %d)\n", ip, country, netmask)

}
<commit_msg>ex: depend on this fork, not ancestor<commit_after>package main

import (
	"fmt"
	"github.com/etix/geoip"
)

func main() {

	file6 := "../db/GeoIPv6.dat"

	gi6, err := geoip.Open(file6)
	if err != nil {
		fmt.Printf("Could not open GeoIPv6 database: %s\n", err)
	}

	gi, err := geoip.Open()
	if err != nil {
		fmt.Printf("Could not open GeoIP database: %s\n", err)
	}

	giasn, err := geoip.Open("../db/GeoIPASNum.dat")
	if err != nil {
		fmt.Printf("Could not open GeoIPASN database: %s\n", err)
	}

	giasn6, err := geoip.Open("../db/GeoIPASNumv6.dat")
	if err != nil {
		fmt.Printf("Could not open GeoIPASN database: %s\n", err)
	}

	if giasn != nil {
		ip := "207.171.7.51"
		asn, netmask := giasn.GetName(ip)
		fmt.Printf("%s: %s (netmask /%d)\n", ip, asn, netmask)

	}

	if gi != nil {
		test4(*gi, "207.171.7.51")
		test4(*gi, "127.0.0.1")
	}
	if gi6 != nil {
		ip := "2607:f238:2::5"
		country, netmask := gi6.GetCountry_v6(ip)
		var asn string
		var asn_netmask int
		if giasn6 != nil {
			asn, asn_netmask = giasn6.GetNameV6(ip)
		}
		fmt.Printf("%s: %s/%d %s/%d\n", ip, country, netmask, asn, asn_netmask)

	}

}

func test4(g geoip.GeoIP, ip string) {
	test(func(s string) (string, int) { return g.GetCountry(s) }, ip)
}

func test(f func(string) (string, int), ip string) {
	country, netmask := f(ip)
	fmt.Printf("ip: %s is [%s] (netmask %d)\n", ip, country, netmask)

}
<|endoftext|>