<commit_before>package pilosa

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"sync"

	"github.com/gogo/protobuf/proto"
	"github.com/pilosa/pilosa/internal"
)

const (
	// FrameSuffixRank is the suffix used for rank-based frames.
	FrameSuffixRank = ".n"
)

// Frame represents a container for fragments.
type Frame struct {
	mu          sync.Mutex
	path        string
	db          string
	name        string
	timeQuantum TimeQuantum

	// Fragments by slice.
	fragments map[uint64]*Fragment

	// Bitmap attribute storage and cache
	bitmapAttrStore *AttrStore

	stats StatsClient
}

// NewFrame returns a new instance of frame.
func NewFrame(path, db, name string) *Frame {
	return &Frame{
		path: path,
		db:   db,
		name: name,

		fragments:       make(map[uint64]*Fragment),
		bitmapAttrStore: NewAttrStore(filepath.Join(path, "data")),

		stats: NopStatsClient,
	}
}

// Name returns the name the frame was initialized with.
func (f *Frame) Name() string { return f.name }

// DB returns the database name the frame was initialized with.
func (f *Frame) DB() string { return f.db }

// Path returns the path the frame was initialized with.
func (f *Frame) Path() string { return f.path }

// BitmapAttrStore returns the attribute storage.
func (f *Frame) BitmapAttrStore() *AttrStore { return f.bitmapAttrStore }

// MaxSlice returns the max slice in the frame.
func (f *Frame) MaxSlice() uint64 {
	f.mu.Lock()
	defer f.mu.Unlock()

	var max uint64
	for slice := range f.fragments {
		if slice > max {
			max = slice
		}
	}
	return max
}

// Open opens and initializes the frame.
func (f *Frame) Open() error {
	if err := func() error {
		// Ensure the frame's path exists.
		if err := os.MkdirAll(f.path, 0777); err != nil {
			return err
		}

		if err := f.loadMeta(); err != nil {
			return err
		}

		if err := f.openFragments(); err != nil {
			return err
		}

		if err := f.bitmapAttrStore.Open(); err != nil {
			return err
		}

		return nil
	}(); err != nil {
		f.Close()
		return err
	}

	return nil
}

// openFragments opens and initializes the fragments inside the frame.
func (f *Frame) openFragments() error {
	file, err := os.Open(f.path)
	if err != nil {
		return err
	}
	defer file.Close()

	fis, err := file.Readdir(0)
	if err != nil {
		return err
	}

	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}

		// Parse filename into integer.
		slice, err := strconv.ParseUint(filepath.Base(fi.Name()), 10, 64)
		if err != nil {
			continue
		}

		frag := f.newFragment(f.FragmentPath(slice), slice)
		if err := frag.Open(); err != nil {
			return fmt.Errorf("open fragment: slice=%s, err=%s", frag.Slice(), err)
		}
		frag.BitmapAttrStore = f.bitmapAttrStore
		f.fragments[frag.Slice()] = frag

		f.stats.Count("maxSlice", 1)
	}

	return nil
}

// loadMeta reads meta data for the frame, if any.
func (f *Frame) loadMeta() error {
	var pb internal.Frame

	// Read data from meta file.
	buf, err := ioutil.ReadFile(filepath.Join(f.path, "meta"))
	if os.IsNotExist(err) {
		f.timeQuantum = ""
		return nil
	} else if err != nil {
		return err
	} else {
		if err := proto.Unmarshal(buf, &pb); err != nil {
			return err
		}
	}

	// Copy metadata fields.
	f.timeQuantum = TimeQuantum(pb.TimeQuantum)

	return nil
}

// saveMeta writes meta data for the frame.
func (f *Frame) saveMeta() error {
	// Marshal metadata.
	buf, err := proto.Marshal(&internal.Frame{TimeQuantum: string(f.timeQuantum)})
	if err != nil {
		return err
	}

	// Write to meta file.
	if err := ioutil.WriteFile(filepath.Join(f.path, "meta"), buf, 0666); err != nil {
		return err
	}

	return nil
}

// Close closes the frame and its fragments.
func (f *Frame) Close() error {
	f.mu.Lock()
	defer f.mu.Unlock()

	// Close the attribute store.
	if f.bitmapAttrStore != nil {
		_ = f.bitmapAttrStore.Close()
	}

	// Close all fragments.
	for _, frag := range f.fragments {
		_ = frag.Close()
	}
	f.fragments = make(map[uint64]*Fragment)

	return nil
}

// TimeQuantum returns the time quantum for the frame.
func (f *Frame) TimeQuantum() TimeQuantum {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.timeQuantum
}

// SetTimeQuantum sets the time quantum for the frame.
func (f *Frame) SetTimeQuantum(q TimeQuantum) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	// Validate input.
	if !q.Valid() {
		return ErrInvalidTimeQuantum
	}

	// Update value on frame.
	f.timeQuantum = q

	// Perist meta data to disk.
	if err := f.saveMeta(); err != nil {
		return err
	}

	return nil
}

// FragmentPath returns the path to a fragment in the frame.
func (f *Frame) FragmentPath(slice uint64) string {
	return filepath.Join(f.path, strconv.FormatUint(slice, 10))
}

// Fragment returns a fragment in the frame by slice.
func (f *Frame) Fragment(slice uint64) *Fragment {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.fragment(slice)
}

func (f *Frame) fragment(slice uint64) *Fragment { return f.fragments[slice] }

// Fragments returns a list of all fragments in the frame.
func (f *Frame) Fragments() []*Fragment {
	f.mu.Lock()
	defer f.mu.Unlock()

	other := make([]*Fragment, 0, len(f.fragments))
	for _, fragment := range f.fragments {
		other = append(other, fragment)
	}
	return other
}

// CreateFragmentIfNotExists returns a fragment in the frame by slice.
func (f *Frame) CreateFragmentIfNotExists(slice uint64) (*Fragment, error) {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.createFragmentIfNotExists(slice)
}

func (f *Frame) createFragmentIfNotExists(slice uint64) (*Fragment, error) {
	// Find fragment in cache first.
	if frag := f.fragments[slice]; frag != nil {
		return frag, nil
	}

	// Initialize and open fragment.
	frag := f.newFragment(f.FragmentPath(slice), slice)
	if err := frag.Open(); err != nil {
		return nil, err
	}
	frag.BitmapAttrStore = f.bitmapAttrStore

	// Save to lookup.
	f.fragments[slice] = frag

	f.stats.Count("maxSlice", 1)

	return frag, nil
}

func (f *Frame) newFragment(path string, slice uint64) *Fragment {
	frag := NewFragment(path, f.db, f.name, slice)
	frag.stats = f.stats.WithTags(fmt.Sprintf("slice:%d", slice))
	return frag
}

// SetBit sets a bit within the frame.
func (f *Frame) SetBit(bitmapID, profileID uint64) (changed bool, err error) {
	slice := bitmapID / SliceWidth
	frag, err := f.CreateFragmentIfNotExists(slice)
	if err != nil {
		return changed, err
	}
	return frag.SetBit(bitmapID, profileID)
}

type frameSlice []*Frame

func (p frameSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p frameSlice) Len() int           { return len(p) }
func (p frameSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }

// FrameInfo represents schema information for a frame.
type FrameInfo struct {
	Name string `json:"name"`
}

type frameInfoSlice []*FrameInfo

func (p frameInfoSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p frameInfoSlice) Len() int           { return len(p) }
func (p frameInfoSlice) Less(i, j int) bool { return p[i].Name < p[j].Name }
<commit_msg>Fixes broken index sync test.<commit_after>package pilosa

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"sync"

	"github.com/gogo/protobuf/proto"
	"github.com/pilosa/pilosa/internal"
)

const (
	// FrameSuffixRank is the suffix used for rank-based frames.
	FrameSuffixRank = ".n"
)

// Frame represents a container for fragments.
type Frame struct {
	mu          sync.Mutex
	path        string
	db          string
	name        string
	timeQuantum TimeQuantum

	// Fragments by slice.
	fragments map[uint64]*Fragment

	// Bitmap attribute storage and cache
	bitmapAttrStore *AttrStore

	stats StatsClient
}

// NewFrame returns a new instance of frame.
func NewFrame(path, db, name string) *Frame {
	return &Frame{
		path: path,
		db:   db,
		name: name,

		fragments:       make(map[uint64]*Fragment),
		bitmapAttrStore: NewAttrStore(filepath.Join(path, "data")),

		stats: NopStatsClient,
	}
}

// Name returns the name the frame was initialized with.
func (f *Frame) Name() string { return f.name }

// DB returns the database name the frame was initialized with.
func (f *Frame) DB() string { return f.db }

// Path returns the path the frame was initialized with.
func (f *Frame) Path() string { return f.path }

// BitmapAttrStore returns the attribute storage.
func (f *Frame) BitmapAttrStore() *AttrStore { return f.bitmapAttrStore }

// MaxSlice returns the max slice in the frame.
func (f *Frame) MaxSlice() uint64 {
	f.mu.Lock()
	defer f.mu.Unlock()

	var max uint64
	for slice := range f.fragments {
		if slice > max {
			max = slice
		}
	}
	return max
}

// Open opens and initializes the frame.
func (f *Frame) Open() error {
	if err := func() error {
		// Ensure the frame's path exists.
		if err := os.MkdirAll(f.path, 0777); err != nil {
			return err
		}

		if err := f.loadMeta(); err != nil {
			return err
		}

		if err := f.openFragments(); err != nil {
			return err
		}

		if err := f.bitmapAttrStore.Open(); err != nil {
			return err
		}

		return nil
	}(); err != nil {
		f.Close()
		return err
	}

	return nil
}

// openFragments opens and initializes the fragments inside the frame.
func (f *Frame) openFragments() error {
	file, err := os.Open(f.path)
	if err != nil {
		return err
	}
	defer file.Close()

	fis, err := file.Readdir(0)
	if err != nil {
		return err
	}

	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}

		// Parse filename into integer.
		slice, err := strconv.ParseUint(filepath.Base(fi.Name()), 10, 64)
		if err != nil {
			continue
		}

		frag := f.newFragment(f.FragmentPath(slice), slice)
		if err := frag.Open(); err != nil {
			return fmt.Errorf("open fragment: slice=%s, err=%s", frag.Slice(), err)
		}
		frag.BitmapAttrStore = f.bitmapAttrStore
		f.fragments[frag.Slice()] = frag

		f.stats.Count("maxSlice", 1)
	}

	return nil
}

// loadMeta reads meta data for the frame, if any.
func (f *Frame) loadMeta() error {
	var pb internal.Frame

	// Read data from meta file.
	buf, err := ioutil.ReadFile(filepath.Join(f.path, "meta"))
	if os.IsNotExist(err) {
		f.timeQuantum = ""
		return nil
	} else if err != nil {
		return err
	} else {
		if err := proto.Unmarshal(buf, &pb); err != nil {
			return err
		}
	}

	// Copy metadata fields.
	f.timeQuantum = TimeQuantum(pb.TimeQuantum)

	return nil
}

// saveMeta writes meta data for the frame.
func (f *Frame) saveMeta() error {
	// Marshal metadata.
	buf, err := proto.Marshal(&internal.Frame{TimeQuantum: string(f.timeQuantum)})
	if err != nil {
		return err
	}

	// Write to meta file.
	if err := ioutil.WriteFile(filepath.Join(f.path, "meta"), buf, 0666); err != nil {
		return err
	}

	return nil
}

// Close closes the frame and its fragments.
func (f *Frame) Close() error {
	f.mu.Lock()
	defer f.mu.Unlock()

	// Close the attribute store.
	if f.bitmapAttrStore != nil {
		_ = f.bitmapAttrStore.Close()
	}

	// Close all fragments.
	for _, frag := range f.fragments {
		_ = frag.Close()
	}
	f.fragments = make(map[uint64]*Fragment)

	return nil
}

// TimeQuantum returns the time quantum for the frame.
func (f *Frame) TimeQuantum() TimeQuantum {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.timeQuantum
}

// SetTimeQuantum sets the time quantum for the frame.
func (f *Frame) SetTimeQuantum(q TimeQuantum) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	// Validate input.
	if !q.Valid() {
		return ErrInvalidTimeQuantum
	}

	// Update value on frame.
	f.timeQuantum = q

	// Persist meta data to disk.
	if err := f.saveMeta(); err != nil {
		return err
	}

	return nil
}

// FragmentPath returns the path to a fragment in the frame.
func (f *Frame) FragmentPath(slice uint64) string {
	return filepath.Join(f.path, strconv.FormatUint(slice, 10))
}

// Fragment returns a fragment in the frame by slice.
func (f *Frame) Fragment(slice uint64) *Fragment {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.fragment(slice)
}

func (f *Frame) fragment(slice uint64) *Fragment { return f.fragments[slice] }

// Fragments returns a list of all fragments in the frame.
func (f *Frame) Fragments() []*Fragment {
	f.mu.Lock()
	defer f.mu.Unlock()

	other := make([]*Fragment, 0, len(f.fragments))
	for _, fragment := range f.fragments {
		other = append(other, fragment)
	}
	return other
}

// CreateFragmentIfNotExists returns a fragment in the frame by slice.
func (f *Frame) CreateFragmentIfNotExists(slice uint64) (*Fragment, error) {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.createFragmentIfNotExists(slice)
}

func (f *Frame) createFragmentIfNotExists(slice uint64) (*Fragment, error) {
	// Find fragment in cache first.
	if frag := f.fragments[slice]; frag != nil {
		return frag, nil
	}

	// Initialize and open fragment.
	frag := f.newFragment(f.FragmentPath(slice), slice)
	if err := frag.Open(); err != nil {
		return nil, err
	}
	frag.BitmapAttrStore = f.bitmapAttrStore

	// Save to lookup.
	f.fragments[slice] = frag

	f.stats.Count("maxSlice", 1)

	return frag, nil
}

func (f *Frame) newFragment(path string, slice uint64) *Fragment {
	frag := NewFragment(path, f.db, f.name, slice)
	frag.stats = f.stats.WithTags(fmt.Sprintf("slice:%d", slice))
	return frag
}

// SetBit sets a bit within the frame.
func (f *Frame) SetBit(bitmapID, profileID uint64) (changed bool, err error) {
	slice := profileID / SliceWidth
	frag, err := f.CreateFragmentIfNotExists(slice)
	if err != nil {
		return changed, err
	}
	return frag.SetBit(bitmapID, profileID)
}

type frameSlice []*Frame

func (p frameSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p frameSlice) Len() int           { return len(p) }
func (p frameSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }

// FrameInfo represents schema information for a frame.
type FrameInfo struct {
	Name string `json:"name"`
}

type frameInfoSlice []*FrameInfo

func (p frameInfoSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p frameInfoSlice) Len() int           { return len(p) }
func (p frameInfoSlice) Less(i, j int) bool { return p[i].Name < p[j].Name }
<|endoftext|>


<commit_before>package parse

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
)

// STATUS xxx, incompelete. need to redo the  parseGIF logic to detect optional chunks, and have a loop

func GIF(file *os.File) *ParsedLayout {

	if !isGIF(file) {
		return nil
	}
	return parseGIF(file)
}

func isGIF(file *os.File) bool {

	file.Seek(0, os.SEEK_SET)
	r := io.Reader(file)
	var b [5]byte
	if err := binary.Read(r, binary.LittleEndian, &b); err != nil {
		return false
	}
	if b[0] != 'G' || b[1] != 'I' || b[2] != 'F' || b[3] != '8' {
		return false
	}
	if b[4] != '7' && b[4] != '9' {
		return false
	}
	return true
}

func parseGIF(file *os.File) *ParsedLayout {

	res := ParsedLayout{}

	res.Layout = append(res.Layout, gifHeader(file))
	res.Layout = append(res.Layout, gifLogicalDescriptor(file))

	// XXX extract to a var
	sizeOfGCT := res.decodeBitfieldFromInfo(file, "size of the global color table")
	fmt.Println(sizeOfGCT)

	gctToLengthMap := map[byte]int64{
		0: 2 * 3,
		1: 4 * 3,
		2: 8 * 3,
		3: 16 * 3,
		4: 32 * 3,
		5: 64 * 3,
		6: 128 * 3,
		7: 256 * 3,
	}

	if gctByteLen, ok := gctToLengthMap[byte(sizeOfGCT)]; ok {

		res.Layout = append(res.Layout, gifGlobalColorTable(file, gctByteLen))
	}

	gfxExt := gifGraphicsControlExtension(file) // // XXX "first byte is extension introducer. All extension blocks begin with 21"
	if gfxExt != nil {
		res.Layout = append(res.Layout, *gfxExt)
	}

	imgDescriptor := gifImageDescriptor(file) // XXX  The first byte is the image separator. Every image descriptor begins with the value 2C.
	if imgDescriptor != nil {
		res.Layout = append(res.Layout, *imgDescriptor)
	}

	localColorTbl := gifLocalColorTable(file) // XXX directly after image descriptor, depending on some flag ???
	if localColorTbl != nil {
		res.Layout = append(res.Layout, *localColorTbl)
	}

	res.Layout = append(res.Layout, gifImageData(file)) // XXX ?

	res.Layout = append(res.Layout, gifTrailer(file)) // XXX value 0x3b

	return &res
}

func gifHeader(file *os.File) Layout {

	return Layout{
		Offset: 0,
		Length: 6,
		Info:   "header",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: 0, Length: 3, Info: "signature", Type: ASCII},
			Layout{Offset: 3, Length: 3, Info: "version", Type: ASCII},
		},
	}
}

func gifTrailer(file *os.File) Layout {
	baseOffset := int64(0x44) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 1,
		Info:   "trailer",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "trailer", Type: Uint8},
		},
	}
	return res
}

func gifImageData(file *os.File) Layout {

	baseOffset := int64(0x2b) // XXX base is unknown ...
	length := int64(25)       // XXX length=

	res := Layout{
		Offset: baseOffset,
		Length: length,
		Info:   "image data",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: length, Info: "image data", Type: Uint8},
		},
	}
	return res
}

func gifImageDescriptor(file *os.File) *Layout {

	baseOffset := int64(0x21) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 10,
		Info:   "image descriptor",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "image separator", Type: Uint8},
			Layout{Offset: baseOffset + 1, Length: 2, Info: "image left", Type: Uint16le},
			Layout{Offset: baseOffset + 3, Length: 2, Info: "image top", Type: Uint16le},
			Layout{Offset: baseOffset + 5, Length: 2, Info: "image width", Type: Uint16le},
			Layout{Offset: baseOffset + 7, Length: 2, Info: "image height", Type: Uint16le},
			Layout{Offset: baseOffset + 9, Length: 1, Info: "packed #3", Type: Uint8},
		},
	}
	return &res
}

func gifGlobalColorTable(file *os.File, byteLen int64) Layout {

	baseOffset := int64(0x0d)

	childs := []Layout{}

	cnt := 0
	for i := int64(0); i < byteLen; i += 3 {
		cnt++
		childs = append(childs, Layout{Offset: baseOffset + i, Length: 3, Info: fmt.Sprintf("color %d", cnt), Type: RGB})
	}

	return Layout{
		Offset: baseOffset,
		Length: byteLen,
		Info:   "global color table",
		Type:   Group,
		Childs: childs,
	}
}

func gifLocalColorTable(file *os.File) *Layout {
	// XXX The local color table would always immediately follow an
	// image descriptor but will only be there if the local color table flag is set to 1

	// XXX not present in sample
	return nil
}

func gifGraphicsControlExtension(file *os.File) *Layout {

	// XXX this is optional, how do we detect if it is there?
	// return nil

	// XXX "first byte is extension introducer. All extension blocks begin with 21"
	// XXX "Finally we have the block terminator which is always 00. "

	baseOffset := int64(0x19) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 8,
		Info:   "gfx control extension",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "extension introducer", Type: Uint8},
			Layout{Offset: baseOffset + 1, Length: 1, Info: "graphic control label", Type: Uint8},
			Layout{Offset: baseOffset + 2, Length: 1, Info: "byte size", Type: Uint8},
			Layout{Offset: baseOffset + 3, Length: 1, Info: "packed #2", Type: Uint8},
			Layout{Offset: baseOffset + 4, Length: 2, Info: "delay time", Type: Uint16le},
			Layout{Offset: baseOffset + 6, Length: 1, Info: "transparent color index", Type: Uint8},
			Layout{Offset: baseOffset + 7, Length: 1, Info: "block terminator", Type: Uint8},
		},
	}
	return &res
}

func gifLogicalDescriptor(file *os.File) Layout {
	base := int64(0x06)
	return Layout{
		Offset: base,
		Length: 7,
		Info:   "logical screen descriptor",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: base, Length: 2, Info: "width", Type: Uint16le},

			Layout{Offset: base + 2, Length: 2, Info: "height", Type: Uint16le},

			// Packed contains the following four subfields of data (bit 0 is the least significant bit, or LSB):
			//    Bits 0-2    Size of the Global Color Table
			//    Bit 3   Color Table Sort Flag
			//    Bits 4-6    Color Resolution

			// XXX bitmask decode bpp and color resolution:
			Layout{Offset: base + 4, Length: 1, Info: "packed", Type: Uint8, Masks: []Mask{
				Mask{Low: 0, Length: 3, Info: "size of the global color table"}, // XXX extract to a var
				Mask{Low: 3, Length: 1, Info: "color table sort flag"},
				Mask{Low: 4, Length: 3, Info: "color resolution"},
				Mask{Low: 7, Length: 1, Info: "reserved xxx"},
			}},

			Layout{Offset: base + 5, Length: 1, Info: "background color", Type: Uint8},

			Layout{Offset: base + 6, Length: 1, Info: "aspect ratio", Type: Uint8},
		},
	}
}
<commit_msg>improve gif decoder<commit_after>package parse

import (
	"encoding/binary"
	"fmt"
	"os"
)

// STATUS xxx, incompelete. need to redo the  parseGIF logic to detect optional chunks, and have a loop

var (
	gctToLengthMap = map[byte]int64{
		0: 2 * 3,
		1: 4 * 3,
		2: 8 * 3,
		3: 16 * 3,
		4: 32 * 3,
		5: 64 * 3,
		6: 128 * 3,
		7: 256 * 3,
	}
)

// Section indicators.
const (
	sExtension       = 0x21
	sImageDescriptor = 0x2C
	sTrailer         = 0x3B
)

func GIF(file *os.File) *ParsedLayout {

	if !isGIF(file) {
		return nil
	}
	return parseGIF(file)
}

func isGIF(file *os.File) bool {

	file.Seek(0, os.SEEK_SET)

	var b [5]byte
	if err := binary.Read(file, binary.LittleEndian, &b); err != nil {
		return false
	}
	if b[0] != 'G' || b[1] != 'I' || b[2] != 'F' || b[3] != '8' {
		return false
	}
	if b[4] != '7' && b[4] != '9' {
		return false
	}
	return true
}

func parseGIF(file *os.File) *ParsedLayout {

	res := ParsedLayout{}

	res.Layout = append(res.Layout, gifHeader(file))
	res.Layout = append(res.Layout, gifLogicalDescriptor(file))

	sizeOfGCT := res.decodeBitfieldFromInfo(file, "size of the global color table")
	if gctByteLen, ok := gctToLengthMap[byte(sizeOfGCT)]; ok {
		res.Layout = append(res.Layout, gifGlobalColorTable(file, gctByteLen))
	}

	for {

		var b byte
		if err := binary.Read(file, binary.LittleEndian, &b); err != nil {
			fmt.Println("error", err)
			return nil
		}

		switch b {
		case sExtension:
			// XXX All extension blocks begin with 21
			gfxExt := gifGraphicsControlExtension(file)
			if gfxExt != nil {
				res.Layout = append(res.Layout, *gfxExt)
			}

		case sImageDescriptor:
			imgDescriptor := gifImageDescriptor(file)
			if imgDescriptor != nil {
				res.Layout = append(res.Layout, *imgDescriptor)
			}

			// XXX directly after image descriptor, depending on some flag ???
			localColorTbl := gifLocalColorTable(file)
			if localColorTbl != nil {
				res.Layout = append(res.Layout, *localColorTbl)
			}
			res.Layout = append(res.Layout, gifImageData(file)) // XXX ?

		case sTrailer:
			res.Layout = append(res.Layout, gifTrailer(file)) // XXX value 0x3b
			return &res
		}
	}
}

func gifHeader(file *os.File) Layout {

	return Layout{
		Offset: 0,
		Length: 6,
		Info:   "header",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: 0, Length: 3, Info: "signature", Type: ASCII},
			Layout{Offset: 3, Length: 3, Info: "version", Type: ASCII},
		},
	}
}

func gifTrailer(file *os.File) Layout {
	baseOffset := int64(0x44) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 1,
		Info:   "trailer",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "trailer", Type: Uint8},
		},
	}
	return res
}

func gifImageData(file *os.File) Layout {

	baseOffset := int64(0x2b) // XXX base is unknown ...
	length := int64(25)       // XXX length=

	res := Layout{
		Offset: baseOffset,
		Length: length,
		Info:   "image data",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: length, Info: "image data", Type: Uint8},
		},
	}
	return res
}

func gifImageDescriptor(file *os.File) *Layout {

	baseOffset := int64(0x21) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 10,
		Info:   "image descriptor",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "image separator", Type: Uint8},
			Layout{Offset: baseOffset + 1, Length: 2, Info: "image left", Type: Uint16le},
			Layout{Offset: baseOffset + 3, Length: 2, Info: "image top", Type: Uint16le},
			Layout{Offset: baseOffset + 5, Length: 2, Info: "image width", Type: Uint16le},
			Layout{Offset: baseOffset + 7, Length: 2, Info: "image height", Type: Uint16le},
			Layout{Offset: baseOffset + 9, Length: 1, Info: "packed #3", Type: Uint8},
		},
	}
	return &res
}

func gifGlobalColorTable(file *os.File, byteLen int64) Layout {

	baseOffset := int64(0x0d)

	childs := []Layout{}

	cnt := 0
	for i := int64(0); i < byteLen; i += 3 {
		cnt++
		childs = append(childs, Layout{Offset: baseOffset + i, Length: 3, Info: fmt.Sprintf("color %d", cnt), Type: RGB})
	}

	return Layout{
		Offset: baseOffset,
		Length: byteLen,
		Info:   "global color table",
		Type:   Group,
		Childs: childs,
	}
}

func gifLocalColorTable(file *os.File) *Layout {
	// XXX The local color table would always immediately follow an
	// image descriptor but will only be there if the local color table flag is set to 1

	// XXX not present in sample
	return nil
}

func gifGraphicsControlExtension(file *os.File) *Layout {

	// XXX this is optional, how do we detect if it is there?
	// return nil

	// XXX "first byte is extension introducer. All extension blocks begin with 21"
	// XXX "Finally we have the block terminator which is always 00. "

	baseOffset := int64(0x19) // XXX base is unknown ...

	res := Layout{
		Offset: baseOffset,
		Length: 8,
		Info:   "gfx control extension",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: baseOffset, Length: 1, Info: "extension introducer", Type: Uint8},
			Layout{Offset: baseOffset + 1, Length: 1, Info: "graphic control label", Type: Uint8},
			Layout{Offset: baseOffset + 2, Length: 1, Info: "byte size", Type: Uint8},
			Layout{Offset: baseOffset + 3, Length: 1, Info: "packed #2", Type: Uint8},
			Layout{Offset: baseOffset + 4, Length: 2, Info: "delay time", Type: Uint16le},
			Layout{Offset: baseOffset + 6, Length: 1, Info: "transparent color index", Type: Uint8},
			Layout{Offset: baseOffset + 7, Length: 1, Info: "block terminator", Type: Uint8},
		},
	}
	return &res
}

func gifLogicalDescriptor(file *os.File) Layout {
	base := int64(0x06)
	return Layout{
		Offset: base,
		Length: 7,
		Info:   "logical screen descriptor",
		Type:   Group,
		Childs: []Layout{
			Layout{Offset: base, Length: 2, Info: "width", Type: Uint16le},

			Layout{Offset: base + 2, Length: 2, Info: "height", Type: Uint16le},

			// Packed contains the following four subfields of data (bit 0 is the least significant bit, or LSB):
			//    Bits 0-2    Size of the Global Color Table
			//    Bit 3   Color Table Sort Flag
			//    Bits 4-6    Color Resolution

			// XXX bitmask decode bpp and color resolution:
			Layout{Offset: base + 4, Length: 1, Info: "packed", Type: Uint8, Masks: []Mask{
				Mask{Low: 0, Length: 3, Info: "size of the global color table"}, // XXX extract to a var
				Mask{Low: 3, Length: 1, Info: "color table sort flag"},
				Mask{Low: 4, Length: 3, Info: "color resolution"},
				Mask{Low: 7, Length: 1, Info: "reserved xxx"},
			}},

			Layout{Offset: base + 5, Length: 1, Info: "background color", Type: Uint8},

			Layout{Offset: base + 6, Length: 1, Info: "aspect ratio", Type: Uint8},
		},
	}
}
<|endoftext|>


<commit_before>package clickhouse

import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/lomik/zapwriter"

	"go.uber.org/zap"
)

var ErrUvarintRead = errors.New("ReadUvarint: Malformed array")
var ErrUvarintOverflow = errors.New("ReadUvarint: varint overflows a 64-bit integer")
var ErrClickHouseResponse = errors.New("Malformed response from clickhouse")

func formatSQL(q string) string {
	s := strings.Split(q, "\n")
	for i := 0; i < len(s); i++ {
		s[i] = strings.TrimSpace(s[i])
	}

	return strings.Join(s, " ")
}

func Escape(s string) string {
	s = strings.Replace(s, `\`, `\\`, -1)
	s = strings.Replace(s, `'`, `\'`, -1)
	return s
}

func Query(ctx context.Context, dsn string, query string, timeout time.Duration) ([]byte, error) {
	return Post(ctx, dsn, query, nil, timeout)
}

func Post(ctx context.Context, dsn string, query string, postBody io.Reader, timeout time.Duration) ([]byte, error) {
	return do(ctx, dsn, query, postBody, false, timeout)
}

func PostGzip(ctx context.Context, dsn string, query string, postBody io.Reader, timeout time.Duration) ([]byte, error) {
	return do(ctx, dsn, query, postBody, true, timeout)
}

func Reader(ctx context.Context, dsn string, query string, timeout time.Duration) (io.ReadCloser, error) {
	return reader(ctx, dsn, query, nil, false, timeout)
}

func reader(ctx context.Context, dsn string, query string, postBody io.Reader, gzip bool, timeout time.Duration) (bodyReader io.ReadCloser, err error) {
	start := time.Now()

	queryForLogger := query
	if len(queryForLogger) > 500 {
		queryForLogger = queryForLogger[:395] + "<...>" + queryForLogger[len(queryForLogger)-100:]
	}
	logger := zapwriter.Logger("query").With(zap.String("query", formatSQL(queryForLogger)))

	defer func() {
		d := time.Since(start)
		log := logger.With(
			zap.Duration("time", d),
		)
		// fmt.Println(time.Since(start), formatSQL(queryForLogger))
		if err != nil {
			log.Error("query", zap.Error(err))
		} else {
			log.Info("query")
		}
	}()

	p, err := url.Parse(dsn)
	if err != nil {
		return
	}

	queryWithRequestID := query
	if requestID, ok := ctx.Value("requestID").(string); ok {
		if strings.Index(requestID, "*/") < 0 { // prevent injection
			queryWithRequestID = fmt.Sprintf("/* id:%s */ %s", requestID, query)
			logger = logger.With(zap.String("request_id", requestID))
		}
	}

	if postBody != nil {
		q := p.Query()
		q.Set("query", queryWithRequestID)
		p.RawQuery = q.Encode()
	} else {
		postBody = strings.NewReader(queryWithRequestID)
	}

	url := p.String()

	req, err := http.NewRequest("POST", url, postBody)
	if err != nil {
		return
	}

	if gzip {
		req.Header.Add("Content-Encoding", "gzip")
	}

	client := &http.Client{Timeout: timeout}
	resp, err := client.Do(req)
	if err != nil {
		return
	}

	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		err = fmt.Errorf("clickhouse response status %d: %s", resp.StatusCode, string(body))
		return
	}

	bodyReader = resp.Body
	return
}

func do(ctx context.Context, dsn string, query string, postBody io.Reader, gzip bool, timeout time.Duration) ([]byte, error) {
	bodyReader, err := reader(ctx, dsn, query, postBody, gzip, timeout)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(bodyReader)
	bodyReader.Close()
	if err != nil {
		return nil, err
	}

	return body, nil
}

func ReadUvarint(array []byte) (uint64, int, error) {
	var x uint64
	var s uint
	l := len(array) - 1
	for i := 0; ; i++ {
		if i > l {
			return x, i + 1, ErrUvarintRead
		}
		if array[i] < 0x80 {
			if i > 9 || i == 9 && array[i] > 1 {
				return x, i + 1, ErrUvarintOverflow
			}
			return x | uint64(array[i])<<s, i + 1, nil
		}
		x |= uint64(array[i]&0x7f) << s
		s += 7
	}
}
<commit_msg>replace comment in clickhouse sql with query id<commit_after>package clickhouse

import (
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/lomik/zapwriter"

	"go.uber.org/zap"
)

var ErrUvarintRead = errors.New("ReadUvarint: Malformed array")
var ErrUvarintOverflow = errors.New("ReadUvarint: varint overflows a 64-bit integer")
var ErrClickHouseResponse = errors.New("Malformed response from clickhouse")

func formatSQL(q string) string {
	s := strings.Split(q, "\n")
	for i := 0; i < len(s); i++ {
		s[i] = strings.TrimSpace(s[i])
	}

	return strings.Join(s, " ")
}

func Escape(s string) string {
	s = strings.Replace(s, `\`, `\\`, -1)
	s = strings.Replace(s, `'`, `\'`, -1)
	return s
}

func Query(ctx context.Context, dsn string, query string, timeout time.Duration) ([]byte, error) {
	return Post(ctx, dsn, query, nil, timeout)
}

func Post(ctx context.Context, dsn string, query string, postBody io.Reader, timeout time.Duration) ([]byte, error) {
	return do(ctx, dsn, query, postBody, false, timeout)
}

func PostGzip(ctx context.Context, dsn string, query string, postBody io.Reader, timeout time.Duration) ([]byte, error) {
	return do(ctx, dsn, query, postBody, true, timeout)
}

func Reader(ctx context.Context, dsn string, query string, timeout time.Duration) (io.ReadCloser, error) {
	return reader(ctx, dsn, query, nil, false, timeout)
}

func reader(ctx context.Context, dsn string, query string, postBody io.Reader, gzip bool, timeout time.Duration) (bodyReader io.ReadCloser, err error) {
	start := time.Now()

	queryForLogger := query
	if len(queryForLogger) > 500 {
		queryForLogger = queryForLogger[:395] + "<...>" + queryForLogger[len(queryForLogger)-100:]
	}
	logger := zapwriter.Logger("query").With(zap.String("query", formatSQL(queryForLogger)))

	defer func() {
		d := time.Since(start)
		log := logger.With(
			zap.Duration("time", d),
		)
		// fmt.Println(time.Since(start), formatSQL(queryForLogger))
		if err != nil {
			log.Error("query", zap.Error(err))
		} else {
			log.Info("query")
		}
	}()

	p, err := url.Parse(dsn)
	if err != nil {
		return
	}

	var b [16]byte
	binary.LittleEndian.PutUint64(b[:], rand.Uint64())
	binary.LittleEndian.PutUint64(b[8:], rand.Uint64())
	queryID := fmt.Sprintf("%x", b)

	var requestID string
	if value, ok := ctx.Value("requestID").(string); ok {
		requestID = value
	}

	q := p.Query()
	q.Set("query_id", fmt.Sprintf("%s::%s", requestID, queryID))
	p.RawQuery = q.Encode()

	if postBody != nil {
		q := p.Query()
		q.Set("query", query)
		p.RawQuery = q.Encode()
	} else {
		postBody = strings.NewReader(query)
	}

	url := p.String()

	req, err := http.NewRequest("POST", url, postBody)
	if err != nil {
		return
	}

	if gzip {
		req.Header.Add("Content-Encoding", "gzip")
	}

	client := &http.Client{Timeout: timeout}
	resp, err := client.Do(req)
	if err != nil {
		return
	}

	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		err = fmt.Errorf("clickhouse response status %d: %s", resp.StatusCode, string(body))
		return
	}

	bodyReader = resp.Body
	return
}

func do(ctx context.Context, dsn string, query string, postBody io.Reader, gzip bool, timeout time.Duration) ([]byte, error) {
	bodyReader, err := reader(ctx, dsn, query, postBody, gzip, timeout)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(bodyReader)
	bodyReader.Close()
	if err != nil {
		return nil, err
	}

	return body, nil
}

func ReadUvarint(array []byte) (uint64, int, error) {
	var x uint64
	var s uint
	l := len(array) - 1
	for i := 0; ; i++ {
		if i > l {
			return x, i + 1, ErrUvarintRead
		}
		if array[i] < 0x80 {
			if i > 9 || i == 9 && array[i] > 1 {
				return x, i + 1, ErrUvarintOverflow
			}
			return x | uint64(array[i])<<s, i + 1, nil
		}
		x |= uint64(array[i]&0x7f) << s
		s += 7
	}
}
<|endoftext|>


<commit_before>// Glide is a command line utility that manages Go project dependencies and
// your GOPATH.
//
// Dependencies are managed via a glide.yaml in the root of a project. The yaml
// file lets you specify projects, versions (tags, branches, or references),
// and even alias one location in as other one. Aliasing is useful when supporting
// forks without needing to rewrite the imports in a codebase.
//
// A glide.yaml file looks like:
//
// 		package: github.com/Masterminds/glide
// 		imports:
//			- package: github.com/Masterminds/cookoo
//			  vcs: git
//			  ref: 1.1.0
//			  subpackages: **
//			- package: github.com/kylelemons/go-gypsy
//			  subpackages: yaml
//
// Glide puts dependencies in a _vendor directory. Go utilities require this to
// be in your GOPATH. Glide makes this easy. Use the `glide in` command to enter
// a shell (your default) with the GOPATH set to the projects _vendor directory.
// To leave this shell simply exit it.
//
// If your .bashrc, .zshrc, or other startup shell sets your GOPATH you many need
// to optionally set it using something like:
//
//		if [ "" = "${GOPATH}" ]; then
//		  export GOPATH="/some/dir"
//		fi
//
// For more information use the `glide help` command or see https://github.com/Masterminds/glide
package main

import (
	"github.com/Masterminds/glide/cmd"

	"github.com/Masterminds/cookoo"
	"github.com/codegangsta/cli"

	"fmt"
	"os"
)

var version string = "0.3.0-dev"

const Summary = "Manage Go projects with ease."
const Usage = `Manage dependencies, naming, and GOPATH for your Go projects.

Each project should have a 'glide.yaml' file in the project directory. Files
look something like this:

	package: github.com/Masterminds/glide
	imports:
		- package: github.com/Masterminds/cookoo
		  vcs: git
		  ref: 1.1.0
		  subpackages: **
  		- package: github.com/kylelemons/go-gypsy
		  subpackages: yaml
`

func main() {
	reg, router, cxt := cookoo.Cookoo()

	routes(reg, cxt)

	app := cli.NewApp()
	app.Name = "glide"
	app.Usage = Usage
	app.Version = version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "yaml, y",
			Value: "glide.yaml",
			Usage: "Set a YAML configuration file.",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "Quiet (no info or debug messages)",
		},
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		cxt.Put("os.Args", os.Args)
		cxt.Put("command", command)
		setupHandler(c, "@plugin", cxt, router)
	}

	app.Commands = commands(cxt, router)

	app.Run(os.Args)
}

func commands(cxt cookoo.Context, router *cookoo.Router) []cli.Command {
	return []cli.Command{
		{
			Name:      "create",
			ShortName: "init",
			Usage:     "Initialize a new project, creating a template glide.yaml",
			Action: func(c *cli.Context) {
				setupHandler(c, "create", cxt, router)
			},
		},
		{
			Name:  "in",
			Usage: "Glide into a commandline shell preconfigured for your project",
			Action: func(c *cli.Context) {
				setupHandler(c, "in", cxt, router)
			},
		},
		{
			Name:  "install",
			Usage: "Install all packages in the glide.yaml",
			Action: func(c *cli.Context) {
				setupHandler(c, "install", cxt, router)
			},
		},
		{
			Name:  "into",
			Usage: "The same as running \"cd /my/project && glide in\"",
			Action: func(c *cli.Context) {
				cxt.Put("toPath", c.Args()[0])
				setupHandler(c, "into", cxt, router)
			},
		},
		{
			Name:  "godeps",
			Usage: "Import Godeps and Godeps-Git files and display the would-be yaml file",
			Action: func(c *cli.Context) {
				setupHandler(c, "godeps", cxt, router)
			},
		},
		{
			Name:  "gopath",
			Usage: "Display the GOPATH for the present project",
			Description: `Emits the GOPATH for the current project. Useful for
   things like manually setting GOPATH: GOPATH=$(glide gopath)`,
			Action: func(c *cli.Context) {
				setupHandler(c, "gopath", cxt, router)
			},
		},
		{
			Name:  "pin",
			Usage: "Print a YAML file with all of the packages pinned to the current version",
			Action: func(c *cli.Context) {
				setupHandler(c, "pin", cxt, router)
			},
		},
		{
			Name:  "rebuild",
			Usage: "Rebuild ('go build') the dependencies",
			Action: func(c *cli.Context) {
				setupHandler(c, "rebuild", cxt, router)
			},
		},
		{
			Name:      "status",
			ShortName: "s",
			Usage:     "Display a status report",
			Action: func(c *cli.Context) {
				setupHandler(c, "status", cxt, router)
			},
		},
		{
			Name:      "update",
			ShortName: "up",
			Usage:     "Update existing packages",
			Action: func(c *cli.Context) {
				setupHandler(c, "update", cxt, router)
			},
		},
		{
			Name:  "guess",
			Usage: "Guess dependencies for existing source.",
			Action: func(c *cli.Context) {
				setupHandler(c, "guess", cxt, router)
			},
		},
	}
}

func setupHandler(c *cli.Context, route string, cxt cookoo.Context, router *cookoo.Router) {
	cxt.Put("q", c.GlobalBool("quiet"))
	cxt.Put("yaml", c.GlobalString("yaml"))
	if err := router.HandleRequest(route, cxt, false); err != nil {
		fmt.Printf("Oops! %s\n", err)
		os.Exit(1)
	}
}

func routes(reg *cookoo.Registry, cxt cookoo.Context) {
	reg.Route("@startup", "Parse args and send to the right subcommand.").
		// TODO: Add setup for debug in addition to quiet.
		Does(cmd.BeQuiet, "quiet").
		Using("quiet").From("cxt:q")

	reg.Route("@ready", "Prepare for glide commands.").
		Does(cmd.ReadyToGlide, "ready").Using("filename").From("cxt:yaml").
		Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml")

	reg.Route("into", "Creates a new Glide shell.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Does(cmd.Into, "in").Using("into").From("cxt:toPath").
		Using("into").WithDefault("").From("cxt:toPath").
		Includes("@ready")

	reg.Route("in", "Set GOPATH and supporting env vars.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Includes("@ready").
		Does(cmd.Into, "in").
		Using("into").WithDefault("").From("cxt:toPath").
		Using("conf").From("cxt:cfg")

	reg.Route("gopath", "Return the GOPATH for the present project.").
		Includes("@startup").
		Does(cmd.In, "gopath")

	reg.Route("install", "Install dependencies.").
		Includes("@startup").
		Does(cmd.InGopath, "pathIsRight").
		Includes("@ready").
		Does(cmd.Mkdir, "dir").Using("dir").WithDefault("_vendor").
		Does(cmd.LinkPackage, "alias").
		Does(cmd.GetImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("update", "Update dependencies.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.UpdateImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("rebuild", "Rebuild dependencies").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("pin", "Print a YAML file with all of the packages pinned to the current version.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("godeps", "Read a Godeps file").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.Godeps, "godeps").
		Does(cmd.AddDependencies, "addGodeps").
		Using("dependencies").From("cxt:godeps").
		Using("conf").From("cxt:cfg").
		Does(cmd.GodepsGit, "godepsGit").
		Does(cmd.AddDependencies, "addGodepsGit").
		Using("dependencies").From("cxt:godepsGit").
		Using("conf").From("cxt:cfg").
		// Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("guess", "Guess dependencies").
		Includes("@ready").
		Does(cmd.GuessDeps, "")

	reg.Route("create", "Initialize Glide").
		Includes("@startup").
		Does(cmd.InitGlide, "init").Using("filename").From("cxt:yaml")

	reg.Route("status", "Status").
		Includes("@startup").
		Does(cmd.Status, "status")

	reg.Route("@plugin", "Try to send to a plugin.").
		Includes("@ready").
		Does(cmd.DropToShell, "plugin").
		Using("command").From("cxt:command")
}
<commit_msg>Minor tabs vs. spaces tweaks in glide.go<commit_after>// Glide is a command line utility that manages Go project dependencies and
// your GOPATH.
//
// Dependencies are managed via a glide.yaml in the root of a project. The yaml
// file lets you specify projects, versions (tags, branches, or references),
// and even alias one location in as other one. Aliasing is useful when supporting
// forks without needing to rewrite the imports in a codebase.
//
// A glide.yaml file looks like:
//
//		package: github.com/Masterminds/glide
//		imports:
//			- package: github.com/Masterminds/cookoo
//			  vcs: git
//			  ref: 1.1.0
//			  subpackages: **
//			- package: github.com/kylelemons/go-gypsy
//			  subpackages: yaml
//
// Glide puts dependencies in a _vendor directory. Go utilities require this to
// be in your GOPATH. Glide makes this easy. Use the `glide in` command to enter
// a shell (your default) with the GOPATH set to the projects _vendor directory.
// To leave this shell simply exit it.
//
// If your .bashrc, .zshrc, or other startup shell sets your GOPATH you many need
// to optionally set it using something like:
//
//		if [ "" = "${GOPATH}" ]; then
//		  export GOPATH="/some/dir"
//		fi
//
// For more information use the `glide help` command or see https://github.com/Masterminds/glide
package main

import (
	"github.com/Masterminds/glide/cmd"

	"github.com/Masterminds/cookoo"
	"github.com/codegangsta/cli"

	"fmt"
	"os"
)

var version string = "0.3.0-dev"

const Summary = "Manage Go projects with ease."
const Usage = `Manage dependencies, naming, and GOPATH for your Go projects.

Each project should have a 'glide.yaml' file in the project directory. Files
look something like this:

	package: github.com/Masterminds/glide
	imports:
		- package: github.com/Masterminds/cookoo
		  vcs: git
		  ref: 1.1.0
		  subpackages: **
		- package: github.com/kylelemons/go-gypsy
		  subpackages: yaml
`

func main() {
	reg, router, cxt := cookoo.Cookoo()

	routes(reg, cxt)

	app := cli.NewApp()
	app.Name = "glide"
	app.Usage = Usage
	app.Version = version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "yaml, y",
			Value: "glide.yaml",
			Usage: "Set a YAML configuration file.",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "Quiet (no info or debug messages)",
		},
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		cxt.Put("os.Args", os.Args)
		cxt.Put("command", command)
		setupHandler(c, "@plugin", cxt, router)
	}

	app.Commands = commands(cxt, router)

	app.Run(os.Args)
}

func commands(cxt cookoo.Context, router *cookoo.Router) []cli.Command {
	return []cli.Command{
		{
			Name:      "create",
			ShortName: "init",
			Usage:     "Initialize a new project, creating a template glide.yaml",
			Action: func(c *cli.Context) {
				setupHandler(c, "create", cxt, router)
			},
		},
		{
			Name:  "in",
			Usage: "Glide into a commandline shell preconfigured for your project",
			Action: func(c *cli.Context) {
				setupHandler(c, "in", cxt, router)
			},
		},
		{
			Name:  "install",
			Usage: "Install all packages in the glide.yaml",
			Action: func(c *cli.Context) {
				setupHandler(c, "install", cxt, router)
			},
		},
		{
			Name:  "into",
			Usage: "The same as running \"cd /my/project && glide in\"",
			Action: func(c *cli.Context) {
				cxt.Put("toPath", c.Args()[0])
				setupHandler(c, "into", cxt, router)
			},
		},
		{
			Name:  "godeps",
			Usage: "Import Godeps and Godeps-Git files and display the would-be yaml file",
			Action: func(c *cli.Context) {
				setupHandler(c, "godeps", cxt, router)
			},
		},
		{
			Name:  "gopath",
			Usage: "Display the GOPATH for the present project",
			Description: `Emits the GOPATH for the current project. Useful for
   things like manually setting GOPATH: GOPATH=$(glide gopath)`,
			Action: func(c *cli.Context) {
				setupHandler(c, "gopath", cxt, router)
			},
		},
		{
			Name:  "pin",
			Usage: "Print a YAML file with all of the packages pinned to the current version",
			Action: func(c *cli.Context) {
				setupHandler(c, "pin", cxt, router)
			},
		},
		{
			Name:  "rebuild",
			Usage: "Rebuild ('go build') the dependencies",
			Action: func(c *cli.Context) {
				setupHandler(c, "rebuild", cxt, router)
			},
		},
		{
			Name:      "status",
			ShortName: "s",
			Usage:     "Display a status report",
			Action: func(c *cli.Context) {
				setupHandler(c, "status", cxt, router)
			},
		},
		{
			Name:      "update",
			ShortName: "up",
			Usage:     "Update existing packages",
			Action: func(c *cli.Context) {
				setupHandler(c, "update", cxt, router)
			},
		},
		{
			Name:  "guess",
			Usage: "Guess dependencies for existing source.",
			Action: func(c *cli.Context) {
				setupHandler(c, "guess", cxt, router)
			},
		},
	}
}

func setupHandler(c *cli.Context, route string, cxt cookoo.Context, router *cookoo.Router) {
	cxt.Put("q", c.GlobalBool("quiet"))
	cxt.Put("yaml", c.GlobalString("yaml"))
	if err := router.HandleRequest(route, cxt, false); err != nil {
		fmt.Printf("Oops! %s\n", err)
		os.Exit(1)
	}
}

func routes(reg *cookoo.Registry, cxt cookoo.Context) {
	reg.Route("@startup", "Parse args and send to the right subcommand.").
		// TODO: Add setup for debug in addition to quiet.
		Does(cmd.BeQuiet, "quiet").
		Using("quiet").From("cxt:q")

	reg.Route("@ready", "Prepare for glide commands.").
		Does(cmd.ReadyToGlide, "ready").Using("filename").From("cxt:yaml").
		Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml")

	reg.Route("into", "Creates a new Glide shell.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Does(cmd.Into, "in").Using("into").From("cxt:toPath").
		Using("into").WithDefault("").From("cxt:toPath").
		Includes("@ready")

	reg.Route("in", "Set GOPATH and supporting env vars.").
		Includes("@startup").
		Does(cmd.AlreadyGliding, "isGliding").
		Includes("@ready").
		Does(cmd.Into, "in").
		Using("into").WithDefault("").From("cxt:toPath").
		Using("conf").From("cxt:cfg")

	reg.Route("gopath", "Return the GOPATH for the present project.").
		Includes("@startup").
		Does(cmd.In, "gopath")

	reg.Route("install", "Install dependencies.").
		Includes("@startup").
		Does(cmd.InGopath, "pathIsRight").
		Includes("@ready").
		Does(cmd.Mkdir, "dir").Using("dir").WithDefault("_vendor").
		Does(cmd.LinkPackage, "alias").
		Does(cmd.GetImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("update", "Update dependencies.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.UpdateImports, "dependencies").Using("conf").From("cxt:cfg").
		Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("rebuild", "Rebuild dependencies").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.CowardMode, "_").
		Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")

	reg.Route("pin", "Print a YAML file with all of the packages pinned to the current version.").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("godeps", "Read a Godeps file").
		Includes("@startup").
		Includes("@ready").
		Does(cmd.Godeps, "godeps").
		Does(cmd.AddDependencies, "addGodeps").
		Using("dependencies").From("cxt:godeps").
		Using("conf").From("cxt:cfg").
		Does(cmd.GodepsGit, "godepsGit").
		Does(cmd.AddDependencies, "addGodepsGit").
		Using("dependencies").From("cxt:godepsGit").
		Using("conf").From("cxt:cfg").
		// Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
		Does(cmd.MergeToYaml, "merged").Using("conf").From("cxt:cfg").
		Does(cmd.WriteYaml, "out").Using("yaml.Node").From("cxt:merged")

	reg.Route("guess", "Guess dependencies").
		Includes("@ready").
		Does(cmd.GuessDeps, "")

	reg.Route("create", "Initialize Glide").
		Includes("@startup").
		Does(cmd.InitGlide, "init").Using("filename").From("cxt:yaml")

	reg.Route("status", "Status").
		Includes("@startup").
		Does(cmd.Status, "status")

	reg.Route("@plugin", "Try to send to a plugin.").
		Includes("@ready").
		Does(cmd.DropToShell, "plugin").
		Using("command").From("cxt:command")
}
<|endoftext|>


<commit_before>/*
Package gobbr provides a wrapper interface around the Boolberry
daemon and wallet RPC interfaces.

Example use:

 bbr := gobbr.NewDaemon("http://localhost:10102")
 bh, err := d.GetBlockHeaderByHeight(1)
 if err == nil {
         fmt.Printf("Block %d has timestamp %d\n", bh.Height, bh.Timestamp)
 }

This package is still under development and many features are not yet
supported.  Interfaces may change at any time.
*/

package gobbr

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	Multiplier = (1e12)
	TransferFee = 100000000  /* in uint64 units */
)

type JsonResponse struct {
	Id      int    `json:"id"`
	Jsonrpc string `json:"jsonrpc"`
}

func ReadPostQuery(url string, data []byte) ([]byte, error) {
	rd := bytes.NewReader(data)
	resp, err := http.Post(url, "application/json", rd)
	if err != nil {
		return nil, err
	}
	response_body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	resp.Body.Close()
	return response_body, nil
}

func DoJSONQuery(url string, dest interface{}, args map[string]interface{}) error {
	args["jsonrpc"] = "2.0"
	jsonbuf, err := json.Marshal(args)
	if err != nil {
		fmt.Println("error on marshal: ", err)
		os.Exit(-1)
	}
	response_body, err := ReadPostQuery(url, jsonbuf)
	if err != nil {
		return err
	}
	err = json.Unmarshal(response_body, &dest)
	if err != nil {
		return err
	}
	return nil
}

type Daemon struct {
	address string
}

func NewDaemon(address string) *Daemon {
	/* Todo:  Connect and keep connection cached */
	d := &Daemon{address}
	return d
}

type Wallet struct {
	address string
}

func NewWallet(address string) *Wallet {
	/* Todo:  Connect and keep connection cached */
	d := &Wallet{address}
	return d
}

func (d *Daemon) DoJSONQuery(dest interface{}, args map[string]interface{}) error {
	return DoJSONQuery(d.address+"/json_rpc", dest, args)
}

func (w *Wallet) DoJSONQuery(dest interface{}, args map[string]interface{}) error {
	return DoJSONQuery(w.address+"/json_rpc", dest, args)
}

/*
 * Queries about the blockchain
 */

type BlockHeader struct {
	Timestamp uint64 `json:"timestamp"`
	Height    uint64 `json:"height"`
	/* INCOMPLETE */
}

type GetBlockHeaderResponse struct {
	JsonResponse
	Result struct {
		Status      string      `json:"status"`
		BlockHeader BlockHeader `json:"block_header"`
	}
}

type QueryBlockHeader struct {
	Height uint64 `json:"height"`
}

func (d *Daemon) GetBlockHeaderByHeight(height uint64) (bh BlockHeader, err error) {
	var resp GetBlockHeaderResponse
	err = d.DoJSONQuery(&resp, map[string]interface{}{
		"method": "getblockheaderbyheight",
		"params": &QueryBlockHeader{height},
	})
	return resp.Result.BlockHeader, err

}

/*
 * Wallet queries
 */

type Balance struct {
	Balance         uint64 `json:"balance"`
	UnlockedBalance uint64 `json:"unlocked_balance"`
}

type BalanceResponse struct {
	JsonResponse
	Result Balance `json:"result"`
}

func (w *Wallet) GetBalance() (balance Balance, err error) {
	var resp BalanceResponse
	err = w.DoJSONQuery(&resp, map[string]interface{}{
		"method": "getbalance",
	})
	return resp.Result, err
}

type TransferDestination struct {
	Amount uint64 `json:"amount"`
	Address string `json:"address"`
}

type Transfer struct {
	Destinations []TransferDestination `json:"destinations"`
	Fee uint64 `json:"fee"`
	Mixin uint64 `json:"mixin"`
	UnlockTime uint64 `json:"unlock_time"`
	PaymentId string `json:"payment_id_hex"`
}

type TransferResponse struct {
	JsonResponse
	Result struct {
		TxHash string `json:"tx_hash"`
	} `json:"result"`
}

func (w *Wallet) Transfer(destination string, amount uint64, mixinCount uint64, paymentId string) (txid string, err error) {
	var resp TransferResponse
	var req = &Transfer{}
	req.Destinations = []TransferDestination{ TransferDestination{amount, destination}}
	req.Fee = TransferFee
	req.Mixin = mixinCount
	req.UnlockTime = 0
	req.PaymentId = paymentId /* must be hex string */

	err = w.DoJSONQuery(&resp, map[string]interface{}{
		"method": "transfer",
		"params":req,
	})

	return resp.Result.TxHash, err
}<commit_msg>Adding listpayments API.  Now is a good time to go work on the error handling before adding more functions.<commit_after>/*
Package gobbr provides a wrapper interface around the Boolberry
daemon and wallet RPC interfaces.

Example use:

 bbr := gobbr.NewDaemon("http://localhost:10102")
 bh, err := d.GetBlockHeaderByHeight(1)
 if err == nil {
         fmt.Printf("Block %d has timestamp %d\n", bh.Height, bh.Timestamp)
 }

This package is still under development and many features are not yet
supported.  Interfaces may change at any time.
*/

package gobbr

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	Multiplier = (1e12)
	TransferFee = 100000000  /* in uint64 units */
)

type JsonResponse struct {
	Id      int    `json:"id"`
	Jsonrpc string `json:"jsonrpc"`
}

func ReadPostQuery(url string, data []byte) ([]byte, error) {
	rd := bytes.NewReader(data)
	resp, err := http.Post(url, "application/json", rd)
	if err != nil {
		return nil, err
	}
	response_body, err := ioutil.ReadAll(resp.Body)
	fmt.Println("responsebody: ", string(response_body))
	if err != nil {
		return nil, err
	}
	resp.Body.Close()
	return response_body, nil
}

func DoJSONQuery(url string, dest interface{}, args map[string]interface{}) error {
	args["jsonrpc"] = "2.0"
	jsonbuf, err := json.Marshal(args)
	if err != nil {
		fmt.Println("error on marshal: ", err)
		os.Exit(-1)
	}
	response_body, err := ReadPostQuery(url, jsonbuf)
	if err != nil {
		return err
	}
	err = json.Unmarshal(response_body, &dest)
	if err != nil {
		return err
	}
	return nil
}

type Daemon struct {
	address string
}

func NewDaemon(address string) *Daemon {
	/* Todo:  Connect and keep connection cached */
	d := &Daemon{address}
	return d
}

type Wallet struct {
	address string
}

func NewWallet(address string) *Wallet {
	/* Todo:  Connect and keep connection cached */
	d := &Wallet{address}
	return d
}

func (d *Daemon) DoJSONQuery(dest interface{}, args map[string]interface{}) error {
	return DoJSONQuery(d.address+"/json_rpc", dest, args)
}

func (w *Wallet) DoJSONQuery(dest interface{}, args map[string]interface{}) error {
	return DoJSONQuery(w.address+"/json_rpc", dest, args)
}

/*
 * Queries about the blockchain
 */

type BlockHeader struct {
	Timestamp uint64 `json:"timestamp"`
	Height    uint64 `json:"height"`
	/* INCOMPLETE */
}

type GetBlockHeaderResponse struct {
	JsonResponse
	Result struct {
		Status      string      `json:"status"`
		BlockHeader BlockHeader `json:"block_header"`
	}
}

type QueryBlockHeader struct {
	Height uint64 `json:"height"`
}

func (d *Daemon) GetBlockHeaderByHeight(height uint64) (bh BlockHeader, err error) {
	var resp GetBlockHeaderResponse
	err = d.DoJSONQuery(&resp, map[string]interface{}{
		"method": "getblockheaderbyheight",
		"params": &QueryBlockHeader{height},
	})
	return resp.Result.BlockHeader, err

}

/*
 * Wallet queries
 */

type Balance struct {
	Balance         uint64 `json:"balance"`
	UnlockedBalance uint64 `json:"unlocked_balance"`
}

type BalanceResponse struct {
	JsonResponse
	Result Balance `json:"result"`
}

func (w *Wallet) GetBalance() (balance Balance, err error) {
	var resp BalanceResponse
	err = w.DoJSONQuery(&resp, map[string]interface{}{
		"method": "getbalance",
	})
	return resp.Result, err
}

type TransferDestination struct {
	Amount uint64 `json:"amount"`
	Address string `json:"address"`
}

type Transfer struct {
	Destinations []TransferDestination `json:"destinations"`
	Fee uint64 `json:"fee"`
	Mixin uint64 `json:"mixin"`
	UnlockTime uint64 `json:"unlock_time"`
	PaymentId string `json:"payment_id_hex"`
}

type TransferResponse struct {
	JsonResponse
	Result struct {
		TxHash string `json:"tx_hash"`
	} `json:"result"`
}

func (w *Wallet) Transfer(destination string, amount uint64, mixinCount uint64, paymentId string) (txid string, err error) {
	var resp TransferResponse
	var req = &Transfer{}
	req.Destinations = []TransferDestination{ TransferDestination{amount, destination}}
	req.Fee = TransferFee
	req.Mixin = mixinCount
	req.UnlockTime = 0
	req.PaymentId = paymentId /* must be hex string */

	err = w.DoJSONQuery(&resp, map[string]interface{}{
		"method": "transfer",
		"params":req,
	})

	return resp.Result.TxHash, err
}

type PaymentDetails struct {
	TxHash string `json:"tx_hash"`
	Amount uint64 `json:"amount"`
	BlockHeight uint64 `json:"block_height"`
	UnlockTime uint64 `json:"unlock_time"`
}

type PaymentsResponse struct {
	JsonResponse
	Result struct {
		Payments []PaymentDetails `json:"payments"`
	}
}

type PaymentsRequest struct {
	PaymentId string `json:"payment_id"`
}

func (w *Wallet) GetPayments(paymentId string) (payments []PaymentDetails, err error) {
	var resp PaymentsResponse
	var req PaymentsRequest
	req.PaymentId = paymentId
	err = w.DoJSONQuery(&resp, map[string]interface{}{
		"method": "get_payments",
		"params":req,
	})
	//fmt.Println("Resp: ", resp)
	return resp.Result.Payments, err
}

/*
 * Known bugs tracking:
 * -- Functions need to check error field returned in JSON and map those back to
 *    a golang error
 * -- GetPayments is mostly untested because the API call needs a payment ID
 *
 * Todo tracking:
 * -- Add support for some of the "info" outputs from the daemon -- those
 *    would make for nice sample apps for, e.g., showing network state.
 */<|endoftext|>


<commit_before>//Package gobcy implements a wrapper for the http://www.blockcypher.com API.
//You can use it to interact with addresses, transactions, and blocks from
//various blockchains, including Bitcoin's main and test3 chains,
//and the BlockCypher test chain.

//Please note: we assume you use are using a 64-bit architecture for deployment,
//which automatically makes `int` types 64-bit. Without 64-bit ints, some values
//might overflow on certain calls, depending on the blockchain you are querying.
//If you are using a 32-bit system, you can change all `int` types to `int64` to
//explicitly work around this issue.
package gobcy

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/url"
)

const baseURL = "https://api.blockcypher.com/v1/"

//API stores your BlockCypher Token, and the coin/chain
//you're querying. Coins can be "btc","bcy","ltc", and "doge".
//Chains can be "main", "test3", or "test", depending on the Coin.
//Check http://dev.blockcypher.com/ for more information.
//All your credentials are stored within an API struct, as are
//many of the API methods.
//You can allocate an API struct like so:
//	bc = gobcy.API{"your-api-token","btc","main"}
//Then query as you like:
//	chain = bc.GetChain()
type API struct {
	Token, Coin, Chain string
}

//getResponse is a boilerplate for HTTP GET responses.
func getResponse(target *url.URL) (resp *http.Response, err error) {
	resp, err = http.Get(target.String())
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//postResponse is a boilerplate for HTTP POST responses.
func postResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	resp, err = http.Post(target.String(), "application/json", data)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//putResponse is a boilerplate for HTTP PUT responses.
func putResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("PUT", target.String(), data)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//deleteResponse is a boilerplate for HTTP DELETE responses.
func deleteResponse(target *url.URL) (resp *http.Response, err error) {
	req, err := http.NewRequest("DELETE", target.String(), nil)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//constructs BlockCypher URLs for requests
func (api *API) buildURL(u string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	//add token to url, if present
	if api.Token != "" {
		values := target.Query()
		values.Set("token", api.Token)
		target.RawQuery = values.Encode()
	}
	return
}

//constructs BlockCypher URLs with parameters for requests
func (api *API) buildURLParams(u string, params map[string]string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	values := target.Query()
	//Set parameters
	for k, v := range params {
		values.Set(k, v)
	}
	//add token to url, if present
	if api.Token != "" {
		values.Set("token", api.Token)
	}
	target.RawQuery = values.Encode()
	return
}
<commit_msg>missing comment line<commit_after>//Package gobcy implements a wrapper for the http://www.blockcypher.com API.
//You can use it to interact with addresses, transactions, and blocks from
//various blockchains, including Bitcoin's main and test3 chains,
//and the BlockCypher test chain.
//
//Please note: we assume you use are using a 64-bit architecture for deployment,
//which automatically makes `int` types 64-bit. Without 64-bit ints, some values
//might overflow on certain calls, depending on the blockchain you are querying.
//If you are using a 32-bit system, you can change all `int` types to `int64` to
//explicitly work around this issue.
package gobcy

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/url"
)

const baseURL = "https://api.blockcypher.com/v1/"

//API stores your BlockCypher Token, and the coin/chain
//you're querying. Coins can be "btc","bcy","ltc", and "doge".
//Chains can be "main", "test3", or "test", depending on the Coin.
//Check http://dev.blockcypher.com/ for more information.
//All your credentials are stored within an API struct, as are
//many of the API methods.
//You can allocate an API struct like so:
//	bc = gobcy.API{"your-api-token","btc","main"}
//Then query as you like:
//	chain = bc.GetChain()
type API struct {
	Token, Coin, Chain string
}

//getResponse is a boilerplate for HTTP GET responses.
func getResponse(target *url.URL) (resp *http.Response, err error) {
	resp, err = http.Get(target.String())
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//postResponse is a boilerplate for HTTP POST responses.
func postResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	resp, err = http.Post(target.String(), "application/json", data)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//putResponse is a boilerplate for HTTP PUT responses.
func putResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("PUT", target.String(), data)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//deleteResponse is a boilerplate for HTTP DELETE responses.
func deleteResponse(target *url.URL) (resp *http.Response, err error) {
	req, err := http.NewRequest("DELETE", target.String(), nil)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//constructs BlockCypher URLs for requests
func (api *API) buildURL(u string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	//add token to url, if present
	if api.Token != "" {
		values := target.Query()
		values.Set("token", api.Token)
		target.RawQuery = values.Encode()
	}
	return
}

//constructs BlockCypher URLs with parameters for requests
func (api *API) buildURLParams(u string, params map[string]string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	values := target.Query()
	//Set parameters
	for k, v := range params {
		values.Set(k, v)
	}
	//add token to url, if present
	if api.Token != "" {
		values.Set("token", api.Token)
	}
	target.RawQuery = values.Encode()
	return
}
<|endoftext|>


<commit_before>package gobls

const DefaultBufferSize = 16 * 1024

// Scanner provides an interface for reading newline-delimited lines
// of text. It is similar to `bufio.Scanner`, but wraps
// `bufio.ReadLine` so lines of arbitrary length can be
// scanned. Successive calls to the Scan method will step through the
// lines of a file, skipping the newline whitespace between lines.
//
// Scanning stops unrecoverably at EOF, or at the first I/O
// error. Unlike `bufio.Scanner`, howver, attempting to scan a line
// longer than `bufio.MaxScanTokenSize` will not result in an error,
// but will return the long line.
//
// It is not necessary to check for errors by calling the Err method
// until after scanning stops, when the Scan method returns false.
type Scanner interface {
	Bytes() []byte
	Err() error
	Scan() bool
	Text() string
}
<commit_msg>golint<commit_after>package gobls

// DefaultBufferSize specifies the initial bytes size each gobls scanner will allocate to be used
// for aggregation of line fragments.
const DefaultBufferSize = 16 * 1024

// Scanner provides an interface for reading newline-delimited lines
// of text. It is similar to `bufio.Scanner`, but wraps
// `bufio.ReadLine` so lines of arbitrary length can be
// scanned. Successive calls to the Scan method will step through the
// lines of a file, skipping the newline whitespace between lines.
//
// Scanning stops unrecoverably at EOF, or at the first I/O
// error. Unlike `bufio.Scanner`, howver, attempting to scan a line
// longer than `bufio.MaxScanTokenSize` will not result in an error,
// but will return the long line.
//
// It is not necessary to check for errors by calling the Err method
// until after scanning stops, when the Scan method returns false.
type Scanner interface {
	Bytes() []byte
	Err() error
	Scan() bool
	Text() string
}
<|endoftext|>


<commit_before>//一个简单的生成错误的帮助类
package goerr

import (
	"bytes"
	"fmt"
	"strconv"
)

// new errorContext with error and string
//
// return error
func Errorf(err error, format string, p ...interface{}) error {
	return &errorContext{text: fmt.Sprintf(format, p...), err: err, code: -1}
}

// new errorContext with error
//
//  return  error
func Error(err error) *errorContext {
	return &errorContext{err: err, code: -1}
}

// new errorContext with string
func String(format string, p ...interface{}) *errorContext {
	return &errorContext{text: fmt.Sprintf(format, p...), code: -1}
}

//new error
type errorContext struct {
	code int
	text string
	file string
	line int
	err  error
}

func (e *errorContext) Format(format string, p ...interface{}) *errorContext {
	e.text = fmt.Sprintf(format, p...)
	return e
}
func (e *errorContext) Code(code int) *errorContext {
	e.code = code
	return e
}
func (e *errorContext) Line(line int) *errorContext {
	e.line = line
	return e
}
func (e *errorContext) File(file string) *errorContext {
	e.file = file
	return e
}

//实现error接口
func (e *errorContext) Error() string {
	var buffer bytes.Buffer
	if e.file != "" {
		buffer.WriteString("File: ")
		buffer.WriteString(e.file)
		buffer.WriteString("\t")
	}
	if e.line != -1 {
		bs := strconv.AppendInt(nil, int64(e.line), 10)
		buffer.WriteString("Line: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.code != 0 {
		bs := strconv.AppendInt(nil, int64(e.code), 10)
		buffer.WriteString("Error Code: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.text != "" {
		buffer.WriteString("Text: ")
		buffer.WriteString(e.text)
		buffer.WriteString("\t")
	}
	if e.err != nil {
		buffer.WriteString("\nTrace: ")
		buffer.WriteString(e.err.Error())
	}
	return buffer.String()
}
<commit_msg>new error<commit_after>//一个简单的生成错误的帮助类
package goerr

import (
	"bytes"
	"fmt"
	"strconv"
)

// new errorContext with error and string
//
// return error
func Errorf(err error, format string, p ...interface{}) error {
	return &errorContext{text: fmt.Sprintf(format, p...), err: err, line: -1}
}

// new errorContext with error
//
//  return  error
func Error(err error) *errorContext {
	return &errorContext{err: err, line: -1}
}

// new errorContext with string
func String(format string, p ...interface{}) *errorContext {
	return &errorContext{text: fmt.Sprintf(format, p...), line: -1}
}

//new error
type errorContext struct {
	code int
	text string
	file string
	line int
	err  error
}

func (e *errorContext) Format(format string, p ...interface{}) *errorContext {
	e.text = fmt.Sprintf(format, p...)
	return e
}
func (e *errorContext) Code(code int) *errorContext {
	e.code = code
	return e
}
func (e *errorContext) Line(line int) *errorContext {
	e.line = line
	return e
}
func (e *errorContext) File(file string) *errorContext {
	e.file = file
	return e
}

// trace error message
func (e *errorContext) Trace() string {
	var buffer bytes.Buffer
	if e.file != "" {
		buffer.WriteString("File: ")
		buffer.WriteString(e.file)
		buffer.WriteRune('\t')
	}
	if e.line != -1 {
		bs := strconv.AppendInt(nil, int64(e.line), 10)
		buffer.WriteString("Line: ")
		buffer.Write(bs)
		buffer.WriteRune('\t')
	}
	if e.code != 0 {
		bs := strconv.AppendInt(nil, int64(e.code), 10)
		buffer.WriteString("Error Code: ")
		buffer.Write(bs)
		buffer.WriteRune('\t')
	}
	if e.text != "" {
		buffer.WriteString("Text: ")
		buffer.WriteString(e.text)
		buffer.WriteRune('\t')
	}
	if e.err != nil {
		buffer.WriteString("\nTrace: ")
		buffer.WriteRune('\t')
	}
	return buffer.String()
}

//实现error接口
func (e *errorContext) Error() string {
	if e.text != "" {
		return e.text
	} else if e.err != nil {
		return e.err.Error()
	} else {
		return e.Trace()
	}
}
<|endoftext|>


<commit_before>//一个简单的生成错误的帮助类
package goerr

import (
	"bytes"
	"fmt"
	"strconv"
)

// return new error
//
// return error
func NewError(err error, format string, p ...interface{}) error {
	return &errorContext{text: fmt.Sprintf(format, p...), err: err, code: -1}
}

// return new error
//
//  return  error
func New(err error) *errorContext {
	return &errorContext{err: err, code: -1}
}

//new error
type errorContext struct {
	code int
	text string
	file string
	line int
	err  error
}

func (e *errorContext) Format(format string, p ...interface{}) *errorContext {
	e.text = fmt.Sprintf(format, p...)
	return e
}
func (e *errorContext) Code(code int) *errorContext {
	e.code = code
	return e
}
func (e *errorContext) Line(line int) *errorContext {
	e.line = line
	return e
}
func (e *errorContext) File(file string) *errorContext {
	e.file = file
	return e
}

//实现error接口
func (e *errorContext) Error() string {
	var buffer bytes.Buffer
	if e.file != "" {
		buffer.WriteString("File: ")
		buffer.WriteString(e.file)
		buffer.WriteString("\t")
	}
	if e.line != -1 {
		bs := strconv.AppendInt(nil, int64(e.line), 10)
		buffer.WriteString("Line: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.code != 0 {
		bs := strconv.AppendInt(nil, int64(e.code), 10)
		buffer.WriteString("Error Code: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.text != "" {
		buffer.WriteString("Text: ")
		buffer.WriteString(e.text)
		buffer.WriteString("\t")
	}
	buffer.WriteString("\nTrace: ")
	buffer.WriteString(e.err.Error())
	return buffer.String()
}
<commit_msg>new error<commit_after>//一个简单的生成错误的帮助类
package goerr

import (
	"bytes"
	"fmt"
	"strconv"
)

// new errorContext with error and string
//
// return error
func Errorf(err error, format string, p ...interface{}) error {
	return &errorContext{text: fmt.Sprintf(format, p...), err: err, code: -1}
}

// new errorContext with error
//
//  return  error
func Error(err error) *errorContext {
	return &errorContext{err: err, code: -1}
}

// new errorContext with string
func String(format string, p ...interface{}) *errorContext {
	return &errorContext{text: fmt.Sprintf(format, p...), code: -1}
}

//new error
type errorContext struct {
	code int
	text string
	file string
	line int
	err  error
}

func (e *errorContext) Format(format string, p ...interface{}) *errorContext {
	e.text = fmt.Sprintf(format, p...)
	return e
}
func (e *errorContext) Code(code int) *errorContext {
	e.code = code
	return e
}
func (e *errorContext) Line(line int) *errorContext {
	e.line = line
	return e
}
func (e *errorContext) File(file string) *errorContext {
	e.file = file
	return e
}

//实现error接口
func (e *errorContext) Error() string {
	var buffer bytes.Buffer
	if e.file != "" {
		buffer.WriteString("File: ")
		buffer.WriteString(e.file)
		buffer.WriteString("\t")
	}
	if e.line != -1 {
		bs := strconv.AppendInt(nil, int64(e.line), 10)
		buffer.WriteString("Line: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.code != 0 {
		bs := strconv.AppendInt(nil, int64(e.code), 10)
		buffer.WriteString("Error Code: ")
		buffer.Write(bs)
		buffer.WriteString("\t")
	}
	if e.text != "" {
		buffer.WriteString("Text: ")
		buffer.WriteString(e.text)
		buffer.WriteString("\t")
	}
	buffer.WriteString("\nTrace: ")
	buffer.WriteString(e.err.Error())
	return buffer.String()
}
<|endoftext|>


<commit_before>package main

import (
	// stdlib
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"text/template"

	// external
	"github.com/russross/blackfriday"
)

var (
	config Config
)

type Config struct {
	Port int
	Host string
}

type Page struct {
	Title string
	Body  string
}

func init() {
	flag.IntVar(&config.Port, "port", 4567, "Bind port (default: 4567)")
	flag.StringVar(&config.Host, "host", "0.0.0.0", "Hostname or IP address to listen on (default: 0.0.0.0)")
}

func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, []byte(p.Body), 0600)
}

func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: string(body)}, nil
}

func processLinks(content []byte) []byte {
	re := regexp.MustCompile(`\[(.*)\]\(\)`)
	return re.ReplaceAll(content, []byte("[$1]($1)"))
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content)
	content = blackfriday.MarkdownCommon(content)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
	body := r.FormValue("body")
	p := &Page{Title: title, Body: body}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html"))

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		m := validPath.FindStringSubmatch(r.URL.Path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func main() {
	flag.Parse()
	http.Handle("/static/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))

	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
	if err != nil {
		log.Fatal(err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<commit_msg>Add configuration option for page data directory<commit_after>package main

import (
	// stdlib
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"path/filepath"
	"regexp"
	"text/template"

	// external
	"github.com/russross/blackfriday"
)

var (
	config Config
)

type Config struct {
	Port    int
	Host    string
	DataDir string
}

type Page struct {
	Title string
	Body  string
}

func init() {
	flag.IntVar(&config.Port, "port", 4567, "Bind port")
	flag.StringVar(&config.Host, "host", "0.0.0.0", "Hostname or IP address to listen on")
	flag.StringVar(&config.DataDir, "data-dir", "./data", "Directory for page data")
}

func (p *Page) save() error {
	filename := buildFilename(p.Title)
	return ioutil.WriteFile(filename, []byte(p.Body), 0600)
}

func buildFilename(title string) string {
	return filepath.Join(config.DataDir, (title + ".txt"))
}

func loadPage(title string) (*Page, error) {
	filename := buildFilename(title)
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: string(body)}, nil
}

func processLinks(content []byte) []byte {
	re := regexp.MustCompile(`\[(.*)\]\(\)`)
	return re.ReplaceAll(content, []byte("[$1]($1)"))
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content)
	content = blackfriday.MarkdownCommon(content)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
	body := r.FormValue("body")
	p := &Page{Title: title, Body: body}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html"))

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		m := validPath.FindStringSubmatch(r.URL.Path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func main() {
	flag.Parse()
	http.Handle("/static/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))

	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
	if err != nil {
		log.Fatal(err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"time"
)

// main app struct
type going struct {
	config *GoingConfig
	logger *log.Logger
	// key = yaml base filename without extension
	programs map[string]*Program
}

type GoingConfig struct {
	PidFile          string
	ProgramConfigDir string
	SocketPath       string
}

// wish it was named getGoing, but consistency trumps all
func newGoing(configFile string) *going {
	c, err := newGoingConfig(configFile)
	if err != nil {
		log.Print(err)
		os.Exit(ReturnConfigError)
	}
	g := new(going)
	g.programs = make(map[string]*Program)
	g.config = c
	g.getPrograms()
	return g
}

func (g *going) getPrograms() {
	var p *Program
	var programs []string
	var err error

	programs, err = g.scanProgramConfigDir()
	if err != nil {
		g.logger.Printf("Could not scan program config files in %s.", g.config.ProgramConfigDir)
		os.Exit(ReturnProgramScanError)
	}

	for _, file := range programs {
		p = new(Program)
		p.state = StateNil
		p.config, err = newProgramConfig(file)
		if err != nil {
			g.logger.Printf("Could not read program config file %s. Skipping.", file)
			continue
		}
		key := p.config.Name
		if key == "" {
			key = programName(file)
		}
		g.programs[key] = p
	}
}

func (g *going) scanProgramConfigDir() ([]string, error) {
	programs := []string{}
	dir := g.config.ProgramConfigDir
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && filepath.Ext(path) == ".conf" {
			g.logger.Printf("Loading program conf file %s.", path)
			programs = append(programs, path)
		}
		return nil
	})
	return programs, err
}

func (g *going) runPrograms() {
	for _, program := range g.programs {
		go g.runProgram(program)
	}
}

func (g *going) runProgram(p *Program) {
	name := p.config.Name
	g.logger.Printf("Initializing program %s", name)
	err := p.init()
	if err != nil {
		g.logger.Printf("Could not initializing program %s. Error: %s", name, err)
	}
	g.logger.Printf("Running program %s", name)
	// proc := p.cmd.Process
	//state := p.cmd.ProcessState
	err = p.cmd.Run()
	if err != nil {
		g.logger.Printf("Could not run program %s. Error: %s", name, err)
	}
	for {
		time.Sleep(500 * time.Millisecond)
	}
}

func (g *going) listen() {
	for {
		time.Sleep(500 * time.Millisecond)
	}
}

// Search order for config file in this order:
// global variable flagConfigFile, aka command line -config flag
// environment variable named in const EnvVarConfigFile
// $HOME/.going/going.yaml,
// /etc/going.conf
func findGoingConfigFile() (string, error) {
	if isValidFile(*flagConfigFile) {
		return *flagConfigFile, nil
	}

	envVar := os.Getenv(EnvVarConfigFile)
	if isValidFile(envVar) {
		return envVar, nil
	}

	home := os.Getenv("HOME")
	homeConfig := filepath.Join(home, ".going", "going.yaml")
	if isValidFile(homeConfig) {
		return homeConfig, nil
	}

	etcConfig := "/etc/going/going.yaml"
	if isValidFile(etcConfig) {
		return etcConfig, nil
	}

	return "", errors.New("Could not find config file.")
}

func newGoingConfig(filename string) (*GoingConfig, error) {
	c := new(GoingConfig)
	err := loadYaml(filename, c)

	configDir := filepath.Dir(filename)

	// set defaults
	if c.PidFile == "" {
		c.PidFile = filepath.Join(configDir, "going.pid")
	}

	if c.ProgramConfigDir == "" {
		c.ProgramConfigDir = filepath.Join(configDir, "programs")
	}

	return c, err
}
<commit_msg>program config files changed to yaml extension<commit_after>package main

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"time"
)

// main app struct
type going struct {
	config *GoingConfig
	logger *log.Logger
	// key = yaml base filename without extension
	programs map[string]*Program
}

type GoingConfig struct {
	PidFile          string
	ProgramConfigDir string
	SocketPath       string
}

// wish it was named getGoing, but consistency trumps all
func newGoing(configFile string) *going {
	c, err := newGoingConfig(configFile)
	if err != nil {
		log.Print(err)
		os.Exit(ReturnConfigError)
	}
	g := new(going)
	g.programs = make(map[string]*Program)
	g.config = c
	g.getPrograms()
	return g
}

func (g *going) getPrograms() {
	var p *Program
	var programs []string
	var err error

	programs, err = g.scanProgramConfigDir()
	if err != nil {
		g.logger.Printf("Could not scan program config files in %s.", g.config.ProgramConfigDir)
		os.Exit(ReturnProgramScanError)
	}

	for _, file := range programs {
		p = new(Program)
		p.state = StateNil
		p.config, err = newProgramConfig(file)
		if err != nil {
			g.logger.Printf("Could not read program config file %s. Skipping.", file)
			continue
		}
		key := p.config.Name
		if key == "" {
			key = programName(file)
		}
		g.programs[key] = p
	}
}

func (g *going) scanProgramConfigDir() ([]string, error) {
	programs := []string{}
	dir := g.config.ProgramConfigDir
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && filepath.Ext(path) == ".yaml" {
			g.logger.Printf("Loading program conf file %s.", path)
			programs = append(programs, path)
		}
		return nil
	})
	return programs, err
}

func (g *going) runPrograms() {
	for _, program := range g.programs {
		go g.runProgram(program)
	}
}

func (g *going) runProgram(p *Program) {
	name := p.config.Name
	g.logger.Printf("Initializing program %s", name)
	err := p.init()
	if err != nil {
		g.logger.Printf("Could not initializing program %s. Error: %s", name, err)
	}
	g.logger.Printf("Running program %s", name)
	// proc := p.cmd.Process
	//state := p.cmd.ProcessState
	err = p.cmd.Run()
	if err != nil {
		g.logger.Printf("Could not run program %s. Error: %s", name, err)
	}
	for {
		time.Sleep(500 * time.Millisecond)
	}
}

func (g *going) listen() {
	for {
		time.Sleep(500 * time.Millisecond)
	}
}

// Search order for config file in this order:
// global variable flagConfigFile, aka command line -config flag
// environment variable named in const EnvVarConfigFile
// $HOME/.going/going.yaml,
// /etc/going.conf
func findGoingConfigFile() (string, error) {
	if isValidFile(*flagConfigFile) {
		return *flagConfigFile, nil
	}

	envVar := os.Getenv(EnvVarConfigFile)
	if isValidFile(envVar) {
		return envVar, nil
	}

	home := os.Getenv("HOME")
	homeConfig := filepath.Join(home, ".going", "going.yaml")
	if isValidFile(homeConfig) {
		return homeConfig, nil
	}

	etcConfig := "/etc/going/going.yaml"
	if isValidFile(etcConfig) {
		return etcConfig, nil
	}

	return "", errors.New("Could not find config file.")
}

func newGoingConfig(filename string) (*GoingConfig, error) {
	c := new(GoingConfig)
	err := loadYaml(filename, c)

	configDir := filepath.Dir(filename)

	// set defaults
	if c.PidFile == "" {
		c.PidFile = filepath.Join(configDir, "going.pid")
	}

	if c.ProgramConfigDir == "" {
		c.ProgramConfigDir = filepath.Join(configDir, "programs")
	}

	return c, err
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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.
*/

package main

// ClusterAutoscalerVersion contains version of CA.
const ClusterAutoscalerVersion = "0.6.0-beta2"
<commit_msg>Set CA version to 0.6.0<commit_after>/*
Copyright 2016 The Kubernetes 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.
*/

package main

// ClusterAutoscalerVersion contains version of CA.
const ClusterAutoscalerVersion = "0.6.0"
<|endoftext|>