<commit_before>package cmux

import (
	"bytes"
	"io"
	"net"
	"sync"
	"testing"
)

type mockConn struct {
	net.Conn
	r io.Reader
}

func (c *mockConn) Read(b []byte) (n int, err error) {
	return c.r.Read(b)
}

func BenchmarkCMuxConn(b *testing.B) {
	benchHTTPPayload := make([]byte, 4096)
	copy(benchHTTPPayload, []byte("GET http://www.w3.org/ HTTP/1.1"))

	m := New(nil).(*cMux)
	l := m.Match(HTTP1Fast())

	go func() {
		for {
			if _, err := l.Accept(); err != nil {
				return
			}
		}
	}()

	donec := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(b.N)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c := &mockConn{
			r: bytes.NewReader(benchHTTPPayload),
		}
		m.serve(c, donec, &wg)
	}
}
<commit_msg>Add more benchmarks<commit_after>package cmux

import (
	"bytes"
	"io"
	"net"
	"sync"
	"testing"

	"golang.org/x/net/http2"
)

var (
	benchHTTP1Payload = make([]byte, 4096)
	benchHTTP2Payload = make([]byte, 4096)
)

func init() {
	copy(benchHTTP1Payload, []byte("GET http://www.w3.org/ HTTP/1.1"))
	copy(benchHTTP2Payload, http2.ClientPreface)
}

type mockConn struct {
	net.Conn
	r io.Reader
}

func (c *mockConn) Read(b []byte) (n int, err error) {
	return c.r.Read(b)
}

func discard(l net.Listener) {
	for {
		if _, err := l.Accept(); err != nil {
			return
		}
	}
}

func BenchmarkCMuxConnHTTP1(b *testing.B) {
	m := New(nil).(*cMux)
	l := m.Match(HTTP1Fast())

	go discard(l)

	donec := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(b.N)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c := &mockConn{
			r: bytes.NewReader(benchHTTP1Payload),
		}
		m.serve(c, donec, &wg)
	}
}

func BenchmarkCMuxConnHTTP2(b *testing.B) {
	m := New(nil).(*cMux)
	l := m.Match(HTTP2())
	go discard(l)

	donec := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(b.N)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c := &mockConn{
			r: bytes.NewReader(benchHTTP2Payload),
		}
		m.serve(c, donec, &wg)
	}
}

func BenchmarkCMuxConnHTTP1n2(b *testing.B) {
	m := New(nil).(*cMux)
	l1 := m.Match(HTTP1Fast())
	l2 := m.Match(HTTP2())

	go discard(l1)
	go discard(l2)

	donec := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(b.N)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c := &mockConn{
			r: bytes.NewReader(benchHTTP2Payload),
		}
		m.serve(c, donec, &wg)
	}
}

func BenchmarkCMuxConnHTTP2n1(b *testing.B) {
	m := New(nil).(*cMux)
	l2 := m.Match(HTTP2())
	l1 := m.Match(HTTP1Fast())

	go discard(l1)
	go discard(l2)

	donec := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(b.N)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		c := &mockConn{
			r: bytes.NewReader(benchHTTP1Payload),
		}
		m.serve(c, donec, &wg)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire_test

import (
	"bytes"
	"github.com/conformal/btcwire"
	"io/ioutil"
	"testing"
)

// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write
// a single byte variable length integer.
func BenchmarkWriteVarInt1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 1)
	}
}

// BenchmarkWriteVarInt3 performs a benchmark on how long it takes to write
// a three byte variable length integer.
func BenchmarkWriteVarInt3(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 65535)
	}
}

// BenchmarkWriteVarInt5 performs a benchmark on how long it takes to write
// a five byte variable length integer.
func BenchmarkWriteVarInt5(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 4294967295)
	}
}

// BenchmarkWriteVarInt9 performs a benchmark on how long it takes to write
// a nine byte variable length integer.
func BenchmarkWriteVarInt9(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 18446744073709551615)
	}
}

// BenchmarkReadVarInt1 performs a benchmark on how long it takes to read
// a single byte variable length integer.
func BenchmarkReadVarInt1(b *testing.B) {
	buf := []byte{0x01}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt3 performs a benchmark on how long it takes to read
// a three byte variable length integer.
func BenchmarkReadVarInt3(b *testing.B) {
	buf := []byte{0x0fd, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt5 performs a benchmark on how long it takes to read
// a five byte variable length integer.
func BenchmarkReadVarInt5(b *testing.B) {
	buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt9 performs a benchmark on how long it takes to read
// a nine byte variable length integer.
func BenchmarkReadVarInt9(b *testing.B) {
	buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a
// four byte variable length string.
func BenchmarkReadVarStr4(b *testing.B) {
	buf := []byte{0x04, 't', 'e', 's', 't'}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarString(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a
// ten byte variable length string.
func BenchmarkReadVarStr10(b *testing.B) {
	buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarString(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkWriteVarStr4 performs a benchmark on how long it takes to write a
// four byte variable length string.
func BenchmarkWriteVarStr4(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarString(ioutil.Discard, 0, "test")
	}
}

// BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a
// ten byte variable length string.
func BenchmarkWriteVarStr10(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345")
	}
}

// BenchmarkReadOutPoint performs a benchmark on how long it takes to read a
// transaction output point.
func BenchmarkReadOutPoint(b *testing.B) {
	buf := []byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
		0xff, 0xff, 0xff, 0xff, // Previous output index
	}
	var op btcwire.OutPoint
	for i := 0; i < b.N; i++ {
		btcwire.TstReadOutPoint(bytes.NewBuffer(buf), 0, 0, &op)
	}
}

// BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a
// transaction output point.
func BenchmarkWriteOutPoint(b *testing.B) {
	op := &btcwire.OutPoint{
		Hash:  btcwire.ShaHash{},
		Index: 0,
	}
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteOutPoint(ioutil.Discard, 0, 0, op)
	}
}

// BenchmarkReadTxOut performs a benchmark on how long it takes to read a
// transaction output.
func BenchmarkReadTxOut(b *testing.B) {
	buf := []byte{
		0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
		0x43, // Varint for length of pk script
		0x41, // OP_DATA_65
		0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c,
		0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16,
		0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c,
		0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c,
		0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4,
		0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6,
		0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e,
		0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58,
		0xee, // 65-byte signature
		0xac, // OP_CHECKSIG
	}
	var txOut btcwire.TxOut
	for i := 0; i < b.N; i++ {
		btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut)
	}
}

// BenchmarkWriteTxOut performs a benchmark on how long it takes to write
// a transaction output.
func BenchmarkWriteTxOut(b *testing.B) {
	txOut := blockOne.Transactions[0].TxOut[0]
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteTxOut(ioutil.Discard, 0, 0, txOut)
	}
}

// BenchmarkReadTxIn performs a benchmark on how long it takes to read a
// transaction input.
func BenchmarkReadTxIn(b *testing.B) {
	buf := []byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
		0xff, 0xff, 0xff, 0xff, // Previous output index
		0x07,                                     // Varint for length of signature script
		0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script
		0xff, 0xff, 0xff, 0xff, // Sequence
	}
	var txIn btcwire.TxIn
	for i := 0; i < b.N; i++ {
		btcwire.TstReadTxIn(bytes.NewBuffer(buf), 0, 0, &txIn)
	}
}

// BenchmarkWriteTxIn performs a benchmark on how long it takes to write
// a transaction input.
func BenchmarkWriteTxIn(b *testing.B) {
	txIn := blockOne.Transactions[0].TxIn[0]
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteTxIn(ioutil.Discard, 0, 0, txIn)
	}
}
<commit_msg>Add benchmarks for transaction Serialize.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire_test

import (
	"bytes"
	"github.com/conformal/btcwire"
	"io/ioutil"
	"testing"
)

// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write
// a single byte variable length integer.
func BenchmarkWriteVarInt1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 1)
	}
}

// BenchmarkWriteVarInt3 performs a benchmark on how long it takes to write
// a three byte variable length integer.
func BenchmarkWriteVarInt3(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 65535)
	}
}

// BenchmarkWriteVarInt5 performs a benchmark on how long it takes to write
// a five byte variable length integer.
func BenchmarkWriteVarInt5(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 4294967295)
	}
}

// BenchmarkWriteVarInt9 performs a benchmark on how long it takes to write
// a nine byte variable length integer.
func BenchmarkWriteVarInt9(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarInt(ioutil.Discard, 0, 18446744073709551615)
	}
}

// BenchmarkReadVarInt1 performs a benchmark on how long it takes to read
// a single byte variable length integer.
func BenchmarkReadVarInt1(b *testing.B) {
	buf := []byte{0x01}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt3 performs a benchmark on how long it takes to read
// a three byte variable length integer.
func BenchmarkReadVarInt3(b *testing.B) {
	buf := []byte{0x0fd, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt5 performs a benchmark on how long it takes to read
// a five byte variable length integer.
func BenchmarkReadVarInt5(b *testing.B) {
	buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarInt9 performs a benchmark on how long it takes to read
// a nine byte variable length integer.
func BenchmarkReadVarInt9(b *testing.B) {
	buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a
// four byte variable length string.
func BenchmarkReadVarStr4(b *testing.B) {
	buf := []byte{0x04, 't', 'e', 's', 't'}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarString(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a
// ten byte variable length string.
func BenchmarkReadVarStr10(b *testing.B) {
	buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
	for i := 0; i < b.N; i++ {
		btcwire.TstReadVarString(bytes.NewBuffer(buf), 0)
	}
}

// BenchmarkWriteVarStr4 performs a benchmark on how long it takes to write a
// four byte variable length string.
func BenchmarkWriteVarStr4(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarString(ioutil.Discard, 0, "test")
	}
}

// BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a
// ten byte variable length string.
func BenchmarkWriteVarStr10(b *testing.B) {
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345")
	}
}

// BenchmarkReadOutPoint performs a benchmark on how long it takes to read a
// transaction output point.
func BenchmarkReadOutPoint(b *testing.B) {
	buf := []byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
		0xff, 0xff, 0xff, 0xff, // Previous output index
	}
	var op btcwire.OutPoint
	for i := 0; i < b.N; i++ {
		btcwire.TstReadOutPoint(bytes.NewBuffer(buf), 0, 0, &op)
	}
}

// BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a
// transaction output point.
func BenchmarkWriteOutPoint(b *testing.B) {
	op := &btcwire.OutPoint{
		Hash:  btcwire.ShaHash{},
		Index: 0,
	}
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteOutPoint(ioutil.Discard, 0, 0, op)
	}
}

// BenchmarkReadTxOut performs a benchmark on how long it takes to read a
// transaction output.
func BenchmarkReadTxOut(b *testing.B) {
	buf := []byte{
		0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
		0x43, // Varint for length of pk script
		0x41, // OP_DATA_65
		0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c,
		0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16,
		0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c,
		0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c,
		0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4,
		0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6,
		0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e,
		0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58,
		0xee, // 65-byte signature
		0xac, // OP_CHECKSIG
	}
	var txOut btcwire.TxOut
	for i := 0; i < b.N; i++ {
		btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut)
	}
}

// BenchmarkWriteTxOut performs a benchmark on how long it takes to write
// a transaction output.
func BenchmarkWriteTxOut(b *testing.B) {
	txOut := blockOne.Transactions[0].TxOut[0]
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteTxOut(ioutil.Discard, 0, 0, txOut)
	}
}

// BenchmarkReadTxIn performs a benchmark on how long it takes to read a
// transaction input.
func BenchmarkReadTxIn(b *testing.B) {
	buf := []byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
		0xff, 0xff, 0xff, 0xff, // Previous output index
		0x07,                                     // Varint for length of signature script
		0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script
		0xff, 0xff, 0xff, 0xff, // Sequence
	}
	var txIn btcwire.TxIn
	for i := 0; i < b.N; i++ {
		btcwire.TstReadTxIn(bytes.NewBuffer(buf), 0, 0, &txIn)
	}
}

// BenchmarkWriteTxIn performs a benchmark on how long it takes to write
// a transaction input.
func BenchmarkWriteTxIn(b *testing.B) {
	txIn := blockOne.Transactions[0].TxIn[0]
	for i := 0; i < b.N; i++ {
		btcwire.TstWriteTxIn(ioutil.Discard, 0, 0, txIn)
	}
}

// BenchmarkSerializeTx performs a benchmark on how long it takes to serialize
// a transaction.
func BenchmarkSerializeTx(b *testing.B) {
	tx := blockOne.Transactions[0]
	for i := 0; i < b.N; i++ {
		tx.BtcEncode(ioutil.Discard, 0)

	}
}
<|endoftext|>


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

// Package dotpath is all about Pathinking - Path..think.ing - Path.ink.ing - Pa.think.ing - Pa.thin.king ...
//
// Package dotpath is intended as a parser for user-provided strings
// separated by some single character delimiter (which is not a Dot)
// such as filepath information or other hierarchical identifiers
// and gives a better meaning to multiple dots and trailing slashes:
//
//  ... => 'use Subtree also'
//  ..  => 'use Parent also', if .. is part of trailing dots and slashes
//  ./  => 'this MUST be a directory', if a trailing slash is given
//
// lexical.go: strictly lexical analysis of fullPath
//
// lexical.go uses some dedicated functions exported by pathsplitter.go, and the packages "strings" and "do/string".
//
// Typical use is upon e.g. flag.Args(), flags.StringVar(...)
package dotpath

// DotPath represents a lexically analysed filepath string.
//
// Special attention is given to slashes; especially to trailing slash(es)
// as indicator for "I mean: directory! Not file.",
// and to sequences of multiple dots; in particular tripledots "..."
// as indicators for subtree recursion, and trailing doubledots
// as indicators for "waydown" accumulation along parents/anchestors.
//
// Hint: Use New(path string) *DotPath for single entries, or
// Parse(pathNames ...string) for multiple entries.
//
// Note: A DotPath is immutable, and thus concurrency safe.
type DotPath struct {
	separator  string   // the one-char separator - must not be dot
	original   string   // the original input - never touched - String()
	volumeName string   // the VolumeName (if any)
	rootSlashs string   // leading slash(es) (if any)
	trailSlash string   // trailing slash(es) (if any)
	fullPath   string   // less any rooting                   - Name()
	lessDown   string   // less any triple ... dots           - Path
	lessTail   string   // lowest explicitly mentioned level  - Base
	goUpTail   []string // one dot plus the list of .. found in tail
	butDots    bool     // anything but dots?
}

// New returns a parsed *DotPath - separated by sep
//  Note: sep must have len == 1 and must not be dot
func New(path, sep string) *DotPath {
	if len(sep) != 1 {
		panic("DotPath: Separator must have length == 1!")
	}
	if sep == Dot {
		panic("DotPath: Separator must not be a Dot1!")
	}
	dp := new(DotPath)
	dp.separator = sep
	dp.original = noEmpty(path) // make sure it's not empty
	return dp.fill()
}

// NewPath returns a parsed *DotPath - separated by go's PathSeparator Slash `/`
func NewPath(path string) *DotPath {
	return New(path, OsPathSeparator)
}

// NewFilePath returns a parsed *DotPath - separated by the current os.PathSeparator
func NewFilePath(path string) *DotPath {
	return New(path, OsPathSeparator)
}

func (dp *DotPath) fill() *DotPath {
	dp = dp.getVolumeName()                            // VolumenName (if any)
	dp = dp.stripVolumeName()                          // fullPath = original less VolumeName (if any)
	dp = dp.stripPrefixSlashes()                       // fullPath = fullPath less leading slash(es) (if any);
	dp = dp.stripSuffixSlashes()                       // fullPath = fullPath less trailing slash(es) (if any);
	dp.butDots = false                                 // butDots  = initialised
	dp = dp.fullPathNoMultipleDots()                   // fullPath = fullPath with cleaned sequences of any multiple consecutive dots;
	dp.lessDown = dp.fullPath                          // lessDown = fullPath
	dp = dp.lessDownLessTripleDots()                   // lessDown = lessDown less any tripledots
	dp.lessTail, dp.goUpTail = dp.lessDown, []string{} // lessTail = lessDown
	dp = dp.lessTailLessDoubleDots()                   // lessTail = lessDown less trailing doubledots;

	return dp
}

func (dp *DotPath) verbosefill() *DotPath {
	dp = dp.getVolumeName()             // VolumenName (if any)
	dp = dp.stripVolumeName()           // fullPath = original less VolumeName (if any)
	println("dp.fullPath", dp.fullPath) //
	dp = dp.stripPrefixSlashes()        // fullPath = fullPath less leading slash(es) (if any);
	dp = dp.stripSuffixSlashes()        // fullPath = fullPath less trailing slash(es) (if any);
	dp.butDots = false                  // butDots  = initialised
	dp = dp.fullPathNoMultipleDots()    // fullPath = fullPath with cleaned sequences of any multiple consecutive dots;
	println("dp.fullPath", dp.fullPath, "\tbutDots", dp.butDots)
	dp.lessDown = dp.fullPath                          // lessDown = fullPath
	println("dp.lessDown", dp.lessDown)                //
	dp = dp.lessDownLessTripleDots()                   // lessDown = lessDown less any tripledots
	println("dp.lessDown", dp.lessDown, "\tless ...")  //
	dp.lessTail, dp.goUpTail = dp.lessDown, []string{} // lessTail = lessDown
	println("dp.lessTail", dp.lessTail)                //
	dp = dp.lessTailLessDoubleDots()                   // lessTail = lessDown less trailing doubledots;
	println("dp.lessTail", dp.lessTail, "\tless ..")   //

	return dp
}

// LooksLikeIsAbs - returns true if some leading Slash was found
func (dp *DotPath) LooksLikeIsAbs() bool {
	return (len(dp.rootSlashs) > 0)
}

// LooksLikeIsDir - returns true if some trailing Slash was found
func (dp *DotPath) LooksLikeIsDir() bool {
	return (len(dp.trailSlash) > 0)
}

// Separator - returns the single character separator string
func (dp *DotPath) Separator() string {
	return dp.separator
}

// String - returns the original input - skipping nothing
func (dp *DotPath) String() string {
	return dp.original
}

// PathName - returns the full analysed path - incl. any triple ... dots
//  Note: intentionally, path.Cleaning is is not applied as
//  some tripledot might disappear due to being followed by some doubledot.
func (dp *DotPath) PathName() string {
	return dp.volumeName + dp.rootSlashs + dp.fullPath + dp.trailSlash
}

// PathBase - returns the path - less any triple ... dots and trailing up .. double dots,
// (including volumename and trailing delimiter, if any).
func (dp *DotPath) PathBase() string {
	return dp.goodPath(dp.lessTail)
}

// PathText - returns the path - less any triple ... dots,
// (including volumename and trailing delimiter, if any).
func (dp *DotPath) PathText() string {
	return dp.goodPath(dp.lessDown)
}

// Path - returns the path - less any triple ... dots and any (eventual) trailing slash
// (including volumename, if any).
func (dp *DotPath) Path() string {
	return dp.clean(dp.volumeName + dp.rootSlashs + dp.lessDown)
}

// RecursePathS returns any (partial) path which ends in a Down ...
func (dp *DotPath) RecursePathS() (pathS []string) {

	for _, downPath := range dp.downPathS() {
		pathS = append(pathS, dp.goodPath(downPath))
	}
	return pathS
}

// WaydownPathS returns any (partial) path which is followed by some trailing GoUp ..
//  Note: such pathS should be considered before PathBase(), and are
//  only relevant if PathText() != PathBase(); Path() would be the first WaydownPath
func (dp *DotPath) WaydownPathS() (pathS []string) {

	for pos := len(dp.goUpTail); pos > 0; pos-- { // shrinking list of GoUp's
		pathS = append(pathS, dp.goodPath(dp.goUpPath(pos)))
	}
	return pathS
}

// PathS conveniently returns any WaydownPath and the Base.
//  Note: If there is no way down mentioned (and thus: Path and Base are same),
//  the returned list just holds this single element: the Path
func (dp *DotPath) PathS() (pathS []string) {
	pathS = append(pathS, dp.WaydownPathS()...)
	pathS = append(pathS, dp.PathBase())
	return pathS
}

// HasVolumeName - returns true if some filepath.VolumeName was found
//  Note: only relevant, if separator == OsPathSeparator, e.g. NewFilePath
func (dp *DotPath) HasVolumeName() bool {
	return (len(dp.volumeName) > 0)
}

// VolumeName - returns the VolumeName, if any
//  Note: only relevant, if separator == OsPathSeparator, e.g. NewFilePath
func (dp *DotPath) VolumeName() string {
	return dp.volumeName
}

// Intentionally we differ from Clean here and respect any trailSlash,
// as such indicates unambigously: a directory is intended to be named.
func (dp *DotPath) goodPath(pathName string) (fullName string) {
	return dp.clean(dp.volumeName+dp.rootSlashs+pathName) + dp.trailSlash
}

/*
Note: We focus on 'trailing' dots!

base/../foo/../bar/..	=> bar/.. & bar

Otherwise we get things like these, with duplicate visits:

base					=> base)
base/..					=> .)
base/../foo/			=> foo)
base/../foo/..			=> .	which we had before!)
base/../foo/../bar		=> bar
base/../foo/../bar/..	=> .	which we had before!)

root/base/../foo/../../bar/../..

root/base					 		=> root/base
root/base/..						=> root
root/base/../foo					=> root/foo
root/base/../foo/..					=> root	which we had before!)
root/base/../foo/../..				=> .
root/base/../foo/../../bar			=> bar
root/base/../foo/../../bar/..		=> .		which we had before!)
root/base/../foo/../../bar/../..	=> ..

*/
<commit_msg>refine docu<commit_after>// Copyright 2016 Andreas Pannewitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dotpath is all about Pathinking - Path..think.ing - Path.ink.ing - Pa.think.ing - Pa.thin.king ...
//
// Package dotpath is intended as a parser for user-provided strings
// separated by some single character delimiter (which is not a Dot)
// such as filepath information or other hierarchical identifiers
// and gives an extended meaning to multiple dots and trailing slashes:
//
//  ... => 'use Subtree also'
//  ..  => 'use Parent also', if .. is part of trailing dots and slashes
//  ./  => 'this MUST be a directory', if a trailing slash is given
//
// lexical.go: strictly lexical analysis of fullPath
//
// lexical.go uses some dedicated functions exported by pathsplitter.go, and the packages "strings" and "do/string".
//
// Typical use is upon e.g. flag.Args(), flags.StringVar(...)
package dotpath

// DotPath represents a lexically analysed filepath string.
//
// Special attention is given to slashes; especially to trailing slash(es)
// as indicator for "I mean: directory! Not file.",
// and to sequences of multiple dots; in particular tripledots "..."
// as indicators for subtree recursion, and trailing doubledots
// as indicators for "waydown" accumulation along parents/anchestors.
//
// Hint: Use New(path string) *DotPath for single entries, or
// Parse(pathNames ...string) for multiple entries.
//
// Note: A DotPath is immutable, and thus concurrency safe.
type DotPath struct {
	separator  string   // the one-char separator - must not be dot
	original   string   // the original input - never touched - String()
	volumeName string   // the VolumeName (if any)
	rootSlashs string   // leading slash(es) (if any)
	trailSlash string   // trailing slash(es) (if any)
	fullPath   string   // less any rooting                   - Name()
	lessDown   string   // less any triple ... dots           - Path
	lessTail   string   // lowest explicitly mentioned level  - Base
	goUpTail   []string // one dot plus the list of .. found in tail
	butDots    bool     // anything but dots?
}

// New returns a parsed *DotPath - separated by sep
//  Note: sep must have len == 1 and must not be dot
func New(path, sep string) *DotPath {
	if len(sep) != 1 {
		panic("DotPath: Separator must have length == 1!")
	}
	if sep == Dot {
		panic("DotPath: Separator must not be a Dot1!")
	}
	dp := new(DotPath)
	dp.separator = sep
	dp.original = noEmpty(path) // make sure it's not empty
	return dp.fill()
}

// NewPath returns a parsed *DotPath - separated by go's PathSeparator Slash `/`
func NewPath(path string) *DotPath {
	return New(path, OsPathSeparator)
}

// NewFilePath returns a parsed *DotPath - separated by the current os.PathSeparator
func NewFilePath(path string) *DotPath {
	return New(path, OsPathSeparator)
}

func (dp *DotPath) fill() *DotPath {
	dp = dp.getVolumeName()                            // VolumenName (if any)
	dp = dp.stripVolumeName()                          // fullPath = original less VolumeName (if any)
	dp = dp.stripPrefixSlashes()                       // fullPath = fullPath less leading slash(es) (if any);
	dp = dp.stripSuffixSlashes()                       // fullPath = fullPath less trailing slash(es) (if any);
	dp.butDots = false                                 // butDots  = initialised
	dp = dp.fullPathNoMultipleDots()                   // fullPath = fullPath with cleaned sequences of any multiple consecutive dots;
	dp.lessDown = dp.fullPath                          // lessDown = fullPath
	dp = dp.lessDownLessTripleDots()                   // lessDown = lessDown less any tripledots
	dp.lessTail, dp.goUpTail = dp.lessDown, []string{} // lessTail = lessDown
	dp = dp.lessTailLessDoubleDots()                   // lessTail = lessDown less trailing doubledots;

	return dp
}

func (dp *DotPath) verbosefill() *DotPath {
	dp = dp.getVolumeName()             // VolumenName (if any)
	dp = dp.stripVolumeName()           // fullPath = original less VolumeName (if any)
	println("dp.fullPath", dp.fullPath) //
	dp = dp.stripPrefixSlashes()        // fullPath = fullPath less leading slash(es) (if any);
	dp = dp.stripSuffixSlashes()        // fullPath = fullPath less trailing slash(es) (if any);
	dp.butDots = false                  // butDots  = initialised
	dp = dp.fullPathNoMultipleDots()    // fullPath = fullPath with cleaned sequences of any multiple consecutive dots;
	println("dp.fullPath", dp.fullPath, "\tbutDots", dp.butDots)
	dp.lessDown = dp.fullPath                          // lessDown = fullPath
	println("dp.lessDown", dp.lessDown)                //
	dp = dp.lessDownLessTripleDots()                   // lessDown = lessDown less any tripledots
	println("dp.lessDown", dp.lessDown, "\tless ...")  //
	dp.lessTail, dp.goUpTail = dp.lessDown, []string{} // lessTail = lessDown
	println("dp.lessTail", dp.lessTail)                //
	dp = dp.lessTailLessDoubleDots()                   // lessTail = lessDown less trailing doubledots;
	println("dp.lessTail", dp.lessTail, "\tless ..")   //

	return dp
}

// LooksLikeIsAbs - returns true if some leading Slash was found
func (dp *DotPath) LooksLikeIsAbs() bool {
	return (len(dp.rootSlashs) > 0)
}

// LooksLikeIsDir - returns true if some trailing Slash was found
func (dp *DotPath) LooksLikeIsDir() bool {
	return (len(dp.trailSlash) > 0)
}

// Separator - returns the single character separator string
func (dp *DotPath) Separator() string {
	return dp.separator
}

// String - returns the original input - skipping nothing
func (dp *DotPath) String() string {
	return dp.original
}

// PathName - returns the full analysed path - incl. any triple ... dots
//  Note: intentionally, path.Cleaning is is not applied as
//  some tripledot might disappear due to being followed by some doubledot.
func (dp *DotPath) PathName() string {
	return dp.volumeName + dp.rootSlashs + dp.fullPath + dp.trailSlash
}

// PathBase - returns the path - less any triple ... dots and trailing up .. double dots,
// (including volumename and trailing delimiter, if any).
func (dp *DotPath) PathBase() string {
	return dp.goodPath(dp.lessTail)
}

// PathText - returns the path - less any triple ... dots,
// (including volumename and trailing delimiter, if any).
func (dp *DotPath) PathText() string {
	return dp.goodPath(dp.lessDown)
}

// Path - returns the path - less any triple ... dots and any (eventual) trailing slash
// (including volumename, if any).
func (dp *DotPath) Path() string {
	return dp.clean(dp.volumeName + dp.rootSlashs + dp.lessDown)
}

// RecursePathS returns any (partial) path which ends in a Down ...
func (dp *DotPath) RecursePathS() (pathS []string) {

	for _, downPath := range dp.downPathS() {
		pathS = append(pathS, dp.goodPath(downPath))
	}
	return pathS
}

// WaydownPathS returns any (partial) path which is followed by some trailing GoUp ..
//  Note: such pathS should be considered before PathBase(), and are
//  only relevant if PathText() != PathBase(); Path() would be the first WaydownPath
func (dp *DotPath) WaydownPathS() (pathS []string) {

	for pos := len(dp.goUpTail); pos > 0; pos-- { // shrinking list of GoUp's
		pathS = append(pathS, dp.goodPath(dp.goUpPath(pos)))
	}
	return pathS
}

// PathS conveniently returns any WaydownPath and the Base.
//  Note: If there is no way down mentioned (and thus: Path and Base are same),
//  the returned list just holds this single element: the Path
func (dp *DotPath) PathS() (pathS []string) {
	pathS = append(pathS, dp.WaydownPathS()...)
	pathS = append(pathS, dp.PathBase())
	return pathS
}

// HasVolumeName - returns true if some filepath.VolumeName was found
//  Note: only relevant, if separator == OsPathSeparator, e.g. NewFilePath
func (dp *DotPath) HasVolumeName() bool {
	return (len(dp.volumeName) > 0)
}

// VolumeName - returns the VolumeName, if any
//  Note: only relevant, if separator == OsPathSeparator, e.g. NewFilePath
func (dp *DotPath) VolumeName() string {
	return dp.volumeName
}

// Intentionally we differ from Clean here and respect any trailSlash,
// as such indicates unambigously: a directory is intended to be named.
func (dp *DotPath) goodPath(pathName string) (fullName string) {
	return dp.clean(dp.volumeName+dp.rootSlashs+pathName) + dp.trailSlash
}

/*
Note: We focus on 'trailing' dots!

base/../foo/../bar/..	=> bar/.. & bar

Otherwise we get things like these, with duplicate visits:

base					=> base)
base/..					=> .)
base/../foo/			=> foo)
base/../foo/..			=> .	which we had before!)
base/../foo/../bar		=> bar
base/../foo/../bar/..	=> .	which we had before!)

root/base/../foo/../../bar/../..

root/base					 		=> root/base
root/base/..						=> root
root/base/../foo					=> root/foo
root/base/../foo/..					=> root	which we had before!)
root/base/../foo/../..				=> .
root/base/../foo/../../bar			=> bar
root/base/../foo/../../bar/..		=> .		which we had before!)
root/base/../foo/../../bar/../..	=> ..

*/
<|endoftext|>


<commit_before>package wrapper

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"time"

	"github.com/gocql/gocql"
	log "github.com/sirupsen/logrus"
)

// Schema file to create keyspace if required
const (
	schemaDefaultPath     = "/usr/local/bin"
	schemaDefaultFileName = "schema.sql"

	envCassandraSchemaPath     = "CASSANDRA_SCHEMA_PATH"
	envCassandraSchemaFileName = "CASSANDRA_SCHEMA_FILE_NAME"
)

var schemaPath = "/usr/local/bin"
var schemaFileName = "schema.sql"

// Package level initialization.
//
// init functions are automatically executed when the programs starts
func init() {

	// reading and setting up environment variables
	schemaPath = getenv(envCassandraSchemaPath, schemaDefaultPath)
	schemaFileName = getenv(envCassandraSchemaFileName, schemaDefaultFileName)

	log.Debugf("Got schema path: %s", schemaPath)
	log.Debugf("Got schema file name: %s", schemaFileName)
}

// sessionInitializer is an initializer for a cassandra session
type sessionInitializer struct {
	clusterHostName string
	keyspace        string
}

// sessionHolder stores a cassandra session
type sessionHolder struct {
	session SessionInterface
}

// New return a cassandra session Initializer
func New(clusterHostName, keyspace string) Initializer {
	return sessionInitializer{
		clusterHostName: clusterHostName,
		keyspace:        keyspace,
	}
}

// Initialize waits for a Cassandra session, initializes Cassandra keyspace and creates tables if required.
// NOTE: Needs to be called only once on the app startup, won't fail if it is called multiple times but is not necessary.
//
// Params:
//	clusterHostName: Cassandra cluster host
//	systemKeyspace: System keyspace
//	appKeyspace: Application keyspace
//	connectionTimeout: timeout to get the connection
func Initialize(clusterHostName, systemKeyspace, appKeyspace string, connectionTimeout time.Duration) {
	log.Debug("Setting up cassandra db")
	connectionHolder, err := loop(connectionTimeout, New(clusterHostName, systemKeyspace), "cassandra-db")
	if err != nil {
		log.Fatalf("error connecting to Cassandra db: %v", err)
		panic(err)
	}
	defer connectionHolder.CloseSession()

	log.Debug("Setting up cassandra keyspace")
	err = createAppKeyspaceIfRequired(clusterHostName, systemKeyspace, appKeyspace)
	if err != nil {
		log.Fatalf("error creating keyspace for Cassandra db: %v", err)
		panic(err)
	}

	log.Info("Cassandra keyspace has been set up")
}

// NewSession starts a new cassandra session for the given keyspace
// NOTE: It is responsibility of the caller to close this new session.
//
// Returns a session Holder for the session, or an error if can't start the session
func (i sessionInitializer) NewSession() (Holder, error) {
	session, err := newKeyspaceSession(i.clusterHostName, i.keyspace, 600*time.Millisecond)
	if err != nil {
		log.Errorf("error starting Cassandra session for the cluster hostname: %s and keyspace: %s - %v",
			i.clusterHostName, i.keyspace, err)
		return nil, err
	}
	sessionRetry := sessionRetry{session}
	connectionHolder := sessionHolder{sessionRetry}
	return connectionHolder, nil
}

// GetSession returns the stored cassandra session
func (holder sessionHolder) GetSession() SessionInterface {
	return holder.session
}

// CloseSession closes the cassandra session
func (holder sessionHolder) CloseSession() {
	holder.session.Close()
}

// newKeyspaceSession returns a new session for the given keyspace
func newKeyspaceSession(clusterHostName, keyspace string, clusterTimeout time.Duration) (*gocql.Session, error) {
	log.Infof("Creating new cassandra session for cluster hostname: %s and keyspace: %s", clusterHostName, keyspace)
	cluster := gocql.NewCluster(clusterHostName)
	cluster.Keyspace = keyspace
	cluster.Timeout = clusterTimeout
	return cluster.CreateSession()
}

// createAppKeyspaceIfRequired creates the keyspace for the app if it doesn't exist
func createAppKeyspaceIfRequired(clusterHostName, systemKeyspace, appKeyspace string) error {
	// Getting the schema file if exist
	stmtList, err := getStmtsFromFile(path.Join(schemaPath, schemaFileName))
	if err != nil {
		return err
	}
	if stmtList == nil { // Didn't fail but returned nil, probably the file does not exist
		return nil
	}

	log.Info("about to create a session with a 5 minute timeout to allow for all schema creation")
	session, err := newKeyspaceSession(clusterHostName, systemKeyspace, 5*time.Minute)
	if err != nil {
		return err
	}
	currentKeyspace := systemKeyspace

	var sessionList []*gocql.Session
	defer func() {
		for _, s := range sessionList {
			if s != nil && !s.Closed() {
				s.Close()
			}
		}
	}()

	log.Debugf("Creating new keyspace if required: %s", appKeyspace)

	for _, stmt := range stmtList {
		log.Debugf("Executing statement: %s", stmt)

		// New session for use statement
		newKeyspace, isCaseSensitive := getKeyspaceNameFromUseStmt(stmt)
		if newKeyspace != "" {
			if (isCaseSensitive && newKeyspace != currentKeyspace) || (!isCaseSensitive &&
				strings.ToLower(newKeyspace) != strings.ToLower(currentKeyspace)) {
				log.Infof("about to create a session with a 5 minute timeout to set keyspace: %s", newKeyspace)
				session, err = newKeyspaceSession(clusterHostName, newKeyspace, 5*time.Minute) //5 minutes
				if err != nil {
					return err
				}
				currentKeyspace = newKeyspace
				sessionList = append(sessionList, session)
				log.Debugf("Changed to new keyspace: %s", newKeyspace)
			}
			continue
		}

		// execute statement
		err = session.Query(stmt).Exec()
		if err != nil {
			return err
		}
		log.Debug("Statement executed")
	}

	log.Debugf("Created new keyspace: %s", appKeyspace)
	return nil
}

// getStmtsFromFile extracts CQL statements from the file
func getStmtsFromFile(fileName string, ) ([]string, error) {
	// Verify first if the file exist
	if _, err := os.Stat(fileName); err != nil {
		if os.IsNotExist(err) { // Does not exist
			log.Warnf("no schema file [%s] found initializing Cassandra.", fileName)
			return nil, nil
		}
	}

	content, err := ioutil.ReadFile(fileName)
	if err != nil {
		return nil, err
	}

	pattern := regexp.MustCompile(`(?ms)([^"';]*?)("(?:[^"]|"")*"|'(?:[^']|'')*'|\$\$.*?\$\$|(/\*.*?\*/)|((?:--|//).*?$)|;\n?)`)

	var stmtList []string

	i := 0
	contentLength := len(content)
	var stmt bytes.Buffer
	for i < contentLength {
		subIndexes := pattern.FindSubmatchIndex(content[i:])
		if len(subIndexes) > 0 {
			end := subIndexes[1]
			stmt.Write(getMatch(content, i, subIndexes, 2, 3))
			stmtTail := getMatch(content, i, subIndexes, 4, 5)
			comment := getMatch(content, i, subIndexes, 6, 7)
			lineComment := getMatch(content, i, subIndexes, 8, 9)
			if comment == nil && lineComment == nil {
				if stmtTail != nil && string(bytes.TrimSpace(stmtTail)) == ";" {
					stmtList = append(stmtList, stmt.String())
					stmt.Reset()
				} else {
					stmt.Write(stmtTail)
				}
			}
			i = i + end
		} else {
			break
		}
	}

	return stmtList, nil

}

// getMatch returns the matched substring if there's a match, nil otherwise
func getMatch(src []byte, base int, match []int, start int, end int, ) []byte {
	if match[start] >= 0 {
		return src[base+match[start] : base+match[end]]
	} else {
		return nil
	}
}

// getKeyspaceNameFromUseStmt return keyspace name for use statement
func getKeyspaceNameFromUseStmt(stmt string, ) (string, bool) {
	pattern := regexp.MustCompile(`(?ms)[Uu][Ss][Ee]\s+("(?:[^"]|"")+"|\w+)`)
	if pattern.MatchString(stmt) {
		match := pattern.FindStringSubmatch(stmt)
		if len(match) > 1 {
			keyspace := match[1]
			caseSensitive := false
			if strings.HasPrefix(keyspace, "\"") && strings.HasSuffix(keyspace, "\"") {
				keyspace = strings.Trim(keyspace, "\"")
				caseSensitive = true
			}
			return keyspace, caseSensitive
		}
	}
	return "", false
}

// Loop is a loop that tries to get a connection until a timeout is reached
//
// Params:
//	 timeout: timeout to get the connection
//	 initializer : initializer to start the session
//	 connectionHost : name of host for the connection
//
// Returns a session Holder to store the session, or an error if the timeout was reached
func loop(timeout time.Duration, initializer Initializer, connectionHost string, ) (Holder, error) {
	log.Debugf("Connection loop to connect to %s, timeout to use: %s", connectionHost, timeout)
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	timeoutExceeded := time.After(timeout)
	for {
		select {
		case <-timeoutExceeded:
			return nil, fmt.Errorf("connection to %s failed after %s timeout", connectionHost, timeout)

		case <-ticker.C:
			log.Infof("Trying to connect to: %s", connectionHost)
			connectionHolder, err := initializer.NewSession()
			if err == nil {
				log.Infof("Successful connection to: %s", connectionHost)
				return connectionHolder, nil
			}
			log.Infof("Trying to connect to %s, failed attempt: %v", connectionHost, err)
		}
	}

}

// getenv get a string value from an environment variable
// or return the given default value if the environment variable is not set
//
// Params:
//  envVariable : environment variable
//  defaultValue : value to return if environment variable is not set
//
// Returns the string value for the specified variable
func getenv(envVariable string, defaultValue string) string {

	log.Debugf("Setting value for: %s", envVariable)
	returnValue := defaultValue
	log.Debugf("Default value for %s : %s", envVariable, defaultValue)
	envStr := os.Getenv(envVariable)
	if envStr != "" {
		returnValue = envStr
		log.Debugf("Init value for %s set to: %s", envVariable, envStr)
	}

	return returnValue
}
<commit_msg>Janus#463 cassandra repo (#470)<commit_after>package wrapper

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"time"

	"github.com/gocql/gocql"
	log "github.com/sirupsen/logrus"
)

// Schema file to create keyspace if required
const (
	schemaDefaultPath     = "/usr/local/bin"
	schemaDefaultFileName = "schema.sql"

	envCassandraSchemaPath     = "CASSANDRA_SCHEMA_PATH"
	envCassandraSchemaFileName = "CASSANDRA_SCHEMA_FILE_NAME"
)

var schemaPath = "/usr/local/bin"
var schemaFileName = "schema.sql"
var clusterConsistency = gocql.Quorum

// Package level initialization.
//
// init functions are automatically executed when the programs starts
func init() {

	// reading and setting up environment variables
	schemaPath = getenv(envCassandraSchemaPath, schemaDefaultPath)
	schemaFileName = getenv(envCassandraSchemaFileName, schemaDefaultFileName)

	log.Debugf("Got schema path: %s", schemaPath)
	log.Debugf("Got schema file name: %s", schemaFileName)
}

// sessionInitializer is an initializer for a cassandra session
type sessionInitializer struct {
	clusterHostName string
	keyspace        string
	consistency gocql.Consistency
}

// sessionHolder stores a cassandra session
type sessionHolder struct {
	session SessionInterface
}

// New return a cassandra session Initializer
func New(clusterHostName, keyspace string) Initializer {
	log.Debugf("in new")
	consistencyEnv := getenv("CLUSTER_CONSISTENCY", clusterConsistency.String())
	consistency := checkConsistency(consistencyEnv)
	return sessionInitializer{
		clusterHostName: clusterHostName,
		keyspace:        keyspace,
		consistency: consistency,
	}
}

// Initialize waits for a Cassandra session, initializes Cassandra keyspace and creates tables if required.
// NOTE: Needs to be called only once on the app startup, won't fail if it is called multiple times but is not necessary.
//
// Params:
//	clusterHostName: Cassandra cluster host
//	systemKeyspace: System keyspace
//	appKeyspace: Application keyspace
//	connectionTimeout: timeout to get the connection
func Initialize(clusterHostName, systemKeyspace, appKeyspace string, connectionTimeout time.Duration) {
	log.Debug("Setting up cassandra db")
	connectionHolder, err := loop(connectionTimeout, New(clusterHostName, systemKeyspace), "cassandra-db")
	if err != nil {
		log.Fatalf("error connecting to Cassandra db: %v", err)
		panic(err)
	}
	defer connectionHolder.CloseSession()

	log.Debug("Setting up cassandra keyspace")
	err = createAppKeyspaceIfRequired(clusterHostName, systemKeyspace, appKeyspace)
	if err != nil {
		log.Fatalf("error creating keyspace for Cassandra db: %v", err)
		panic(err)
	}

	log.Info("Cassandra keyspace has been set up")
}

// NewSession starts a new cassandra session for the given keyspace
// NOTE: It is responsibility of the caller to close this new session.
//
// Returns a session Holder for the session, or an error if can't start the session
func (i sessionInitializer) NewSession() (Holder, error) {
	session, err := newKeyspaceSession(i.clusterHostName, i.keyspace, 600*time.Millisecond)
	if err != nil {
		log.Errorf("error starting Cassandra session for the cluster hostname: %s and keyspace: %s - %v",
			i.clusterHostName, i.keyspace, err)
		return nil, err
	}
	sessionRetry := sessionRetry{session}
	connectionHolder := sessionHolder{sessionRetry}
	return connectionHolder, nil
}

// GetSession returns the stored cassandra session
func (holder sessionHolder) GetSession() SessionInterface {
	return holder.session
}

// CloseSession closes the cassandra session
func (holder sessionHolder) CloseSession() {
	holder.session.Close()
}

// newKeyspaceSession returns a new session for the given keyspace
func newKeyspaceSession(clusterHostName, keyspace string, clusterTimeout time.Duration) (*gocql.Session, error) {
	log.Infof("Creating new cassandra session for cluster hostname: %s and keyspace: %s", clusterHostName, keyspace)
	cluster := gocql.NewCluster(clusterHostName)
	cluster.Keyspace = keyspace
	cluster.Timeout = clusterTimeout
	consistencyEnv := getenv("CLUSTER_CONSISTENCY", clusterConsistency.String())
	consistency := checkConsistency(consistencyEnv)
	cluster.Consistency = consistency
	return cluster.CreateSession()
}

// createAppKeyspaceIfRequired creates the keyspace for the app if it doesn't exist
func createAppKeyspaceIfRequired(clusterHostName, systemKeyspace, appKeyspace string) error {
	// Getting the schema file if exist
	stmtList, err := getStmtsFromFile(path.Join(schemaPath, schemaFileName))
	if err != nil {
		return err
	}
	if stmtList == nil { // Didn't fail but returned nil, probably the file does not exist
		return nil
	}

	log.Info("about to create a session with a 5 minute timeout to allow for all schema creation")
	session, err := newKeyspaceSession(clusterHostName, systemKeyspace, 5*time.Minute)
	if err != nil {
		return err
	}
	currentKeyspace := systemKeyspace

	var sessionList []*gocql.Session
	defer func() {
		for _, s := range sessionList {
			if s != nil && !s.Closed() {
				s.Close()
			}
		}
	}()

	log.Debugf("Creating new keyspace if required: %s", appKeyspace)

	for _, stmt := range stmtList {
		log.Debugf("Executing statement: %s", stmt)
		// New session for use statement
		newKeyspace, isCaseSensitive := getKeyspaceNameFromUseStmt(stmt)
		if newKeyspace != "" {
			if (isCaseSensitive && newKeyspace != currentKeyspace) || (!isCaseSensitive &&
				strings.ToLower(newKeyspace) != strings.ToLower(currentKeyspace)) {
				log.Infof("about to create a session with a 5 minute timeout to set keyspace: %s", newKeyspace)
				session, err = newKeyspaceSession(clusterHostName, newKeyspace, 5*time.Minute) //5 minutes
				if err != nil {
					return err
				}
				currentKeyspace = newKeyspace
				sessionList = append(sessionList, session)
				log.Debugf("Changed to new keyspace: %s", newKeyspace)
			}
			continue
		}

		// execute statement
		err = session.Query(stmt).Exec()
		if err != nil {
			log.Error("statement error: %v", err)
			return err
		}
		log.Debug("Statement executed")
	}

	log.Debugf("app keyspace set to: %s", appKeyspace)
	return nil
}

// getStmtsFromFile extracts CQL statements from the file
func getStmtsFromFile(fileName string, ) ([]string, error) {
	// Verify first if the file exist
	if _, err := os.Stat(fileName); err != nil {
		if os.IsNotExist(err) { // Does not exist
			log.Warnf("no schema file [%s] found initializing Cassandra.", fileName)
			return nil, nil
		}
	}

	content, err := ioutil.ReadFile(fileName)
	if err != nil {
		return nil, err
	}

	pattern := regexp.MustCompile(`(?ms)([^"';]*?)("(?:[^"]|"")*"|'(?:[^']|'')*'|\$\$.*?\$\$|(/\*.*?\*/)|((?:--|//).*?$)|;\n?)`)

	var stmtList []string

	i := 0
	contentLength := len(content)
	var stmt bytes.Buffer
	for i < contentLength {
		subIndexes := pattern.FindSubmatchIndex(content[i:])
		if len(subIndexes) > 0 {
			end := subIndexes[1]
			stmt.Write(getMatch(content, i, subIndexes, 2, 3))
			stmtTail := getMatch(content, i, subIndexes, 4, 5)
			comment := getMatch(content, i, subIndexes, 6, 7)
			lineComment := getMatch(content, i, subIndexes, 8, 9)
			if comment == nil && lineComment == nil {
				if stmtTail != nil && string(bytes.TrimSpace(stmtTail)) == ";" {
					stmtList = append(stmtList, stmt.String())
					stmt.Reset()
				} else {
					stmt.Write(stmtTail)
				}
			}
			i = i + end
		} else {
			break
		}
	}

	return stmtList, nil

}

// getMatch returns the matched substring if there's a match, nil otherwise
func getMatch(src []byte, base int, match []int, start int, end int, ) []byte {
	if match[start] >= 0 {
		return src[base+match[start] : base+match[end]]
	} else {
		return nil
	}
}

// getKeyspaceNameFromUseStmt return keyspace name for use statement
func getKeyspaceNameFromUseStmt(stmt string, ) (string, bool) {
	pattern := regexp.MustCompile(`(?ms)[Uu][Ss][Ee]\s+("(?:[^"]|"")+"|\w+)`)
	if pattern.MatchString(stmt) {
		match := pattern.FindStringSubmatch(stmt)
		if len(match) > 1 {
			keyspace := match[1]
			caseSensitive := false
			if strings.HasPrefix(keyspace, "\"") && strings.HasSuffix(keyspace, "\"") {
				keyspace = strings.Trim(keyspace, "\"")
				caseSensitive = true
			}
			return keyspace, caseSensitive
		}
	}
	return "", false
}

// Loop is a loop that tries to get a connection until a timeout is reached
//
// Params:
//	 timeout: timeout to get the connection
//	 initializer : initializer to start the session
//	 connectionHost : name of host for the connection
//
// Returns a session Holder to store the session, or an error if the timeout was reached
func loop(timeout time.Duration, initializer Initializer, connectionHost string, ) (Holder, error) {
	log.Debugf("Connection loop to connect to %s, timeout to use: %s", connectionHost, timeout)
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	timeoutExceeded := time.After(timeout)
	for {
		select {
		case <-timeoutExceeded:
			return nil, fmt.Errorf("connection to %s failed after %s timeout", connectionHost, timeout)

		case <-ticker.C:
			log.Infof("Trying to connect to: %s", connectionHost)
			connectionHolder, err := initializer.NewSession()
			if err == nil {
				log.Infof("Successful connection to: %s", connectionHost)
				return connectionHolder, nil
			}
			log.Infof("Trying to connect to %s, failed attempt: %v", connectionHost, err)
		}
	}

}

// getenv get a string value from an environment variable
// or return the given default value if the environment variable is not set
//
// Params:
//  envVariable : environment variable
//  defaultValue : value to return if environment variable is not set
//
// Returns the string value for the specified variable
func getenv(envVariable string, defaultValue string) string {

	log.Debugf("Setting value for: %s", envVariable)
	returnValue := defaultValue
	log.Debugf("Default value for %s : %s", envVariable, defaultValue)
	envStr := os.Getenv(envVariable)
	if envStr != "" {
		returnValue = envStr
		log.Debugf("Init value for %s set to: %s", envVariable, envStr)
	}

	return returnValue
}

func checkConsistency(envVar string) gocql.Consistency {
	switch strings.ToLower(envVar) {
	case "any":
		log.Debugf("consistency set to any")
		return gocql.Any
	case "one":
		log.Debugf("consistency set to one")
		return gocql.One
	case "two":
		log.Debugf("consistency set to two")
		return gocql.Two
	case "three":
		log.Debugf("consistency set to three")
		return gocql.Three
	case "quorum":
		log.Debugf("consistency set to quorum")
		return gocql.Quorum
	case "all":
		log.Debugf("consistency set to all")
		return gocql.All
	case "localquorum":
		log.Debugf("consistency set to local quorum")
		return gocql.LocalQuorum
	case "eachquorum":
		log.Debugf("consistency set to each quorum")
		return gocql.EachQuorum
	case "localone":
		log.Debugf("consistency set to local one")
		return gocql.LocalOne
	default:
		log.Debugf("consistency set to %s", clusterConsistency.String())
		return clusterConsistency
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var cmdAura = &Command{
	Usage: "aura",
	Short: "force aura push -resourcepath=<filepath>",
	Long: `
	The aura command needs context to work. If you execute "aura get"
	it will create a folder structure that provides the context for
	aura components on disk.

	The aura components will be created in "metadata/aurabundles/<componentname>"
	relative to the current working directory and a .manifest file will be
	created that associates components and their artifacts with their ids in
	the database.

	To create a new component (application, evt or component), create a new
	folder under "aura". Then create a new file in your new folder. You
	must follow a naming convention for your files to enable proper definition
	of the component type.

	Naming convention <compnentName><artifact type>.<file type extension>
	Examples: 	metadata
					aura
						MyApp
							MyAppApplication.app
							MyAppStyle.css
						MyList
							MyComponent.cmp
							MyComponentHelper.js
							MyComponentStyle.css

	force aura push -f <fullFilePath> -b <bundle name>

	force aura create -t=<entity type> <entityName>

	force aura delete -f=<fullFilePath>

	force aura list

	`,
}

func init() {
	cmdAura.Run = runAura
	cmdAura.Flag.Var(&resourcepath, "p", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&metadataType, "entitytype", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&auraentityname, "entityname", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&metadataType, "t", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&auraentityname, "n", "", "fully qualified file name for entity")
}

var (
	auraentityname string
)

func runAura(cmd *Command, args []string) {
	if err := cmd.Flag.Parse(args[0:]); err != nil {
		os.Exit(2)
	}

	force, _ := ActiveForce()

	subcommand := args[0]
	// Sublime hack - the way sublime passes parameters seems to
	// break the flag parsing by sending a single element array
	// for the args. ARGH!!!
	if strings.HasPrefix(subcommand, "delete ") {
		what := strings.Split(subcommand, " ")
		if err := cmd.Flag.Parse(what[1:]); err != nil {
			ErrorAndExit(err.Error())
		}
		subcommand = what[0]
	}

	switch strings.ToLower(subcommand) {
	case "create":
		/*if *auraentitytype == "" || *auraentityname == "" {
			fmt.Println("Must specify entity type and name")
			os.Exit(2)
		}*/
		ErrorAndExit("force aura create not yet implemented")

	case "delete":
		runDeleteAura()
	case "list":
		bundles, err := force.GetAuraBundlesList()
		if err != nil {
			ErrorAndExit(err.Error())
		}
		for _, bundle := range bundles.Records {
			fmt.Println(bundle["DeveloperName"])
		}
	case "push":
		runPushAura(cmd, args)
	}
}

func runDeleteAura() {
	absPath, _ := filepath.Abs(resourcepath[0])
	//resourcepath = absPath

	if InAuraBundlesFolder(absPath) {
		info, err := os.Stat(absPath)
		if err != nil {
			ErrorAndExit(err.Error())
		}
		manifest, err := GetManifest(absPath)
		isBundle := false
		if info.IsDir() {
			force, _ := ActiveForce()
			manifest, err = GetManifest(filepath.Join(absPath, ".manifest"))
			bid := ""
			if err != nil { // Could not find a manifest, use bundle name
				// Try to look up the bundle by name
				b, err := force.GetAuraBundleByName(filepath.Base(absPath))
				if err != nil {
					ErrorAndExit(err.Error())
				} else {
					if len(b.Records) == 0 {
						ErrorAndExit(fmt.Sprintf("No bundle definition named %q", filepath.Base(absPath)))
					} else {
						bid = b.Records[0]["Id"].(string)
					}
				}
			} else {
				bid = manifest.Id
			}

			err = force.DeleteToolingRecord("AuraDefinitionBundle", bid)
			if err != nil {
				ErrorAndExit(err.Error())
			}
			// Now walk the bundle and remove all the atrifacts
			filepath.Walk(absPath, func(path string, inf os.FileInfo, err error) error {
				os.Remove(path)
				return nil
			})
			os.Remove(absPath)
			fmt.Println("Bundle ", filepath.Base(absPath), " deleted.")
			return
		}

		for key := range manifest.Files {
			mfile := manifest.Files[key].FileName
			cfile := absPath
			if !filepath.IsAbs(mfile) {
				cfile = filepath.Base(cfile)
			}
			if isBundle {
				if !filepath.IsAbs(mfile) {
					cfile = filepath.Join(absPath, mfile)
				} else {
					cfile = mfile
					deleteAuraDefinition(manifest, key)
				}
			} else {
				if mfile == cfile {
					deleteAuraDefinition(manifest, key)
					return
				}
			}
		}
		if isBundle {
			// Need to remove the bundle using the id in the manifest
			deleteAuraDefinitionBundle(manifest)
		}
	}
}
func deleteAuraDefinitionBundle(manifest BundleManifest) {
	force, err := ActiveForce()
	err = force.DeleteToolingRecord("AuraDefinitionBundle", manifest.Id)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	os.Remove(filepath.Join(resourcepath[0], ".manifest"))
	os.Remove(resourcepath[0])
}

func deleteAuraDefinition(manifest BundleManifest, key int) {
	force, err := ActiveForce()
	err = force.DeleteToolingRecord("AuraDefinition", manifest.Files[key].ComponentId)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	fname := manifest.Files[key].FileName
	os.Remove(fname)
	manifest.Files = append(manifest.Files[:key], manifest.Files[key+1:]...)
	bmBody, _ := json.Marshal(manifest)
	ioutil.WriteFile(filepath.Join(filepath.Dir(fname), ".manifest"), bmBody, 0644)
}
<commit_msg>this should cause a web hook<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)
// Brief comment to fire commit

var cmdAura = &Command{
	Usage: "aura",
	Short: "force aura push -resourcepath=<filepath>",
	Long: `
	The aura command needs context to work. If you execute "aura get"
	it will create a folder structure that provides the context for
	aura components on disk.

	The aura components will be created in "metadata/aurabundles/<componentname>"
	relative to the current working directory and a .manifest file will be
	created that associates components and their artifacts with their ids in
	the database.

	To create a new component (application, evt or component), create a new
	folder under "aura". Then create a new file in your new folder. You
	must follow a naming convention for your files to enable proper definition
	of the component type.

	Naming convention <compnentName><artifact type>.<file type extension>
	Examples: 	metadata
					aura
						MyApp
							MyAppApplication.app
							MyAppStyle.css
						MyList
							MyComponent.cmp
							MyComponentHelper.js
							MyComponentStyle.css

	force aura push -f <fullFilePath> -b <bundle name>

	force aura create -t=<entity type> <entityName>

	force aura delete -f=<fullFilePath>

	force aura list

	`,
}

func init() {
	cmdAura.Run = runAura
	cmdAura.Flag.Var(&resourcepath, "p", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&metadataType, "entitytype", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&auraentityname, "entityname", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&metadataType, "t", "", "fully qualified file name for entity")
	cmdAura.Flag.StringVar(&auraentityname, "n", "", "fully qualified file name for entity")
}

var (
	auraentityname string
)

func runAura(cmd *Command, args []string) {
	if err := cmd.Flag.Parse(args[0:]); err != nil {
		os.Exit(2)
	}

	force, _ := ActiveForce()

	subcommand := args[0]
	// Sublime hack - the way sublime passes parameters seems to
	// break the flag parsing by sending a single element array
	// for the args. ARGH!!!
	if strings.HasPrefix(subcommand, "delete ") {
		what := strings.Split(subcommand, " ")
		if err := cmd.Flag.Parse(what[1:]); err != nil {
			ErrorAndExit(err.Error())
		}
		subcommand = what[0]
	}

	switch strings.ToLower(subcommand) {
	case "create":
		/*if *auraentitytype == "" || *auraentityname == "" {
			fmt.Println("Must specify entity type and name")
			os.Exit(2)
		}*/
		ErrorAndExit("force aura create not yet implemented")

	case "delete":
		runDeleteAura()
	case "list":
		bundles, err := force.GetAuraBundlesList()
		if err != nil {
			ErrorAndExit(err.Error())
		}
		for _, bundle := range bundles.Records {
			fmt.Println(bundle["DeveloperName"])
		}
	case "push":
		runPushAura(cmd, args)
	}
}

func runDeleteAura() {
	absPath, _ := filepath.Abs(resourcepath[0])
	//resourcepath = absPath

	if InAuraBundlesFolder(absPath) {
		info, err := os.Stat(absPath)
		if err != nil {
			ErrorAndExit(err.Error())
		}
		manifest, err := GetManifest(absPath)
		isBundle := false
		if info.IsDir() {
			force, _ := ActiveForce()
			manifest, err = GetManifest(filepath.Join(absPath, ".manifest"))
			bid := ""
			if err != nil { // Could not find a manifest, use bundle name
				// Try to look up the bundle by name
				b, err := force.GetAuraBundleByName(filepath.Base(absPath))
				if err != nil {
					ErrorAndExit(err.Error())
				} else {
					if len(b.Records) == 0 {
						ErrorAndExit(fmt.Sprintf("No bundle definition named %q", filepath.Base(absPath)))
					} else {
						bid = b.Records[0]["Id"].(string)
					}
				}
			} else {
				bid = manifest.Id
			}

			err = force.DeleteToolingRecord("AuraDefinitionBundle", bid)
			if err != nil {
				ErrorAndExit(err.Error())
			}
			// Now walk the bundle and remove all the atrifacts
			filepath.Walk(absPath, func(path string, inf os.FileInfo, err error) error {
				os.Remove(path)
				return nil
			})
			os.Remove(absPath)
			fmt.Println("Bundle ", filepath.Base(absPath), " deleted.")
			return
		}

		for key := range manifest.Files {
			mfile := manifest.Files[key].FileName
			cfile := absPath
			if !filepath.IsAbs(mfile) {
				cfile = filepath.Base(cfile)
			}
			if isBundle {
				if !filepath.IsAbs(mfile) {
					cfile = filepath.Join(absPath, mfile)
				} else {
					cfile = mfile
					deleteAuraDefinition(manifest, key)
				}
			} else {
				if mfile == cfile {
					deleteAuraDefinition(manifest, key)
					return
				}
			}
		}
		if isBundle {
			// Need to remove the bundle using the id in the manifest
			deleteAuraDefinitionBundle(manifest)
		}
	}
}
func deleteAuraDefinitionBundle(manifest BundleManifest) {
	force, err := ActiveForce()
	err = force.DeleteToolingRecord("AuraDefinitionBundle", manifest.Id)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	os.Remove(filepath.Join(resourcepath[0], ".manifest"))
	os.Remove(resourcepath[0])
}

func deleteAuraDefinition(manifest BundleManifest, key int) {
	force, err := ActiveForce()
	err = force.DeleteToolingRecord("AuraDefinition", manifest.Files[key].ComponentId)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	fname := manifest.Files[key].FileName
	os.Remove(fname)
	manifest.Files = append(manifest.Files[:key], manifest.Files[key+1:]...)
	bmBody, _ := json.Marshal(manifest)
	ioutil.WriteFile(filepath.Join(filepath.Dir(fname), ".manifest"), bmBody, 0644)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"fmt"
)

type Season struct {
	year int16
}

type Sport struct {
	name string
	path string
}

func listSports(root string) (sports []*Sport) {
	files, err := ioutil.ReadDir(root)
	if err != nil {
		log.Fatal(err)
	}

	for _, f := range files {
		log.Println("file " + f.Name())
		if f.IsDir() {
			sport := new(Sport)
			sport.name = f.Name()
			sport.path = root + "/" + f.Name()
			sports = append(sports, sport)
		}
	}

	return sports
}

func createDatabase(root string, outPath string) error {
	log.Println("Creating database with root at " + root)
	log.Println("Outputing to " + outPath)
	sports := listSports(root)

	for _, sport := range sports {
		fmt.Printf("sport %s %s\n", sport.name, sport.path)
	}

	return nil
}
<commit_msg>List seasons<commit_after>package main

import (
	"io/ioutil"
	"log"
	"regexp"
	"strconv"
)

type Season struct {
	year int
}

type Sport struct {
	name    string
	path    string
	seasons []*Season
}

func listSports(root string) (sports []*Sport) {
	files, err := ioutil.ReadDir(root)
	if err != nil {
		log.Fatal(err)
	}

	for _, f := range files {
		if f.IsDir() {
			sport := new(Sport)
			sport.name = f.Name()
			sport.path = root + "/" + f.Name()
			sports = append(sports, sport)
		}
	}

	return sports
}

func listSeasons(sport *Sport) (seasons []*Season) {
	files, err := ioutil.ReadDir(sport.path)
	if err != nil {
		log.Fatal(err)
	}

	for _, f := range files {
		match, _ := regexp.MatchString("^\\d{4}$", f.Name())
		if f.IsDir() && match {
			season := new(Season)
			season.year, _ = strconv.Atoi(f.Name())
		}
	}

	return nil
}

func createDatabase(root string, outPath string) error {
	log.Println("Creating database with root at " + root)
	log.Println("Outputing to " + outPath)
	sports := listSports(root)

	for _, sport := range sports {
		log.Println("Processing sport " + sport.name)
		sport.seasons = listSeasons(sport)
		for _, season := range sport.seasons {
			log.Printf("Processing year %d\n", season.year)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcs

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/jacobsa/gcloud/httputil"
	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	storagev1 "google.golang.org/api/storage/v1"
	"google.golang.org/cloud"
	"google.golang.org/cloud/storage"
)

const userAgent = "github.com-jacobsa-gloud-gcs"

// Bucket represents a GCS bucket, pre-bound with a bucket name and necessary
// authorization information.
//
// Each method that may block accepts a context object that is used for
// deadlines and cancellation. Users need not package authorization information
// into the context object (using cloud.WithContext or similar).
type Bucket interface {
	Name() string

	// Create a reader for the contents of a particular generation of an object.
	// The caller must arrange for the reader to be closed when it is no longer
	// needed.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/get
	NewReader(
		ctx context.Context,
		req *ReadObjectRequest) (io.ReadCloser, error)

	// Create or overwrite an object according to the supplied request. The new
	// object is guaranteed to exist immediately for the purposes of reading (and
	// eventually for listing) after this method returns a nil error. It is
	// guaranteed not to exist before req.Contents returns io.EOF.
	//
	// If the request fails due to a precondition not being met, the error will
	// be of type *PreconditionError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/insert
	//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
	CreateObject(
		ctx context.Context,
		req *CreateObjectRequest) (*Object, error)

	// Return current information about the object with the given name.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/get
	StatObject(
		ctx context.Context,
		req *StatObjectRequest) (*Object, error)

	// List the objects in the bucket that meet the criteria defined by the
	// request, returning a result object that contains the results and
	// potentially a cursor for retrieving the next portion of the larger set of
	// results.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/list
	ListObjects(
		ctx context.Context,
		req *ListObjectsRequest) (*Listing, error)

	// Update the object specified by newAttrs.Name, patching using the non-zero
	// fields of newAttrs.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/patch
	UpdateObject(
		ctx context.Context,
		req *UpdateObjectRequest) (*Object, error)

	// Delete the object with the given name.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/delete
	DeleteObject(ctx context.Context, name string) error
}

type bucket struct {
	projID     string
	client     *http.Client
	rawService *storagev1.Service
	name       string
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	// Set up the query for the URL.
	query := make(url.Values)
	query.Set("projection", "full")

	if req.Prefix != "" {
		query.Set("prefix", req.Prefix)
	}

	if req.Delimiter != "" {
		query.Set("delimiter", req.Delimiter)
	}

	if req.ContinuationToken != "" {
		query.Set("pageToken", req.ContinuationToken)
	}

	if req.MaxResults != 0 {
		query.Set("maxResults", fmt.Sprintf("%v", req.MaxResults))
	}

	// Construct an appropriate URL (cf. http://goo.gl/aVSAhT).
	opaque := fmt.Sprintf(
		"//www.googleapis.com/storage/v1/b/%s/o",
		httputil.EncodePathSegment(b.Name()))

	url := &url.URL{
		Scheme:   "https",
		Opaque:   opaque,
		RawQuery: query.Encode(),
	}

	// Call the server.
	httpRes, err := b.client.Get(url.String())
	if err != nil {
		err = fmt.Errorf("Get: %v", err)
		return
	}

	defer googleapi.CloseBody(httpRes)

	// Check for HTTP-level errors.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// Parse the response.
	var rawListing *storagev1.Objects
	if err = json.NewDecoder(httpRes.Body).Decode(&rawListing); err != nil {
		return
	}

	// Convert the response.
	if listing, err = toListing(rawListing); err != nil {
		return
	}

	return
}

func (b *bucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	// Construct an appropriate URL.
	//
	// The documentation (http://goo.gl/gZo4oj) is extremely vague about how this
	// is supposed to work. As of 2015-03-13, it says only that "for most
	// operations" you can use the following form to access an object:
	//
	//     storage.googleapis.com/<bucket>/<object>
	//
	// In Google-internal bug 19718068, it was clarified that the intent is that
	// each of the bucket and object names are encoded into a single path
	// segment, as defined by RFC 3986.
	bucketSegment := httputil.EncodePathSegment(b.name)
	objectSegment := httputil.EncodePathSegment(req.Name)
	opaque := fmt.Sprintf(
		"//storage.googleapis.com/%s/%s",
		bucketSegment,
		objectSegment)

	url := &url.URL{
		Scheme: "https",
		Opaque: opaque,
	}

	// Add a generation condition, if specified.
	if req.Generation != 0 {
		url.RawQuery = fmt.Sprintf("generation=%v", req.Generation)
	}

	// Call the server.
	httpRes, err := b.client.Get(url.String())
	if err != nil {
		err = fmt.Errorf("Get: %v", err)
		return
	}

	// Check for HTTP error statuses.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		googleapi.CloseBody(httpRes)

		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// The body contains the object data.
	rc = httpRes.Body

	return
}

func (b *bucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	o, err = createObject(b.client, b.Name(), ctx, req)
	return
}

func (b *bucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	// Call the wrapped package.
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	wrappedObj, err := storage.StatObject(authContext, b.name, req.Name)

	// Transform errors.
	if err == storage.ErrObjectNotExist {
		err = &NotFoundError{
			Err: err,
		}

		return
	}

	// Transform the object.
	o = fromWrappedObject(wrappedObj)

	return
}

func (b *bucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	// Set up a map representing the JSON object we want to send to GCS. For now,
	// we don't treat empty strings specially.
	jsonMap := make(map[string]interface{})

	if req.ContentType != nil {
		jsonMap["contentType"] = req.ContentType
	}

	if req.ContentEncoding != nil {
		jsonMap["contentEncoding"] = req.ContentEncoding
	}

	if req.ContentLanguage != nil {
		jsonMap["contentLanguage"] = req.ContentLanguage
	}

	if req.CacheControl != nil {
		jsonMap["cacheControl"] = req.CacheControl
	}

	// Implement the convention that a pointer to an empty string means to delete
	// the field (communicated to GCS by setting it to null in the JSON).
	for k, v := range jsonMap {
		if *(v.(*string)) == "" {
			jsonMap[k] = nil
		}
	}

	// Add a field for user metadata if appropriate.
	if req.Metadata != nil {
		jsonMap["metadata"] = req.Metadata
	}

	// Set up a reader for the JSON object.
	body, err := googleapi.WithoutDataWrapper.JSONReader(jsonMap)
	if err != nil {
		return
	}

	// Set up URL params.
	urlParams := make(url.Values)
	urlParams.Set("projection", "full")

	// Set up the URL with a tempalte that we will later expand.
	url := googleapi.ResolveRelative(
		b.rawService.BasePath,
		"b/{bucket}/o/{object}")

	url += "?" + urlParams.Encode()

	// Create an HTTP request using NewRequest, which parses the URL string.
	// Expand the URL object it creates.
	httpReq, err := httputil.NewRequest("PATCH", url, body, userAgent)
	if err != nil {
		err = fmt.Errorf("httputil.NewRequest: %v", err)
		return
	}

	googleapi.Expand(
		httpReq.URL,
		map[string]string{
			"bucket": b.Name(),
			"object": req.Name,
		})

	// Set up HTTP request headers.
	httpReq.Header.Set("Content-Type", "application/json")

	// Execute the HTTP request.
	httpRes, err := b.client.Do(httpReq)
	if err != nil {
		return
	}

	defer googleapi.CloseBody(httpRes)

	// Check for HTTP-level errors.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// Parse the response.
	var rawObject *storagev1.Object
	if err = json.NewDecoder(httpRes.Body).Decode(&rawObject); err != nil {
		return
	}

	// Convert the response.
	if o, err = toObject(rawObject); err != nil {
		err = fmt.Errorf("toObject: %v", err)
		return
	}

	return
}

func (b *bucket) DeleteObject(ctx context.Context, name string) (err error) {
	// Call the wrapped package.
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	err = storage.DeleteObject(authContext, b.name, name)

	// Transform errors.
	if err == storage.ErrObjectNotExist {
		err = &NotFoundError{
			Err: err,
		}
	}

	// Handle the fact that as of 2015-03-12, the wrapped package does not
	// correctly return ErrObjectNotExist here.
	if typed, ok := err.(*googleapi.Error); ok {
		if typed.Code == http.StatusNotFound {
			err = &NotFoundError{Err: typed}
		}
	}

	return
}

func newBucket(
	projID string,
	client *http.Client,
	rawService *storagev1.Service,
	name string) Bucket {
	return &bucket{
		projID:     projID,
		client:     client,
		rawService: rawService,
		name:       name,
	}
}
<commit_msg>Use httputil.NewRequest instead of Get.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcs

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/jacobsa/gcloud/httputil"
	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	storagev1 "google.golang.org/api/storage/v1"
	"google.golang.org/cloud"
	"google.golang.org/cloud/storage"
)

const userAgent = "github.com-jacobsa-gloud-gcs"

// Bucket represents a GCS bucket, pre-bound with a bucket name and necessary
// authorization information.
//
// Each method that may block accepts a context object that is used for
// deadlines and cancellation. Users need not package authorization information
// into the context object (using cloud.WithContext or similar).
type Bucket interface {
	Name() string

	// Create a reader for the contents of a particular generation of an object.
	// The caller must arrange for the reader to be closed when it is no longer
	// needed.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/get
	NewReader(
		ctx context.Context,
		req *ReadObjectRequest) (io.ReadCloser, error)

	// Create or overwrite an object according to the supplied request. The new
	// object is guaranteed to exist immediately for the purposes of reading (and
	// eventually for listing) after this method returns a nil error. It is
	// guaranteed not to exist before req.Contents returns io.EOF.
	//
	// If the request fails due to a precondition not being met, the error will
	// be of type *PreconditionError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/insert
	//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
	CreateObject(
		ctx context.Context,
		req *CreateObjectRequest) (*Object, error)

	// Return current information about the object with the given name.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/get
	StatObject(
		ctx context.Context,
		req *StatObjectRequest) (*Object, error)

	// List the objects in the bucket that meet the criteria defined by the
	// request, returning a result object that contains the results and
	// potentially a cursor for retrieving the next portion of the larger set of
	// results.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/list
	ListObjects(
		ctx context.Context,
		req *ListObjectsRequest) (*Listing, error)

	// Update the object specified by newAttrs.Name, patching using the non-zero
	// fields of newAttrs.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/patch
	UpdateObject(
		ctx context.Context,
		req *UpdateObjectRequest) (*Object, error)

	// Delete the object with the given name.
	//
	// If the object doesn't exist, err will be of type *NotFoundError.
	//
	// Official documentation:
	//     https://cloud.google.com/storage/docs/json_api/v1/objects/delete
	DeleteObject(ctx context.Context, name string) error
}

type bucket struct {
	projID     string
	client     *http.Client
	rawService *storagev1.Service
	name       string
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	// Set up the query for the URL.
	query := make(url.Values)
	query.Set("projection", "full")

	if req.Prefix != "" {
		query.Set("prefix", req.Prefix)
	}

	if req.Delimiter != "" {
		query.Set("delimiter", req.Delimiter)
	}

	if req.ContinuationToken != "" {
		query.Set("pageToken", req.ContinuationToken)
	}

	if req.MaxResults != 0 {
		query.Set("maxResults", fmt.Sprintf("%v", req.MaxResults))
	}

	// Construct an appropriate URL (cf. http://goo.gl/aVSAhT).
	opaque := fmt.Sprintf(
		"//www.googleapis.com/storage/v1/b/%s/o",
		httputil.EncodePathSegment(b.Name()))

	url := &url.URL{
		Scheme:   "https",
		Opaque:   opaque,
		RawQuery: query.Encode(),
	}

	// Create an HTTP request.
	httpReq, err := httputil.NewRequest("GET", url, nil, userAgent)
	if err != nil {
		err = fmt.Errorf("httputil.NewRequest: %v", err)
		return
	}

	// Call the server.
	httpRes, err := b.client.Do(httpReq)
	if err != nil {
		err = fmt.Errorf("HTTP client: %v", err)
		return
	}

	defer googleapi.CloseBody(httpRes)

	// Check for HTTP-level errors.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// Parse the response.
	var rawListing *storagev1.Objects
	if err = json.NewDecoder(httpRes.Body).Decode(&rawListing); err != nil {
		return
	}

	// Convert the response.
	if listing, err = toListing(rawListing); err != nil {
		return
	}

	return
}

func (b *bucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	// Construct an appropriate URL.
	//
	// The documentation (http://goo.gl/gZo4oj) is extremely vague about how this
	// is supposed to work. As of 2015-03-13, it says only that "for most
	// operations" you can use the following form to access an object:
	//
	//     storage.googleapis.com/<bucket>/<object>
	//
	// In Google-internal bug 19718068, it was clarified that the intent is that
	// each of the bucket and object names are encoded into a single path
	// segment, as defined by RFC 3986.
	bucketSegment := httputil.EncodePathSegment(b.name)
	objectSegment := httputil.EncodePathSegment(req.Name)
	opaque := fmt.Sprintf(
		"//storage.googleapis.com/%s/%s",
		bucketSegment,
		objectSegment)

	url := &url.URL{
		Scheme: "https",
		Opaque: opaque,
	}

	// Add a generation condition, if specified.
	if req.Generation != 0 {
		url.RawQuery = fmt.Sprintf("generation=%v", req.Generation)
	}

	// Create an HTTP request.
	httpReq, err := httputil.NewRequest("GET", url, nil, userAgent)
	if err != nil {
		err = fmt.Errorf("httputil.NewRequest: %v", err)
		return
	}

	// Call the server.
	httpRes, err := b.client.Do(httpReq)
	if err != nil {
		err = fmt.Errorf("HTTP client: %v", err)
		return
	}

	// Check for HTTP error statuses.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		googleapi.CloseBody(httpRes)

		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// The body contains the object data.
	rc = httpRes.Body

	return
}

func (b *bucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	o, err = createObject(b.client, b.Name(), ctx, req)
	return
}

func (b *bucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	// Call the wrapped package.
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	wrappedObj, err := storage.StatObject(authContext, b.name, req.Name)

	// Transform errors.
	if err == storage.ErrObjectNotExist {
		err = &NotFoundError{
			Err: err,
		}

		return
	}

	// Transform the object.
	o = fromWrappedObject(wrappedObj)

	return
}

func (b *bucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	// Set up a map representing the JSON object we want to send to GCS. For now,
	// we don't treat empty strings specially.
	jsonMap := make(map[string]interface{})

	if req.ContentType != nil {
		jsonMap["contentType"] = req.ContentType
	}

	if req.ContentEncoding != nil {
		jsonMap["contentEncoding"] = req.ContentEncoding
	}

	if req.ContentLanguage != nil {
		jsonMap["contentLanguage"] = req.ContentLanguage
	}

	if req.CacheControl != nil {
		jsonMap["cacheControl"] = req.CacheControl
	}

	// Implement the convention that a pointer to an empty string means to delete
	// the field (communicated to GCS by setting it to null in the JSON).
	for k, v := range jsonMap {
		if *(v.(*string)) == "" {
			jsonMap[k] = nil
		}
	}

	// Add a field for user metadata if appropriate.
	if req.Metadata != nil {
		jsonMap["metadata"] = req.Metadata
	}

	// Set up a reader for the JSON object.
	body, err := googleapi.WithoutDataWrapper.JSONReader(jsonMap)
	if err != nil {
		return
	}

	// Set up URL params.
	urlParams := make(url.Values)
	urlParams.Set("projection", "full")

	// Set up the URL with a tempalte that we will later expand.
	url := googleapi.ResolveRelative(
		b.rawService.BasePath,
		"b/{bucket}/o/{object}")

	url += "?" + urlParams.Encode()

	// Create an HTTP request using NewRequest, which parses the URL string.
	// Expand the URL object it creates.
	httpReq, err := httputil.NewRequest("PATCH", url, body, userAgent)
	if err != nil {
		err = fmt.Errorf("httputil.NewRequest: %v", err)
		return
	}

	googleapi.Expand(
		httpReq.URL,
		map[string]string{
			"bucket": b.Name(),
			"object": req.Name,
		})

	// Set up HTTP request headers.
	httpReq.Header.Set("Content-Type", "application/json")

	// Execute the HTTP request.
	httpRes, err := b.client.Do(httpReq)
	if err != nil {
		return
	}

	defer googleapi.CloseBody(httpRes)

	// Check for HTTP-level errors.
	if err = googleapi.CheckResponse(httpRes); err != nil {
		// Special case: handle not found errors.
		if typed, ok := err.(*googleapi.Error); ok {
			if typed.Code == http.StatusNotFound {
				err = &NotFoundError{Err: typed}
			}
		}

		return
	}

	// Parse the response.
	var rawObject *storagev1.Object
	if err = json.NewDecoder(httpRes.Body).Decode(&rawObject); err != nil {
		return
	}

	// Convert the response.
	if o, err = toObject(rawObject); err != nil {
		err = fmt.Errorf("toObject: %v", err)
		return
	}

	return
}

func (b *bucket) DeleteObject(ctx context.Context, name string) (err error) {
	// Call the wrapped package.
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	err = storage.DeleteObject(authContext, b.name, name)

	// Transform errors.
	if err == storage.ErrObjectNotExist {
		err = &NotFoundError{
			Err: err,
		}
	}

	// Handle the fact that as of 2015-03-12, the wrapped package does not
	// correctly return ErrObjectNotExist here.
	if typed, ok := err.(*googleapi.Error); ok {
		if typed.Code == http.StatusNotFound {
			err = &NotFoundError{Err: typed}
		}
	}

	return
}

func newBucket(
	projID string,
	client *http.Client,
	rawService *storagev1.Service,
	name string) Bucket {
	return &bucket{
		projID:     projID,
		client:     client,
		rawService: rawService,
		name:       name,
	}
}
<|endoftext|>


<commit_before>package cruncy

// VERSION of the application
const VERSION = "0.9.2"
<commit_msg>Updated version<commit_after>package cruncy

// VERSION of the application
const VERSION = "0.9.4"
<|endoftext|>