<commit_before>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package prefixdb

import (
	"sync"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/database/nodb"
	"github.com/ava-labs/avalanchego/utils/hashing"
)

const (
	defaultBufCap = 256
)

var (
	_ database.Database = &Database{}
	_ database.Batch    = &batch{}
	_ database.Iterator = &iterator{}
)

// Database partitions a database into a sub-database by prefixing all keys with
// a unique value.
type Database struct {
	lock sync.RWMutex
	// All keys in this db begin with this byte slice
	dbPrefix []byte
	// The underlying storage
	db database.Database
	// Holds unused []byte
	bufferPool sync.Pool
}

// New returns a new prefixed database
func New(prefix []byte, db database.Database) *Database {
	if prefixDB, ok := db.(*Database); ok {
		simplePrefix := make([]byte, len(prefixDB.dbPrefix)+len(prefix))
		copy(simplePrefix, prefixDB.dbPrefix)
		copy(simplePrefix[len(prefixDB.dbPrefix):], prefix)
		return NewNested(simplePrefix, prefixDB.db)
	}
	return NewNested(prefix, db)
}

// NewNested returns a new prefixed database without attempting to compress
// prefixes.
func NewNested(prefix []byte, db database.Database) *Database {
	return &Database{
		dbPrefix: hashing.ComputeHash256(prefix),
		db:       db,
		bufferPool: sync.Pool{
			New: func() interface{} {
				return make([]byte, 0, defaultBufCap)
			},
		},
	}
}

// Has implements the Database interface
// Assumes that it is OK for the argument to db.db.Has
// to be modified after db.db.Has returns
// [key] may be modified after this method returns.
func (db *Database) Has(key []byte) (bool, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return false, database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	has, err := db.db.Has(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return has, err
}

// Get implements the Database interface
// Assumes that it is OK for the argument to db.db.Get
// to be modified after db.db.Get returns.
// [key] may be modified after this method returns.
func (db *Database) Get(key []byte) ([]byte, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return nil, database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	val, err := db.db.Get(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return val, err
}

// Put implements the Database interface
// Assumes that it is OK for the argument to db.db.Put
// to be modified after db.db.Put returns.
// [key] can be modified after this method returns.
// [value] should not be modified.
func (db *Database) Put(key, value []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()

	if db.db == nil {
		return database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	err := db.db.Put(prefixedKey, value)
	db.bufferPool.Put(prefixedKey)
	return err
}

// Delete implements the Database interface.
// Assumes that it is OK for the argument to db.db.Delete
// to be modified after db.db.Delete returns.
// [key] may be modified after this method returns.
func (db *Database) Delete(key []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()

	if db.db == nil {
		return database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	err := db.db.Delete(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return err
}

// NewBatch implements the Database interface
func (db *Database) NewBatch() database.Batch {
	return &batch{
		Batch: db.db.NewBatch(),
		db:    db,
	}
}

// NewIterator implements the Database interface
func (db *Database) NewIterator() database.Iterator {
	return db.NewIteratorWithStartAndPrefix(nil, nil)
}

// NewIteratorWithStart implements the Database interface
func (db *Database) NewIteratorWithStart(start []byte) database.Iterator {
	return db.NewIteratorWithStartAndPrefix(start, nil)
}

// NewIteratorWithPrefix implements the Database interface
func (db *Database) NewIteratorWithPrefix(prefix []byte) database.Iterator {
	return db.NewIteratorWithStartAndPrefix(nil, prefix)
}

// NewIteratorWithStartAndPrefix implements the Database interface.
// Assumes it is safe to modify the arguments to db.db.NewIteratorWithStartAndPrefix after it returns.
// It is safe to modify [start] and [prefix] after this method returns.
func (db *Database) NewIteratorWithStartAndPrefix(start, prefix []byte) database.Iterator {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return &nodb.Iterator{Err: database.ErrClosed}
	}
	prefixedStart := db.prefix(start)
	prefixedPrefix := db.prefix(prefix)
	it := &iterator{
		Iterator: db.db.NewIteratorWithStartAndPrefix(prefixedStart, prefixedPrefix),
		db:       db,
	}
	db.bufferPool.Put(prefixedStart)
	db.bufferPool.Put(prefixedPrefix)
	return it
}

// Stat implements the Database interface
func (db *Database) Stat(stat string) (string, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return "", database.ErrClosed
	}
	return db.db.Stat(stat)
}

// Compact implements the Database interface
func (db *Database) Compact(start, limit []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()

	if db.db == nil {
		return database.ErrClosed
	}
	return db.db.Compact(db.prefix(start), db.prefix(limit))
}

// Close implements the Database interface
func (db *Database) Close() error {
	db.lock.Lock()
	defer db.lock.Unlock()

	if db.db == nil {
		return database.ErrClosed
	}
	db.db = nil
	return nil
}

// Return a copy of [key], prepended with this db's prefix.
// The returned slice should be put back in the pool
// when it's done being used.
func (db *Database) prefix(key []byte) []byte {
	// Get a []byte from the pool
	prefixedKey := db.bufferPool.Get().([]byte)
	keyLen := len(db.dbPrefix) + len(key)
	if cap(prefixedKey) >= keyLen {
		// The [] byte we got from the pool is big enough to hold the prefixed key
		prefixedKey = prefixedKey[:keyLen]
	} else {
		// The []byte from the pool wasn't big enough.
		// Put it back and allocate a new, bigger one
		db.bufferPool.Put(prefixedKey)
		prefixedKey = make([]byte, keyLen)
	}
	copy(prefixedKey, db.dbPrefix)
	copy(prefixedKey[len(db.dbPrefix):], key)
	return prefixedKey
}

type keyValue struct {
	key    []byte
	value  []byte
	delete bool
}

// Batch of database operations
type batch struct {
	database.Batch
	db *Database

	// Each key is prepended with the database's prefix.
	// Each byte slice underlying a key should be returned to the pool
	// when this batch is reset.
	writes []keyValue
}

// Put implements the Batch interface
// Assumes that it is OK for the argument to b.Batch.Put
// to be modified after b.Batch.Put returns
// [key] may be modified after this method returns.
// [value] may not be modified after this method returns.
func (b *batch) Put(key, value []byte) error {
	prefixedKey := b.db.prefix(key)
	b.writes = append(b.writes, keyValue{prefixedKey, value, false})
	return b.Batch.Put(prefixedKey, value)
}

// Delete implements the Batch interface
// Assumes that it is OK for the argument to b.Batch.Delete
// to be modified after b.Batch.Delete returns
// [key] may be modified after this method returns.
func (b *batch) Delete(key []byte) error {
	prefixedKey := b.db.prefix(key)
	b.writes = append(b.writes, keyValue{prefixedKey, nil, true})
	return b.Batch.Delete(prefixedKey)
}

// Write flushes any accumulated data to the memory database.
func (b *batch) Write() error {
	b.db.lock.Lock()
	defer b.db.lock.Unlock()

	if b.db.db == nil {
		return database.ErrClosed
	}
	return b.Batch.Write()
}

// Reset resets the batch for reuse.
func (b *batch) Reset() {
	// Return the byte buffers underneath each key back to the pool.
	// Don't return the byte buffers underneath each value back to the pool
	// because we assume in batch.Repley that it's not safe to modify the
	// value argument to w.Put.
	for _, kv := range b.writes {
		b.db.bufferPool.Put(kv.key)
	}

	// Clear b.writes
	if cap(b.writes) > len(b.writes)*database.MaxExcessCapacityFactor {
		b.writes = make([]keyValue, 0, cap(b.writes)/database.CapacityReductionFactor)
	} else {
		b.writes = b.writes[:0]
	}
	b.Batch.Reset()
}

// Replay replays the batch contents.
// Assumes it's safe to modify the key argument to w.Delete and w.Put
// after those methods return.
// Assumes it's not safe to modify the value argument to w.Put after calling that method.
// Assumes [keyvalue.value] will not be modified because we assume that in batch.Put.
func (b *batch) Replay(w database.KeyValueWriterDeleter) error {
	for _, keyvalue := range b.writes {
		keyWithoutPrefix := keyvalue.key[len(b.db.dbPrefix):]
		if keyvalue.delete {
			if err := w.Delete(keyWithoutPrefix); err != nil {
				return err
			}
		} else {
			if err := w.Put(keyWithoutPrefix, keyvalue.value); err != nil {
				return err
			}
		}
	}
	return nil
}

type iterator struct {
	database.Iterator
	db *Database
}

// Key calls the inner iterators Key and strips the prefix
func (it *iterator) Key() []byte {
	key := it.Iterator.Key()
	if prefixLen := len(it.db.dbPrefix); len(key) >= prefixLen {
		return key[prefixLen:]
	}
	return key
}
<commit_msg>Remove unneeded locking from prefixdb (#1065)<commit_after>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package prefixdb

import (
	"sync"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/database/nodb"
	"github.com/ava-labs/avalanchego/utils/hashing"
)

const (
	defaultBufCap = 256
)

var (
	_ database.Database = &Database{}
	_ database.Batch    = &batch{}
	_ database.Iterator = &iterator{}
)

// Database partitions a database into a sub-database by prefixing all keys with
// a unique value.
type Database struct {
	// All keys in this db begin with this byte slice
	dbPrefix []byte
	// Holds unused []byte
	bufferPool sync.Pool

	// lock needs to be held during Close to guarantee db will not be set to nil
	// concurrently with another operation. All other operations can hold RLock.
	lock sync.RWMutex
	// The underlying storage
	db database.Database
}

// New returns a new prefixed database
func New(prefix []byte, db database.Database) *Database {
	if prefixDB, ok := db.(*Database); ok {
		simplePrefix := make([]byte, len(prefixDB.dbPrefix)+len(prefix))
		copy(simplePrefix, prefixDB.dbPrefix)
		copy(simplePrefix[len(prefixDB.dbPrefix):], prefix)
		return NewNested(simplePrefix, prefixDB.db)
	}
	return NewNested(prefix, db)
}

// NewNested returns a new prefixed database without attempting to compress
// prefixes.
func NewNested(prefix []byte, db database.Database) *Database {
	return &Database{
		dbPrefix: hashing.ComputeHash256(prefix),
		db:       db,
		bufferPool: sync.Pool{
			New: func() interface{} {
				return make([]byte, 0, defaultBufCap)
			},
		},
	}
}

// Has implements the Database interface
// Assumes that it is OK for the argument to db.db.Has
// to be modified after db.db.Has returns
// [key] may be modified after this method returns.
func (db *Database) Has(key []byte) (bool, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return false, database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	has, err := db.db.Has(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return has, err
}

// Get implements the Database interface
// Assumes that it is OK for the argument to db.db.Get
// to be modified after db.db.Get returns.
// [key] may be modified after this method returns.
func (db *Database) Get(key []byte) ([]byte, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return nil, database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	val, err := db.db.Get(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return val, err
}

// Put implements the Database interface
// Assumes that it is OK for the argument to db.db.Put
// to be modified after db.db.Put returns.
// [key] can be modified after this method returns.
// [value] should not be modified.
func (db *Database) Put(key, value []byte) error {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	err := db.db.Put(prefixedKey, value)
	db.bufferPool.Put(prefixedKey)
	return err
}

// Delete implements the Database interface.
// Assumes that it is OK for the argument to db.db.Delete
// to be modified after db.db.Delete returns.
// [key] may be modified after this method returns.
func (db *Database) Delete(key []byte) error {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return database.ErrClosed
	}
	prefixedKey := db.prefix(key)
	err := db.db.Delete(prefixedKey)
	db.bufferPool.Put(prefixedKey)
	return err
}

// NewBatch implements the Database interface
func (db *Database) NewBatch() database.Batch {
	return &batch{
		Batch: db.db.NewBatch(),
		db:    db,
	}
}

// NewIterator implements the Database interface
func (db *Database) NewIterator() database.Iterator {
	return db.NewIteratorWithStartAndPrefix(nil, nil)
}

// NewIteratorWithStart implements the Database interface
func (db *Database) NewIteratorWithStart(start []byte) database.Iterator {
	return db.NewIteratorWithStartAndPrefix(start, nil)
}

// NewIteratorWithPrefix implements the Database interface
func (db *Database) NewIteratorWithPrefix(prefix []byte) database.Iterator {
	return db.NewIteratorWithStartAndPrefix(nil, prefix)
}

// NewIteratorWithStartAndPrefix implements the Database interface.
// Assumes it is safe to modify the arguments to db.db.NewIteratorWithStartAndPrefix after it returns.
// It is safe to modify [start] and [prefix] after this method returns.
func (db *Database) NewIteratorWithStartAndPrefix(start, prefix []byte) database.Iterator {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return &nodb.Iterator{Err: database.ErrClosed}
	}
	prefixedStart := db.prefix(start)
	prefixedPrefix := db.prefix(prefix)
	it := &iterator{
		Iterator: db.db.NewIteratorWithStartAndPrefix(prefixedStart, prefixedPrefix),
		db:       db,
	}
	db.bufferPool.Put(prefixedStart)
	db.bufferPool.Put(prefixedPrefix)
	return it
}

// Stat implements the Database interface
func (db *Database) Stat(stat string) (string, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return "", database.ErrClosed
	}
	return db.db.Stat(stat)
}

// Compact implements the Database interface
func (db *Database) Compact(start, limit []byte) error {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if db.db == nil {
		return database.ErrClosed
	}
	return db.db.Compact(db.prefix(start), db.prefix(limit))
}

// Close implements the Database interface
func (db *Database) Close() error {
	db.lock.Lock()
	defer db.lock.Unlock()

	if db.db == nil {
		return database.ErrClosed
	}
	db.db = nil
	return nil
}

// Return a copy of [key], prepended with this db's prefix.
// The returned slice should be put back in the pool
// when it's done being used.
func (db *Database) prefix(key []byte) []byte {
	// Get a []byte from the pool
	prefixedKey := db.bufferPool.Get().([]byte)
	keyLen := len(db.dbPrefix) + len(key)
	if cap(prefixedKey) >= keyLen {
		// The [] byte we got from the pool is big enough to hold the prefixed key
		prefixedKey = prefixedKey[:keyLen]
	} else {
		// The []byte from the pool wasn't big enough.
		// Put it back and allocate a new, bigger one
		db.bufferPool.Put(prefixedKey)
		prefixedKey = make([]byte, keyLen)
	}
	copy(prefixedKey, db.dbPrefix)
	copy(prefixedKey[len(db.dbPrefix):], key)
	return prefixedKey
}

type keyValue struct {
	key    []byte
	value  []byte
	delete bool
}

// Batch of database operations
type batch struct {
	database.Batch
	db *Database

	// Each key is prepended with the database's prefix.
	// Each byte slice underlying a key should be returned to the pool
	// when this batch is reset.
	writes []keyValue
}

// Put implements the Batch interface
// Assumes that it is OK for the argument to b.Batch.Put
// to be modified after b.Batch.Put returns
// [key] may be modified after this method returns.
// [value] may not be modified after this method returns.
func (b *batch) Put(key, value []byte) error {
	prefixedKey := b.db.prefix(key)
	b.writes = append(b.writes, keyValue{prefixedKey, value, false})
	return b.Batch.Put(prefixedKey, value)
}

// Delete implements the Batch interface
// Assumes that it is OK for the argument to b.Batch.Delete
// to be modified after b.Batch.Delete returns
// [key] may be modified after this method returns.
func (b *batch) Delete(key []byte) error {
	prefixedKey := b.db.prefix(key)
	b.writes = append(b.writes, keyValue{prefixedKey, nil, true})
	return b.Batch.Delete(prefixedKey)
}

// Write flushes any accumulated data to the memory database.
func (b *batch) Write() error {
	b.db.lock.RLock()
	defer b.db.lock.RUnlock()

	if b.db.db == nil {
		return database.ErrClosed
	}
	return b.Batch.Write()
}

// Reset resets the batch for reuse.
func (b *batch) Reset() {
	// Return the byte buffers underneath each key back to the pool.
	// Don't return the byte buffers underneath each value back to the pool
	// because we assume in batch.Replay that it's not safe to modify the
	// value argument to w.Put.
	for _, kv := range b.writes {
		b.db.bufferPool.Put(kv.key)
	}

	// Clear b.writes
	if cap(b.writes) > len(b.writes)*database.MaxExcessCapacityFactor {
		b.writes = make([]keyValue, 0, cap(b.writes)/database.CapacityReductionFactor)
	} else {
		b.writes = b.writes[:0]
	}
	b.Batch.Reset()
}

// Replay replays the batch contents.
// Assumes it's safe to modify the key argument to w.Delete and w.Put
// after those methods return.
// Assumes it's not safe to modify the value argument to w.Put after calling that method.
// Assumes [keyvalue.value] will not be modified because we assume that in batch.Put.
func (b *batch) Replay(w database.KeyValueWriterDeleter) error {
	for _, keyvalue := range b.writes {
		keyWithoutPrefix := keyvalue.key[len(b.db.dbPrefix):]
		if keyvalue.delete {
			if err := w.Delete(keyWithoutPrefix); err != nil {
				return err
			}
		} else {
			if err := w.Put(keyWithoutPrefix, keyvalue.value); err != nil {
				return err
			}
		}
	}
	return nil
}

type iterator struct {
	database.Iterator
	db *Database
}

// Key calls the inner iterators Key and strips the prefix
func (it *iterator) Key() []byte {
	key := it.Iterator.Key()
	if prefixLen := len(it.db.dbPrefix); len(key) >= prefixLen {
		return key[prefixLen:]
	}
	return key
}
<|endoftext|>


<commit_before>// Query example for GoMySQL
// This script will get the first 5 rows from table test1
package main

import (
	"mysql"
	"fmt"
	"os"
)

func main() {
	// Create new instance
	db := mysql.New()
	// Enable logging
	db.Logging = true
	// Connect to database
	db.Connect("localhost", "root", "********", "gotesting")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Use UTF8
	db.Query("SET NAMES utf8");
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Query database
	res := db.Query("SELECT * FROM test1 LIMIT 5")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Display results
	var row map[string] interface{}
	for {
		row = res.FetchMap()
		if row == nil {
			break
		}
		for key, value := range row {
			fmt.Printf("%s:%v\n", key, value)
		}
	}
}
<commit_msg>added close to query example<commit_after>// Query example for GoMySQL
// This script will get the first 5 rows from table test1
package main

import (
	"mysql"
	"fmt"
	"os"
)

func main() {
	// Create new instance
	db := mysql.New()
	// Enable logging
	db.Logging = true
	// Connect to database
	db.Connect("localhost", "root", "********", "gotesting")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Use UTF8
	db.Query("SET NAMES utf8");
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Query database
	res := db.Query("SELECT * FROM test1 LIMIT 5")
	if db.Errno != 0 {
		fmt.Printf("Error #%d %s\n", db.Errno, db.Error)
		os.Exit(1)
	}
	// Display results
	var row map[string] interface{}
	for {
		row = res.FetchMap()
		if row == nil {
			break
		}
		for key, value := range row {
			fmt.Printf("%s:%v\n", key, value)
		}
	}
	// Close connection
	db.Close()
}
<|endoftext|>


<commit_before><commit_msg>Remove unused telegram.go<commit_after><|endoftext|>


<commit_before>package log_parser

import (
	"bufio"
	"context"
	"os/exec"
	"strings"
	"sync"

	"go.skia.org/infra/go/skerr"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/task_driver/go/td"
)

// Run runs the given command in the given working directory. It calls the
// provided function to emit sub-steps.
func Run(ctx context.Context, cwd string, cmdLine []string, split bufio.SplitFunc, handleToken func(context.Context, string) error, cleanup func(context.Context) error) error {
	ctx = td.StartStep(ctx, td.Props(strings.Join(cmdLine, " ")))
	defer td.EndStep(ctx)

	// Set up the command.
	cmd := exec.CommandContext(ctx, cmdLine[0], cmdLine[1:]...)
	cmd.Dir = cwd
	cmd.Env = td.GetEnv(ctx)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return td.FailStep(ctx, err)
	}
	if err := cmd.Start(); err != nil {
		return td.FailStep(ctx, err)
	}

	// Spin up a goroutine which parses the output of the command and
	// creates sub-steps.
	var wg sync.WaitGroup
	wg.Add(1)

	// runErr records any errors that occur within the goroutine.
	var runErr error

	go func() {
		defer wg.Done()
		scanner := bufio.NewScanner(stdout)
		scanner.Split(split)
		for scanner.Scan() {
			token := scanner.Text()
			if err := handleToken(ctx, token); err != nil {
				runErr = skerr.Wrapf(err, "Failed handling token %q", token)
				sklog.Error(runErr.Error())
			}
		}
		if cleanup != nil {
			if err := cleanup(ctx); err != nil {
				runErr = skerr.Wrapf(err, "Failed during cleanup")
				sklog.Error(runErr.Error())
			}
		}
	}()

	// Wait for the command to finish.
	if err := cmd.Wait(); err != nil {
		// Wait for log processing goroutine to finish.
		wg.Wait()
		return td.FailStep(ctx, err)
	}

	// Wait for log processing goroutine to finish.
	wg.Wait()
	if runErr != nil {
		return td.FailStep(ctx, runErr)
	}
	return nil
}
<commit_msg>[task driver] Fix log parser race<commit_after>package log_parser

import (
	"bufio"
	"context"
	"os/exec"
	"strings"

	"go.skia.org/infra/go/skerr"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/task_driver/go/td"
)

// Run runs the given command in the given working directory. It calls the
// provided function to emit sub-steps.
func Run(ctx context.Context, cwd string, cmdLine []string, split bufio.SplitFunc, handleToken func(context.Context, string) error, cleanup func(context.Context) error) error {
	ctx = td.StartStep(ctx, td.Props(strings.Join(cmdLine, " ")))
	defer td.EndStep(ctx)

	// Set up the command.
	cmd := exec.CommandContext(ctx, cmdLine[0], cmdLine[1:]...)
	cmd.Dir = cwd
	cmd.Env = td.GetEnv(ctx)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return td.FailStep(ctx, err)
	}
	if err := cmd.Start(); err != nil {
		return td.FailStep(ctx, err)
	}

	// parseErr records any errors that occur while parsing output.
	var parseErr error

	// Parse the output of the command and create sub-steps.
	scanner := bufio.NewScanner(stdout)
	scanner.Split(split)
	for scanner.Scan() {
		token := scanner.Text()
		if err := handleToken(ctx, token); err != nil {
			parseErr = skerr.Wrapf(err, "Failed handling token %q", token)
			sklog.Error(parseErr.Error())
		}
	}
	if cleanup != nil {
		if err := cleanup(ctx); err != nil {
			parseErr = skerr.Wrapf(err, "Failed during cleanup")
			sklog.Error(parseErr.Error())
		}
	}

	// Wait for the command to finish.
	if err := cmd.Wait(); err != nil {
		return td.FailStep(ctx, err)
	}
	if parseErr != nil {
		return td.FailStep(ctx, parseErr)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"

	_ "github.com/go-sql-driver/mysql"

	"github.com/domestic-apps/domestic-api/chores"
	"github.com/domestic-apps/domestic-api/tasks"
	"time"
)

type secrets struct {
	Uname string `json:"username"`
	Pwd   string `json:"password"`
}

func main() {
	// get mysql username and password from configuration
	file, err := ioutil.ReadFile("./secrets.json")
	if err != nil {
		log.Fatal("File error: %v\n", err)
	}

	var s secrets
	json.Unmarshal(file, &s)

	// Set up Database
	db, err := sql.Open("mysql",
		s.Uname+":"+s.Pwd+"@tcp(localhost:3306)/domestic?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Prepare statements in application handlers.
	choresHandler := chores.InitializeHandler(db)
	tasksHandler := tasks.InitializeHandler(db)
	http.HandleFunc("/chores/", choresHandler.Handle)
	http.HandleFunc("/tasks/", tasksHandler.Handle)
	// log.Fatal(http.ListenAndServe(":8080", nil))

	// Let's try doing a database changey thing!
	currentTime := time.Now() // We'll query the chores for things at this time.
	//
	stmt, err := db.Prepare("INSERT INTO tasks(chore_id, c_time) SELECT chore_id, NULL from chores where ? = true AND ((dwm = 'd') OR (dwm = 'w' AND day = ?) OR (dwm = 'm' AND date = ?))")

	if err != nil {
	log.Fatal(err)
	}
	log.Println(currentTime.Weekday(), currentTime.Day())
	_, err = stmt.Exec("morning", currentTime.Weekday(), currentTime.Day())
	log.Println(err)
}
<commit_msg> do it right proper<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"

	_ "github.com/go-sql-driver/mysql"

	"github.com/domestic-apps/domestic-api/chores"
	"github.com/domestic-apps/domestic-api/tasks"
	"time"
)

type secrets struct {
	Uname string `json:"username"`
	Pwd   string `json:"password"`
}

func main() {
	// get mysql username and password from configuration
	file, err := ioutil.ReadFile("./secrets.json")
	if err != nil {
		log.Fatal("File error: %v\n", err)
	}

	var s secrets
	json.Unmarshal(file, &s)

	// Set up Database
	db, err := sql.Open("mysql",
		s.Uname+":"+s.Pwd+"@tcp(localhost:3306)/domestic?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Prepare statements in application handlers.
	choresHandler := chores.InitializeHandler(db)
	tasksHandler := tasks.InitializeHandler(db)
	http.HandleFunc("/chores/", choresHandler.Handle)
	http.HandleFunc("/tasks/", tasksHandler.Handle)
	// log.Fatal(http.ListenAndServe(":8080", nil))

	// Let's try doing a database changey thing!
	currentTime := time.Now() // We'll query the chores for things at this time.
	//
	stmt, err := db.Prepare("INSERT INTO tasks(chore_id, c_time) SELECT chore_id, NULL from chores where (morning = ? OR night = ?) AND ((dwm = 'd') OR (dwm = 'w' AND day = ?) OR (dwm = 'm' AND date = ?))")

	if err != nil {
	log.Fatal(err)
	}
	log.Println(currentTime.Weekday(), currentTime.Day())
	_, err = stmt.Exec(1, -1, currentTime.Weekday(), currentTime.Day())
	log.Println(err)
}
<|endoftext|>


<commit_before>package transloadit

import (
	"fmt"
)

type Template struct {
	Name string `json:"name"`
	// See AddStep for simple usage.
	Steps map[string]map[string]interface{} `json:"content"`
}

type templateGetResponse struct {
	Name    string `json:"name"`
	Content struct {
		Steps map[string]map[string]interface{} `json:"steps"`
	} `json:"content"`
}

type TemplateList struct {
	Templates []TemplateListItem `json:"items"`
	Count     int                `json:"count"`
}

type TemplateListItem struct {
	Id    string                 `json:"id"`
	Name  string                 `json:"name"`
	Steps map[string]interface{} `json:"json"`
}

// Creates a new template instance which can be saved to transloadit.
func NewTemplate(name string) *Template {
	return &Template{
		Name:  name,
		Steps: make(map[string]map[string]interface{}),
	}
}

// Save the template.
func (client *Client) CreateTemplate(template *Template) (string, error) {
	content := map[string]interface{}{
		"name": template.Name,
		"template": map[string]interface{}{
			"steps": template.Steps,
		},
	}

	res, err := client.request("POST", "templates", content, nil)
	if err != nil {
		return "", fmt.Errorf("unable to create template: %s", err)
	}

	return res["template_id"].(string), nil
}

// Get information about a template using its id.
func (client *Client) GetTemplate(templateId string) (*Template, error) {
	var templateGet templateGetResponse
	_, err := client.request("GET", "templates/"+templateId, nil, &templateGet)
	if err != nil {
		return nil, fmt.Errorf("unable to get template: %s", err)
	}

	var template Template
	template.Name = templateGet.Name
	template.Steps = templateGet.Content.Steps

	return &template, nil
}

// Add another step to the template.
func (template *Template) AddStep(name string, step map[string]interface{}) {
	template.Steps[name] = step
}

// Delete a template from the list.
func (client *Client) DeleteTemplate(templateId string) error {
	_, err := client.request("DELETE", "templates/"+templateId, nil, nil)
	if err != nil {
		return fmt.Errorf("unable to delete template: %s", err)
	}

	return nil
}

// Update the name and content of the template defined using the id.
func (client *Client) EditTemplate(templateId string, newTemplate *Template) error {
	// Create signature
	content := map[string]interface{}{
		"name": newTemplate.Name,
		"template": map[string]interface{}{
			"steps": newTemplate.Steps,
		},
	}

	_, err := client.request("PUT", "templates/"+templateId, content, nil)
	return err
}

// List all templates matching the criterias.
func (client *Client) ListTemplates(options *ListOptions) (*TemplateList, error) {
	var templates TemplateList
	_, err := client.listRequest("templates", options, &templates)
	return &templates, err
}
<commit_msg>Remove usage of obsolent and removed response value<commit_after>package transloadit

import (
	"fmt"
)

type Template struct {
	Name string `json:"name"`
	// See AddStep for simple usage.
	Steps map[string]map[string]interface{} `json:"content"`
}

type templateGetResponse struct {
	Name    string `json:"name"`
	Content struct {
		Steps map[string]map[string]interface{} `json:"steps"`
	} `json:"content"`
}

type TemplateList struct {
	Templates []TemplateListItem `json:"items"`
	Count     int                `json:"count"`
}

type TemplateListItem struct {
	Id    string                 `json:"id"`
	Name  string                 `json:"name"`
	Steps map[string]interface{} `json:"json"`
}

// Creates a new template instance which can be saved to transloadit.
func NewTemplate(name string) *Template {
	return &Template{
		Name:  name,
		Steps: make(map[string]map[string]interface{}),
	}
}

// Save the template.
func (client *Client) CreateTemplate(template *Template) (string, error) {
	content := map[string]interface{}{
		"name": template.Name,
		"template": map[string]interface{}{
			"steps": template.Steps,
		},
	}

	res, err := client.request("POST", "templates", content, nil)
	if err != nil {
		return "", fmt.Errorf("unable to create template: %s", err)
	}

	return res["id"].(string), nil
}

// Get information about a template using its id.
func (client *Client) GetTemplate(templateId string) (*Template, error) {
	var templateGet templateGetResponse
	_, err := client.request("GET", "templates/"+templateId, nil, &templateGet)
	if err != nil {
		return nil, fmt.Errorf("unable to get template: %s", err)
	}

	var template Template
	template.Name = templateGet.Name
	template.Steps = templateGet.Content.Steps

	return &template, nil
}

// Add another step to the template.
func (template *Template) AddStep(name string, step map[string]interface{}) {
	template.Steps[name] = step
}

// Delete a template from the list.
func (client *Client) DeleteTemplate(templateId string) error {
	_, err := client.request("DELETE", "templates/"+templateId, nil, nil)
	if err != nil {
		return fmt.Errorf("unable to delete template: %s", err)
	}

	return nil
}

// Update the name and content of the template defined using the id.
func (client *Client) EditTemplate(templateId string, newTemplate *Template) error {
	// Create signature
	content := map[string]interface{}{
		"name": newTemplate.Name,
		"template": map[string]interface{}{
			"steps": newTemplate.Steps,
		},
	}

	_, err := client.request("PUT", "templates/"+templateId, content, nil)
	return err
}

// List all templates matching the criterias.
func (client *Client) ListTemplates(options *ListOptions) (*TemplateList, error) {
	var templates TemplateList
	_, err := client.listRequest("templates", options, &templates)
	return &templates, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

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

func groupByMulti(entries []*RuntimeContainer, key, sep string) map[string][]*RuntimeContainer {
	groups := make(map[string][]*RuntimeContainer)
	for _, v := range entries {
		value := deepGet(*v, key)
		if value != nil {
			items := strings.Split(value.(string), sep)
			for _, item := range items {
				groups[item] = append(groups[item], v)
			}

		}
	}
	return groups
}

func groupBy(entries []*RuntimeContainer, key string) map[string][]*RuntimeContainer {
	groups := make(map[string][]*RuntimeContainer)
	for _, v := range entries {
		value := deepGet(*v, key)
		if value != nil {
			groups[value.(string)] = append(groups[value.(string)], v)
		}
	}
	return groups
}

func contains(item map[string]string, key string) bool {
	if _, ok := item[key]; ok {
		return true
	}
	return false
}

func generateFile(config Config, containers []*RuntimeContainer) bool {
	templatePath := config.Template
	tmpl, err := template.New(filepath.Base(templatePath)).Funcs(template.FuncMap{
		"contains":     contains,
		"exists":       exists,
		"groupBy":      groupBy,
		"groupByMulti": groupByMulti,
		"split":        strings.Split,
	}).ParseFiles(templatePath)
	if err != nil {
		log.Fatalf("unable to parse template: %s", err)
	}

	filteredContainers := []*RuntimeContainer{}
	if config.OnlyPublished {
		for _, container := range containers {
			if len(container.PublishedAddresses()) > 0 {
				filteredContainers = append(filteredContainers, container)
			}
		}
	} else if config.OnlyExposed {
		for _, container := range containers {
			if len(container.Addresses) > 0 {
				filteredContainers = append(filteredContainers, container)
			}
		}
	} else {
		filteredContainers = containers
	}

	dest := os.Stdout
	if config.Dest != "" {
		dest, err = ioutil.TempFile("", "docker-gen")
		defer func() {
			dest.Close()
			os.Remove(dest.Name())
		}()
		if err != nil {
			log.Fatalf("unable to create temp file: %s\n", err)
		}
	}

	var buf bytes.Buffer
	multiwriter := io.MultiWriter(dest, &buf)
	err = tmpl.ExecuteTemplate(multiwriter, filepath.Base(templatePath), filteredContainers)
	if err != nil {
		log.Fatalf("template error: %s\n", err)
	}

	if config.Dest != "" {

		contents := []byte{}
		if _, err := os.Stat(config.Dest); err == nil {
			contents, err = ioutil.ReadFile(config.Dest)
			if err != nil {
				log.Fatalf("unable to compare current file contents: %s: %s\n", config.Dest, err)
			}
		}

		if bytes.Compare(contents, buf.Bytes()) != 0 {
			err = os.Rename(dest.Name(), config.Dest)
			if err != nil {
				log.Fatalf("unable to create dest file %s: %s\n", config.Dest, err)
			}
			log.Printf("Generated '%s' from %d containers", config.Dest, len(filteredContainers))
			return true
		}
		return false
	}
	return true
}
<commit_msg>Fix unable to create dest file/invalid cross-device link<commit_after>package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

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

func groupByMulti(entries []*RuntimeContainer, key, sep string) map[string][]*RuntimeContainer {
	groups := make(map[string][]*RuntimeContainer)
	for _, v := range entries {
		value := deepGet(*v, key)
		if value != nil {
			items := strings.Split(value.(string), sep)
			for _, item := range items {
				groups[item] = append(groups[item], v)
			}

		}
	}
	return groups
}

func groupBy(entries []*RuntimeContainer, key string) map[string][]*RuntimeContainer {
	groups := make(map[string][]*RuntimeContainer)
	for _, v := range entries {
		value := deepGet(*v, key)
		if value != nil {
			groups[value.(string)] = append(groups[value.(string)], v)
		}
	}
	return groups
}

func contains(item map[string]string, key string) bool {
	if _, ok := item[key]; ok {
		return true
	}
	return false
}

func generateFile(config Config, containers []*RuntimeContainer) bool {
	templatePath := config.Template
	tmpl, err := template.New(filepath.Base(templatePath)).Funcs(template.FuncMap{
		"contains":     contains,
		"exists":       exists,
		"groupBy":      groupBy,
		"groupByMulti": groupByMulti,
		"split":        strings.Split,
	}).ParseFiles(templatePath)
	if err != nil {
		log.Fatalf("unable to parse template: %s", err)
	}

	filteredContainers := []*RuntimeContainer{}
	if config.OnlyPublished {
		for _, container := range containers {
			if len(container.PublishedAddresses()) > 0 {
				filteredContainers = append(filteredContainers, container)
			}
		}
	} else if config.OnlyExposed {
		for _, container := range containers {
			if len(container.Addresses) > 0 {
				filteredContainers = append(filteredContainers, container)
			}
		}
	} else {
		filteredContainers = containers
	}

	dest := os.Stdout
	if config.Dest != "" {
		dest, err = ioutil.TempFile(filepath.Dir(config.Dest), "docker-gen")
		defer func() {
			dest.Close()
			os.Remove(dest.Name())
		}()
		if err != nil {
			log.Fatalf("unable to create temp file: %s\n", err)
		}
	}

	var buf bytes.Buffer
	multiwriter := io.MultiWriter(dest, &buf)
	err = tmpl.ExecuteTemplate(multiwriter, filepath.Base(templatePath), filteredContainers)
	if err != nil {
		log.Fatalf("template error: %s\n", err)
	}

	if config.Dest != "" {

		contents := []byte{}
		if _, err := os.Stat(config.Dest); err == nil {
			contents, err = ioutil.ReadFile(config.Dest)
			if err != nil {
				log.Fatalf("unable to compare current file contents: %s: %s\n", config.Dest, err)
			}
		}

		if bytes.Compare(contents, buf.Bytes()) != 0 {
			err = os.Rename(dest.Name(), config.Dest)
			if err != nil {
				log.Fatalf("unable to create dest file %s: %s\n", config.Dest, err)
			}
			log.Printf("Generated '%s' from %d containers", config.Dest, len(filteredContainers))
			return true
		}
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Reads the templates and writes the substituted templates

package main

import (
	"bytes"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path"
	"regexp"
	"strings"
)

// Holds the desired template
type template struct {
	Package      string
	Name         string
	Args         []string
	NewPackage   string
	Dir          string
	templateName string
	templateArgs []string
	mappings     map[string]string
	newIsPublic  bool
	inputFile    string
}

// findPackageName reads all the go packages in the curent directory
// and finds which package they are in
func findPackageName() string {
	p, err := build.Default.Import(".", ".", build.ImportMode(0))
	if err != nil {
		fatalf("Failed to read packages in current directory: %v", err)
	}
	return p.Name
}

// init the template instantiation
func newTemplate(dir, pkg, templateArgsString string) *template {
	name, templateArgs := parseTemplateAndArgs(templateArgsString)
	return &template{
		Package:    pkg,
		Name:       name,
		Args:       templateArgs,
		Dir:        dir,
		mappings:   make(map[string]string),
		NewPackage: findPackageName(),
	}
}

// Add a mapping for identifier
func (t *template) addMapping(name string) {
	replacementName := ""
	if !strings.Contains(name, t.templateName) {
		// If name doesn't contain template name then just prefix it
		innerName := strings.ToUpper(t.Name[:1]) + t.Name[1:]
		replacementName = name + innerName
		debugf("Top level definition '%s' doesn't contain template name '%s', using '%s'", name, t.templateName, replacementName)
	} else {
		// make sure the new identifier will follow
		// Go casing style (newMySet not newmySet).
		innerName := t.Name
		if strings.Index(name, t.templateName) != 0 {
			innerName = strings.ToUpper(innerName[:1]) + innerName[1:]
		}
		replacementName = strings.Replace(name, t.templateName, innerName, 1)
	}
	// If new template name is not public then make sure
	// the exported name is not public too
	if !t.newIsPublic && ast.IsExported(replacementName) {
		replacementName = strings.ToLower(replacementName[:1]) + replacementName[1:]
	}
	t.mappings[name] = replacementName
}

// Parse the arguments string Template(A, B, C)
func parseTemplateAndArgs(s string) (name string, args []string) {
	expr, err := parser.ParseExpr(s)
	if err != nil {
		fatalf("Failed to parse %q: %v", s, err)
	}
	debugf("expr = %#v\n", expr)
	callExpr, ok := expr.(*ast.CallExpr)
	if !ok {
		fatalf("Failed to parse %q: expecting Identifier(...)", s)
	}
	debugf("fun = %#v", callExpr.Fun)
	fn, ok := callExpr.Fun.(*ast.Ident)
	if !ok {
		fatalf("Failed to parse %q: expecting Identifier(...)", s)
	}
	name = fn.Name
	for i, arg := range callExpr.Args {
		var buf bytes.Buffer
		debugf("arg[%d] = %#v", i, arg)
		format.Node(&buf, token.NewFileSet(), arg)
		s := buf.String()
		debugf("parsed = %q", s)
		args = append(args, s)
	}
	return
}

// "template type Set(A)"
var matchTemplateType = regexp.MustCompile(`^//\s*template\s+type\s+(\w+\s*.*?)\s*$`)

func (t *template) findTemplateDefinition(f *ast.File) {
	// Inspect the comments
	t.templateName = ""
	t.templateArgs = nil
	for _, cg := range f.Comments {
		for _, x := range cg.List {
			matches := matchTemplateType.FindStringSubmatch(x.Text)
			if matches != nil {
				if t.templateName != "" {
					fatalf("Found multiple template definitions in %s", t.inputFile)
				}
				t.templateName, t.templateArgs = parseTemplateAndArgs(matches[1])
			}
		}
	}
	if t.templateName == "" {
		fatalf("Didn't find template definition in %s", t.inputFile)
	}
	if len(t.templateArgs) != len(t.Args) {
		fatalf("Wrong number of arguments - template is expecting %d but %d supplied", len(t.Args), len(t.templateArgs))
	}
	debugf("templateName = %v, templateArgs = %v", t.templateName, t.templateArgs)
}

// Ouput the go formatted file
//
// Exits with a fatal error on error
func outputFile(fset *token.FileSet, f *ast.File, path string) {
	fd, err := os.Create(path)
	if err != nil {
		fatalf("Failed to open %q: %s", path, err)
	}
	if err := format.Node(fd, fset, f); err != nil {
		fatalf("Failed to format %q: %s", path, err)
	}
	err = fd.Close()
	if err != nil {
		fatalf("Failed to close %q: %s", path, err)
	}
}

// Parses a file into a Fileset and Ast
//
// Dies with a fatal error on error
func parseFile(path string) (*token.FileSet, *ast.File) {
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		fatalf("Failed to parse file: %s", err)
	}
	return fset, f
}

// Returns true if haystack contains needle
func containsString(needle string, haystack []string) bool {
	for _, item := range haystack {
		if item == needle {
			return true
		}
	}
	return false
}

// Replace the identifers in f
func replaceIdentifier(f *ast.File, old, new string) {
	// Inspect the AST and print all identifiers and literals.
	ast.Inspect(f, func(n ast.Node) bool {
		switch x := n.(type) {
		case *ast.Ident:
			// We replace the identifier name
			// which is a bit untidy if we weren't
			// replacing with an identifier
			if x.Name == old {
				x.Name = new
			}
		}
		return true
	})
}

// Parses the template file
func (t *template) parse(inputFile string) {
	t.inputFile = inputFile
	// Make the name mappings
	t.newIsPublic = ast.IsExported(t.Name)

	fset, f := parseFile(inputFile)
	t.findTemplateDefinition(f)

	// debugf("Decls = %#v", f.Decls)
	// Find names which need to be adjusted
	namesToMangle := []string{}
	newDecls := []ast.Decl{}
	for _, Decl := range f.Decls {
		remove := false
		switch d := Decl.(type) {
		case *ast.GenDecl:
			// A general definition
			switch d.Tok {
			case token.IMPORT:
				// Ignore imports
			case token.CONST, token.VAR:
				// Find and remove identifiers found in template
				// params
				emptySpecs := []int{}
				for i, spec := range d.Specs {
					namesToRemove := []int{}
					v := spec.(*ast.ValueSpec)
					for j, name := range v.Names {
						debugf("VAR or CONST %v", name.Name)
						namesToMangle = append(namesToMangle, name.Name)
						if containsString(name.Name, t.templateArgs) {
							namesToRemove = append(namesToRemove, j)
						}
					}
					// Shuffle the names to remove out of v.Names and v.Values
					for i := len(namesToRemove) - 1; i >= 0; i-- {
						p := namesToRemove[i]
						v.Names = append(v.Names[:p], v.Names[p+1:]...)
						v.Values = append(v.Values[:p], v.Values[p+1:]...)
					}
					// If empty then add to slice to remove later
					if len(v.Names) == 0 {
						emptySpecs = append(emptySpecs, i)
					}
				}
				// Remove now-empty specs
				for i := len(emptySpecs) - 1; i >= 0; i-- {
					p := emptySpecs[i]
					d.Specs = append(d.Specs[:p], d.Specs[p+1:]...)
				}
				remove = len(d.Specs) == 0
			case token.TYPE:
				if len(d.Specs) != 1 {
					fatalf("Unexpected specs on TYPE")
				}
				typeSpec := d.Specs[0].(*ast.TypeSpec)
				debugf("Type %v", typeSpec.Name.Name)
				namesToMangle = append(namesToMangle, typeSpec.Name.Name)
				// Remove type A if it is a template definition
				remove = containsString(typeSpec.Name.Name, t.templateArgs)
			default:
				logf("Unknown type %s", d.Tok)
			}
			debugf("GenDecl = %#v", d)
		case *ast.FuncDecl:
			// A function definition
			if d.Recv != nil {
				// No receiver == method - ignore this function
			} else {
				//debugf("FuncDecl = %#v", d)
				debugf("FuncDecl = %s", d.Name.Name)
				namesToMangle = append(namesToMangle, d.Name.Name)
				// Remove func A() if it is a template definition
				remove = containsString(d.Name.Name, t.templateArgs)
			}
		default:
			fatalf("Unknown Decl %#v", Decl)
		}
		if !remove {
			newDecls = append(newDecls, Decl)
		}
	}
	debugf("Names to mangle = %#v", namesToMangle)

	// Remove the stub type definitions "type A int" from the package
	f.Decls = newDecls

	// Map the type definitions A -> string, B -> int
	for i := range t.Args {
		t.mappings[t.templateArgs[i]] = t.Args[i]
	}

	found := false
	for _, name := range namesToMangle {
		if name == t.templateName {
			found = true
			t.addMapping(name)
		} else if _, found := t.mappings[name]; !found {
			t.addMapping(name)
		}

	}
	if !found {
		fatalf("No definition for template type '%s'", t.templateName)
	}
	debugf("mappings = %#v", t.mappings)

	// Replace the identifiers
	for name, replacement := range t.mappings {
		replaceIdentifier(f, name, replacement)
	}

	// Change the package to the local package name
	f.Name.Name = t.NewPackage

	// Output
	outputFileName := "gotemplate_" + t.Name + ".go"
	outputFile(fset, f, outputFileName)

	// gofmt one last time to sort out messy identifier substution
	fset, f = parseFile(outputFileName)
	outputFile(fset, f, outputFileName)
	logf("Written '%s'", outputFileName)
}

// Instantiate the template package
func (t *template) instantiate() {
	logf("Substituting %q with %s(%s) into package %s", t.Package, t.Name, strings.Join(t.Args, ","), t.NewPackage)

	p, err := build.Default.Import(t.Package, t.Dir, build.ImportMode(0))
	if err != nil {
		fatalf("Import %s failed: %s", t.Package, err)
	}
	//debugf("package = %#v", p)
	debugf("Dir = %#v", p.Dir)
	// FIXME CgoFiles ?
	debugf("Go files = %#v", p.GoFiles)

	if len(p.GoFiles) == 0 {
		fatalf("No go files found for package '%s'", t.Package)
	}
	// FIXME
	if len(p.GoFiles) != 1 {
		fatalf("Found more than one go file in '%s' - can only cope with 1 for the moment, sorry", t.Package)
	}

	templateFilePath := path.Join(p.Dir, p.GoFiles[0])
	t.parse(templateFilePath)
}
<commit_msg>Rename containsString into t.isTemplateArgument for clearer code<commit_after>// Reads the templates and writes the substituted templates

package main

import (
	"bytes"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path"
	"regexp"
	"strings"
)

// Holds the desired template
type template struct {
	Package      string
	Name         string
	Args         []string
	NewPackage   string
	Dir          string
	templateName string
	templateArgs []string
	mappings     map[string]string
	newIsPublic  bool
	inputFile    string
}

// findPackageName reads all the go packages in the curent directory
// and finds which package they are in
func findPackageName() string {
	p, err := build.Default.Import(".", ".", build.ImportMode(0))
	if err != nil {
		fatalf("Failed to read packages in current directory: %v", err)
	}
	return p.Name
}

// init the template instantiation
func newTemplate(dir, pkg, templateArgsString string) *template {
	name, templateArgs := parseTemplateAndArgs(templateArgsString)
	return &template{
		Package:    pkg,
		Name:       name,
		Args:       templateArgs,
		Dir:        dir,
		mappings:   make(map[string]string),
		NewPackage: findPackageName(),
	}
}

// Add a mapping for identifier
func (t *template) addMapping(name string) {
	replacementName := ""
	if !strings.Contains(name, t.templateName) {
		// If name doesn't contain template name then just prefix it
		innerName := strings.ToUpper(t.Name[:1]) + t.Name[1:]
		replacementName = name + innerName
		debugf("Top level definition '%s' doesn't contain template name '%s', using '%s'", name, t.templateName, replacementName)
	} else {
		// make sure the new identifier will follow
		// Go casing style (newMySet not newmySet).
		innerName := t.Name
		if strings.Index(name, t.templateName) != 0 {
			innerName = strings.ToUpper(innerName[:1]) + innerName[1:]
		}
		replacementName = strings.Replace(name, t.templateName, innerName, 1)
	}
	// If new template name is not public then make sure
	// the exported name is not public too
	if !t.newIsPublic && ast.IsExported(replacementName) {
		replacementName = strings.ToLower(replacementName[:1]) + replacementName[1:]
	}
	t.mappings[name] = replacementName
}

// Parse the arguments string Template(A, B, C)
func parseTemplateAndArgs(s string) (name string, args []string) {
	expr, err := parser.ParseExpr(s)
	if err != nil {
		fatalf("Failed to parse %q: %v", s, err)
	}
	debugf("expr = %#v\n", expr)
	callExpr, ok := expr.(*ast.CallExpr)
	if !ok {
		fatalf("Failed to parse %q: expecting Identifier(...)", s)
	}
	debugf("fun = %#v", callExpr.Fun)
	fn, ok := callExpr.Fun.(*ast.Ident)
	if !ok {
		fatalf("Failed to parse %q: expecting Identifier(...)", s)
	}
	name = fn.Name
	for i, arg := range callExpr.Args {
		var buf bytes.Buffer
		debugf("arg[%d] = %#v", i, arg)
		format.Node(&buf, token.NewFileSet(), arg)
		s := buf.String()
		debugf("parsed = %q", s)
		args = append(args, s)
	}
	return
}

// "template type Set(A)"
var matchTemplateType = regexp.MustCompile(`^//\s*template\s+type\s+(\w+\s*.*?)\s*$`)

func (t *template) findTemplateDefinition(f *ast.File) {
	// Inspect the comments
	t.templateName = ""
	t.templateArgs = nil
	for _, cg := range f.Comments {
		for _, x := range cg.List {
			matches := matchTemplateType.FindStringSubmatch(x.Text)
			if matches != nil {
				if t.templateName != "" {
					fatalf("Found multiple template definitions in %s", t.inputFile)
				}
				t.templateName, t.templateArgs = parseTemplateAndArgs(matches[1])
			}
		}
	}
	if t.templateName == "" {
		fatalf("Didn't find template definition in %s", t.inputFile)
	}
	if len(t.templateArgs) != len(t.Args) {
		fatalf("Wrong number of arguments - template is expecting %d but %d supplied", len(t.Args), len(t.templateArgs))
	}
	debugf("templateName = %v, templateArgs = %v", t.templateName, t.templateArgs)
}

// Ouput the go formatted file
//
// Exits with a fatal error on error
func outputFile(fset *token.FileSet, f *ast.File, path string) {
	fd, err := os.Create(path)
	if err != nil {
		fatalf("Failed to open %q: %s", path, err)
	}
	if err := format.Node(fd, fset, f); err != nil {
		fatalf("Failed to format %q: %s", path, err)
	}
	err = fd.Close()
	if err != nil {
		fatalf("Failed to close %q: %s", path, err)
	}
}

// Parses a file into a Fileset and Ast
//
// Dies with a fatal error on error
func parseFile(path string) (*token.FileSet, *ast.File) {
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		fatalf("Failed to parse file: %s", err)
	}
	return fset, f
}

// Replace the identifers in f
func replaceIdentifier(f *ast.File, old, new string) {
	// Inspect the AST and print all identifiers and literals.
	ast.Inspect(f, func(n ast.Node) bool {
		switch x := n.(type) {
		case *ast.Ident:
			// We replace the identifier name
			// which is a bit untidy if we weren't
			// replacing with an identifier
			if x.Name == old {
				x.Name = new
			}
		}
		return true
	})
}

// Return true if name is a template argument
func (t *template) isTemplateArgument(name string) bool {
	for _, item := range t.templateArgs {
		if item == name {
			return true
		}
	}
	return false
}

// Parses the template file
func (t *template) parse(inputFile string) {
	t.inputFile = inputFile
	// Make the name mappings
	t.newIsPublic = ast.IsExported(t.Name)

	fset, f := parseFile(inputFile)
	t.findTemplateDefinition(f)

	// debugf("Decls = %#v", f.Decls)
	// Find names which need to be adjusted
	namesToMangle := []string{}
	newDecls := []ast.Decl{}
	for _, Decl := range f.Decls {
		remove := false
		switch d := Decl.(type) {
		case *ast.GenDecl:
			// A general definition
			switch d.Tok {
			case token.IMPORT:
				// Ignore imports
			case token.CONST, token.VAR:
				// Find and remove identifiers found in template
				// params
				emptySpecs := []int{}
				for i, spec := range d.Specs {
					namesToRemove := []int{}
					v := spec.(*ast.ValueSpec)
					for j, name := range v.Names {
						debugf("VAR or CONST %v", name.Name)
						namesToMangle = append(namesToMangle, name.Name)
						if t.isTemplateArgument(name.Name) {
							namesToRemove = append(namesToRemove, j)
						}
					}
					// Shuffle the names to remove out of v.Names and v.Values
					for i := len(namesToRemove) - 1; i >= 0; i-- {
						p := namesToRemove[i]
						v.Names = append(v.Names[:p], v.Names[p+1:]...)
						v.Values = append(v.Values[:p], v.Values[p+1:]...)
					}
					// If empty then add to slice to remove later
					if len(v.Names) == 0 {
						emptySpecs = append(emptySpecs, i)
					}
				}
				// Remove now-empty specs
				for i := len(emptySpecs) - 1; i >= 0; i-- {
					p := emptySpecs[i]
					d.Specs = append(d.Specs[:p], d.Specs[p+1:]...)
				}
				remove = len(d.Specs) == 0
			case token.TYPE:
				if len(d.Specs) != 1 {
					fatalf("Unexpected specs on TYPE")
				}
				typeSpec := d.Specs[0].(*ast.TypeSpec)
				debugf("Type %v", typeSpec.Name.Name)
				namesToMangle = append(namesToMangle, typeSpec.Name.Name)
				// Remove type A if it is a template definition
				remove = t.isTemplateArgument(typeSpec.Name.Name)
			default:
				logf("Unknown type %s", d.Tok)
			}
			debugf("GenDecl = %#v", d)
		case *ast.FuncDecl:
			// A function definition
			if d.Recv != nil {
				// Has receiver so is a method - ignore this function
			} else {
				//debugf("FuncDecl = %#v", d)
				debugf("FuncDecl = %s", d.Name.Name)
				namesToMangle = append(namesToMangle, d.Name.Name)
				// Remove func A() if it is a template definition
				remove = t.isTemplateArgument(d.Name.Name)
			}
		default:
			fatalf("Unknown Decl %#v", Decl)
		}
		if !remove {
			newDecls = append(newDecls, Decl)
		}
	}
	debugf("Names to mangle = %#v", namesToMangle)

	// Remove the stub type definitions "type A int" from the package
	f.Decls = newDecls

	// Map the type definitions A -> string, B -> int
	for i := range t.Args {
		t.mappings[t.templateArgs[i]] = t.Args[i]
	}

	found := false
	for _, name := range namesToMangle {
		if name == t.templateName {
			found = true
			t.addMapping(name)
		} else if _, found := t.mappings[name]; !found {
			t.addMapping(name)
		}

	}
	if !found {
		fatalf("No definition for template type '%s'", t.templateName)
	}
	debugf("mappings = %#v", t.mappings)

	// Replace the identifiers
	for name, replacement := range t.mappings {
		replaceIdentifier(f, name, replacement)
	}

	// Change the package to the local package name
	f.Name.Name = t.NewPackage

	// Output
	outputFileName := "gotemplate_" + t.Name + ".go"
	outputFile(fset, f, outputFileName)

	// gofmt one last time to sort out messy identifier substution
	fset, f = parseFile(outputFileName)
	outputFile(fset, f, outputFileName)
	logf("Written '%s'", outputFileName)
}

// Instantiate the template package
func (t *template) instantiate() {
	logf("Substituting %q with %s(%s) into package %s", t.Package, t.Name, strings.Join(t.Args, ","), t.NewPackage)

	p, err := build.Default.Import(t.Package, t.Dir, build.ImportMode(0))
	if err != nil {
		fatalf("Import %s failed: %s", t.Package, err)
	}
	//debugf("package = %#v", p)
	debugf("Dir = %#v", p.Dir)
	// FIXME CgoFiles ?
	debugf("Go files = %#v", p.GoFiles)

	if len(p.GoFiles) == 0 {
		fatalf("No go files found for package '%s'", t.Package)
	}
	// FIXME
	if len(p.GoFiles) != 1 {
		fatalf("Found more than one go file in '%s' - can only cope with 1 for the moment, sorry", t.Package)
	}

	templateFilePath := path.Join(p.Dir, p.GoFiles[0])
	t.parse(templateFilePath)
}
<|endoftext|>


<commit_before>package dwn

import (
	"encoding/json"
	"net/http"
	"time"

	"log"

	"io/ioutil"

	"github.com/satori/go.uuid"
	"golang.org/x/crypto/bcrypt"
)

// TokenHandler takes in unencrypted credentials (email and password) via form values,
// hashes the password with bcrypt, compares to the stored hash, and returns Unauthorized
// or a token (uuid version 4) representing the session.
func TokenHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("could not read login request json body:", err)
		http.Error(w, "could not read login request json body", http.StatusInternalServerError)
		return
	}
	var req TokenRequest
	err = json.Unmarshal(body, &req)

	var user User
	err = Db.One("Email", req.Email, &user)
	if err != nil {
		log.Println("could not load user to build session:", err, "for email", req.Email)
		http.Error(w, "incorrect email or password", http.StatusBadRequest)
		return
	}
	if CheckPasswordHash(req.Password, user.Password) {
		session := Session{
			Token:     uuid.NewV4(),
			User:      user,
			CreatedAt: time.Now(),
			HeartBeat: time.Now(),
		}
		err = Db.Save(&session)
		if err != nil {
			log.Println("could not save session:", err)
			http.Error(w, "could not save session", http.StatusInternalServerError)
			return
		}
		json.NewEncoder(w).Encode(session)
	} else {
		log.Println("incorrect password:", req.Password, "for user:", user.Email)
		http.Error(w, "incorrect email or password", http.StatusBadRequest)
		return
	}
}

const (
	_ = iota
	// RoleAdmin denotes an administrator
	RoleAdmin = iota
	// RoleUser denotes an unpriviledged user
	RoleUser = iota
)

// User represents and application user
type User struct {
	ID        int    `storm:"id,increment"`
	Role      int    `storm:"index"`
	Email     string `storm:"unique"`
	Password  string `json:"-"`
	Name      string
	CreatedAt time.Time
}

type UserInfo struct {
	ID      int
	Name    string
	IsAdmin bool
}

// Session represents a user session
type Session struct {
	Token     uuid.UUID `storm:"id"`
	User      User      `storm:"index"`
	CreatedAt time.Time
	HeartBeat time.Time
}

// TokenRequest holds the incoming request for a token (session key)
type TokenRequest struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

// HashPassword takes a plaintext password string and returns a hash from bcrypt
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes), err
}

// CheckPasswordHash compares the hash of a plain password with a stored
// hash, returning a bool match result
func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// InRole checks to see that an http request comes from a user in a specified role.
func InRole(r *http.Request, role int) (bool, error) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		return false, err
	}
	return session.User.Role == role, nil
}

// SessionFor returns the session for the current request
func SessionFor(r *http.Request) (Session, error) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		return session, err
	}
	return session, nil
}

// LogoutHandler handles requests to log out. If the session exists, it is deleted.
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		http.Error(w, "Could not find session.", http.StatusBadRequest)
		return
	}
	if err := Db.DeleteStruct(&session); err != nil {
		log.Println("Could not delete session:", err)
		http.Error(w, "Could not delete session.", http.StatusBadRequest)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
<commit_msg>comment exporterd UserInfo struct<commit_after>package dwn

import (
	"encoding/json"
	"net/http"
	"time"

	"log"

	"io/ioutil"

	"github.com/satori/go.uuid"
	"golang.org/x/crypto/bcrypt"
)

// TokenHandler takes in unencrypted credentials (email and password) via form values,
// hashes the password with bcrypt, compares to the stored hash, and returns Unauthorized
// or a token (uuid version 4) representing the session.
func TokenHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println("could not read login request json body:", err)
		http.Error(w, "could not read login request json body", http.StatusInternalServerError)
		return
	}
	var req TokenRequest
	err = json.Unmarshal(body, &req)

	var user User
	err = Db.One("Email", req.Email, &user)
	if err != nil {
		log.Println("could not load user to build session:", err, "for email", req.Email)
		http.Error(w, "incorrect email or password", http.StatusBadRequest)
		return
	}
	if CheckPasswordHash(req.Password, user.Password) {
		session := Session{
			Token:     uuid.NewV4(),
			User:      user,
			CreatedAt: time.Now(),
			HeartBeat: time.Now(),
		}
		err = Db.Save(&session)
		if err != nil {
			log.Println("could not save session:", err)
			http.Error(w, "could not save session", http.StatusInternalServerError)
			return
		}
		json.NewEncoder(w).Encode(session)
	} else {
		log.Println("incorrect password:", req.Password, "for user:", user.Email)
		http.Error(w, "incorrect email or password", http.StatusBadRequest)
		return
	}
}

const (
	_ = iota
	// RoleAdmin denotes an administrator
	RoleAdmin = iota
	// RoleUser denotes an unpriviledged user
	RoleUser = iota
)

// User represents and application user
type User struct {
	ID        int    `storm:"id,increment"`
	Role      int    `storm:"index"`
	Email     string `storm:"unique"`
	Password  string `json:"-"`
	Name      string
	CreatedAt time.Time
}

// UserInfo represents user information safe for showing to other users
type UserInfo struct {
	ID      int
	Name    string
	IsAdmin bool
}

// Session represents a user session
type Session struct {
	Token     uuid.UUID `storm:"id"`
	User      User      `storm:"index"`
	CreatedAt time.Time
	HeartBeat time.Time
}

// TokenRequest holds the incoming request for a token (session key)
type TokenRequest struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

// HashPassword takes a plaintext password string and returns a hash from bcrypt
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes), err
}

// CheckPasswordHash compares the hash of a plain password with a stored
// hash, returning a bool match result
func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// InRole checks to see that an http request comes from a user in a specified role.
func InRole(r *http.Request, role int) (bool, error) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		return false, err
	}
	return session.User.Role == role, nil
}

// SessionFor returns the session for the current request
func SessionFor(r *http.Request) (Session, error) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		return session, err
	}
	return session, nil
}

// LogoutHandler handles requests to log out. If the session exists, it is deleted.
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
	token := r.Header.Get("X-DWN-TOKEN")
	var session Session
	if err := Db.One("Token", token, &session); err != nil {
		http.Error(w, "Could not find session.", http.StatusBadRequest)
		return
	}
	if err := Db.DeleteStruct(&session); err != nil {
		log.Println("Could not delete session:", err)
		http.Error(w, "Could not delete session.", http.StatusBadRequest)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/user"
	"path"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/route53"
)

type recordSet struct {
	name         string
	value        string // ip
	rsType       string
	ttl          int64
	hostedZoneID string
}

const (
	progName   = "dyndns53"
	ipFileName = "." + progName + "-ip"
)

func main() {
	log.SetPrefix(progName + ": ")
	log.SetFlags(0)

	var recSet recordSet
	var logFn string
	flag.StringVar(&recSet.name, "name", "", "record set name (domain)")
	flag.StringVar(&recSet.rsType, "type", "A", `record set type; "A" or "AAAA"`)
	flag.Int64Var(&recSet.ttl, "ttl", 300, "TTL (time to live) in seconds")
	flag.StringVar(&recSet.hostedZoneID, "zone", "", "hosted zone id")
	flag.StringVar(&logFn, "log", "", "file name to log to (default is stdout)")
	if len(os.Args) == 1 {
		flag.Usage()
		os.Exit(1)
	}
	flag.Parse()

	recSet.name = strings.TrimSuffix(recSet.name, ".") + "." // append . if missing
	if err := recSet.validate(); err != nil {
		log.Fatal(err)
	}

	if logFn != "" {
		f, err := os.OpenFile(logFn, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("log file: %v", err)
		}
		defer f.Close()

		log.SetFlags(log.LstdFlags) // restore standard flags
		log.SetOutput(f)            // log to file
	}

	ip, err := currentIPAddress()
	if err != nil {
		log.Fatal(err)
	}

	if ip == lastIPAddress() {
		log.Printf("current IP address is %s; nothing to do", ip)
		os.Exit(0)
	}

	recSet.value = ip
	_, err = recSet.upsert()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("current IP address is %s; upsert request sent", ip)

	if err := updateLastIPAddress(ip); err != nil {
		log.Fatal(err)
	}
}

func currentIPAddress() (string, error) {
	resp, err := http.Get("http://checkip.amazonaws.com/")
	if err != nil {
		return "", fmt.Errorf("currentIPAddress: %v", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("currentIPAddress: %v", err)
	}
	ip := strings.TrimSpace(string(body))
	return ip, nil
}

func lastIPAddress() string {
	data, err := ioutil.ReadFile(ipFileName)
	if err != nil {
		return ""
	}
	return string(data)
}

func updateLastIPAddress(ip string) error {
	if err := ioutil.WriteFile(ipFileName, []byte(ip), 0611); err != nil {
		return fmt.Errorf("updateLastIPAddress: %v", err)
	}
	return nil
}

func (rs *recordSet) upsert() (*route53.ChangeResourceRecordSetsOutput, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}
	credentialsPath := path.Join(usr.HomeDir, ".aws", "credentials")
	credentials := credentials.NewSharedCredentials(credentialsPath, progName)

	sess, err := session.NewSession()
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}

	svc := route53.New(sess, &aws.Config{Credentials: credentials})
	params := &route53.ChangeResourceRecordSetsInput{
		ChangeBatch: &route53.ChangeBatch{
			Changes: []*route53.Change{
				{
					Action: aws.String("UPSERT"),
					ResourceRecordSet: &route53.ResourceRecordSet{
						Name: aws.String(rs.name),
						Type: aws.String(rs.rsType),
						TTL:  aws.Int64(rs.ttl),
						ResourceRecords: []*route53.ResourceRecord{
							{
								Value: aws.String(rs.value),
							},
						},
					},
				},
			},
		},
		HostedZoneId: aws.String(rs.hostedZoneID),
	}
	resp, err := svc.ChangeResourceRecordSets(params)
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}
	return resp, nil
}

func (rs *recordSet) validate() error {
	if rs.name == "" {
		return fmt.Errorf("missing record set name")
	}
	if !strings.HasSuffix(rs.name, ".") {
		return fmt.Errorf(`record set name must end with a "."`)
	}
	if rs.rsType == "" {
		return fmt.Errorf("missing record set type")
	}
	if rs.rsType != "A" && rs.rsType != "AAAA" {
		return fmt.Errorf("invalid record set type: %s", rs.rsType)
	}
	if rs.ttl < 1 {
		return fmt.Errorf("invalid record set TTL: %d", rs.ttl)
	}
	if rs.hostedZoneID == "" {
		return fmt.Errorf("missing hosted zone id")
	}
	return nil
}
<commit_msg>Fix last IP address file permissions<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/user"
	"path"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/route53"
)

type recordSet struct {
	name         string
	value        string // ip
	rsType       string
	ttl          int64
	hostedZoneID string
}

const (
	progName   = "dyndns53"
	ipFileName = "." + progName + "-ip"
)

func main() {
	log.SetPrefix(progName + ": ")
	log.SetFlags(0)

	var recSet recordSet
	var logFn string
	flag.StringVar(&recSet.name, "name", "", "record set name (domain)")
	flag.StringVar(&recSet.rsType, "type", "A", `record set type; "A" or "AAAA"`)
	flag.Int64Var(&recSet.ttl, "ttl", 300, "TTL (time to live) in seconds")
	flag.StringVar(&recSet.hostedZoneID, "zone", "", "hosted zone id")
	flag.StringVar(&logFn, "log", "", "file name to log to (default is stdout)")
	if len(os.Args) == 1 {
		flag.Usage()
		os.Exit(1)
	}
	flag.Parse()

	recSet.name = strings.TrimSuffix(recSet.name, ".") + "." // append . if missing
	if err := recSet.validate(); err != nil {
		log.Fatal(err)
	}

	if logFn != "" {
		f, err := os.OpenFile(logFn, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("log file: %v", err)
		}
		defer f.Close()

		log.SetFlags(log.LstdFlags) // restore standard flags
		log.SetOutput(f)            // log to file
	}

	ip, err := currentIPAddress()
	if err != nil {
		log.Fatal(err)
	}

	if ip == lastIPAddress() {
		log.Printf("current IP address is %s; nothing to do", ip)
		os.Exit(0)
	}

	recSet.value = ip
	_, err = recSet.upsert()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("current IP address is %s; upsert request sent", ip)

	if err := updateLastIPAddress(ip); err != nil {
		log.Fatal(err)
	}
}

func currentIPAddress() (string, error) {
	resp, err := http.Get("http://checkip.amazonaws.com/")
	if err != nil {
		return "", fmt.Errorf("currentIPAddress: %v", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("currentIPAddress: %v", err)
	}
	ip := strings.TrimSpace(string(body))
	return ip, nil
}

func lastIPAddress() string {
	data, err := ioutil.ReadFile(ipFileName)
	if err != nil {
		return ""
	}
	return string(data)
}

func updateLastIPAddress(ip string) error {
	if err := ioutil.WriteFile(ipFileName, []byte(ip), 0644); err != nil {
		return fmt.Errorf("updateLastIPAddress: %v", err)
	}
	return nil
}

func (rs *recordSet) upsert() (*route53.ChangeResourceRecordSetsOutput, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}
	credentialsPath := path.Join(usr.HomeDir, ".aws", "credentials")
	credentials := credentials.NewSharedCredentials(credentialsPath, progName)

	sess, err := session.NewSession()
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}

	svc := route53.New(sess, &aws.Config{Credentials: credentials})
	params := &route53.ChangeResourceRecordSetsInput{
		ChangeBatch: &route53.ChangeBatch{
			Changes: []*route53.Change{
				{
					Action: aws.String("UPSERT"),
					ResourceRecordSet: &route53.ResourceRecordSet{
						Name: aws.String(rs.name),
						Type: aws.String(rs.rsType),
						TTL:  aws.Int64(rs.ttl),
						ResourceRecords: []*route53.ResourceRecord{
							{
								Value: aws.String(rs.value),
							},
						},
					},
				},
			},
		},
		HostedZoneId: aws.String(rs.hostedZoneID),
	}
	resp, err := svc.ChangeResourceRecordSets(params)
	if err != nil {
		return nil, fmt.Errorf("(*recordSet).upsert: %v", err)
	}
	return resp, nil
}

func (rs *recordSet) validate() error {
	if rs.name == "" {
		return fmt.Errorf("missing record set name")
	}
	if !strings.HasSuffix(rs.name, ".") {
		return fmt.Errorf(`record set name must end with a "."`)
	}
	if rs.rsType == "" {
		return fmt.Errorf("missing record set type")
	}
	if rs.rsType != "A" && rs.rsType != "AAAA" {
		return fmt.Errorf("invalid record set type: %s", rs.rsType)
	}
	if rs.ttl < 1 {
		return fmt.Errorf("invalid record set TTL: %d", rs.ttl)
	}
	if rs.hostedZoneID == "" {
		return fmt.Errorf("missing hosted zone id")
	}
	return nil
}
<|endoftext|>


<commit_before>package lib

import (
	"encoding/json"
	"fmt"
	"github.com/influxdb/influxdb/client/v2"
	"github.com/subutai-io/Subutai/agent/config"
	"os"
)

var (
	tableCPU  = "host_cpu"
	tableNet  = "host_net"
	tableMem  = "host_memory"
	tableDisk = "host_disk"
)

// queryDB convenience function to query the database
func queryInfluxDB(clnt client.Client, cmd string) (res []client.Result, err error) {
	q := client.Query{
		Command:  cmd,
		Database: config.Influxdb.Db,
	}
	if response, err := clnt.Query(q); err == nil {
		if response.Error() != nil {
			return res, response.Error()
		}
		res = response.Results
	}
	return res, nil
}

func HostMetrics(host, start, end string) {
	// Make client
	c, _ := client.NewHTTPClient(client.HTTPConfig{
		Addr:               "https://" + config.Influxdb.Server + ":8086",
		Username:           config.Influxdb.User,
		Password:           config.Influxdb.Pass,
		InsecureSkipVerify: true,
	})
	hostname, _ := os.Hostname()
	if host != hostname {
		tableCPU = "lxc_cpu"
		tableNet = "lxc_net"
		tableMem = "lxc_memory"
		tableDisk = "lxc_disk"
	}
	fmt.Println("{\"Metrics\":")
	res, _ := queryInfluxDB(c, `
			SELECT non_negative_derivative(mean(value),1s) as value
			FROM day.`+tableCPU+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(1m), type fill(none);

			SELECT non_negative_derivative(mean(value),1s) as value
			FROM day.`+tableNet+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(1m), iface, type fill(none);

			SELECT mean(value) as value
			FROM day.`+tableMem+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(1m), type fill(none);

			SELECT mean(value) as value
			FROM day.`+tableDisk+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(1m), mount, type fill(none);
		`)
	out, _ := json.Marshal(res)
	fmt.Println(string(out))
	fmt.Println("}")
}
<commit_msg>Added more detailed output for metrics binding<commit_after>package lib

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/influxdb/influxdb/client/v2"

	"github.com/subutai-io/Subutai/agent/config"
	"github.com/subutai-io/Subutai/agent/log"
)

var (
	tableCPU  = "host_cpu"
	tableNet  = "host_net"
	tableMem  = "host_memory"
	tableDisk = "host_disk"

	timeRange = "day"
	timeGroup = "1m"
)

// queryDB convenience function to query the database
func queryInfluxDB(clnt client.Client, cmd string) (res []client.Result, err error) {
	q := client.Query{
		Command:  cmd,
		Database: config.Influxdb.Db,
	}
	if response, err := clnt.Query(q); err == nil {
		if response.Error() != nil {
			return res, response.Error()
		}
		res = response.Results
	}
	return res, nil
}

func HostMetrics(host, start, end string) {
	// Make client
	c, _ := client.NewHTTPClient(client.HTTPConfig{
		Addr:               "https://" + config.Influxdb.Server + ":8086",
		Username:           config.Influxdb.User,
		Password:           config.Influxdb.Pass,
		InsecureSkipVerify: true,
	})
	hostname, _ := os.Hostname()
	if host != hostname {
		tableCPU = "lxc_cpu"
		tableNet = "lxc_net"
		tableMem = "lxc_memory"
		tableDisk = "lxc_disk"
	}
	a, err := time.Parse("2006-01-02 15:04:05", start)
	log.Check(log.ErrorLevel, "Parsing start date", err)
	b, err := time.Parse("2006-01-02 15:04:05", end)
	log.Check(log.ErrorLevel, "Parsing end date", err)

	delta := b.Sub(a)
	if delta.Hours() <= 1 {
		timeRange = "hour"
		timeGroup = "30s"
	} else if delta.Hours() > 24 {
		timeRange = "week"
		timeGroup = "5m"
	}

	fmt.Println("{\"Metrics\":")
	res, _ := queryInfluxDB(c, `
			SELECT non_negative_derivative(mean(value),1s) as value
			FROM `+timeRange+`.`+tableCPU+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(`+timeGroup+`), type fill(none);

			SELECT non_negative_derivative(mean(value),1s) as value
			FROM `+timeRange+`.`+tableNet+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(`+timeGroup+`), iface, type fill(none);

			SELECT mean(value) as value
			FROM `+timeRange+`.`+tableMem+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(`+timeGroup+`), type fill(none);

			SELECT mean(value) as value
			FROM `+timeRange+`.`+tableDisk+`
			WHERE hostname = '`+host+`' AND time > '`+start+`' AND time < '`+end+`'
			GROUP BY time(`+timeGroup+`), mount, type fill(none);
		`)
	out, _ := json.Marshal(res)
	fmt.Println(string(out))
	fmt.Println("}")
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/go-version"
	"github.com/hashicorp/terraform/flatmap"
)

func TestNewContextRequiredVersion(t *testing.T) {
	cases := []struct {
		Name    string
		Module  string
		Version string
		Value   string
		Err     bool
	}{
		{
			"no requirement",
			"",
			"0.1.0",
			"",
			false,
		},

		{
			"doesn't match",
			"",
			"0.1.0",
			"> 0.6.0",
			true,
		},

		{
			"matches",
			"",
			"0.7.0",
			"> 0.6.0",
			false,
		},

		{
			"module matches",
			"context-required-version-module",
			"0.5.0",
			"",
			false,
		},

		{
			"module doesn't match",
			"context-required-version-module",
			"0.4.0",
			"",
			true,
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
			// Reset the version for the tests
			old := SemVersion
			SemVersion = version.Must(version.NewVersion(tc.Version))
			defer func() { SemVersion = old }()

			name := "context-required-version"
			if tc.Module != "" {
				name = tc.Module
			}
			mod := testModule(t, name)
			if tc.Value != "" {
				mod.Config().Terraform.RequiredVersion = tc.Value
			}
			_, err := NewContext(&ContextOpts{
				Module: mod,
			})
			if (err != nil) != tc.Err {
				t.Fatalf("err: %s", err)
			}
			if err != nil {
				return
			}
		})
	}
}

func TestNewContextState(t *testing.T) {
	cases := map[string]struct {
		Input *ContextOpts
		Err   bool
	}{
		"empty TFVersion": {
			&ContextOpts{
				State: &State{},
			},
			false,
		},

		"past TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: "0.1.2"},
			},
			false,
		},

		"equal TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: Version},
			},
			false,
		},

		"future TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: "99.99.99"},
			},
			true,
		},

		"future TFVersion, allowed": {
			&ContextOpts{
				State:              &State{TFVersion: "99.99.99"},
				StateFutureAllowed: true,
			},
			false,
		},
	}

	for k, tc := range cases {
		ctx, err := NewContext(tc.Input)
		if (err != nil) != tc.Err {
			t.Fatalf("%s: err: %s", k, err)
		}
		if err != nil {
			continue
		}

		// Version should always be set to our current
		if ctx.state.TFVersion != Version {
			t.Fatalf("%s: state not set to current version", k)
		}
	}
}

func testContext2(t *testing.T, opts *ContextOpts) *Context {
	// Enable the shadow graph
	opts.Shadow = true

	ctx, err := NewContext(opts)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	return ctx
}

func testDataApplyFn(
	info *InstanceInfo,
	d *InstanceDiff) (*InstanceState, error) {
	return testApplyFn(info, new(InstanceState), d)
}

func testDataDiffFn(
	info *InstanceInfo,
	c *ResourceConfig) (*InstanceDiff, error) {
	return testDiffFn(info, new(InstanceState), c)
}

func testApplyFn(
	info *InstanceInfo,
	s *InstanceState,
	d *InstanceDiff) (*InstanceState, error) {
	if d.Destroy {
		return nil, nil
	}

	id := "foo"
	if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
		id = idAttr.New
	}

	result := &InstanceState{
		ID:         id,
		Attributes: make(map[string]string),
	}

	// Copy all the prior attributes
	for k, v := range s.Attributes {
		result.Attributes[k] = v
	}

	if d != nil {
		result = result.MergeDiff(d)
	}
	return result, nil
}

func testDiffFn(
	info *InstanceInfo,
	s *InstanceState,
	c *ResourceConfig) (*InstanceDiff, error) {
	diff := new(InstanceDiff)
	diff.Attributes = make(map[string]*ResourceAttrDiff)

	if s != nil {
		diff.DestroyTainted = s.Tainted
	}

	for k, v := range c.Raw {
		// Ignore __-prefixed keys since they're used for magic
		if k[0] == '_' && k[1] == '_' {
			continue
		}

		if k == "nil" {
			return nil, nil
		}

		// This key is used for other purposes
		if k == "compute_value" {
			continue
		}

		if k == "compute" {
			attrDiff := &ResourceAttrDiff{
				Old:         "",
				New:         "",
				NewComputed: true,
			}

			if cv, ok := c.Config["compute_value"]; ok {
				if cv.(string) == "1" {
					attrDiff.NewComputed = false
					attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
				}
			}

			diff.Attributes[v.(string)] = attrDiff
			continue
		}

		// If this key is not computed, then look it up in the
		// cleaned config.
		found := false
		for _, ck := range c.ComputedKeys {
			if ck == k {
				found = true
				break
			}
		}
		if !found {
			v = c.Config[k]
		}

		for k, attrDiff := range testFlatAttrDiffs(k, v) {
			if k == "require_new" {
				attrDiff.RequiresNew = true
			}
			if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
				attrDiff.RequiresNew = true
			}

			if attr, ok := s.Attributes[k]; ok {
				attrDiff.Old = attr
			}

			diff.Attributes[k] = attrDiff
		}
	}

	for _, k := range c.ComputedKeys {
		diff.Attributes[k] = &ResourceAttrDiff{
			Old:         "",
			NewComputed: true,
		}
	}

	// If we recreate this resource because it's tainted, we keep all attrs
	if !diff.RequiresNew() {
		for k, v := range diff.Attributes {
			if v.NewComputed {
				continue
			}

			old, ok := s.Attributes[k]
			if !ok {
				continue
			}

			if old == v.New {
				delete(diff.Attributes, k)
			}
		}
	}

	if !diff.Empty() {
		diff.Attributes["type"] = &ResourceAttrDiff{
			Old: "",
			New: info.Type,
		}
	}

	return diff, nil
}

// generate ResourceAttrDiffs for nested data structures in tests
func testFlatAttrDiffs(k string, i interface{}) map[string]*ResourceAttrDiff {
	diffs := make(map[string]*ResourceAttrDiff)
	// check for strings and empty containers first
	switch t := i.(type) {
	case string:
		diffs[k] = &ResourceAttrDiff{New: t}
		return diffs
	case map[string]interface{}:
		if len(t) == 0 {
			diffs[k] = &ResourceAttrDiff{New: ""}
			return diffs
		}
	case []interface{}:
		if len(t) == 0 {
			diffs[k] = &ResourceAttrDiff{New: ""}
			return diffs
		}
	}

	flat := flatmap.Flatten(map[string]interface{}{k: i})

	for k, v := range flat {
		attrDiff := &ResourceAttrDiff{
			Old: "",
			New: v,
		}
		diffs[k] = attrDiff
	}

	return diffs
}

func testProvider(prefix string) *MockResourceProvider {
	p := new(MockResourceProvider)
	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
		return s, nil
	}
	p.ResourcesReturn = []ResourceType{
		ResourceType{
			Name: fmt.Sprintf("%s_instance", prefix),
		},
	}

	return p
}

func testProvisioner() *MockResourceProvisioner {
	p := new(MockResourceProvisioner)
	return p
}

func checkStateString(t *testing.T, state *State, expected string) {
	actual := strings.TrimSpace(state.String())
	expected = strings.TrimSpace(expected)

	if actual != expected {
		t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
	}
}

func resourceState(resourceType, resourceID string) *ResourceState {
	return &ResourceState{
		Type: resourceType,
		Primary: &InstanceState{
			ID: resourceID,
		},
	}
}

// Test helper that gives a function 3 seconds to finish, assumes deadlock and
// fails test if it does not.
func testCheckDeadlock(t *testing.T, f func()) {
	timeout := make(chan bool, 1)
	done := make(chan bool, 1)
	go func() {
		time.Sleep(3 * time.Second)
		timeout <- true
	}()
	go func(f func(), done chan bool) {
		defer func() { done <- true }()
		f()
	}(f, done)
	select {
	case <-timeout:
		t.Fatalf("timed out! probably deadlock")
	case <-done:
		// ok
	}
}

const testContextGraph = `
root: root
aws_instance.bar
  aws_instance.bar -> provider.aws
aws_instance.foo
  aws_instance.foo -> provider.aws
provider.aws
root
  root -> aws_instance.bar
  root -> aws_instance.foo
`

const testContextRefreshModuleStr = `
aws_instance.web: (tainted)
  ID = bar

module.child:
  aws_instance.web:
    ID = new
`

const testContextRefreshOutputStr = `
aws_instance.web:
  ID = foo
  foo = bar

Outputs:

foo = bar
`

const testContextRefreshOutputPartialStr = `
<no state>
`

const testContextRefreshTaintedStr = `
aws_instance.web: (tainted)
  ID = foo
`
<commit_msg>core: return explicit caption if tests fail to construct context<commit_after>package terraform

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/go-version"
	"github.com/hashicorp/terraform/flatmap"
)

func TestNewContextRequiredVersion(t *testing.T) {
	cases := []struct {
		Name    string
		Module  string
		Version string
		Value   string
		Err     bool
	}{
		{
			"no requirement",
			"",
			"0.1.0",
			"",
			false,
		},

		{
			"doesn't match",
			"",
			"0.1.0",
			"> 0.6.0",
			true,
		},

		{
			"matches",
			"",
			"0.7.0",
			"> 0.6.0",
			false,
		},

		{
			"module matches",
			"context-required-version-module",
			"0.5.0",
			"",
			false,
		},

		{
			"module doesn't match",
			"context-required-version-module",
			"0.4.0",
			"",
			true,
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
			// Reset the version for the tests
			old := SemVersion
			SemVersion = version.Must(version.NewVersion(tc.Version))
			defer func() { SemVersion = old }()

			name := "context-required-version"
			if tc.Module != "" {
				name = tc.Module
			}
			mod := testModule(t, name)
			if tc.Value != "" {
				mod.Config().Terraform.RequiredVersion = tc.Value
			}
			_, err := NewContext(&ContextOpts{
				Module: mod,
			})
			if (err != nil) != tc.Err {
				t.Fatalf("err: %s", err)
			}
			if err != nil {
				return
			}
		})
	}
}

func TestNewContextState(t *testing.T) {
	cases := map[string]struct {
		Input *ContextOpts
		Err   bool
	}{
		"empty TFVersion": {
			&ContextOpts{
				State: &State{},
			},
			false,
		},

		"past TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: "0.1.2"},
			},
			false,
		},

		"equal TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: Version},
			},
			false,
		},

		"future TFVersion": {
			&ContextOpts{
				State: &State{TFVersion: "99.99.99"},
			},
			true,
		},

		"future TFVersion, allowed": {
			&ContextOpts{
				State:              &State{TFVersion: "99.99.99"},
				StateFutureAllowed: true,
			},
			false,
		},
	}

	for k, tc := range cases {
		ctx, err := NewContext(tc.Input)
		if (err != nil) != tc.Err {
			t.Fatalf("%s: err: %s", k, err)
		}
		if err != nil {
			continue
		}

		// Version should always be set to our current
		if ctx.state.TFVersion != Version {
			t.Fatalf("%s: state not set to current version", k)
		}
	}
}

func testContext2(t *testing.T, opts *ContextOpts) *Context {
	// Enable the shadow graph
	opts.Shadow = true

	ctx, err := NewContext(opts)
	if err != nil {
		t.Fatalf("failed to create test context\n\n%s\n", err)
	}

	return ctx
}

func testDataApplyFn(
	info *InstanceInfo,
	d *InstanceDiff) (*InstanceState, error) {
	return testApplyFn(info, new(InstanceState), d)
}

func testDataDiffFn(
	info *InstanceInfo,
	c *ResourceConfig) (*InstanceDiff, error) {
	return testDiffFn(info, new(InstanceState), c)
}

func testApplyFn(
	info *InstanceInfo,
	s *InstanceState,
	d *InstanceDiff) (*InstanceState, error) {
	if d.Destroy {
		return nil, nil
	}

	id := "foo"
	if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
		id = idAttr.New
	}

	result := &InstanceState{
		ID:         id,
		Attributes: make(map[string]string),
	}

	// Copy all the prior attributes
	for k, v := range s.Attributes {
		result.Attributes[k] = v
	}

	if d != nil {
		result = result.MergeDiff(d)
	}
	return result, nil
}

func testDiffFn(
	info *InstanceInfo,
	s *InstanceState,
	c *ResourceConfig) (*InstanceDiff, error) {
	diff := new(InstanceDiff)
	diff.Attributes = make(map[string]*ResourceAttrDiff)

	if s != nil {
		diff.DestroyTainted = s.Tainted
	}

	for k, v := range c.Raw {
		// Ignore __-prefixed keys since they're used for magic
		if k[0] == '_' && k[1] == '_' {
			continue
		}

		if k == "nil" {
			return nil, nil
		}

		// This key is used for other purposes
		if k == "compute_value" {
			continue
		}

		if k == "compute" {
			attrDiff := &ResourceAttrDiff{
				Old:         "",
				New:         "",
				NewComputed: true,
			}

			if cv, ok := c.Config["compute_value"]; ok {
				if cv.(string) == "1" {
					attrDiff.NewComputed = false
					attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
				}
			}

			diff.Attributes[v.(string)] = attrDiff
			continue
		}

		// If this key is not computed, then look it up in the
		// cleaned config.
		found := false
		for _, ck := range c.ComputedKeys {
			if ck == k {
				found = true
				break
			}
		}
		if !found {
			v = c.Config[k]
		}

		for k, attrDiff := range testFlatAttrDiffs(k, v) {
			if k == "require_new" {
				attrDiff.RequiresNew = true
			}
			if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
				attrDiff.RequiresNew = true
			}

			if attr, ok := s.Attributes[k]; ok {
				attrDiff.Old = attr
			}

			diff.Attributes[k] = attrDiff
		}
	}

	for _, k := range c.ComputedKeys {
		diff.Attributes[k] = &ResourceAttrDiff{
			Old:         "",
			NewComputed: true,
		}
	}

	// If we recreate this resource because it's tainted, we keep all attrs
	if !diff.RequiresNew() {
		for k, v := range diff.Attributes {
			if v.NewComputed {
				continue
			}

			old, ok := s.Attributes[k]
			if !ok {
				continue
			}

			if old == v.New {
				delete(diff.Attributes, k)
			}
		}
	}

	if !diff.Empty() {
		diff.Attributes["type"] = &ResourceAttrDiff{
			Old: "",
			New: info.Type,
		}
	}

	return diff, nil
}

// generate ResourceAttrDiffs for nested data structures in tests
func testFlatAttrDiffs(k string, i interface{}) map[string]*ResourceAttrDiff {
	diffs := make(map[string]*ResourceAttrDiff)
	// check for strings and empty containers first
	switch t := i.(type) {
	case string:
		diffs[k] = &ResourceAttrDiff{New: t}
		return diffs
	case map[string]interface{}:
		if len(t) == 0 {
			diffs[k] = &ResourceAttrDiff{New: ""}
			return diffs
		}
	case []interface{}:
		if len(t) == 0 {
			diffs[k] = &ResourceAttrDiff{New: ""}
			return diffs
		}
	}

	flat := flatmap.Flatten(map[string]interface{}{k: i})

	for k, v := range flat {
		attrDiff := &ResourceAttrDiff{
			Old: "",
			New: v,
		}
		diffs[k] = attrDiff
	}

	return diffs
}

func testProvider(prefix string) *MockResourceProvider {
	p := new(MockResourceProvider)
	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
		return s, nil
	}
	p.ResourcesReturn = []ResourceType{
		ResourceType{
			Name: fmt.Sprintf("%s_instance", prefix),
		},
	}

	return p
}

func testProvisioner() *MockResourceProvisioner {
	p := new(MockResourceProvisioner)
	return p
}

func checkStateString(t *testing.T, state *State, expected string) {
	actual := strings.TrimSpace(state.String())
	expected = strings.TrimSpace(expected)

	if actual != expected {
		t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
	}
}

func resourceState(resourceType, resourceID string) *ResourceState {
	return &ResourceState{
		Type: resourceType,
		Primary: &InstanceState{
			ID: resourceID,
		},
	}
}

// Test helper that gives a function 3 seconds to finish, assumes deadlock and
// fails test if it does not.
func testCheckDeadlock(t *testing.T, f func()) {
	timeout := make(chan bool, 1)
	done := make(chan bool, 1)
	go func() {
		time.Sleep(3 * time.Second)
		timeout <- true
	}()
	go func(f func(), done chan bool) {
		defer func() { done <- true }()
		f()
	}(f, done)
	select {
	case <-timeout:
		t.Fatalf("timed out! probably deadlock")
	case <-done:
		// ok
	}
}

const testContextGraph = `
root: root
aws_instance.bar
  aws_instance.bar -> provider.aws
aws_instance.foo
  aws_instance.foo -> provider.aws
provider.aws
root
  root -> aws_instance.bar
  root -> aws_instance.foo
`

const testContextRefreshModuleStr = `
aws_instance.web: (tainted)
  ID = bar

module.child:
  aws_instance.web:
    ID = new
`

const testContextRefreshOutputStr = `
aws_instance.web:
  ID = foo
  foo = bar

Outputs:

foo = bar
`

const testContextRefreshOutputPartialStr = `
<no state>
`

const testContextRefreshTaintedStr = `
aws_instance.web: (tainted)
  ID = foo
`
<|endoftext|>