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

package main

import (
	"database/sql"
	"os"
	"syscall"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

const rootNodeID = 1

const (
	fsSchema = `
CREATE DATABASE IF NOT EXISTS fs;

CREATE TABLE IF NOT EXISTS fs.namespace (
  parentID INT,
  name     STRING,
  id       INT,
  PRIMARY KEY (parentID, name)
);

CREATE TABLE IF NOT EXISTS fs.inode (
  id    INT PRIMARY KEY,
  inode STRING
);

CREATE TABLE IF NOT EXISTS fs.block (
  id    INT,
  block INT,
  data  BYTES,
  PRIMARY KEY (id, block)
);
`
)

var _ fs.FS = &CFS{}               // Root
var _ fs.FSInodeGenerator = &CFS{} // GenerateInode

// CFS implements a filesystem on top of cockroach.
type CFS struct {
	db *sql.DB
}

func initSchema(db *sql.DB) error {
	_, err := db.Exec(fsSchema)
	return err
}

// create inserts a new node.
// parentID: inode ID of the parent directory.
// name: name of the new node
// node: new node
func (cfs CFS) create(parentID uint64, name string, node *Node) error {
	inode := node.toJSON()
	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}
	const insertNode = `INSERT INTO fs.inode VALUES ($1, $2)`
	if _, err := tx.Exec(insertNode, node.ID, inode); err != nil {
		_ = tx.Rollback()
		return err
	}
	const insertNamespace = `INSERT INTO fs.namespace VALUES ($1, $2, $3)`
	if _, err := tx.Exec(insertNamespace, parentID, name, node.ID); err != nil {
		_ = tx.Rollback()
		return err
	}
	return tx.Commit()
}

// remove removes a node give its name and its parent ID.
// If 'checkChildren' is true, fails if the node has children.
func (cfs CFS) remove(parentID uint64, name string, checkChildren bool) error {
	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}

	// Start by looking up the node ID.
	const lookupSQL = `
SELECT id FROM fs.namespace WHERE (parentID, name) = ($1, $2)`

	var id uint64
	if err := tx.QueryRow(lookupSQL, parentID, name).Scan(&id); err != nil {
		_ = tx.Rollback()
		return err
	}

	// Check if there are any children.
	if checkChildren {
		if err := checkIsEmpty(tx, id); err != nil {
			_ = tx.Rollback()
			return err
		}
	}

	// Delete all entries.
	const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
	if _, err := tx.Exec(deleteNamespace, parentID, name); err != nil {
		_ = tx.Rollback()
		return err
	}
	const deleteInode = `DELETE FROM fs.inode WHERE id = $1`
	if _, err := tx.Exec(deleteInode, id); err != nil {
		_ = tx.Rollback()
		return err
	}
	const deleteBlock = `DELETE FROM fs.block WHERE id = $1`
	if _, err := tx.Exec(deleteBlock, id); err != nil {
		_ = tx.Rollback()
		return err
	}

	return tx.Commit()
}

func (cfs CFS) lookup(parentID uint64, name string) (*Node, error) {
	return getInode(cfs.db, parentID, name)
}

// list returns the children of the node with id 'parentID'.
// Dirent consists of:
// Inode uint64
// Type DirentType (optional)
// Name string
// TODO(pmattis): lookup all inodes and fill in the type, this will save a Getattr().
func (cfs CFS) list(parentID uint64) ([]fuse.Dirent, error) {
	rows, err := cfs.db.Query(`SELECT name, id FROM fs.namespace WHERE parentID = $1`, parentID)
	if err != nil {
		return nil, err
	}

	var results []fuse.Dirent
	for rows.Next() {
		dirent := fuse.Dirent{Type: fuse.DT_Unknown}
		if err := rows.Scan(&dirent.Name, &dirent.Inode); err != nil {
			return nil, err
		}
		results = append(results, dirent)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return results, nil
}

// validateRename takes a source and destination node and verifies that
// a rename can be performed from source to destination.
// source must not be nil. destination can be.
func validateRename(tx *sql.Tx, source, destination *Node) error {
	if destination == nil {
		// No object at destination: good.
		return nil
	}

	if source.isDir() {
		if destination.isDir() {
			// Both are directories: destination must be empty
			return checkIsEmpty(tx, destination.ID)
		}
		// directory -> file: not allowed.
		return fuse.Errno(syscall.ENOTDIR)
	}

	// Source is a file.
	if destination.isDir() {
		// file -> directory: not allowed.
		return fuse.Errno(syscall.EISDIR)
	}
	return nil
}

// rename moves 'oldParentID/oldName' to 'newParentID/newName'.
// If 'newParentID/newName' already exists, it is deleted.
// See NOTE on node.go:Rename.
func (cfs CFS) rename(oldParentID, newParentID uint64, oldName, newName string) error {
	if oldParentID == newParentID && oldName == newName {
		return nil
	}

	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}

	// Lookup source inode.
	srcObject, err := getInode(tx, oldParentID, oldName)
	if err != nil {
		_ = tx.Rollback()
		return err
	}

	// Lookup destination inode.
	destObject, err := getInode(tx, newParentID, newName)
	if err != nil && err != sql.ErrNoRows {
		_ = tx.Rollback()
		return err
	}

	// Check that the rename is allowed.
	if err := validateRename(tx, srcObject, destObject); err != nil {
		_ = tx.Rollback()
		return err
	}

	// At this point we know the following:
	// - srcObject is not nil
	// - destObject may be nil. If not, its inode can be deleted.
	if destObject == nil {
		// No new object: use INSERT.
		const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
		if _, err := tx.Exec(deleteNamespace, oldParentID, oldName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const insertNamespace = `INSERT INTO fs.namespace VALUES ($1, $2, $3)`
		if _, err := tx.Exec(insertNamespace, newParentID, newName, srcObject.ID); err != nil {
			_ = tx.Rollback()
			return err
		}
	} else {
		// Destination exists.
		const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
		if _, err := tx.Exec(deleteNamespace, oldParentID, oldName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const updateNamespace = `UPDATE fs.namespace SET id = $1 WHERE (parentID, name) = ($2, $3)`
		if _, err := tx.Exec(updateNamespace, srcObject.ID, newParentID, newName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const deleteInode = `DELETE FROM fs.inode WHERE id = $1`
		if _, err := tx.Exec(deleteInode, destObject.ID); err != nil {
			_ = tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

// Root returns the filesystem's root node.
// This node is special: it has a fixed ID and is not persisted.
func (cfs CFS) Root() (fs.Node, error) {
	return &Node{cfs: cfs, ID: rootNodeID, Mode: os.ModeDir | defaultPerms}, nil
}

// GenerateInode returns a new inode ID.
func (cfs CFS) GenerateInode(parentInode uint64, name string) uint64 {
	return cfs.newUniqueID()
}

func (cfs CFS) newUniqueID() (id uint64) {
	if err := cfs.db.QueryRow(`SELECT experimental_unique_int()`).Scan(&id); err != nil {
		panic(err)
	}
	return
}

// newFileNode returns a new node struct corresponding to a file.
func (cfs CFS) newFileNode() *Node {
	return &Node{
		cfs:  cfs,
		ID:   cfs.newUniqueID(),
		Mode: defaultPerms,
	}
}

// newDirNode returns a new node struct corresponding to a directory.
func (cfs CFS) newDirNode() *Node {
	return &Node{
		cfs:  cfs,
		ID:   cfs.newUniqueID(),
		Mode: os.ModeDir | defaultPerms,
	}
}

// newSymlinkNode returns a new node struct corresponding to a symlink.
func (cfs CFS) newSymlinkNode() *Node {
	return &Node{
		cfs: cfs,
		ID:  cfs.newUniqueID(),
		// Symlinks don't have permissions, allow all.
		Mode: os.ModeSymlink | allPerms,
	}
}
<commit_msg>Replace experimental_unique_int() with unique_rowid()<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Marc Berhault (marc@cockroachlabs.com)

package main

import (
	"database/sql"
	"os"
	"syscall"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

const rootNodeID = 1

const (
	fsSchema = `
CREATE DATABASE IF NOT EXISTS fs;

CREATE TABLE IF NOT EXISTS fs.namespace (
  parentID INT,
  name     STRING,
  id       INT,
  PRIMARY KEY (parentID, name)
);

CREATE TABLE IF NOT EXISTS fs.inode (
  id    INT PRIMARY KEY,
  inode STRING
);

CREATE TABLE IF NOT EXISTS fs.block (
  id    INT,
  block INT,
  data  BYTES,
  PRIMARY KEY (id, block)
);
`
)

var _ fs.FS = &CFS{}               // Root
var _ fs.FSInodeGenerator = &CFS{} // GenerateInode

// CFS implements a filesystem on top of cockroach.
type CFS struct {
	db *sql.DB
}

func initSchema(db *sql.DB) error {
	_, err := db.Exec(fsSchema)
	return err
}

// create inserts a new node.
// parentID: inode ID of the parent directory.
// name: name of the new node
// node: new node
func (cfs CFS) create(parentID uint64, name string, node *Node) error {
	inode := node.toJSON()
	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}
	const insertNode = `INSERT INTO fs.inode VALUES ($1, $2)`
	if _, err := tx.Exec(insertNode, node.ID, inode); err != nil {
		_ = tx.Rollback()
		return err
	}
	const insertNamespace = `INSERT INTO fs.namespace VALUES ($1, $2, $3)`
	if _, err := tx.Exec(insertNamespace, parentID, name, node.ID); err != nil {
		_ = tx.Rollback()
		return err
	}
	return tx.Commit()
}

// remove removes a node give its name and its parent ID.
// If 'checkChildren' is true, fails if the node has children.
func (cfs CFS) remove(parentID uint64, name string, checkChildren bool) error {
	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}

	// Start by looking up the node ID.
	const lookupSQL = `
SELECT id FROM fs.namespace WHERE (parentID, name) = ($1, $2)`

	var id uint64
	if err := tx.QueryRow(lookupSQL, parentID, name).Scan(&id); err != nil {
		_ = tx.Rollback()
		return err
	}

	// Check if there are any children.
	if checkChildren {
		if err := checkIsEmpty(tx, id); err != nil {
			_ = tx.Rollback()
			return err
		}
	}

	// Delete all entries.
	const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
	if _, err := tx.Exec(deleteNamespace, parentID, name); err != nil {
		_ = tx.Rollback()
		return err
	}
	const deleteInode = `DELETE FROM fs.inode WHERE id = $1`
	if _, err := tx.Exec(deleteInode, id); err != nil {
		_ = tx.Rollback()
		return err
	}
	const deleteBlock = `DELETE FROM fs.block WHERE id = $1`
	if _, err := tx.Exec(deleteBlock, id); err != nil {
		_ = tx.Rollback()
		return err
	}

	return tx.Commit()
}

func (cfs CFS) lookup(parentID uint64, name string) (*Node, error) {
	return getInode(cfs.db, parentID, name)
}

// list returns the children of the node with id 'parentID'.
// Dirent consists of:
// Inode uint64
// Type DirentType (optional)
// Name string
// TODO(pmattis): lookup all inodes and fill in the type, this will save a Getattr().
func (cfs CFS) list(parentID uint64) ([]fuse.Dirent, error) {
	rows, err := cfs.db.Query(`SELECT name, id FROM fs.namespace WHERE parentID = $1`, parentID)
	if err != nil {
		return nil, err
	}

	var results []fuse.Dirent
	for rows.Next() {
		dirent := fuse.Dirent{Type: fuse.DT_Unknown}
		if err := rows.Scan(&dirent.Name, &dirent.Inode); err != nil {
			return nil, err
		}
		results = append(results, dirent)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return results, nil
}

// validateRename takes a source and destination node and verifies that
// a rename can be performed from source to destination.
// source must not be nil. destination can be.
func validateRename(tx *sql.Tx, source, destination *Node) error {
	if destination == nil {
		// No object at destination: good.
		return nil
	}

	if source.isDir() {
		if destination.isDir() {
			// Both are directories: destination must be empty
			return checkIsEmpty(tx, destination.ID)
		}
		// directory -> file: not allowed.
		return fuse.Errno(syscall.ENOTDIR)
	}

	// Source is a file.
	if destination.isDir() {
		// file -> directory: not allowed.
		return fuse.Errno(syscall.EISDIR)
	}
	return nil
}

// rename moves 'oldParentID/oldName' to 'newParentID/newName'.
// If 'newParentID/newName' already exists, it is deleted.
// See NOTE on node.go:Rename.
func (cfs CFS) rename(oldParentID, newParentID uint64, oldName, newName string) error {
	if oldParentID == newParentID && oldName == newName {
		return nil
	}

	tx, err := cfs.db.Begin()
	if err != nil {
		return err
	}

	// Lookup source inode.
	srcObject, err := getInode(tx, oldParentID, oldName)
	if err != nil {
		_ = tx.Rollback()
		return err
	}

	// Lookup destination inode.
	destObject, err := getInode(tx, newParentID, newName)
	if err != nil && err != sql.ErrNoRows {
		_ = tx.Rollback()
		return err
	}

	// Check that the rename is allowed.
	if err := validateRename(tx, srcObject, destObject); err != nil {
		_ = tx.Rollback()
		return err
	}

	// At this point we know the following:
	// - srcObject is not nil
	// - destObject may be nil. If not, its inode can be deleted.
	if destObject == nil {
		// No new object: use INSERT.
		const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
		if _, err := tx.Exec(deleteNamespace, oldParentID, oldName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const insertNamespace = `INSERT INTO fs.namespace VALUES ($1, $2, $3)`
		if _, err := tx.Exec(insertNamespace, newParentID, newName, srcObject.ID); err != nil {
			_ = tx.Rollback()
			return err
		}
	} else {
		// Destination exists.
		const deleteNamespace = `DELETE FROM fs.namespace WHERE (parentID, name) = ($1, $2)`
		if _, err := tx.Exec(deleteNamespace, oldParentID, oldName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const updateNamespace = `UPDATE fs.namespace SET id = $1 WHERE (parentID, name) = ($2, $3)`
		if _, err := tx.Exec(updateNamespace, srcObject.ID, newParentID, newName); err != nil {
			_ = tx.Rollback()
			return err
		}

		const deleteInode = `DELETE FROM fs.inode WHERE id = $1`
		if _, err := tx.Exec(deleteInode, destObject.ID); err != nil {
			_ = tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

// Root returns the filesystem's root node.
// This node is special: it has a fixed ID and is not persisted.
func (cfs CFS) Root() (fs.Node, error) {
	return &Node{cfs: cfs, ID: rootNodeID, Mode: os.ModeDir | defaultPerms}, nil
}

// GenerateInode returns a new inode ID.
func (cfs CFS) GenerateInode(parentInode uint64, name string) uint64 {
	return cfs.newUniqueID()
}

func (cfs CFS) newUniqueID() (id uint64) {
	if err := cfs.db.QueryRow(`SELECT unique_rowid()`).Scan(&id); err != nil {
		panic(err)
	}
	return
}

// newFileNode returns a new node struct corresponding to a file.
func (cfs CFS) newFileNode() *Node {
	return &Node{
		cfs:  cfs,
		ID:   cfs.newUniqueID(),
		Mode: defaultPerms,
	}
}

// newDirNode returns a new node struct corresponding to a directory.
func (cfs CFS) newDirNode() *Node {
	return &Node{
		cfs:  cfs,
		ID:   cfs.newUniqueID(),
		Mode: os.ModeDir | defaultPerms,
	}
}

// newSymlinkNode returns a new node struct corresponding to a symlink.
func (cfs CFS) newSymlinkNode() *Node {
	return &Node{
		cfs: cfs,
		ID:  cfs.newUniqueID(),
		// Symlinks don't have permissions, allow all.
		Mode: os.ModeSymlink | allPerms,
	}
}
<|endoftext|>


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

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 1 identifying the caller of Caller.  (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 starting at the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	return funcline_go(f, pc)
}

// implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int)

// mid returns the current os thread (m) id.
func mid() uint32

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<commit_msg>runtime: fix docs for Caller and Callers The previous attempt to explain this got it backwards (all the more reason to be sad we couldn't make the two functions behave the same).<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller.  (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	return funcline_go(f, pc)
}

// implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int)

// mid returns the current os thread (m) id.
func mid() uint32

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<|endoftext|>


<commit_before>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"

	"github.com/codegangsta/cli"
	"github.com/nodetemple/nodetemple/common"
	"github.com/nodetemple/nodetemple/nodectl/util"
	"github.com/nodetemple/nodetemple/nodectl/command"
)

func main() {
	app := cli.NewApp()
	app.Name = "nodectl"
	app.Usage = "CLI for an orchestration of CoreOS and Kubernetes cluster"
	app.Version = common.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "providers, p", Usage: "A comma-separated list of IaaS providers ("+strings.Join(common.AvailableProviders, ",")+") and API keys, format: 'provider:api-key,...'", EnvVar: util.EnvVarConv(app.Name, "providers"),},
		cli.BoolFlag{Name: "debug", Usage: "Print out more debug information to stderr"},
	}
	app.Before = appBefore
	app.Commands = []cli.Command{
		command.DemoCmd,
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		util.Err("unknown command '%v'\nRun '%v help [command]' for usage information", command, c.App.Name)
	}

	app.RunAndExitOnError()
}

func appBefore(c *cli.Context) error {
	if c.String("providers") == "" && !c.Bool("help") && !c.Bool("h") && !c.Bool("version") && !c.Bool("v") && !util.StringSliceContains(c.Args(), "help") && !util.StringSliceContains(c.Args(), "h") && c.Args().Present() {
		util.Err("set at least one provider with a valid API key")
	}

	return nil
}
<commit_msg>Lookup for global flags<commit_after>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"

	"github.com/codegangsta/cli"
	"github.com/nodetemple/nodetemple/common"
	"github.com/nodetemple/nodetemple/nodectl/util"
	"github.com/nodetemple/nodetemple/nodectl/command"
)

func main() {
	app := cli.NewApp()
	app.Name = "nodectl"
	app.Usage = "CLI for an orchestration of CoreOS and Kubernetes cluster"
	app.Version = common.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "providers, p", Usage: "A comma-separated list of IaaS providers ("+strings.Join(common.AvailableProviders, ",")+") and API keys, format: 'provider:api-key,...'", EnvVar: util.EnvVarConv(app.Name, "providers"),},
		cli.BoolFlag{Name: "debug", Usage: "Print out more debug information to stderr"},
	}
	app.Before = appBefore
	app.Commands = []cli.Command{
		command.DemoCmd,
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		util.Err("unknown command '%v'\nRun '%v help [command]' for usage information", command, c.App.Name)
	}

	app.RunAndExitOnError()
}

func appBefore(c *cli.Context) error {
	if c.GlobalString("providers") == "" && !c.GlobalBool("help") && !c.GlobalBool("h") && !c.GlobalBool("version") && !c.GlobalBool("v") && !util.StringSliceContains(c.Args(), "help") && !util.StringSliceContains(c.Args(), "h") && c.Args().Present() {
		util.Err("set at least one provider with a valid API key")
	}

	return nil
}
<|endoftext|>


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

package btcrpcclient

import (
	"encoding/hex"
	"encoding/json"
	"github.com/conformal/btcjson"
	"github.com/conformal/btcutil"
)

// FutureGetGenerateResult is a future promise to deliver the result of a
// GetGenerateAsync RPC invocation (or an applicable error).
type FutureGetGenerateResult chan *response

// Receive waits for the response promised by the future and returns true if the
// server is set to mine, otherwise false.
func (r FutureGetGenerateResult) Receive() (bool, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return false, err
	}

	// Unmarshal result as a boolean.
	var result bool
	err = json.Unmarshal(res, &result)
	if err != nil {
		return false, err
	}

	return result, nil
}

// GetGenerateAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetGenerate for the blocking version and more details.
func (c *Client) GetGenerateAsync() FutureGetGenerateResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetGenerateCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetGenerate returns true if the server is set to mine, otherwise false.
func (c *Client) GetGenerate() (bool, error) {
	return c.GetGenerateAsync().Receive()
}

// FutureSetGenerateResult is a future promise to deliver the result of a
// SetGenerateAsync RPC invocation (or an applicable error).
type FutureSetGenerateResult chan *response

// Receive waits for the response promised by the future and returns an error if
// any occurred when setting the server to generate coins (mine) or not.
func (r FutureSetGenerateResult) Receive() error {
	_, err := receiveFuture(r)
	if err != nil {
		return err
	}

	return nil
}

// SetGenerateAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See SetGenerate for the blocking version and more details.
func (c *Client) SetGenerateAsync(enable bool, numCPUs int) FutureSetGenerateResult {
	id := c.NextID()
	cmd, err := btcjson.NewSetGenerateCmd(id, enable, numCPUs)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// SetGenerate sets the server to generate coins (mine) or not.
func (c *Client) SetGenerate(enable bool, numCPUs int) error {
	return c.SetGenerateAsync(enable, numCPUs).Receive()
}

// FutureGetHashesPerSecResult is a future promise to deliver the result of a
// GetHashesPerSecAsync RPC invocation (or an applicable error).
type FutureGetHashesPerSecResult chan *response

// Receive waits for the response promised by the future and returns a recent
// hashes per second performance measurement while generating coins (mining).
// Zero is returned if the server is not mining.
func (r FutureGetHashesPerSecResult) Receive() (int64, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return -1, err
	}

	// Unmarshal result as an int64.
	var result int64
	err = json.Unmarshal(res, &result)
	if err != nil {
		return 0, err
	}

	return result, nil
}

// GetHashesPerSecAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetHashesPerSec for the blocking version and more details.
func (c *Client) GetHashesPerSecAsync() FutureGetHashesPerSecResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetHashesPerSecCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetHashesPerSec returns a recent hashes per second performance measurement
// while generating coins (mining).  Zero is returned if the server is not
// mining.
func (c *Client) GetHashesPerSec() (int64, error) {
	return c.GetHashesPerSecAsync().Receive()
}

// FutureGetMiningInfoResult is a future promise to deliver the result of a
// GetMiningInfoAsync RPC invocation (or an applicable error).
type FutureGetMiningInfoResult chan *response

// Receive waits for the response promised by the future and returns the mining
// information.
func (r FutureGetMiningInfoResult) Receive() (*btcjson.GetMiningInfoResult, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return nil, err
	}

	// Unmarshal result as a getmininginfo result object.
	var infoResult btcjson.GetMiningInfoResult
	err = json.Unmarshal(res, &infoResult)
	if err != nil {
		return nil, err
	}

	return &infoResult, nil
}

// GetMiningInfoAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetMiningInfo for the blocking version and more details.
func (c *Client) GetMiningInfoAsync() FutureGetMiningInfoResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetMiningInfoCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetMiningInfo returns mining information.
func (c *Client) GetMiningInfo() (*btcjson.GetMiningInfoResult, error) {
	return c.GetMiningInfoAsync().Receive()
}

// FutureGetNetworkHashPS is a future promise to deliver the result of a
// GetNetworkHashPSAsync RPC invocation (or an applicable error).
type FutureGetNetworkHashPS chan *response

// Receive waits for the response promised by the future and returns the
// estimated network hashes per second for the block heights provided by the
// parameters.
func (r FutureGetNetworkHashPS) Receive() (int64, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return -1, err
	}

	// Unmarshal result as an int64.
	var result int64
	err = json.Unmarshal(res, &result)
	if err != nil {
		return 0, err
	}

	return result, nil
}

// GetNetworkHashPSAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS for the blocking version and more details.
func (c *Client) GetNetworkHashPSAsync() FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS returns the estimated network hashes per second using the
// default number of blocks and the most recent block height.
//
// See GetNetworkHashPS2 to override the number of blocks to use and
// GetNetworkHashPS3 to override the height at which to calculate the estimate.
func (c *Client) GetNetworkHashPS() (int64, error) {
	return c.GetNetworkHashPSAsync().Receive()
}

// GetNetworkHashPS2Async returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS2 for the blocking version and more details.
func (c *Client) GetNetworkHashPS2Async(blocks int) FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS2 returns the estimated network hashes per second for the
// specified previous number of blocks working backwards from the most recent
// block height.  The blocks parameter can also be -1 in which case the number
// of blocks since the last difficulty change will be used.
//
// See GetNetworkHashPS to use defaults and GetNetworkHashPS3 to override the
// height at which to calculate the estimate.
func (c *Client) GetNetworkHashPS2(blocks int) (int64, error) {
	return c.GetNetworkHashPS2Async(blocks).Receive()
}

// GetNetworkHashPS3Async returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS3 for the blocking version and more details.
func (c *Client) GetNetworkHashPS3Async(blocks, height int) FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks, height)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS3 returns the estimated network hashes per second for the
// specified previous number of blocks working backwards from the specified
// block height.  The blocks parameter can also be -1 in which case the number
// of blocks since the last difficulty change will be used.
//
// See GetNetworkHashPS and GetNetworkHashPS2 to use defaults.
func (c *Client) GetNetworkHashPS3(blocks, height int) (int64, error) {
	return c.GetNetworkHashPS3Async(blocks, height).Receive()
}

// FutureGetWork is a future promise to deliver the result of a
// GetWorkAsync RPC invocation (or an applicable error).
type FutureGetWork chan *response

// Receive waits for the response promised by the future and returns the hash
// data to work on.
func (r FutureGetWork) Receive() (*btcjson.GetWorkResult, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return nil, err
	}

	// Unmarshal result as a getwork result object.
	var result btcjson.GetWorkResult
	err = json.Unmarshal(res, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// GetWorkAsync returns an instance of a type that can be used to get the result
// of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetWork for the blocking version and more details.
func (c *Client) GetWorkAsync() FutureGetWork {
	id := c.NextID()
	cmd, err := btcjson.NewGetWorkCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetWork returns hash data to work on.
//
// See GetWorkSubmit to submit the found solution.
func (c *Client) GetWork() (*btcjson.GetWorkResult, error) {
	return c.GetWorkAsync().Receive()
}

// FutureGetWorkSubmit is a future promise to deliver the result of a
// GetWorkSubmitAsync RPC invocation (or an applicable error).
type FutureGetWorkSubmit chan *response

// Receive waits for the response promised by the future and returns whether
// or not the submitted block header was accepted.
func (r FutureGetWorkSubmit) Receive() (bool, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return false, err
	}

	// Unmarshal result as a boolean.
	var accepted bool
	err = json.Unmarshal(res, &accepted)
	if err != nil {
		return false, err
	}

	return accepted, nil
}

// GetWorkSubmitAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetWorkSubmit for the blocking version and more details.
func (c *Client) GetWorkSubmitAsync(data string) FutureGetWorkSubmit {
	id := c.NextID()
	cmd, err := btcjson.NewGetWorkCmd(id, data)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetWorkSubmit submits a block header which is a solution to previously
// requested data and returns whether or not the solution was accepted.
//
// See GetWork to request data to work on.
func (c *Client) GetWorkSubmit(data string) (bool, error) {
	return c.GetWorkSubmitAsync(data).Receive()
}

// FutureSubmitBlockResult is a future promise to deliver the result of a
// SubmitBlockAsync RPC invocation (or an applicable error).
type FutureSubmitBlockResult chan *response

// Receive waits for the response promised by the future and returns an error if
// any occurred when submitting the block.
func (r FutureSubmitBlockResult) Receive() error {
	_, err := receiveFuture(r)
	if err != nil {
		return err
	}

	return nil

}

// SubmitBlockAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See SubmitBlock for the blocking version and more details.
func (c *Client) SubmitBlockAsync(block *btcutil.Block, options *btcjson.SubmitBlockOptions) FutureSubmitBlockResult {
	blockHex := ""
	if block != nil {
		blockBytes, err := block.Bytes()
		if err != nil {
			return newFutureError(err)
		}

		blockHex = hex.EncodeToString(blockBytes)
	}

	id := c.NextID()
	cmd, err := btcjson.NewSubmitBlockCmd(id, blockHex, options)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// SubmitBlock attempts to submit a new block into the bitcoin network.
func (c *Client) SubmitBlock(block *btcutil.Block, options *btcjson.SubmitBlockOptions) error {
	return c.SubmitBlockAsync(block, options).Receive()
}

// TODO(davec): Implement GetBlockTemplate
<commit_msg>Detect error strings on SumitBlock.<commit_after>// Copyright (c) 2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcrpcclient

import (
	"encoding/hex"
	"encoding/json"
	"github.com/conformal/btcjson"
	"github.com/conformal/btcutil"
)

// FutureGetGenerateResult is a future promise to deliver the result of a
// GetGenerateAsync RPC invocation (or an applicable error).
type FutureGetGenerateResult chan *response

// Receive waits for the response promised by the future and returns true if the
// server is set to mine, otherwise false.
func (r FutureGetGenerateResult) Receive() (bool, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return false, err
	}

	// Unmarshal result as a boolean.
	var result bool
	err = json.Unmarshal(res, &result)
	if err != nil {
		return false, err
	}

	return result, nil
}

// GetGenerateAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetGenerate for the blocking version and more details.
func (c *Client) GetGenerateAsync() FutureGetGenerateResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetGenerateCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetGenerate returns true if the server is set to mine, otherwise false.
func (c *Client) GetGenerate() (bool, error) {
	return c.GetGenerateAsync().Receive()
}

// FutureSetGenerateResult is a future promise to deliver the result of a
// SetGenerateAsync RPC invocation (or an applicable error).
type FutureSetGenerateResult chan *response

// Receive waits for the response promised by the future and returns an error if
// any occurred when setting the server to generate coins (mine) or not.
func (r FutureSetGenerateResult) Receive() error {
	_, err := receiveFuture(r)
	if err != nil {
		return err
	}

	return nil
}

// SetGenerateAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See SetGenerate for the blocking version and more details.
func (c *Client) SetGenerateAsync(enable bool, numCPUs int) FutureSetGenerateResult {
	id := c.NextID()
	cmd, err := btcjson.NewSetGenerateCmd(id, enable, numCPUs)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// SetGenerate sets the server to generate coins (mine) or not.
func (c *Client) SetGenerate(enable bool, numCPUs int) error {
	return c.SetGenerateAsync(enable, numCPUs).Receive()
}

// FutureGetHashesPerSecResult is a future promise to deliver the result of a
// GetHashesPerSecAsync RPC invocation (or an applicable error).
type FutureGetHashesPerSecResult chan *response

// Receive waits for the response promised by the future and returns a recent
// hashes per second performance measurement while generating coins (mining).
// Zero is returned if the server is not mining.
func (r FutureGetHashesPerSecResult) Receive() (int64, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return -1, err
	}

	// Unmarshal result as an int64.
	var result int64
	err = json.Unmarshal(res, &result)
	if err != nil {
		return 0, err
	}

	return result, nil
}

// GetHashesPerSecAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetHashesPerSec for the blocking version and more details.
func (c *Client) GetHashesPerSecAsync() FutureGetHashesPerSecResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetHashesPerSecCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetHashesPerSec returns a recent hashes per second performance measurement
// while generating coins (mining).  Zero is returned if the server is not
// mining.
func (c *Client) GetHashesPerSec() (int64, error) {
	return c.GetHashesPerSecAsync().Receive()
}

// FutureGetMiningInfoResult is a future promise to deliver the result of a
// GetMiningInfoAsync RPC invocation (or an applicable error).
type FutureGetMiningInfoResult chan *response

// Receive waits for the response promised by the future and returns the mining
// information.
func (r FutureGetMiningInfoResult) Receive() (*btcjson.GetMiningInfoResult, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return nil, err
	}

	// Unmarshal result as a getmininginfo result object.
	var infoResult btcjson.GetMiningInfoResult
	err = json.Unmarshal(res, &infoResult)
	if err != nil {
		return nil, err
	}

	return &infoResult, nil
}

// GetMiningInfoAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetMiningInfo for the blocking version and more details.
func (c *Client) GetMiningInfoAsync() FutureGetMiningInfoResult {
	id := c.NextID()
	cmd, err := btcjson.NewGetMiningInfoCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetMiningInfo returns mining information.
func (c *Client) GetMiningInfo() (*btcjson.GetMiningInfoResult, error) {
	return c.GetMiningInfoAsync().Receive()
}

// FutureGetNetworkHashPS is a future promise to deliver the result of a
// GetNetworkHashPSAsync RPC invocation (or an applicable error).
type FutureGetNetworkHashPS chan *response

// Receive waits for the response promised by the future and returns the
// estimated network hashes per second for the block heights provided by the
// parameters.
func (r FutureGetNetworkHashPS) Receive() (int64, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return -1, err
	}

	// Unmarshal result as an int64.
	var result int64
	err = json.Unmarshal(res, &result)
	if err != nil {
		return 0, err
	}

	return result, nil
}

// GetNetworkHashPSAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS for the blocking version and more details.
func (c *Client) GetNetworkHashPSAsync() FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS returns the estimated network hashes per second using the
// default number of blocks and the most recent block height.
//
// See GetNetworkHashPS2 to override the number of blocks to use and
// GetNetworkHashPS3 to override the height at which to calculate the estimate.
func (c *Client) GetNetworkHashPS() (int64, error) {
	return c.GetNetworkHashPSAsync().Receive()
}

// GetNetworkHashPS2Async returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS2 for the blocking version and more details.
func (c *Client) GetNetworkHashPS2Async(blocks int) FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS2 returns the estimated network hashes per second for the
// specified previous number of blocks working backwards from the most recent
// block height.  The blocks parameter can also be -1 in which case the number
// of blocks since the last difficulty change will be used.
//
// See GetNetworkHashPS to use defaults and GetNetworkHashPS3 to override the
// height at which to calculate the estimate.
func (c *Client) GetNetworkHashPS2(blocks int) (int64, error) {
	return c.GetNetworkHashPS2Async(blocks).Receive()
}

// GetNetworkHashPS3Async returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetNetworkHashPS3 for the blocking version and more details.
func (c *Client) GetNetworkHashPS3Async(blocks, height int) FutureGetNetworkHashPS {
	id := c.NextID()
	cmd, err := btcjson.NewGetNetworkHashPSCmd(id, blocks, height)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetNetworkHashPS3 returns the estimated network hashes per second for the
// specified previous number of blocks working backwards from the specified
// block height.  The blocks parameter can also be -1 in which case the number
// of blocks since the last difficulty change will be used.
//
// See GetNetworkHashPS and GetNetworkHashPS2 to use defaults.
func (c *Client) GetNetworkHashPS3(blocks, height int) (int64, error) {
	return c.GetNetworkHashPS3Async(blocks, height).Receive()
}

// FutureGetWork is a future promise to deliver the result of a
// GetWorkAsync RPC invocation (or an applicable error).
type FutureGetWork chan *response

// Receive waits for the response promised by the future and returns the hash
// data to work on.
func (r FutureGetWork) Receive() (*btcjson.GetWorkResult, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return nil, err
	}

	// Unmarshal result as a getwork result object.
	var result btcjson.GetWorkResult
	err = json.Unmarshal(res, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// GetWorkAsync returns an instance of a type that can be used to get the result
// of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetWork for the blocking version and more details.
func (c *Client) GetWorkAsync() FutureGetWork {
	id := c.NextID()
	cmd, err := btcjson.NewGetWorkCmd(id)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetWork returns hash data to work on.
//
// See GetWorkSubmit to submit the found solution.
func (c *Client) GetWork() (*btcjson.GetWorkResult, error) {
	return c.GetWorkAsync().Receive()
}

// FutureGetWorkSubmit is a future promise to deliver the result of a
// GetWorkSubmitAsync RPC invocation (or an applicable error).
type FutureGetWorkSubmit chan *response

// Receive waits for the response promised by the future and returns whether
// or not the submitted block header was accepted.
func (r FutureGetWorkSubmit) Receive() (bool, error) {
	res, err := receiveFuture(r)
	if err != nil {
		return false, err
	}

	// Unmarshal result as a boolean.
	var accepted bool
	err = json.Unmarshal(res, &accepted)
	if err != nil {
		return false, err
	}

	return accepted, nil
}

// GetWorkSubmitAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetWorkSubmit for the blocking version and more details.
func (c *Client) GetWorkSubmitAsync(data string) FutureGetWorkSubmit {
	id := c.NextID()
	cmd, err := btcjson.NewGetWorkCmd(id, data)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// GetWorkSubmit submits a block header which is a solution to previously
// requested data and returns whether or not the solution was accepted.
//
// See GetWork to request data to work on.
func (c *Client) GetWorkSubmit(data string) (bool, error) {
	return c.GetWorkSubmitAsync(data).Receive()
}

// FutureSubmitBlockResult is a future promise to deliver the result of a
// SubmitBlockAsync RPC invocation (or an applicable error).
type FutureSubmitBlockResult chan *response

// Receive waits for the response promised by the future and returns an error if
// any occurred when submitting the block.
func (r FutureSubmitBlockResult) Receive() error {
	res, err := receiveFuture(r)
	if err != nil {
		return err
	}

	resStr := string(res)
	if resStr != "null" {
		return errors.New(resStr)
	}

	return nil

}

// SubmitBlockAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See SubmitBlock for the blocking version and more details.
func (c *Client) SubmitBlockAsync(block *btcutil.Block, options *btcjson.SubmitBlockOptions) FutureSubmitBlockResult {
	blockHex := ""
	if block != nil {
		blockBytes, err := block.Bytes()
		if err != nil {
			return newFutureError(err)
		}

		blockHex = hex.EncodeToString(blockBytes)
	}

	id := c.NextID()
	cmd, err := btcjson.NewSubmitBlockCmd(id, blockHex, options)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}

// SubmitBlock attempts to submit a new block into the bitcoin network.
func (c *Client) SubmitBlock(block *btcutil.Block, options *btcjson.SubmitBlockOptions) error {
	return c.SubmitBlockAsync(block, options).Receive()
}

// TODO(davec): Implement GetBlockTemplate
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"compress/gzip"
	"flag"
	"fmt"
	log "github.com/cihub/seelog"
	"github.com/conformal/goleveldb/leveldb"
	"github.com/kac-/umint/utxo"
	"github.com/mably/btcnet"
	"github.com/mably/btcutil"
	"github.com/mably/btcwire"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const ()

var (
	testnet     bool
	diff        float64
	days        uint
	startString string
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s: [ADDR|TX:IDX]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Float64Var(&diff, "diff", 10.0, "display success on diff ")
	flag.UintVar(&days, "days", 7, "number of days to check")
	flag.StringVar(&startString, "from", "now", "date from which scan [i.e. 2014-09-12]")
	flag.Parse()
}

func main() {
	var (
		err            error
		params         = &btcnet.MainNetParams
		addrOrOutPoint string
		addr           *btcutil.AddressPubKeyHash
		outPoint       *btcwire.OutPoint
	)

	configSeelog()
	defer log.Flush()

	url := "https://s3.amazonaws.com/kac-pub/cryptos/peercoin/unspent-135k.tar.gz"

	appHome := btcutil.AppDataDir("ppc-umint", false)
	if err := os.MkdirAll(appHome, 0777); err != nil {
		log.Errorf("create app home(%v): %v\n", appHome, err)
		return
	}
	dbDestinationDir := filepath.Join(appHome, "unspent_db")
	topHeight, topTime, err := utxo.FetchHeightFile(dbDestinationDir)
	if err != nil || topHeight != 135000 {
		var dbTempDir string
		dbTempDir, topHeight, topTime, err = DownloadDB(url)
		defer os.RemoveAll(dbTempDir)
		if err != nil {
			log.Errorf("downloading database failed: %v\n", err)
			return
		}
		err = os.RemoveAll(dbDestinationDir)
		if err != nil {
			log.Errorf("remove database dir(%v): %v\n", dbDestinationDir, err)
			return
		}
		err = os.Rename(dbTempDir, dbDestinationDir)
		if err != nil {
			if strings.HasSuffix(err.Error(), ": invalid cross-device link") {
				// destination is on different partition, we need to copy directory
				err = CopyFile(dbTempDir, dbDestinationDir)
				if err != nil {
					log.Errorf("copying db from %v to %v failed: %v", dbTempDir, dbDestinationDir, err)
					// cleanup
					os.RemoveAll(dbDestinationDir)
					return
				}
			} else {
				log.Errorf("rename/move %v to %v: %v\n", dbTempDir, dbDestinationDir, err)
				return
			}
		}
	}
	log.Infof("got db: %v blocks (%v)", topHeight, topTime.Format("2006-01-02 15:04:05"))

	// db path
	if len(flag.Args()) < 1 {
		fmt.Println("arg required")
		flag.Usage()
		return
	}
	addrOrOutPoint = flag.Arg(0)
	if len(addrOrOutPoint) > 64 { //TXID:IDX
		sa := strings.Split(addrOrOutPoint, ":")
		if len(sa) != 2 {
			fmt.Printf("invalid format of TX:IDX    - %s\n", addrOrOutPoint)
			return
		}
		txSha, err := btcwire.NewShaHashFromStr(sa[0])
		if len(sa[0]) < 64 || err != nil {
			fmt.Printf("invalid TX    - %s\n", sa[0])
			return
		}
		outputIdx, err := strconv.Atoi(sa[1])
		if err != nil {
			fmt.Printf("invalid IDX    - %s\n", sa[1])
			return
		}
		outPoint = btcwire.NewOutPoint(txSha, uint32(outputIdx))
	} else { // ADDR
		decoded, err := btcutil.DecodeAddress(addrOrOutPoint, params)
		if err != nil {
			fmt.Printf("invalid address(%v): %v\n", addrOrOutPoint, err)
			return
		}
		var ok bool
		addr, ok = decoded.(*btcutil.AddressPubKeyHash)
		if !ok {
			fmt.Printf("pub key hash address expected: %v\n", addrOrOutPoint)
		}
	}

	// -from
	start := time.Now()
	if startString != "now" {
		start, err = time.Parse("2006-01-02", startString)
		if err != nil {
			fmt.Printf("invalid -from: %v\n", err)
			return
		}
	}
	end := start.Add(time.Hour * time.Duration(24*days))

	// done, now fire
	if outPoint != nil {
		log.Infof(`params:
tx:      %v
idx:     %v
start:   %v
end:     %v
diff:    %v
`, outPoint.Hash, outPoint.Index, start, end, diff)
	} else {
		log.Infof(`params:
addr:    %v
start:   %v
end:     %v
diff:    %v
`, addr.EncodeAddress(), start, end, diff)
	}

	db, err := leveldb.OpenFile(dbDestinationDir, nil)
	if err != nil {
		fmt.Printf("opening db: %v\n", err)
		return
	}
	if addr != nil {
		ups, _, err := utxo.FetchCoins(db, addr)
		if err != nil {
			log.Criticalf("fetching coins for %v: %v", addr.EncodeAddress(), err)
			return
		}
		for i := range ups {
			err = findStake(ups[i], db, params, start.Unix(), end.Unix(), float32(diff))
			if err != nil {
				log.Errorf("error while searching: %v", err)
			}
		}
	} else {
		err = findStake(outPoint, db, params, start.Unix(), end.Unix(), float32(diff))
		if err != nil {
			log.Errorf("error while searching: %v", err)
		}
	}
	_ = addr
}

func DownloadDB(url string) (dbTempDir string, topHeight uint32, topTime time.Time, err error) {
	var file *os.File
	prefix := filepath.Join(os.TempDir(), fmt.Sprintf("db-download-%v-", time.Now().Unix()))
	filename := url[strings.LastIndex(url, "/")+1:]
	if !strings.HasSuffix(filename, "tar.gz") {
		err = fmt.Errorf("insupported db archive: %v", filename)
		return
	}
	downloadTo := prefix + filename
	dbTempDir = prefix + "db"

	defer os.Remove(downloadTo)
	{ // download
		var resp *http.Response

		log.Infof("downloading %v to %v", url, downloadTo)
		file, err = os.Create(downloadTo)
		if err != nil {
			err = fmt.Errorf("create download destination file(%v): %v", downloadTo, err)
			return
		}
		defer file.Close()

		resp, err = http.Get(url)
		if err != nil {
			err = fmt.Errorf("db archive http request(%v): %v", url, err)
			return
		}
		defer resp.Body.Close()

		_, err = io.Copy(file, resp.Body)
		if err != nil {
			err = fmt.Errorf("copy data from %v to %v: %v", url, downloadTo, err)
			return
		}
	}
	{ // unpack
		var (
			th *tar.Header
			gr *gzip.Reader
		)
		log.Infof("unpacking %v to %v", downloadTo, dbTempDir)

		err = os.MkdirAll(dbTempDir, 0777)
		if err != nil {
			err = fmt.Errorf("create temp db dir(%v): %v", dbTempDir, err)
			return
		}
		file, err = os.Open(downloadTo)
		if err != nil {
			err = fmt.Errorf("open db archive(%v): %v", downloadTo, err)
			return
		}
		defer file.Close()
		gr, err = gzip.NewReader(file)
		if err != nil {
			err = fmt.Errorf("open gzip reader(%v): %v", downloadTo, err)
			return
		}
		tr := tar.NewReader(gr)
		for th, err = tr.Next(); err == nil; {
			fi := th.FileInfo()
			if !fi.IsDir() { // there are only files
				fn := filepath.Join(dbTempDir, fi.Name())
				//fmt.Printf("file: %v\n", fn)
				file, err = os.Create(fn)
				if err != nil {
					err = fmt.Errorf("create archived file(%v): %v", fn, err)
					return
				}
				defer file.Close()
				_, err = io.Copy(file, tr)
				if err != nil {
					err = fmt.Errorf("copy tar data to file(%v): %v", fn, err)
					return
				}
				// TODO(kac-) hotfix for windows 'Sharing violation' on db opening
				file.Close()
			}
			th, err = tr.Next()
		}
		if err != io.EOF {
			err = fmt.Errorf("archive error(%v): %v", downloadTo, err)
			return
		}
	}
	{ // test db
		topHeight, topTime, err = utxo.FetchHeightFile(dbTempDir)
	}

	return
}

func CopyFile(src string, dst string) error {
	srcLen := len(src)
	err := filepath.Walk(src, func(path string, f os.FileInfo, err error) error {
		dpath := dst + path[srcLen:]
		//fmt.Printf("%s (%v) -> %v\n", path, f.Name(), dpath)
		if f.IsDir() {
			err = os.MkdirAll(dpath, 0777)
			if err != nil {
				return fmt.Errorf("mkdir(%v): %v", dpath, err)
			}
		} else {
			in, err := os.Open(path)
			if err != nil {
				return fmt.Errorf("open file(%v): %v", path, err)
			}
			defer in.Close()
			out, err := os.Create(dpath)
			if err != nil {
				return fmt.Errorf("create file(%v): %v", dpath, err)
			}
			defer out.Close()
			_, err = io.Copy(out, in)
			if err != nil {
				return fmt.Errorf("copy content from %v to %v: %v", path, dpath, err)
			}
		}
		return nil
	})
	return err
}

func configSeelog() {
	l, _ := log.LoggerFromConfigAsString(`
<seelog>
	<outputs formatid="main">
		<console />
	</outputs>
	<formats>
		<format id="main" format="[%Level] %Msg%n"/>
	</formats>
</seelog>
`)
	log.ReplaceLogger(l)
}
<commit_msg>fix resource closing<commit_after>package main

import (
	"archive/tar"
	"compress/gzip"
	"flag"
	"fmt"
	log "github.com/cihub/seelog"
	"github.com/conformal/goleveldb/leveldb"
	"github.com/kac-/umint/utxo"
	"github.com/mably/btcnet"
	"github.com/mably/btcutil"
	"github.com/mably/btcwire"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const ()

var (
	testnet     bool
	diff        float64
	days        uint
	startString string
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s: [ADDR|TX:IDX]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Float64Var(&diff, "diff", 10.0, "display success on diff ")
	flag.UintVar(&days, "days", 7, "number of days to check")
	flag.StringVar(&startString, "from", "now", "date from which scan [i.e. 2014-09-12]")
	flag.Parse()
}

func main() {
	var (
		err            error
		params         = &btcnet.MainNetParams
		addrOrOutPoint string
		addr           *btcutil.AddressPubKeyHash
		outPoint       *btcwire.OutPoint
	)

	configSeelog()
	defer log.Flush()

	url := "https://s3.amazonaws.com/kac-pub/cryptos/peercoin/unspent-135k.tar.gz"

	appHome := btcutil.AppDataDir("ppc-umint", false)
	if err := os.MkdirAll(appHome, 0777); err != nil {
		log.Errorf("create app home(%v): %v\n", appHome, err)
		return
	}
	dbDestinationDir := filepath.Join(appHome, "unspent_db")
	topHeight, topTime, err := utxo.FetchHeightFile(dbDestinationDir)
	if err != nil || topHeight != 135000 {
		var dbTempDir string
		dbTempDir, topHeight, topTime, err = DownloadDB(url)
		defer os.RemoveAll(dbTempDir)
		if err != nil {
			log.Errorf("downloading database failed: %v\n", err)
			return
		}
		err = os.RemoveAll(dbDestinationDir)
		if err != nil {
			log.Errorf("remove database dir(%v): %v\n", dbDestinationDir, err)
			return
		}
		err = os.Rename(dbTempDir, dbDestinationDir)
		if err != nil {
			if strings.HasSuffix(err.Error(), ": invalid cross-device link") {
				// destination is on different partition, we need to copy directory
				err = CopyFile(dbTempDir, dbDestinationDir)
				if err != nil {
					log.Errorf("copying db from %v to %v failed: %v", dbTempDir, dbDestinationDir, err)
					// cleanup
					os.RemoveAll(dbDestinationDir)
					return
				}
			} else {
				log.Errorf("rename/move %v to %v: %v\n", dbTempDir, dbDestinationDir, err)
				return
			}
		}
	}
	log.Infof("got db: %v blocks (%v)", topHeight, topTime.Format("2006-01-02 15:04:05"))

	// db path
	if len(flag.Args()) < 1 {
		fmt.Println("arg required")
		flag.Usage()
		return
	}
	addrOrOutPoint = flag.Arg(0)
	if len(addrOrOutPoint) > 64 { //TXID:IDX
		sa := strings.Split(addrOrOutPoint, ":")
		if len(sa) != 2 {
			fmt.Printf("invalid format of TX:IDX    - %s\n", addrOrOutPoint)
			return
		}
		txSha, err := btcwire.NewShaHashFromStr(sa[0])
		if len(sa[0]) < 64 || err != nil {
			fmt.Printf("invalid TX    - %s\n", sa[0])
			return
		}
		outputIdx, err := strconv.Atoi(sa[1])
		if err != nil {
			fmt.Printf("invalid IDX    - %s\n", sa[1])
			return
		}
		outPoint = btcwire.NewOutPoint(txSha, uint32(outputIdx))
	} else { // ADDR
		decoded, err := btcutil.DecodeAddress(addrOrOutPoint, params)
		if err != nil {
			fmt.Printf("invalid address(%v): %v\n", addrOrOutPoint, err)
			return
		}
		var ok bool
		addr, ok = decoded.(*btcutil.AddressPubKeyHash)
		if !ok {
			fmt.Printf("pub key hash address expected: %v\n", addrOrOutPoint)
		}
	}

	// -from
	start := time.Now()
	if startString != "now" {
		start, err = time.Parse("2006-01-02", startString)
		if err != nil {
			fmt.Printf("invalid -from: %v\n", err)
			return
		}
	}
	end := start.Add(time.Hour * time.Duration(24*days))

	// done, now fire
	if outPoint != nil {
		log.Infof(`params:
tx:      %v
idx:     %v
start:   %v
end:     %v
diff:    %v
`, outPoint.Hash, outPoint.Index, start, end, diff)
	} else {
		log.Infof(`params:
addr:    %v
start:   %v
end:     %v
diff:    %v
`, addr.EncodeAddress(), start, end, diff)
	}

	db, err := leveldb.OpenFile(dbDestinationDir, nil)
	if err != nil {
		fmt.Printf("opening db: %v\n", err)
		return
	}
	if addr != nil {
		ups, _, err := utxo.FetchCoins(db, addr)
		if err != nil {
			log.Criticalf("fetching coins for %v: %v", addr.EncodeAddress(), err)
			return
		}
		for i := range ups {
			err = findStake(ups[i], db, params, start.Unix(), end.Unix(), float32(diff))
			if err != nil {
				log.Errorf("error while searching: %v", err)
			}
		}
	} else {
		err = findStake(outPoint, db, params, start.Unix(), end.Unix(), float32(diff))
		if err != nil {
			log.Errorf("error while searching: %v", err)
		}
	}
	_ = addr
}

func DownloadDB(url string) (dbTempDir string, topHeight uint32, topTime time.Time, err error) {
	var file *os.File
	prefix := filepath.Join(os.TempDir(), fmt.Sprintf("db-download-%v-", time.Now().Unix()))
	filename := url[strings.LastIndex(url, "/")+1:]
	if !strings.HasSuffix(filename, "tar.gz") {
		err = fmt.Errorf("insupported db archive: %v", filename)
		return
	}
	downloadTo := prefix + filename
	dbTempDir = prefix + "db"

	defer os.Remove(downloadTo)
	func() { // download, wrap to close files w/ defer
		var resp *http.Response

		log.Infof("downloading %v to %v", url, downloadTo)
		file, err = os.Create(downloadTo)
		if err != nil {
			err = fmt.Errorf("create download destination file(%v): %v", downloadTo, err)
			return
		}
		defer file.Close()

		resp, err = http.Get(url)
		if err != nil {
			err = fmt.Errorf("db archive http request(%v): %v", url, err)
			return
		}
		defer resp.Body.Close()

		_, err = io.Copy(file, resp.Body)
		if err != nil {
			err = fmt.Errorf("copy data from %v to %v: %v", url, downloadTo, err)
			return
		}
	}()

	// unpack
	var (
		th *tar.Header
		gr *gzip.Reader
	)
	log.Infof("unpacking %v to %v", downloadTo, dbTempDir)

	err = os.MkdirAll(dbTempDir, 0777)
	if err != nil {
		err = fmt.Errorf("create temp db dir(%v): %v", dbTempDir, err)
		return
	}
	file, err = os.Open(downloadTo)
	if err != nil {
		err = fmt.Errorf("open db archive(%v): %v", downloadTo, err)
		return
	}
	defer file.Close()
	gr, err = gzip.NewReader(file)
	if err != nil {
		err = fmt.Errorf("open gzip reader(%v): %v", downloadTo, err)
		return
	}
	tr := tar.NewReader(gr)
	for th, err = tr.Next(); err == nil; {
		fi := th.FileInfo()
		if !fi.IsDir() { // there are only files
			func() { // wrap to close files w/ defer
				fn := filepath.Join(dbTempDir, fi.Name())
				file, err = os.Create(fn)
				if err != nil {
					err = fmt.Errorf("create archived file(%v): %v", fn, err)
					return
				}
				defer file.Close()
				_, err = io.Copy(file, tr)
				if err != nil {
					err = fmt.Errorf("copy tar data to file(%v): %v", fn, err)
					return
				}
			}()
		}
		th, err = tr.Next()
	}
	if err != io.EOF {
		err = fmt.Errorf("archive error(%v): %v", downloadTo, err)
		return
	}

	// test db
	topHeight, topTime, err = utxo.FetchHeightFile(dbTempDir)

	return
}

func CopyFile(src string, dst string) error {
	srcLen := len(src)
	err := filepath.Walk(src, func(path string, f os.FileInfo, err error) error {
		dpath := dst + path[srcLen:]
		//fmt.Printf("%s (%v) -> %v\n", path, f.Name(), dpath)
		if f.IsDir() {
			err = os.MkdirAll(dpath, 0777)
			if err != nil {
				return fmt.Errorf("mkdir(%v): %v", dpath, err)
			}
		} else {
			in, err := os.Open(path)
			if err != nil {
				return fmt.Errorf("open file(%v): %v", path, err)
			}
			defer in.Close()
			out, err := os.Create(dpath)
			if err != nil {
				return fmt.Errorf("create file(%v): %v", dpath, err)
			}
			defer out.Close()
			_, err = io.Copy(out, in)
			if err != nil {
				return fmt.Errorf("copy content from %v to %v: %v", path, dpath, err)
			}
		}
		return nil
	})
	return err
}

func configSeelog() {
	l, _ := log.LoggerFromConfigAsString(`
<seelog>
	<outputs formatid="main">
		<console />
	</outputs>
	<formats>
		<format id="main" format="[%Level] %Msg%n"/>
	</formats>
</seelog>
`)
	log.ReplaceLogger(l)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/howeyc/fsnotify"
	"go/build"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
)

func install(buildpath, lastError string) (installed bool, errorOutput string, err error) {
	cmdline := []string{"go", "get", "-v", buildpath}

	cmd := exec.Command("go", cmdline[1:]...)
	bufOut := bytes.NewBuffer([]byte{})
	bufErr := bytes.NewBuffer([]byte{})
	cmd.Stdout = bufOut
	cmd.Stderr = bufErr

	err = cmd.Run()

	if bufErr.Len() != 0 {
		errorOutput = bufErr.String()
		if errorOutput != lastError {
			fmt.Print(bufErr)
		}
		err = errors.New("compile error")
		return
	}

	installed = bufErr.Len() != 0

	return
}

func run(binName, binPath string, args []string) (runch chan bool) {
	runch = make(chan bool)
	go func() {
		cmdline := append([]string{binName}, args...)
		var proc *os.Process
		for _ = range runch {
			if proc != nil {
				proc.Kill()
			}
			cmd := exec.Command(binPath, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			log.Print(cmdline)
			err := cmd.Start()
			if err != nil {
				log.Printf("error on starting process: '%s'\n", err)
			}
			proc = cmd.Process
		}
	}()
	return
}

func getWatcher(buildpath string) (watcher *fsnotify.Watcher, err error) {
	watcher, err = fsnotify.NewWatcher()
	addToWatcher(watcher, buildpath, map[string]bool{})
	return
}

func addToWatcher(watcher *fsnotify.Watcher, importpath string, watching map[string]bool) {
	pkg, err := build.Import(importpath, "", 0)
	if err != nil {
		return
	}
	if pkg.Goroot {
		return
	}
	watcher.Watch(pkg.Dir)
	watching[importpath] = true
	for _, imp := range pkg.Imports {
		if !watching[imp] {
			addToWatcher(watcher, imp, watching)
		}
	}
}

func rerun(buildpath string, args []string) (err error) {
	log.Printf("setting up %s %v", buildpath, args)

	pkg, err := build.Import(buildpath, "", 0)
	if err != nil {
		return
	}

	if pkg.Name != "main" {
		err = errors.New(fmt.Sprintf("expected package %q, got %q", "main", pkg.Name))
		return
	}

	_, binName := path.Split(buildpath)
	var binPath string
	if gobin := os.Getenv("GOBIN"); gobin != "" {
		binPath = filepath.Join(gobin, binName)
	} else {
		binPath = filepath.Join(pkg.BinDir, binName)
	}

	runch := run(binName, binPath, args)

	var errorOutput string
	_, errorOutput, ierr := install(buildpath, errorOutput)
	if ierr == nil {
		runch <- true
	}

	var watcher *fsnotify.Watcher
	watcher, err = getWatcher(buildpath)
	if err != nil {
		return
	}

	for {
		// read event from the watcher
		we, _ := <-watcher.Event
		var installed bool
		installed, errorOutput, _ = install(buildpath, errorOutput)
		if installed {
			log.Print(we.Name)
			// re-build and re-run the application
			runch <- true
			// close the watcher
			watcher.Close()
			// to clean things up: read events from the watcher until events chan is closed.
			go func(events chan *fsnotify.FileEvent) {
				for _ = range events {

				}
			}(watcher.Event)
			// create a new watcher
			log.Println("rescanning")
			watcher, err = getWatcher(buildpath)
			if err != nil {
				return
			}
			// we don't need the errors from the new watcher.
			// therfore we continiously discard them from the channel to avoid a deadlock.
			go func(errors chan error) {
				for _ = range errors {

				}
			}(watcher.Error)
		}
	}
	return
}

func main() {
	if len(os.Args) < 2 {
		log.Fatal("Usage: rerun <import path> [arg]*")
	}
	err := rerun(os.Args[1], os.Args[2:])
	if err != nil {
		log.Print(err)
	}
}
<commit_msg>Using shared buffer. Added comments. Settings installed to true when buf.Len == 0.<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/howeyc/fsnotify"
	"go/build"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
)

func install(buildpath, lastError string) (installed bool, errorOutput string, err error) {
	cmdline := []string{"go", "get", "-v", buildpath}

	// setup the build command, use a shared buffer for both stdOut and stdErr
	cmd := exec.Command("go", cmdline[1:]...)
	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	err = cmd.Run()

	// when there is any output, the go command failed.
	if buf.Len() > 0 {
		errorOutput = buf.String()
		if errorOutput != lastError {
			fmt.Print(errorOutput)
		}
		err = errors.New("compile error")
		return
	}

	// all seems fine
	installed = true
	return
}

func run(binName, binPath string, args []string) (runch chan bool) {
	runch = make(chan bool)
	go func() {
		cmdline := append([]string{binName}, args...)
		var proc *os.Process
		for _ = range runch {
			if proc != nil {
				proc.Kill()
			}
			cmd := exec.Command(binPath, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			log.Print(cmdline)
			err := cmd.Start()
			if err != nil {
				log.Printf("error on starting process: '%s'\n", err)
			}
			proc = cmd.Process
		}
	}()
	return
}

func getWatcher(buildpath string) (watcher *fsnotify.Watcher, err error) {
	watcher, err = fsnotify.NewWatcher()
	addToWatcher(watcher, buildpath, map[string]bool{})
	return
}

func addToWatcher(watcher *fsnotify.Watcher, importpath string, watching map[string]bool) {
	pkg, err := build.Import(importpath, "", 0)
	if err != nil {
		return
	}
	if pkg.Goroot {
		return
	}
	watcher.Watch(pkg.Dir)
	watching[importpath] = true
	for _, imp := range pkg.Imports {
		if !watching[imp] {
			addToWatcher(watcher, imp, watching)
		}
	}
}

func rerun(buildpath string, args []string) (err error) {
	log.Printf("setting up %s %v", buildpath, args)

	pkg, err := build.Import(buildpath, "", 0)
	if err != nil {
		return
	}

	if pkg.Name != "main" {
		err = errors.New(fmt.Sprintf("expected package %q, got %q", "main", pkg.Name))
		return
	}

	_, binName := path.Split(buildpath)
	var binPath string
	if gobin := os.Getenv("GOBIN"); gobin != "" {
		binPath = filepath.Join(gobin, binName)
	} else {
		binPath = filepath.Join(pkg.BinDir, binName)
	}

	runch := run(binName, binPath, args)

	var errorOutput string
	_, errorOutput, ierr := install(buildpath, errorOutput)
	if ierr == nil {
		runch <- true
	}

	var watcher *fsnotify.Watcher
	watcher, err = getWatcher(buildpath)
	if err != nil {
		return
	}

	for {
		// read event from the watcher
		we, _ := <-watcher.Event
		var installed bool
		installed, errorOutput, _ = install(buildpath, errorOutput)
		if installed {
			log.Print(we.Name)
			// re-build and re-run the application
			runch <- true
			// close the watcher
			watcher.Close()
			// to clean things up: read events from the watcher until events chan is closed.
			go func(events chan *fsnotify.FileEvent) {
				for _ = range events {

				}
			}(watcher.Event)
			// create a new watcher
			log.Println("rescanning")
			watcher, err = getWatcher(buildpath)
			if err != nil {
				return
			}
			// we don't need the errors from the new watcher.
			// therfore we continiously discard them from the channel to avoid a deadlock.
			go func(errors chan error) {
				for _ = range errors {

				}
			}(watcher.Error)
		}
	}
	return
}

func main() {
	if len(os.Args) < 2 {
		log.Fatal("Usage: rerun <import path> [arg]*")
	}
	err := rerun(os.Args[1], os.Args[2:])
	if err != nil {
		log.Print(err)
	}
}
<|endoftext|>


<commit_before>package cachet

import (
	"fmt"
)

const (
	// Docs: https://docs.cachethq.io/docs/incident-statuses

	// IncidentStatusScheduled means "This status is used for a scheduled status."
	IncidentStatusScheduled = 0
	// IncidentStatusInvestigating means "You have reports of a problem and you're currently looking into them."
	IncidentStatusInvestigating = 1
	// IncidentStatusIdentified means "You've found the issue and you're working on a fix."
	IncidentStatusIdentified = 2
	// IncidentStatusWatching means "You've since deployed a fix and you're currently watching the situation."
	IncidentStatusWatching = 3
	// IncidentStatusFixed means "The fix has worked, you're happy to close the incident."
	IncidentStatusFixed = 4

	// IncidentVisibilityPublic means "Viewable by public"
	IncidentVisibilityPublic = 1
	// IncidentVisibilityLoggedIn means "Only visible to logged in users"
	IncidentVisibilityLoggedIn = 0
)

// IncidentsService contains REST endpoints that belongs to cachet incidents.
type IncidentsService struct {
	client *Client
}

// Incident entity reflects one single incident
type Incident struct {
	ID              int    `json:"id,omitempty"`
	ComponentID     int    `json:"component_id,omitempty"`
	ComponentStatus int    `json:"component_status,omitempty"`
	Name            string `json:"name,omitempty"`
	Status          int    `json:"status,omitempty"`
	Visible         int    `json:"visible,omitempty"`
	Message         string `json:"message,omitempty"`
	ScheduledAt     string `json:"scheduled_at,omitempty"`
	CreatedAt       string `json:"created_at,omitempty"`
	UpdatedAt       string `json:"updated_at,omitempty"`
	DeletedAt       string `json:"deleted_at,omitempty"`
	HumanStatus     string `json:"human_status,omitempty"`
	Notify          bool   `json:"notify,omitempty"`
}

// IncidentResponse reflects the response of /incidents call
type IncidentResponse struct {
	Meta      Meta       `json:"meta,omitempty"`
	Incidents []Incident `json:"data,omitempty"`
}

// incidentsAPIResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the incident in the "data" key.
type incidentsAPIResponse struct {
	Data *Incident `json:"data"`
}

// GetAll return all incidents.
//
// Docs: https://docs.cachethq.io/docs/get-incidents
func (s *IncidentsService) GetAll() (*IncidentResponse, *Response, error) {
	u := "api/v1/incidents"
	v := new(IncidentResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// Get returns a single incident.
//
// Docs: https://docs.cachethq.io/docs/get-an-incident
func (s *IncidentsService) Get(id int) (*Incident, *Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// Create a new incident.
//
// Docs: https://docs.cachethq.io/docs/incidents
func (s *IncidentsService) Create(i *Incident) (*Incident, *Response, error) {
	u := "api/v1/incidents"
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("POST", u, i, v)
	return v.Data, resp, err
}

// Update updates an incident.
//
// Docs: https://docs.cachethq.io/docs/update-an-incident
func (s *IncidentsService) Update(id int, i *Incident) (*Incident, *Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("PUT", u, i, v)
	return v.Data, resp, err
}

// Delete delete an incident.
//
// Docs: https://docs.cachethq.io/docs/delete-an-incident
func (s *IncidentsService) Delete(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}
<commit_msg>add list options to get all incidents<commit_after>package cachet

import (
	"fmt"
)

const (
	// Docs: https://docs.cachethq.io/docs/incident-statuses

	// IncidentStatusScheduled means "This status is used for a scheduled status."
	IncidentStatusScheduled = 0
	// IncidentStatusInvestigating means "You have reports of a problem and you're currently looking into them."
	IncidentStatusInvestigating = 1
	// IncidentStatusIdentified means "You've found the issue and you're working on a fix."
	IncidentStatusIdentified = 2
	// IncidentStatusWatching means "You've since deployed a fix and you're currently watching the situation."
	IncidentStatusWatching = 3
	// IncidentStatusFixed means "The fix has worked, you're happy to close the incident."
	IncidentStatusFixed = 4

	// IncidentVisibilityPublic means "Viewable by public"
	IncidentVisibilityPublic = 1
	// IncidentVisibilityLoggedIn means "Only visible to logged in users"
	IncidentVisibilityLoggedIn = 0
)

// IncidentsService contains REST endpoints that belongs to cachet incidents.
type IncidentsService struct {
	client *Client
}

// Incident entity reflects one single incident
type Incident struct {
	ID              int    `json:"id,omitempty"`
	ComponentID     int    `json:"component_id,omitempty"`
	ComponentStatus int    `json:"component_status,omitempty"`
	Name            string `json:"name,omitempty"`
	Status          int    `json:"status,omitempty"`
	Visible         int    `json:"visible,omitempty"`
	Message         string `json:"message,omitempty"`
	ScheduledAt     string `json:"scheduled_at,omitempty"`
	CreatedAt       string `json:"created_at,omitempty"`
	UpdatedAt       string `json:"updated_at,omitempty"`
	DeletedAt       string `json:"deleted_at,omitempty"`
	HumanStatus     string `json:"human_status,omitempty"`
	Notify          bool   `json:"notify,omitempty"`
}

// IncidentResponse reflects the response of /incidents call
type IncidentResponse struct {
	Meta      Meta       `json:"meta,omitempty"`
	Incidents []Incident `json:"data,omitempty"`
}

// incidentsAPIResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the incident in the "data" key.
type incidentsAPIResponse struct {
	Data *Incident `json:"data"`
}

// GetAll return all incidents.
//
// Docs: https://docs.cachethq.io/docs/get-incidents
func (s *IncidentsService) GetAll(opt *ListOptions) (*IncidentResponse, *Response, error) {
	u := "api/v1/incidents"
	v := new(IncidentResponse)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// Get returns a single incident.
//
// Docs: https://docs.cachethq.io/docs/get-an-incident
func (s *IncidentsService) Get(id int) (*Incident, *Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// Create a new incident.
//
// Docs: https://docs.cachethq.io/docs/incidents
func (s *IncidentsService) Create(i *Incident) (*Incident, *Response, error) {
	u := "api/v1/incidents"
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("POST", u, i, v)
	return v.Data, resp, err
}

// Update updates an incident.
//
// Docs: https://docs.cachethq.io/docs/update-an-incident
func (s *IncidentsService) Update(id int, i *Incident) (*Incident, *Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)
	v := new(incidentsAPIResponse)

	resp, err := s.client.Call("PUT", u, i, v)
	return v.Data, resp, err
}

// Delete delete an incident.
//
// Docs: https://docs.cachethq.io/docs/delete-an-incident
func (s *IncidentsService) Delete(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/incidents/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}
<|endoftext|>