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

package ld

import (
	"cmd/internal/objabi"
	"cmd/internal/sys"
	"cmd/link/internal/loader"
	"cmd/link/internal/sym"
	"debug/elf"
	"log"
)

// Decoding the type.* symbols.	 This has to be in sync with
// ../../runtime/type.go, or more specifically, with what
// cmd/compile/internal/gc/reflect.go stuffs in these.

// tflag is documented in reflect/type.go.
//
// tflag values must be kept in sync with copies in:
//	cmd/compile/internal/gc/reflect.go
//	cmd/link/internal/ld/decodesym.go
//	reflect/type.go
//	runtime/type.go
const (
	tflagUncommon  = 1 << 0
	tflagExtraStar = 1 << 1
)

func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
	switch sz {
	case 2:
		return uint64(arch.ByteOrder.Uint16(p))
	case 4:
		return uint64(arch.ByteOrder.Uint32(p))
	case 8:
		return arch.ByteOrder.Uint64(p)
	default:
		Exitf("dwarf: decode inuxi %d", sz)
		panic("unreachable")
	}
}

func commonsize(arch *sys.Arch) int      { return 4*arch.PtrSize + 8 + 8 } // runtime._type
func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize }       // runtime.structfield
func uncommonSize() int                  { return 4 + 2 + 2 + 4 + 4 }      // runtime.uncommontype

// Type.commonType.kind
func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
	return p[2*arch.PtrSize+7] & objabi.KindMask //  0x13 / 0x1f
}

// Type.commonType.kind
func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
	return p[2*arch.PtrSize+7] & objabi.KindGCProg //  0x13 / 0x1f
}

// Type.commonType.size
func decodetypeSize(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
}

// Type.commonType.ptrdata
func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
}

// Type.commonType.tflag
func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
	return p[2*arch.PtrSize+4]&tflagUncommon != 0
}

// Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
	return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
}

// Type.FuncType.inCount
func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
	return int(decodeInuxi(arch, p[commonsize(arch):], 2))
}

func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
	return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}

// InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

// Matches runtime/typekind.go and reflect.Kind.
const (
	kindArray     = 17
	kindChan      = 18
	kindFunc      = 19
	kindInterface = 20
	kindMap       = 21
	kindPtr       = 22
	kindSlice     = 23
	kindStruct    = 25
	kindMask      = (1 << 5) - 1
)

func decodeReloc(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Reloc {
	for j := 0; j < relocs.Count(); j++ {
		rel := relocs.At(j)
		if rel.Off() == off {
			return rel
		}
	}
	return loader.Reloc{}
}

func decodeRelocSym(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Sym {
	return decodeReloc(ldr, symIdx, relocs, off).Sym()
}

// decodetypeName decodes the name from a reflect.name.
func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) string {
	r := decodeRelocSym(ldr, symIdx, relocs, int32(off))
	if r == 0 {
		return ""
	}

	data := ldr.Data(r)
	namelen := int(uint16(data[1])<<8 | uint16(data[2]))
	return string(data[3 : 3+namelen])
}

func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
	uadd := commonsize(arch) + 4
	if arch.PtrSize == 8 {
		uadd += 4
	}
	if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
		uadd += uncommonSize()
	}
	return decodeRelocSym(ldr, symIdx, relocs, int32(uadd+i*arch.PtrSize))
}

func decodetypeFuncOutType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
	return decodetypeFuncInType(ldr, arch, symIdx, relocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
}

func decodetypeArrayElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeArrayLen(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int64 {
	data := ldr.Data(symIdx)
	return int64(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

func decodetypeChanElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeMapKey(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeMapValue(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
}

func decodetypePtrElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeStructFieldCount(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int {
	data := ldr.Data(symIdx)
	return int(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

func decodetypeStructFieldArrayOff(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int {
	data := ldr.Data(symIdx)
	off := commonsize(arch) + 4*arch.PtrSize
	if decodetypeHasUncommon(arch, data) {
		off += uncommonSize()
	}
	off += i * structfieldSize(arch)
	return off
}

func decodetypeStructFieldName(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) string {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	relocs := ldr.Relocs(symIdx)
	return decodetypeName(ldr, symIdx, &relocs, off)
}

func decodetypeStructFieldType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(off+arch.PtrSize))
}

func decodetypeStructFieldOffsAnon(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	data := ldr.Data(symIdx)
	return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize))
}

// decodetypeStr returns the contents of an rtype's str field (a nameOff).
func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string {
	relocs := ldr.Relocs(symIdx)
	str := decodetypeName(ldr, symIdx, &relocs, 4*arch.PtrSize+8)
	data := ldr.Data(symIdx)
	if data[2*arch.PtrSize+4]&tflagExtraStar != 0 {
		return str[1:]
	}
	return str
}

func decodetypeGcmask(ctxt *Link, s loader.Sym) []byte {
	if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
		symData := ctxt.loader.Data(s)
		addr := decodetypeGcprogShlib(ctxt, symData)
		ptrdata := decodetypePtrdata(ctxt.Arch, symData)
		sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr)
		if sect != nil {
			bits := ptrdata / int64(ctxt.Arch.PtrSize)
			r := make([]byte, (bits+7)/8)
			// ldshlibsyms avoids closing the ELF file so sect.ReadAt works.
			// If we remove this read (and the ones in decodetypeGcprog), we
			// can close the file.
			_, err := sect.ReadAt(r, int64(addr-sect.Addr))
			if err != nil {
				log.Fatal(err)
			}
			return r
		}
		Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
		return nil
	}
	relocs := ctxt.loader.Relocs(s)
	mask := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
	return ctxt.loader.Data(mask)
}

// Type.commonType.gc
func decodetypeGcprog(ctxt *Link, s loader.Sym) []byte {
	if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
		symData := ctxt.loader.Data(s)
		addr := decodetypeGcprogShlib(ctxt, symData)
		sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr)
		if sect != nil {
			// A gcprog is a 4-byte uint32 indicating length, followed by
			// the actual program.
			progsize := make([]byte, 4)
			_, err := sect.ReadAt(progsize, int64(addr-sect.Addr))
			if err != nil {
				log.Fatal(err)
			}
			progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
			_, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
			if err != nil {
				log.Fatal(err)
			}
			return append(progsize, progbytes...)
		}
		Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
		return nil
	}
	relocs := ctxt.loader.Relocs(s)
	rs := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
	return ctxt.loader.Data(rs)
}

// Find the elf.Section of a given shared library that contains a given address.
func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
	for _, shlib := range ctxt.Shlibs {
		if shlib.Path == path {
			for _, sect := range shlib.File.Sections[1:] { // skip the NULL section
				if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
					return sect
				}
			}
		}
	}
	return nil
}

func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
	return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
<commit_msg>cmd/link: fix off-by-1 error in findShlibSection<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ld

import (
	"cmd/internal/objabi"
	"cmd/internal/sys"
	"cmd/link/internal/loader"
	"cmd/link/internal/sym"
	"debug/elf"
	"log"
)

// Decoding the type.* symbols.	 This has to be in sync with
// ../../runtime/type.go, or more specifically, with what
// cmd/compile/internal/gc/reflect.go stuffs in these.

// tflag is documented in reflect/type.go.
//
// tflag values must be kept in sync with copies in:
//	cmd/compile/internal/gc/reflect.go
//	cmd/link/internal/ld/decodesym.go
//	reflect/type.go
//	runtime/type.go
const (
	tflagUncommon  = 1 << 0
	tflagExtraStar = 1 << 1
)

func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
	switch sz {
	case 2:
		return uint64(arch.ByteOrder.Uint16(p))
	case 4:
		return uint64(arch.ByteOrder.Uint32(p))
	case 8:
		return arch.ByteOrder.Uint64(p)
	default:
		Exitf("dwarf: decode inuxi %d", sz)
		panic("unreachable")
	}
}

func commonsize(arch *sys.Arch) int      { return 4*arch.PtrSize + 8 + 8 } // runtime._type
func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize }       // runtime.structfield
func uncommonSize() int                  { return 4 + 2 + 2 + 4 + 4 }      // runtime.uncommontype

// Type.commonType.kind
func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
	return p[2*arch.PtrSize+7] & objabi.KindMask //  0x13 / 0x1f
}

// Type.commonType.kind
func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
	return p[2*arch.PtrSize+7] & objabi.KindGCProg //  0x13 / 0x1f
}

// Type.commonType.size
func decodetypeSize(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
}

// Type.commonType.ptrdata
func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
}

// Type.commonType.tflag
func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
	return p[2*arch.PtrSize+4]&tflagUncommon != 0
}

// Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
	return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
}

// Type.FuncType.inCount
func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
	return int(decodeInuxi(arch, p[commonsize(arch):], 2))
}

func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
	return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}

// InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
	return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

// Matches runtime/typekind.go and reflect.Kind.
const (
	kindArray     = 17
	kindChan      = 18
	kindFunc      = 19
	kindInterface = 20
	kindMap       = 21
	kindPtr       = 22
	kindSlice     = 23
	kindStruct    = 25
	kindMask      = (1 << 5) - 1
)

func decodeReloc(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Reloc {
	for j := 0; j < relocs.Count(); j++ {
		rel := relocs.At(j)
		if rel.Off() == off {
			return rel
		}
	}
	return loader.Reloc{}
}

func decodeRelocSym(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Sym {
	return decodeReloc(ldr, symIdx, relocs, off).Sym()
}

// decodetypeName decodes the name from a reflect.name.
func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) string {
	r := decodeRelocSym(ldr, symIdx, relocs, int32(off))
	if r == 0 {
		return ""
	}

	data := ldr.Data(r)
	namelen := int(uint16(data[1])<<8 | uint16(data[2]))
	return string(data[3 : 3+namelen])
}

func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
	uadd := commonsize(arch) + 4
	if arch.PtrSize == 8 {
		uadd += 4
	}
	if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
		uadd += uncommonSize()
	}
	return decodeRelocSym(ldr, symIdx, relocs, int32(uadd+i*arch.PtrSize))
}

func decodetypeFuncOutType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
	return decodetypeFuncInType(ldr, arch, symIdx, relocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
}

func decodetypeArrayElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeArrayLen(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int64 {
	data := ldr.Data(symIdx)
	return int64(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

func decodetypeChanElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeMapKey(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeMapValue(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
}

func decodetypePtrElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30
}

func decodetypeStructFieldCount(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int {
	data := ldr.Data(symIdx)
	return int(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}

func decodetypeStructFieldArrayOff(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int {
	data := ldr.Data(symIdx)
	off := commonsize(arch) + 4*arch.PtrSize
	if decodetypeHasUncommon(arch, data) {
		off += uncommonSize()
	}
	off += i * structfieldSize(arch)
	return off
}

func decodetypeStructFieldName(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) string {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	relocs := ldr.Relocs(symIdx)
	return decodetypeName(ldr, symIdx, &relocs, off)
}

func decodetypeStructFieldType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	relocs := ldr.Relocs(symIdx)
	return decodeRelocSym(ldr, symIdx, &relocs, int32(off+arch.PtrSize))
}

func decodetypeStructFieldOffsAnon(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 {
	off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i)
	data := ldr.Data(symIdx)
	return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize))
}

// decodetypeStr returns the contents of an rtype's str field (a nameOff).
func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string {
	relocs := ldr.Relocs(symIdx)
	str := decodetypeName(ldr, symIdx, &relocs, 4*arch.PtrSize+8)
	data := ldr.Data(symIdx)
	if data[2*arch.PtrSize+4]&tflagExtraStar != 0 {
		return str[1:]
	}
	return str
}

func decodetypeGcmask(ctxt *Link, s loader.Sym) []byte {
	if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
		symData := ctxt.loader.Data(s)
		addr := decodetypeGcprogShlib(ctxt, symData)
		ptrdata := decodetypePtrdata(ctxt.Arch, symData)
		sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr)
		if sect != nil {
			bits := ptrdata / int64(ctxt.Arch.PtrSize)
			r := make([]byte, (bits+7)/8)
			// ldshlibsyms avoids closing the ELF file so sect.ReadAt works.
			// If we remove this read (and the ones in decodetypeGcprog), we
			// can close the file.
			_, err := sect.ReadAt(r, int64(addr-sect.Addr))
			if err != nil {
				log.Fatal(err)
			}
			return r
		}
		Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
		return nil
	}
	relocs := ctxt.loader.Relocs(s)
	mask := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
	return ctxt.loader.Data(mask)
}

// Type.commonType.gc
func decodetypeGcprog(ctxt *Link, s loader.Sym) []byte {
	if ctxt.loader.SymType(s) == sym.SDYNIMPORT {
		symData := ctxt.loader.Data(s)
		addr := decodetypeGcprogShlib(ctxt, symData)
		sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr)
		if sect != nil {
			// A gcprog is a 4-byte uint32 indicating length, followed by
			// the actual program.
			progsize := make([]byte, 4)
			_, err := sect.ReadAt(progsize, int64(addr-sect.Addr))
			if err != nil {
				log.Fatal(err)
			}
			progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
			_, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
			if err != nil {
				log.Fatal(err)
			}
			return append(progsize, progbytes...)
		}
		Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
		return nil
	}
	relocs := ctxt.loader.Relocs(s)
	rs := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
	return ctxt.loader.Data(rs)
}

// Find the elf.Section of a given shared library that contains a given address.
func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
	for _, shlib := range ctxt.Shlibs {
		if shlib.Path == path {
			for _, sect := range shlib.File.Sections[1:] { // skip the NULL section
				if sect.Addr <= addr && addr < sect.Addr+sect.Size {
					return sect
				}
			}
		}
	}
	return nil
}

func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
	return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
<|endoftext|>


<commit_before>package move

import (
	t "github.com/asukakenji/pokemon-go/type"
)

type _standard_move struct {
	id     StandardMove
	_type  t.Type
	damage int16
}

type _special_move struct {
	id             SpecialMove
	_type          t.Type
	damage         int16
	energyRequired int8
}

var moves = [...]interface{}{
	nil,
	// Standard Move
	&_standard_move{Acid, t.Poison, 10},
	&_standard_move{Bite, t.Dark, 6},
	&_standard_move{Bubble, t.Water, 15},
	&_standard_move{BugBite, t.Bug, 6},
	&_standard_move{BulletPunch, t.Steel, 10},
	&_standard_move{Confusion, t.Psychic, 12},
	&_standard_move{Cut, t.Normal, 12},
	&_standard_move{DragonBreath, t.Dragon, 6},
	&_standard_move{Ember, t.Fire, 10},
	&_standard_move{FeintAttack, t.Dark, 12},
	&_standard_move{FireFang, t.Fire, 7},
	&_standard_move{FrostBreath, t.Ice, 12},
	&_standard_move{FuryCutter, t.Bug, 3},
	&_standard_move{IceShard, t.Ice, 10},
	&_standard_move{KarateChop, t.Fighting, 6},
	&_standard_move{Lick, t.Ghost, 10},
	&_standard_move{LowKick, t.Fighting, 5},
	&_standard_move{MetalClaw, t.Steel, 12},
	&_standard_move{MudShot, t.Ground, 12},
	&_standard_move{MudSlap, t.Ground, 6},
	&_standard_move{Peck, t.Flying, 10},
	&_standard_move{PoisonJab, t.Poison, 15},
	&_standard_move{PoisonSting, t.Poison, 6},
	&_standard_move{Pound, t.Normal, 8},
	&_standard_move{PsychoCut, t.Psychic, 15},
	&_standard_move{QuickAttack, t.Normal, 10},
	&_standard_move{RazorLeaf, t.Grass, 15},
	&_standard_move{RockSmash, t.Fighting, 5},
	&_standard_move{RockThrow, t.Rock, 12},
	&_standard_move{Scratch, t.Normal, 10},
	&_standard_move{ShadowClaw, t.Ghost, 16},
	&_standard_move{Spark, t.Electric, 7},
	&_standard_move{Splash, t.Water, 0},
	&_standard_move{SteelWing, t.Steel, 15},
	&_standard_move{SuckerPunch, t.Dark, 7},
	&_standard_move{Tackle, t.Normal, 12},
	&_standard_move{ThunderShock, t.Electric, 5},
	&_standard_move{VineWhip, t.Grass, 10},
	&_standard_move{WaterGun, t.Water, 10},
	&_standard_move{WingAttack, t.Flying, 12},
	&_standard_move{ZenHeadbutt, t.Psychic, 15},
	// Special Move
	&_special_move{AerialAce, t.Flying, 25, 4},
	&_special_move{AirCutter, t.Flying, 25, 4},
	&_special_move{AncientPower, t.Rock, 30, 4},
	&_special_move{AquaJet, t.Water, 15, 5},
	&_special_move{AquaTail, t.Water, 50, 2},
	&_special_move{Blizzard, t.Ice, 60, 1},
	&_special_move{BodySlam, t.Normal, 50, 2},
	&_special_move{BoneClub, t.Ground, 20, 4},
	&_special_move{BrickBreak, t.Fighting, 30, 3},
	&_special_move{Brine, t.Water, 15, 5},
	&_special_move{BubbleBeam, t.Water, 25, 4},
	&_special_move{BugBuzz, t.Bug, 50, 2},
	&_special_move{Bulldoze, t.Ground, 30, 4},
	&_special_move{CrossChop, t.Fighting, 55, 2},
	&_special_move{CrossPoison, t.Poison, 20, 4},
	&_special_move{DarkPulse, t.Dark, 45, 3},
	&_special_move{DazzlingGleam, t.Fairy, 45, 3},
	&_special_move{Dig, t.Ground, 45, 3},
	&_special_move{DisarmingVoice, t.Fairy, 20, 5},
	&_special_move{Discharge, t.Electric, 40, 3},
	&_special_move{DragonClaw, t.Dragon, 40, 2},
	&_special_move{DragonPulse, t.Dragon, 50, 2},
	&_special_move{DrainingKiss, t.Fairy, 15, 5},
	&_special_move{DrillPeck, t.Flying, 30, 3},
	&_special_move{DrillRun, t.Ground, 40, 3},
	&_special_move{Earthquake, t.Ground, 60, 1},
	&_special_move{FireBlast, t.Fire, 60, 1},
	&_special_move{FirePunch, t.Fire, 35, 3},
	&_special_move{FlameBurst, t.Fire, 25, 4},
	&_special_move{FlameCharge, t.Fire, 25, 4},
	&_special_move{FlameWheel, t.Fire, 35, 4},
	&_special_move{Flamethrower, t.Fire, 50, 2},
	&_special_move{FlashCannon, t.Steel, 55, 3},
	&_special_move{GunkShot, t.Poison, 60, 1},
	&_special_move{HeatWave, t.Fire, 60, 1},
	&_special_move{HornAttack, t.Normal, 20, 4},
	&_special_move{Hurricane, t.Flying, 60, 1},
	&_special_move{HydroPump, t.Water, 60, 1},
	&_special_move{HyperBeam, t.Normal, 70, 1},
	&_special_move{HyperFang, t.Normal, 35, 3},
	&_special_move{IceBeam, t.Ice, 50, 2},
	&_special_move{IcePunch, t.Ice, 45, 3},
	&_special_move{IcyWind, t.Ice, 15, 5},
	&_special_move{IronHead, t.Steel, 40, 3},
	&_special_move{LeafBlade, t.Grass, 45, 2},
	&_special_move{LowSweep, t.Fighting, 25, 4},
	&_special_move{MagnetBomb, t.Steel, 25, 4},
	&_special_move{Megahorn, t.Bug, 55, 1},
	&_special_move{Moonblast, t.Fairy, 60, 1},
	&_special_move{MudBomb, t.Ground, 25, 4},
	&_special_move{NightSlash, t.Dark, 25, 4},
	&_special_move{OminousWind, t.Ghost, 25, 4},
	&_special_move{PetalBlizzard, t.Grass, 50, 2},
	&_special_move{PlayRough, t.Fairy, 50, 2},
	&_special_move{PoisonFang, t.Poison, 15, 5},
	&_special_move{PowerGem, t.Rock, 40, 3},
	&_special_move{PowerWhip, t.Grass, 60, 1},
	&_special_move{Psybeam, t.Psychic, 35, 4},
	&_special_move{Psychic, t.Psychic, 50, 2},
	&_special_move{Psyshock, t.Psychic, 40, 3},
	&_special_move{RockSlide, t.Rock, 40, 3},
	&_special_move{RockTomb, t.Rock, 25, 4},
	&_special_move{Scald, t.Water, 35, 3},
	&_special_move{SeedBomb, t.Grass, 30, 3},
	&_special_move{ShadowBall, t.Ghost, 40, 3},
	&_special_move{SignalBeam, t.Bug, 35, 3},
	&_special_move{Sludge, t.Poison, 25, 4},
	&_special_move{SludgeBomb, t.Poison, 50, 2},
	&_special_move{SludgeWave, t.Poison, 60, 1},
	&_special_move{SolarBeam, t.Grass, 65, 1},
	&_special_move{Stomp, t.Normal, 25, 4},
	&_special_move{StoneEdge, t.Rock, 55, 1},
	&_special_move{Struggle, t.Normal, 15, 5},
	&_special_move{Submission, t.Fighting, 30, 3},
	&_special_move{Swift, t.Normal, 25, 4},
	&_special_move{Thunder, t.Electric, 65, 1},
	&_special_move{ThunderPunch, t.Electric, 40, 3},
	&_special_move{Thunderbolt, t.Electric, 50, 2},
	&_special_move{Twister, t.Dragon, 15, 5},
	&_special_move{ViceGrip, t.Normal, 15, 5},
	&_special_move{WaterPulse, t.Water, 30, 4},
	&_special_move{Wrap, t.Normal, 15, 5},
	&_special_move{X_Scissor, t.Bug, 30, 3},
}
<commit_msg>Updated the move data to V1.1<commit_after>package move

import (
	t "github.com/asukakenji/pokemon-go/type"
)

type _standard_move struct {
	id     StandardMove
	_type  t.Type
	damage int16
}

type _special_move struct {
	id             SpecialMove
	_type          t.Type
	damage         int16
	energyRequired int8
}

var moves = [...]interface{}{
	nil,
	// Standard Move
	&_standard_move{Acid, t.Poison, 10},
	&_standard_move{Bite, t.Dark, 6},
	&_standard_move{Bubble, t.Water, 25},
	&_standard_move{BugBite, t.Bug, 5},
	&_standard_move{BulletPunch, t.Steel, 10},
	&_standard_move{Confusion, t.Psychic, 15},
	&_standard_move{Cut, t.Normal, 12},
	&_standard_move{DragonBreath, t.Dragon, 6},
	&_standard_move{Ember, t.Fire, 10},
	&_standard_move{FeintAttack, t.Dark, 12},
	&_standard_move{FireFang, t.Fire, 10},
	&_standard_move{FrostBreath, t.Ice, 9},
	&_standard_move{FuryCutter, t.Bug, 3},
	&_standard_move{IceShard, t.Ice, 15},
	&_standard_move{KarateChop, t.Fighting, 6},
	&_standard_move{Lick, t.Ghost, 5},
	&_standard_move{LowKick, t.Fighting, 5},
	&_standard_move{MetalClaw, t.Steel, 12},
	&_standard_move{MudShot, t.Ground, 12},
	&_standard_move{MudSlap, t.Ground, 15},
	&_standard_move{Peck, t.Flying, 10},
	&_standard_move{PoisonJab, t.Poison, 15},
	&_standard_move{PoisonSting, t.Poison, 6},
	&_standard_move{Pound, t.Normal, 7},
	&_standard_move{PsychoCut, t.Psychic, 8},
	&_standard_move{QuickAttack, t.Normal, 10},
	&_standard_move{RazorLeaf, t.Grass, 15},
	&_standard_move{RockSmash, t.Fighting, 15},
	&_standard_move{RockThrow, t.Rock, 12},
	&_standard_move{Scratch, t.Normal, 6},
	&_standard_move{ShadowClaw, t.Ghost, 11},
	&_standard_move{Spark, t.Electric, 7},
	&_standard_move{Splash, t.Water, 0},
	&_standard_move{SteelWing, t.Steel, 15},
	&_standard_move{SuckerPunch, t.Dark, 7},
	&_standard_move{Tackle, t.Normal, 12},
	&_standard_move{ThunderShock, t.Electric, 5},
	&_standard_move{VineWhip, t.Grass, 7},
	&_standard_move{WaterGun, t.Water, 6},
	&_standard_move{WingAttack, t.Flying, 9},
	&_standard_move{ZenHeadbutt, t.Psychic, 12},
	// Special Move
	&_special_move{AerialAce, t.Flying, 30, 4},
	&_special_move{AirCutter, t.Flying, 30, 4},
	&_special_move{AncientPower, t.Rock, 35, 4},
	&_special_move{AquaJet, t.Water, 25, 5},
	&_special_move{AquaTail, t.Water, 45, 2},
	&_special_move{Blizzard, t.Ice, 100, 1},
	&_special_move{BodySlam, t.Normal, 40, 2},
	&_special_move{BoneClub, t.Ground, 25, 4},
	&_special_move{BrickBreak, t.Fighting, 30, 3},
	&_special_move{Brine, t.Water, 25, 5},
	&_special_move{BubbleBeam, t.Water, 30, 4},
	&_special_move{BugBuzz, t.Bug, 75, 2},
	&_special_move{Bulldoze, t.Ground, 35, 4},
	&_special_move{CrossChop, t.Fighting, 60, 1},
	&_special_move{CrossPoison, t.Poison, 25, 4},
	&_special_move{DarkPulse, t.Dark, 45, 3},
	&_special_move{DazzlingGleam, t.Fairy, 55, 3},
	&_special_move{Dig, t.Ground, 70, 3},
	&_special_move{DisarmingVoice, t.Fairy, 25, 5},
	&_special_move{Discharge, t.Electric, 35, 3},
	&_special_move{DragonClaw, t.Dragon, 35, 2},
	&_special_move{DragonPulse, t.Dragon, 65, 2},
	&_special_move{DrainingKiss, t.Fairy, 25, 5},
	&_special_move{DrillPeck, t.Flying, 40, 3},
	&_special_move{DrillRun, t.Ground, 50, 3},
	&_special_move{Earthquake, t.Ground, 100, 1},
	&_special_move{FireBlast, t.Fire, 100, 1},
	&_special_move{FirePunch, t.Fire, 40, 3},
	&_special_move{FlameBurst, t.Fire, 30, 4},
	&_special_move{FlameCharge, t.Fire, 25, 4},
	&_special_move{FlameWheel, t.Fire, 40, 4},
	&_special_move{Flamethrower, t.Fire, 55, 2},
	&_special_move{FlashCannon, t.Steel, 60, 3},
	&_special_move{GunkShot, t.Poison, 65, 1},
	&_special_move{HeatWave, t.Fire, 80, 1},
	&_special_move{HornAttack, t.Normal, 25, 4},
	&_special_move{Hurricane, t.Flying, 80, 1},
	&_special_move{HydroPump, t.Water, 90, 1},
	&_special_move{HyperBeam, t.Normal, 120, 1},
	&_special_move{HyperFang, t.Normal, 35, 3},
	&_special_move{IceBeam, t.Ice, 65, 2},
	&_special_move{IcePunch, t.Ice, 45, 3},
	&_special_move{IcyWind, t.Ice, 25, 5},
	&_special_move{IronHead, t.Steel, 30, 3},
	&_special_move{LeafBlade, t.Grass, 55, 2},
	&_special_move{LowSweep, t.Fighting, 30, 4},
	&_special_move{MagnetBomb, t.Steel, 30, 4},
	&_special_move{Megahorn, t.Bug, 80, 1},
	&_special_move{Moonblast, t.Fairy, 85, 1},
	&_special_move{MudBomb, t.Ground, 30, 4},
	&_special_move{NightSlash, t.Dark, 30, 4},
	&_special_move{OminousWind, t.Ghost, 30, 4},
	&_special_move{PetalBlizzard, t.Grass, 65, 2},
	&_special_move{PlayRough, t.Fairy, 55, 2},
	&_special_move{PoisonFang, t.Poison, 25, 5},
	&_special_move{PowerGem, t.Rock, 40, 3},
	&_special_move{PowerWhip, t.Grass, 70, 1},
	&_special_move{Psybeam, t.Psychic, 40, 4},
	&_special_move{Psychic, t.Psychic, 55, 2},
	&_special_move{Psyshock, t.Psychic, 40, 3},
	&_special_move{RockSlide, t.Rock, 50, 3},
	&_special_move{RockTomb, t.Rock, 30, 4},
	&_special_move{Scald, t.Water, 55, 3},
	&_special_move{SeedBomb, t.Grass, 40, 3},
	&_special_move{ShadowBall, t.Ghost, 45, 3},
	&_special_move{SignalBeam, t.Bug, 45, 3},
	&_special_move{Sludge, t.Poison, 30, 4},
	&_special_move{SludgeBomb, t.Poison, 55, 2},
	&_special_move{SludgeWave, t.Poison, 70, 1},
	&_special_move{SolarBeam, t.Grass, 120, 1},
	&_special_move{Stomp, t.Normal, 30, 4},
	&_special_move{StoneEdge, t.Rock, 80, 1},
	&_special_move{Struggle, t.Normal, 15, 5},
	&_special_move{Submission, t.Fighting, 30, 3},
	&_special_move{Swift, t.Normal, 30, 4},
	&_special_move{Thunder, t.Electric, 100, 1},
	&_special_move{ThunderPunch, t.Electric, 40, 3},
	&_special_move{Thunderbolt, t.Electric, 55, 2},
	&_special_move{Twister, t.Dragon, 25, 5},
	&_special_move{ViceGrip, t.Normal, 25, 5},
	&_special_move{WaterPulse, t.Water, 35, 4},
	&_special_move{Wrap, t.Normal, 25, 5},
	&_special_move{X_Scissor, t.Bug, 35, 3},
}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package identicon

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"strconv"
	"testing"

	"github.com/issue9/assert"
)

var (
	back  = color.RGBA{255, 0, 0, 100}
	fore  = color.RGBA{0, 255, 255, 100}
	fores = []color.Color{color.Black, color.RGBA{200, 2, 5, 100}, color.RGBA{2, 200, 5, 100}}
	size  = 128
)

// 依次画出各个网络的图像。
func TestBlocks(t *testing.T) {
	p := []color.Color{back, fore}

	a := assert.New(t)

	for k, v := range blocks {
		img := image.NewPaletted(image.Rect(0, 0, size*4, size), p) // 横向4张图片大小

		for i := 0; i < 4; i++ {
			v(img, float64(i*size), 0, float64(size), i)
		}

		fi, err := os.Create("./testdata/block-" + strconv.Itoa(k) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

// 产生一组测试图片
func TestDrawBlocks(t *testing.T) {
	a := assert.New(t)

	for i := 0; i < 20; i++ {
		p := image.NewPaletted(image.Rect(0, 0, size, size), []color.Color{back, fore})
		c := (i + 1) % len(centerBlocks)
		b1 := (i + 2) % len(blocks)
		b2 := (i + 3) % len(blocks)
		drawBlocks(p, size, centerBlocks[c], blocks[b1], blocks[b2], 0)

		fi, err := os.Create("./testdata/draw-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, p))
		a.NotError(fi.Close()) // 关闭文件
	}
}

func TestMake(t *testing.T) {
	a := assert.New(t)

	for i := 0; i < 20; i++ {
		img, err := Make(size, back, fore, []byte("make-"+strconv.Itoa(i)))
		a.NotError(err).NotNil(img)

		fi, err := os.Create("./testdata/make-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

func TestIdenticon(t *testing.T) {
	a := assert.New(t)

	ii, err := New(size, back, fores...)
	a.NotError(err).NotNil(ii)

	for i := 0; i < 20; i++ {
		img := ii.Make([]byte("identicon-" + strconv.Itoa(i)))
		a.NotNil(img)

		fi, err := os.Create("./testdata/identicon-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

// BenchmarkMake	    5000	    229378 ns/op
func BenchmarkMake(b *testing.B) {
	a := assert.New(b)
	for i := 0; i < b.N; i++ {
		img, err := Make(size, back, fore, []byte("Make"))
		a.NotError(err).NotNil(img)
	}
}

// BenchmarkIdenticon_Make	   10000	    222127 ns/op
func BenchmarkIdenticon_Make(b *testing.B) {
	a := assert.New(b)

	ii, err := New(size, back, fores...)
	a.NotError(err).NotNil(ii)

	for i := 0; i < b.N; i++ {
		img := ii.Make([]byte("Make"))
		a.NotNil(img)
	}
}
<commit_msg>自动创建测试文件目录<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package identicon

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"strconv"
	"testing"

	"github.com/issue9/assert"
)

var (
	back  = color.RGBA{255, 0, 0, 100}
	fore  = color.RGBA{0, 255, 255, 100}
	fores = []color.Color{color.Black, color.RGBA{200, 2, 5, 100}, color.RGBA{2, 200, 5, 100}}
	size  = 128
)

// 在不存在testdata目录下的情况下，自动创建一个目录。
func TestInit(t *testing.T) {
	a := assert.New(t)

	a.NotError(os.MkdirAll("./testdata/", os.ModePerm))
}

// 依次画出各个网络的图像。
func TestBlocks(t *testing.T) {
	p := []color.Color{back, fore}

	a := assert.New(t)

	for k, v := range blocks {
		img := image.NewPaletted(image.Rect(0, 0, size*4, size), p) // 横向4张图片大小

		for i := 0; i < 4; i++ {
			v(img, float64(i*size), 0, float64(size), i)
		}

		fi, err := os.Create("./testdata/block-" + strconv.Itoa(k) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

// 产生一组测试图片
func TestDrawBlocks(t *testing.T) {
	a := assert.New(t)

	for i := 0; i < 20; i++ {
		p := image.NewPaletted(image.Rect(0, 0, size, size), []color.Color{back, fore})
		c := (i + 1) % len(centerBlocks)
		b1 := (i + 2) % len(blocks)
		b2 := (i + 3) % len(blocks)
		drawBlocks(p, size, centerBlocks[c], blocks[b1], blocks[b2], 0)

		fi, err := os.Create("./testdata/draw-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, p))
		a.NotError(fi.Close()) // 关闭文件
	}
}

func TestMake(t *testing.T) {
	a := assert.New(t)

	for i := 0; i < 20; i++ {
		img, err := Make(size, back, fore, []byte("make-"+strconv.Itoa(i)))
		a.NotError(err).NotNil(img)

		fi, err := os.Create("./testdata/make-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

func TestIdenticon(t *testing.T) {
	a := assert.New(t)

	ii, err := New(size, back, fores...)
	a.NotError(err).NotNil(ii)

	for i := 0; i < 20; i++ {
		img := ii.Make([]byte("identicon-" + strconv.Itoa(i)))
		a.NotNil(img)

		fi, err := os.Create("./testdata/identicon-" + strconv.Itoa(i) + ".png")
		a.NotError(err).NotNil(fi)
		a.NotError(png.Encode(fi, img))
		a.NotError(fi.Close()) // 关闭文件
	}
}

// BenchmarkMake	    5000	    229378 ns/op
func BenchmarkMake(b *testing.B) {
	a := assert.New(b)
	for i := 0; i < b.N; i++ {
		img, err := Make(size, back, fore, []byte("Make"))
		a.NotError(err).NotNil(img)
	}
}

// BenchmarkIdenticon_Make	   10000	    222127 ns/op
func BenchmarkIdenticon_Make(b *testing.B) {
	a := assert.New(b)

	ii, err := New(size, back, fores...)
	a.NotError(err).NotNil(ii)

	for i := 0; i < b.N; i++ {
		img := ii.Make([]byte("Make"))
		a.NotNil(img)
	}
}
<|endoftext|>


<commit_before>// Integration tests for the IngestHelper.
// These tests require access to S3 and Fluctus, but not NSQ.
package bagman_test

import (
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/bitly/go-nsq"
	"github.com/crowdmob/goamz/s3"
	"io/ioutil"
	"os"
	"net/http"
	"strconv"
	"strings"
	"testing"
)

var skipMessagePrinted bool = false

func fluctusAvailable() bool {
	_, err := http.Get(fluctusUrl)
	if err != nil {
		return false
	}
	return true
}

func environmentReady() (bool) {
	if fluctusAvailable() == false {
		if !skipMessagePrinted {
			msg := "Skipping IngestHelper tests because environment variables " +
				"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set."
			fmt.Fprintln(os.Stderr, msg)
			skipMessagePrinted = true
		}
		return false
	}
	if awsEnvAvailable() == false {
		if !skipMessagePrinted {
			msg := fmt.Sprintf("Skipping tests because Fluctus is not "+
				"running at %s", fluctusUrl)
			fmt.Fprintln(os.Stderr, msg)
			skipMessagePrinted = true
		}
		return false
	}
	return true
}

func getS3File() (*bagman.S3File) {
	return &bagman.S3File {
        BucketName: "aptrust.receiving.test.edu",
        Key: s3.Key{
            Key: "ncsu.1840.16-2928.tar",
            LastModified: "2014-04-25T19:01:20.000Z",
            Size: 696320,
            ETag: "\"b4f8f3072f73598fc5b65bf416b6019a\"",
            StorageClass: "STANDARD",
        },
	}
}

func getProcessUtil() (*bagman.ProcessUtil) {
	makeTestDir()
	testConfig := "test"
	return bagman.NewProcessUtil(&testConfig)
}

func getIngestHelper() (*bagman.IngestHelper) {
	msgId := nsq.MessageID{'1', '0','1', '0','1', '0','1', '0','1',
		'0','1', '0','1', '0','1', '0',}
	body := []byte{'h', 'e', 'l', 'l', 'o'}
	nsqMessage := nsq.NewMessage(msgId, body)
	return bagman.NewIngestHelper(getProcessUtil(), nsqMessage, getS3File())
}

func getConfig() (bagman.Config) {
	if &config == nil {
		requestedConfig := "test"
		config = bagman.LoadRequestedConfig(&requestedConfig)
	}
	return config
}

func makeTestDir() {
	config := getConfig()
	os.Mkdir(config.TarDirectory, 0755)
}

// Delete the local files our tests created during processing.
func deleteLocalFiles() {
	config := getConfig()
	files, _ := ioutil.ReadDir(config.TarDirectory)
	for _, file := range files {
		//fmt.Printf("Deleting local file %s\n", file.Name())
		os.RemoveAll(file.Name())
	}
}

// Delete the GenericFiles that our tests stored in aptrust.test.preservation.
func deleteS3Files(genericFiles []*bagman.File, s3Client *bagman.S3Client) {
	for _, file := range genericFiles {
		parts := strings.Split(file.StorageURL, "/")
		bucket := parts[3]
		file := parts[len(parts) - 1]
		//fmt.Printf("Deleting S3 file %s/%s\n", bucket, file)
		err := s3Client.Delete(bucket, file)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error cleaning up file %s/%s: %v", bucket, file, err)
		}
	}
}

func TestBagNeedsProcessing(t *testing.T) {
	if environmentReady() == false {
		return
	}
	processUtil := getProcessUtil()
	s3File := getS3File()
	if bagman.BagNeedsProcessing(s3File, processUtil) == true {
		t.Error("BagNeedsProcessing should have returned false")
	}
}

func TestIncompleteCopyToS3(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()

	helper.Result.TarResult = &bagman.TarResult{}
	helper.Result.TarResult.Files = make([]*bagman.File, 2)
	file0 := &bagman.File{
		StorageURL: "http://blah.blah.blah",
		NeedsSave: true,
	}
	file1 := &bagman.File{
		StorageURL: "",
		NeedsSave: false,
	}
	helper.Result.TarResult.Files[0] = file0
	helper.Result.TarResult.Files[1] = file1

	// Only one file needed saving, and it was saved
	if helper.IncompleteCopyToS3() == true {
		t.Error("helper.IncompleteCopyToS3() should have returned false")
	}

	// Two files need saving, two were saved
	file1.StorageURL = "http://yadda.yadda"
	file1.NeedsSave = true
	if helper.IncompleteCopyToS3() == true {
		t.Error("helper.IncompleteCopyToS3() should have returned false")
	}

	// Two files need saving, one was saved
	file1.StorageURL = ""
	if helper.IncompleteCopyToS3() == false {
		t.Error("helper.IncompleteCopyToS3() should have returned true")
	}

	deleteLocalFiles()
}

func TestFailedAndNoMoreRetries(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()

	// No error message in result and we're on the first attempt.
	helper.Result.NsqMessage.Attempts = 1
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// Presence of ANY error message in result indicates failure.
	// But we're still at attempt #1, so we should be OK
	helper.Result.ErrorMessage = "Oopsie!"
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// We're above the retry threshold, but no error, so we should be OK.
	helper.Result.NsqMessage.Attempts = uint16(helper.ProcUtil.Config.MaxStoreAttempts) * 2
	helper.Result.ErrorMessage = ""
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// Now we have an error and we're above the retry threshold.
	helper.Result.ErrorMessage = "Now you've done it!"
	if helper.FailedAndNoMoreRetries() == false {
		t.Error("helper.FailedAndNoMoreRetries() should have returned true")
	}

	deleteLocalFiles()
}

func TestGetS3Options(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()
	file := &bagman.File{
		Md5: "b4f8f3072f73598fc5b65bf416b6019a",
		Path: "/data/hansel/und/gretel.pdf",
	}
	opts, err := helper.GetS3Options(file)
	if err != nil {
		t.Error(err)
	}
	if opts.ContentMD5 != "tPjzBy9zWY/Ftlv0FrYBmg==" {
		t.Error("Got incorrect base64-encoded md5 string")
	}
	expectedMd5 := "b4f8f3072f73598fc5b65bf416b6019a"
	if opts.Meta["md5"][0] != expectedMd5 {
		t.Errorf("Expected md5 metadata '%s', but found '%s'",
			expectedMd5, opts.Meta["md5"][0])
	}
	if opts.Meta["institution"][0] != "test.edu" {
		t.Errorf("Expected institution metadata 'test.edu', but found '%s'",
			opts.Meta["institution"][0])
	}
	if opts.Meta["bag"][0] != "ncsu.1840.16-2928" {
		t.Errorf("Expected bag metadata 'ncsu.1840.16-2928', but found '%s'",
			opts.Meta["bag"][0])
	}
	if opts.Meta["bagpath"][0] != file.Path {
		t.Errorf("Expected bag metadata '%s', but found '%s'",
			file.Path, opts.Meta["bagpath"][0])
	}
	deleteLocalFiles()
}

func TestUpdateFluctusStatus(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()
	helper.UpdateFluctusStatus(bagman.StageRecord, bagman.StatusStarted)

}

func TestFullProcess(t *testing.T) {
	if environmentReady() == false {
		return
	}

	helper := getIngestHelper()

	helper.FetchTarFile()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Fetch" {
		t.Errorf("Stage should be 'Fetch' but is '%s'", helper.Result.Stage)
	}
	verifyFetchResult(t, helper.Result.FetchResult)

	helper.ProcessBagFile()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Validate" {
		t.Errorf("Stage should be 'Validate' but is '%s'", helper.Result.Stage)
	}
	verifyBagReadResult(t, helper.Result.BagReadResult)

	helper.SaveGenericFiles()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Store" {
		t.Errorf("Stage should be 'Store' but is '%s'", helper.Result.Stage)
	}
	for _, file := range helper.Result.TarResult.Files {
		if file.StorageURL == "" {
			t.Errorf("File '%s' is missing S3 URL", file.Path)
		}
		if file.StoredAt.IsZero() {
			t.Errorf("File '%s' is missing StoredAt time", file.Path)
		}
		if file.StorageMd5 == "" {
			t.Errorf("File '%s' is missing StorageMd5", file.Path)
		}
	}

	helper.LogResult()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}

	errors := helper.DeleteLocalFiles()
	if len(errors) > 0 {
		for _, err := range errors {
			t.Error(err)
		}
	}

	deleteLocalFiles()
	deleteS3Files(helper.Result.TarResult.Files, helper.ProcUtil.S3Client)
}

func verifyResult(t *testing.T, itemName, expected, actual string) {
	if expected != actual {
		t.Errorf("%s expected '%s' but got '%s'", itemName, expected, actual)
	}
}

func verifyFetchResult(t *testing.T, fetchResult *bagman.FetchResult) {
	verifyResult(t, "BucketName", "aptrust.receiving.test.edu", fetchResult.BucketName)
	verifyResult(t, "Key", "ncsu.1840.16-2928.tar", fetchResult.Key)
	verifyResult(t, "LocalTarFile", "tmp/ncsu.1840.16-2928.tar", fetchResult.LocalTarFile)
	verifyResult(t, "RemoteMd5", "b4f8f3072f73598fc5b65bf416b6019a", fetchResult.RemoteMd5)
	verifyResult(t, "LocalMd5", "b4f8f3072f73598fc5b65bf416b6019a", fetchResult.LocalMd5)
	verifyResult(t, "Md5Verified", "true", strconv.FormatBool(fetchResult.Md5Verified))
	verifyResult(t, "Md5Verifiable", "true", strconv.FormatBool(fetchResult.Md5Verifiable))
	verifyResult(t, "ErrorMessage", "", fetchResult.ErrorMessage)
	verifyResult(t, "Warning", "", fetchResult.Warning)
	verifyResult(t, "Retry", "true", strconv.FormatBool(fetchResult.Retry))
}

// Do a high-level check. Other unit tests cover the details
func verifyBagReadResult(t *testing.T, bagReadResult *bagman.BagReadResult) {
	if !strings.HasSuffix(bagReadResult.Path, "/bagman/bagman/tmp/ncsu.1840.16-2928") {
		t.Errorf("Wrong BagReadResult.Path: '%s'", bagReadResult.Path)
	}
	verifyResult(t, "ErrorMessage", "", bagReadResult.ErrorMessage)
	verifyResult(t, "File Count", "9", strconv.FormatInt(int64(len(bagReadResult.Files)), 10))
	verifyResult(t, "Tag Count", "7", strconv.FormatInt(int64(len(bagReadResult.Tags)), 10))
	verifyResult(t, "Checksum Error Count", "0", strconv.FormatInt(int64(len(bagReadResult.ChecksumErrors)), 10))
}
<commit_msg>Fixed config setting name.<commit_after>// Integration tests for the IngestHelper.
// These tests require access to S3 and Fluctus, but not NSQ.
package bagman_test

import (
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/bitly/go-nsq"
	"github.com/crowdmob/goamz/s3"
	"io/ioutil"
	"os"
	"net/http"
	"strconv"
	"strings"
	"testing"
)

var skipMessagePrinted bool = false

func fluctusAvailable() bool {
	_, err := http.Get(fluctusUrl)
	if err != nil {
		return false
	}
	return true
}

func environmentReady() (bool) {
	if fluctusAvailable() == false {
		if !skipMessagePrinted {
			msg := "Skipping IngestHelper tests because environment variables " +
				"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set."
			fmt.Fprintln(os.Stderr, msg)
			skipMessagePrinted = true
		}
		return false
	}
	if awsEnvAvailable() == false {
		if !skipMessagePrinted {
			msg := fmt.Sprintf("Skipping tests because Fluctus is not "+
				"running at %s", fluctusUrl)
			fmt.Fprintln(os.Stderr, msg)
			skipMessagePrinted = true
		}
		return false
	}
	return true
}

func getS3File() (*bagman.S3File) {
	return &bagman.S3File {
        BucketName: "aptrust.receiving.test.edu",
        Key: s3.Key{
            Key: "ncsu.1840.16-2928.tar",
            LastModified: "2014-04-25T19:01:20.000Z",
            Size: 696320,
            ETag: "\"b4f8f3072f73598fc5b65bf416b6019a\"",
            StorageClass: "STANDARD",
        },
	}
}

func getProcessUtil() (*bagman.ProcessUtil) {
	makeTestDir()
	testConfig := "test"
	return bagman.NewProcessUtil(&testConfig)
}

func getIngestHelper() (*bagman.IngestHelper) {
	msgId := nsq.MessageID{'1', '0','1', '0','1', '0','1', '0','1',
		'0','1', '0','1', '0','1', '0',}
	body := []byte{'h', 'e', 'l', 'l', 'o'}
	nsqMessage := nsq.NewMessage(msgId, body)
	return bagman.NewIngestHelper(getProcessUtil(), nsqMessage, getS3File())
}

func getConfig() (bagman.Config) {
	if &config == nil {
		requestedConfig := "test"
		config = bagman.LoadRequestedConfig(&requestedConfig)
	}
	return config
}

func makeTestDir() {
	config := getConfig()
	os.Mkdir(config.TarDirectory, 0755)
}

// Delete the local files our tests created during processing.
func deleteLocalFiles() {
	config := getConfig()
	files, _ := ioutil.ReadDir(config.TarDirectory)
	for _, file := range files {
		//fmt.Printf("Deleting local file %s\n", file.Name())
		os.RemoveAll(file.Name())
	}
}

// Delete the GenericFiles that our tests stored in aptrust.test.preservation.
func deleteS3Files(genericFiles []*bagman.File, s3Client *bagman.S3Client) {
	for _, file := range genericFiles {
		parts := strings.Split(file.StorageURL, "/")
		bucket := parts[3]
		file := parts[len(parts) - 1]
		//fmt.Printf("Deleting S3 file %s/%s\n", bucket, file)
		err := s3Client.Delete(bucket, file)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error cleaning up file %s/%s: %v", bucket, file, err)
		}
	}
}

func TestBagNeedsProcessing(t *testing.T) {
	if environmentReady() == false {
		return
	}
	processUtil := getProcessUtil()
	s3File := getS3File()
	if bagman.BagNeedsProcessing(s3File, processUtil) == true {
		t.Error("BagNeedsProcessing should have returned false")
	}
}

func TestIncompleteCopyToS3(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()

	helper.Result.TarResult = &bagman.TarResult{}
	helper.Result.TarResult.Files = make([]*bagman.File, 2)
	file0 := &bagman.File{
		StorageURL: "http://blah.blah.blah",
		NeedsSave: true,
	}
	file1 := &bagman.File{
		StorageURL: "",
		NeedsSave: false,
	}
	helper.Result.TarResult.Files[0] = file0
	helper.Result.TarResult.Files[1] = file1

	// Only one file needed saving, and it was saved
	if helper.IncompleteCopyToS3() == true {
		t.Error("helper.IncompleteCopyToS3() should have returned false")
	}

	// Two files need saving, two were saved
	file1.StorageURL = "http://yadda.yadda"
	file1.NeedsSave = true
	if helper.IncompleteCopyToS3() == true {
		t.Error("helper.IncompleteCopyToS3() should have returned false")
	}

	// Two files need saving, one was saved
	file1.StorageURL = ""
	if helper.IncompleteCopyToS3() == false {
		t.Error("helper.IncompleteCopyToS3() should have returned true")
	}

	deleteLocalFiles()
}

func TestFailedAndNoMoreRetries(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()

	// No error message in result and we're on the first attempt.
	helper.Result.NsqMessage.Attempts = 1
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// Presence of ANY error message in result indicates failure.
	// But we're still at attempt #1, so we should be OK
	helper.Result.ErrorMessage = "Oopsie!"
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// We're above the retry threshold, but no error, so we should be OK.
	helper.Result.NsqMessage.Attempts = helper.ProcUtil.Config.StoreWorker.MaxAttempts * 2
	helper.Result.ErrorMessage = ""
	if helper.FailedAndNoMoreRetries() == true {
		t.Error("helper.FailedAndNoMoreRetries() should have returned false")
	}

	// Now we have an error and we're above the retry threshold.
	helper.Result.ErrorMessage = "Now you've done it!"
	if helper.FailedAndNoMoreRetries() == false {
		t.Error("helper.FailedAndNoMoreRetries() should have returned true")
	}

	deleteLocalFiles()
}

func TestGetS3Options(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()
	file := &bagman.File{
		Md5: "b4f8f3072f73598fc5b65bf416b6019a",
		Path: "/data/hansel/und/gretel.pdf",
	}
	opts, err := helper.GetS3Options(file)
	if err != nil {
		t.Error(err)
	}
	if opts.ContentMD5 != "tPjzBy9zWY/Ftlv0FrYBmg==" {
		t.Error("Got incorrect base64-encoded md5 string")
	}
	expectedMd5 := "b4f8f3072f73598fc5b65bf416b6019a"
	if opts.Meta["md5"][0] != expectedMd5 {
		t.Errorf("Expected md5 metadata '%s', but found '%s'",
			expectedMd5, opts.Meta["md5"][0])
	}
	if opts.Meta["institution"][0] != "test.edu" {
		t.Errorf("Expected institution metadata 'test.edu', but found '%s'",
			opts.Meta["institution"][0])
	}
	if opts.Meta["bag"][0] != "ncsu.1840.16-2928" {
		t.Errorf("Expected bag metadata 'ncsu.1840.16-2928', but found '%s'",
			opts.Meta["bag"][0])
	}
	if opts.Meta["bagpath"][0] != file.Path {
		t.Errorf("Expected bag metadata '%s', but found '%s'",
			file.Path, opts.Meta["bagpath"][0])
	}
	deleteLocalFiles()
}

func TestUpdateFluctusStatus(t *testing.T) {
	if environmentReady() == false {
		return
	}
	helper := getIngestHelper()
	helper.UpdateFluctusStatus(bagman.StageRecord, bagman.StatusStarted)

}

func TestFullProcess(t *testing.T) {
	if environmentReady() == false {
		return
	}

	helper := getIngestHelper()

	helper.FetchTarFile()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Fetch" {
		t.Errorf("Stage should be 'Fetch' but is '%s'", helper.Result.Stage)
	}
	verifyFetchResult(t, helper.Result.FetchResult)

	helper.ProcessBagFile()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Validate" {
		t.Errorf("Stage should be 'Validate' but is '%s'", helper.Result.Stage)
	}
	verifyBagReadResult(t, helper.Result.BagReadResult)

	helper.SaveGenericFiles()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}
	if helper.Result.Stage != "Store" {
		t.Errorf("Stage should be 'Store' but is '%s'", helper.Result.Stage)
	}
	for _, file := range helper.Result.TarResult.Files {
		if file.StorageURL == "" {
			t.Errorf("File '%s' is missing S3 URL", file.Path)
		}
		if file.StoredAt.IsZero() {
			t.Errorf("File '%s' is missing StoredAt time", file.Path)
		}
		if file.StorageMd5 == "" {
			t.Errorf("File '%s' is missing StorageMd5", file.Path)
		}
	}

	helper.LogResult()
	if helper.Result.ErrorMessage != "" {
		t.Errorf(helper.Result.ErrorMessage)
	}

	errors := helper.DeleteLocalFiles()
	if len(errors) > 0 {
		for _, err := range errors {
			t.Error(err)
		}
	}

	deleteLocalFiles()
	deleteS3Files(helper.Result.TarResult.Files, helper.ProcUtil.S3Client)
}

func verifyResult(t *testing.T, itemName, expected, actual string) {
	if expected != actual {
		t.Errorf("%s expected '%s' but got '%s'", itemName, expected, actual)
	}
}

func verifyFetchResult(t *testing.T, fetchResult *bagman.FetchResult) {
	verifyResult(t, "BucketName", "aptrust.receiving.test.edu", fetchResult.BucketName)
	verifyResult(t, "Key", "ncsu.1840.16-2928.tar", fetchResult.Key)
	verifyResult(t, "LocalTarFile", "tmp/ncsu.1840.16-2928.tar", fetchResult.LocalTarFile)
	verifyResult(t, "RemoteMd5", "b4f8f3072f73598fc5b65bf416b6019a", fetchResult.RemoteMd5)
	verifyResult(t, "LocalMd5", "b4f8f3072f73598fc5b65bf416b6019a", fetchResult.LocalMd5)
	verifyResult(t, "Md5Verified", "true", strconv.FormatBool(fetchResult.Md5Verified))
	verifyResult(t, "Md5Verifiable", "true", strconv.FormatBool(fetchResult.Md5Verifiable))
	verifyResult(t, "ErrorMessage", "", fetchResult.ErrorMessage)
	verifyResult(t, "Warning", "", fetchResult.Warning)
	verifyResult(t, "Retry", "true", strconv.FormatBool(fetchResult.Retry))
}

// Do a high-level check. Other unit tests cover the details
func verifyBagReadResult(t *testing.T, bagReadResult *bagman.BagReadResult) {
	if !strings.HasSuffix(bagReadResult.Path, "/bagman/bagman/tmp/ncsu.1840.16-2928") {
		t.Errorf("Wrong BagReadResult.Path: '%s'", bagReadResult.Path)
	}
	verifyResult(t, "ErrorMessage", "", bagReadResult.ErrorMessage)
	verifyResult(t, "File Count", "9", strconv.FormatInt(int64(len(bagReadResult.Files)), 10))
	verifyResult(t, "Tag Count", "7", strconv.FormatInt(int64(len(bagReadResult.Tags)), 10))
	verifyResult(t, "Checksum Error Count", "0", strconv.FormatInt(int64(len(bagReadResult.ChecksumErrors)), 10))
}
<|endoftext|>


<commit_before>package nimble

const debugMode = true
<commit_msg>Turn off debug mode.<commit_after>package nimble

const debugMode = false
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/crypto/ssh/terminal"

	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/cafebazaar/kupak/logging"
	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
	"github.com/codegangsta/cli"
	"gopkg.in/yaml.v2"
)

func install(c *cli.Context) {
	pakURL := c.Args().First()
	valuesFile := c.Args().Get(1)
	if pakURL == "" {
		logging.Error("Please specify the pak")
		os.Exit(-1)
	}

	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToInstall := pakURL
		repoAddr := c.GlobalString("repo")

		// it's a pak name
		// will install from repo
		if logging.Verbose {
			logging.Log("Looking for " + nameOfPakToInstall + " in " + repoAddr)
		}

		if len(repoAddr) > 0 {
			// TODO: change JoinURL
			repoPaks, _ := pak.RepoFromURL(repoAddr)
			for _, pak := range repoPaks.Paks {
				if pak.Name == nameOfPakToInstall {
					pakURL = pak.URL
					if util.Relative(pakURL) {
						pakURL = util.JoinURL(repoAddr, pakURL)
					}
				}
			}
		}
	}

	p, err := pak.FromURL(pakURL)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}

	values := make(map[string]interface{})
	if c.Bool("interactive") || terminal.IsTerminal(int(os.Stdin.Fd())) {
		values = readValuesInteractively(p)
	} else {
		values = readValuesFromFile(p, valuesFile)
	}

	_, err = pakManager.Install(p, c.GlobalString("namespace"), values)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
}

func readValuesFromFile(p *pak.Pak, path string) map[string]interface{} {
	values := make(map[string]interface{})
	var valuesData []byte
	var err error
	if path == "" {
		valuesData, err = ioutil.ReadAll(os.Stdin)
	} else {
		valuesData, err = ioutil.ReadFile(path)
	}
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	err = yaml.Unmarshal(valuesData, &values)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	return values
}

func readValuesInteractively(p *pak.Pak) map[string]interface{} {
	values := make(map[string]interface{})

	// ask for group
	groupValue, err := scanValue("Group Name (return for random): ", "string", false)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	if groupValue != nil {
		values["group"] = groupValue.(string)
	}

	// ask for all properties
	for i := range p.Properties {
		var prompt string
		if p.Properties[i].Default == nil {
			prompt = fmt.Sprintf("Field \"%s\" [type: %s]? ", p.Properties[i].Name, p.Properties[i].Type)
		} else {
			prompt = fmt.Sprintf("Field \"%s\" [type: %s, default: %v] (return for default)? ", p.Properties[i].Name, p.Properties[i].Type, p.Properties[i].Default)
		}
		value, err := scanValue(prompt, p.Properties[i].Type, p.Properties[i].Default == nil)
		if err != nil {
			logging.Error(fmt.Sprint(err))
			os.Exit(-1)
		}
		if value != nil {
			values[p.Properties[i].Name] = value
		}
	}
	return values
}

func scanValue(prompt string, valueType string, required bool) (interface{}, error) {
	bio := bufio.NewReader(os.Stdin)
	var value []byte
	var err error
	for {
		fmt.Printf(prompt)
		value, _, err = bio.ReadLine()
		if err != nil {
			return nil, err
		}
		if len(value) == 0 && !required {
			return nil, nil
		} else if len(value) == 0 && required {
			continue
		}

		switch valueType {
		case "int":
			i, err := strconv.Atoi(string(value))
			if err != nil {
				fmt.Println("given value is not an int, try again")
				continue
			}
			return i, nil
		case "bool":
			b, err := util.StringToBool(string(value))
			if err != nil {
				fmt.Println(err)
				continue
			}
			return b, nil
		case "string":
			fallthrough
		default:
			return string(value), nil
		}
	}
}
<commit_msg>Added verbose logs to main package files<commit_after>package main

import (
	"golang.org/x/crypto/ssh/terminal"

	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/cafebazaar/kupak/logging"
	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
	"github.com/codegangsta/cli"
	"gopkg.in/yaml.v2"
)

func install(c *cli.Context) {
	pakURL := c.Args().First()
	valuesFile := c.Args().Get(1)
	if pakURL == "" {
		logging.Error("Please specify the pak")
		os.Exit(-1)
	}

	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToInstall := pakURL
		repoAddr := c.GlobalString("repo")

		// it's a pak name
		// will install from repo
		if logging.Verbose {
			logging.Log("Looking for " + nameOfPakToInstall + " in " + repoAddr)
		}

		if len(repoAddr) > 0 {
			// TODO: change JoinURL
			repoPaks, _ := pak.RepoFromURL(repoAddr)
			for _, pak := range repoPaks.Paks {
				if pak.Name == nameOfPakToInstall {
					pakURL = pak.URL
					if util.Relative(pakURL) {
						pakURL = util.JoinURL(repoAddr, pakURL)
					}
				}
			}
		}
	}

	if logging.Verbose {
		logging.Log("Fetching " + pakURL)
	}
	p, err := pak.FromURL(pakURL)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}

	values := make(map[string]interface{})
	if c.Bool("interactive") || terminal.IsTerminal(int(os.Stdin.Fd())) {
		values = readValuesInteractively(p)
	} else {
		values = readValuesFromFile(p, valuesFile)
	}

	_, err = pakManager.Install(p, c.GlobalString("namespace"), values)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
}

func readValuesFromFile(p *pak.Pak, path string) map[string]interface{} {
	values := make(map[string]interface{})
	var valuesData []byte
	var err error
	if path == "" {
		valuesData, err = ioutil.ReadAll(os.Stdin)
	} else {
		valuesData, err = ioutil.ReadFile(path)
	}
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	err = yaml.Unmarshal(valuesData, &values)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	return values
}

func readValuesInteractively(p *pak.Pak) map[string]interface{} {
	values := make(map[string]interface{})

	// ask for group
	groupValue, err := scanValue("Group Name (return for random): ", "string", false)
	if err != nil {
		logging.Error(fmt.Sprint(err))
		os.Exit(-1)
	}
	if groupValue != nil {
		values["group"] = groupValue.(string)
	}

	// ask for all properties
	for i := range p.Properties {
		var prompt string
		if p.Properties[i].Default == nil {
			prompt = fmt.Sprintf("Field \"%s\" [type: %s]? ", p.Properties[i].Name, p.Properties[i].Type)
		} else {
			prompt = fmt.Sprintf("Field \"%s\" [type: %s, default: %v] (return for default)? ", p.Properties[i].Name, p.Properties[i].Type, p.Properties[i].Default)
		}
		value, err := scanValue(prompt, p.Properties[i].Type, p.Properties[i].Default == nil)
		if err != nil {
			logging.Error(fmt.Sprint(err))
			os.Exit(-1)
		}
		if value != nil {
			values[p.Properties[i].Name] = value
		}
	}
	return values
}

func scanValue(prompt string, valueType string, required bool) (interface{}, error) {
	bio := bufio.NewReader(os.Stdin)
	var value []byte
	var err error
	for {
		fmt.Printf(prompt)
		value, _, err = bio.ReadLine()
		if err != nil {
			return nil, err
		}
		if len(value) == 0 && !required {
			return nil, nil
		} else if len(value) == 0 && required {
			continue
		}

		switch valueType {
		case "int":
			i, err := strconv.Atoi(string(value))
			if err != nil {
				fmt.Println("given value is not an int, try again")
				continue
			}
			return i, nil
		case "bool":
			b, err := util.StringToBool(string(value))
			if err != nil {
				fmt.Println(err)
				continue
			}
			return b, nil
		case "string":
			fallthrough
		default:
			return string(value), nil
		}
	}
}
<|endoftext|>


<commit_before>package stripe

import "encoding/json"

// InvoiceLineType is the list of allowed values for the invoice line's type.
type InvoiceLineType string

// List of values that InvoiceLineType can take.
const (
	InvoiceLineTypeInvoiceItem  InvoiceLineType = "invoiceitem"
	InvoiceLineTypeSubscription InvoiceLineType = "subscription"
)

// InvoiceBilling is the type of billing method for this invoice.
type InvoiceBilling string

// List of values that InvoiceBilling can take.
const (
	InvoiceBillingChargeAutomatically InvoiceBilling = "charge_automatically"
	InvoiceBillingSendInvoice         InvoiceBilling = "send_invoice"
)

// InvoiceBillingReason is the reason why a given invoice was created
type InvoiceBillingReason string

// List of values that InvoiceBillingReason can take.
const (
	InvoiceBillingReasonManual                InvoiceBillingReason = "manual"
	InvoiceBillingReasonSubscription          InvoiceBillingReason = "subscription"
	InvoiceBillingReasonSubscriptionCreate    InvoiceBillingReason = "subscription_create"
	InvoiceBillingReasonSubscriptionCycle     InvoiceBillingReason = "subscription_cycle"
	InvoiceBillingReasonSubscriptionThreshold InvoiceBillingReason = "subscription_threshold"
	InvoiceBillingReasonSubscriptionUpdate    InvoiceBillingReason = "subscription_update"
	InvoiceBillingReasonUpcoming              InvoiceBillingReason = "upcoming"
)

// InvoiceBillingStatus is the reason why a given invoice was created
type InvoiceBillingStatus string

// List of values that InvoiceBillingStatus can take.
const (
	InvoiceBillingStatusDraft         InvoiceBillingStatus = "draft"
	InvoiceBillingStatusOpen          InvoiceBillingStatus = "open"
	InvoiceBillingStatusPaid          InvoiceBillingStatus = "paid"
	InvoiceBillingStatusUncollectible InvoiceBillingStatus = "uncollectible"
	InvoiceBillingStatusVoid          InvoiceBillingStatus = "void"
)

// InvoiceUpcomingInvoiceItemPeriodParams represents the period associated with that invoice item
type InvoiceUpcomingInvoiceItemPeriodParams struct {
	End   *int64 `form:"end"`
	Start *int64 `form:"start"`
}

// InvoiceUpcomingInvoiceItemParams is the set of parameters that can be used when adding or modifying
// invoice items on an upcoming invoice.
// For more details see https://stripe.com/docs/api#upcoming_invoice-invoice_items.
type InvoiceUpcomingInvoiceItemParams struct {
	Amount       *int64                                  `form:"amount"`
	Currency     *string                                 `form:"currency"`
	Description  *string                                 `form:"description"`
	Discountable *bool                                   `form:"discountable"`
	InvoiceItem  *string                                 `form:"invoiceitem"`
	Period       *InvoiceUpcomingInvoiceItemPeriodParams `form:"period"`
	Quantity     *int64                                  `form:"quantity"`
	UnitAmount   *int64                                  `form:"unit_amount"`
}

// InvoiceCustomFieldParams represents the parameters associated with one custom field on an invoice.
type InvoiceCustomFieldParams struct {
	Name  *string `form:"name"`
	Value *string `form:"value"`
}

// InvoiceTransferDataParams is the set of parameters allowed for the transfer_data hash.
type InvoiceTransferDataParams struct {
	Destination *string `form:"destination"`
}

// InvoiceParams is the set of parameters that can be used when creating or updating an invoice.
// For more details see https://stripe.com/docs/api#create_invoice, https://stripe.com/docs/api#update_invoice.
type InvoiceParams struct {
	Params               `form:"*"`
	AutoAdvance          *bool                       `form:"auto_advance"`
	ApplicationFeeAmount *int64                      `form:"application_fee_amount"`
	Billing              *string                     `form:"billing"`
	CustomFields         []*InvoiceCustomFieldParams `form:"custom_fields"`
	Customer             *string                     `form:"customer"`
	DaysUntilDue         *int64                      `form:"days_until_due"`
	DefaultSource        *string                     `form:"default_source"`
	Description          *string                     `form:"description"`
	DueDate              *int64                      `form:"due_date"`
	Footer               *string                     `form:"footer"`
	Paid                 *bool                       `form:"paid"`
	StatementDescriptor  *string                     `form:"statement_descriptor"`
	Subscription         *string                     `form:"subscription"`
	TaxPercent           *float64                    `form:"tax_percent"`
	TransferData         *InvoiceTransferDataParams  `form:"transfer_data"`

	// These are all for exclusive use by GetNext.

	Coupon                         *string                           `form:"coupon"`
	InvoiceItems                   *InvoiceUpcomingInvoiceItemParams `form:"invoice_items"`
	SubscriptionBillingCycleAnchor *int64                            `form:"subscription_billing_cycle_anchor"`
	SubscriptionCancelAtPeriodEnd  *bool                             `form:"subscription_cancel_at_period_end"`
	SubscriptionItems              []*SubscriptionItemsParams        `form:"subscription_items"`
	SubscriptionPlan               *string                           `form:"subscription_plan"`
	SubscriptionProrate            *bool                             `form:"subscription_prorate"`
	SubscriptionProrationDate      *int64                            `form:"subscription_proration_date"`
	SubscriptionQuantity           *int64                            `form:"subscription_quantity"`
	SubscriptionTaxPercent         *float64                          `form:"subscription_tax_percent"`
	SubscriptionTrialEnd           *int64                            `form:"subscription_trial_end"`
	SubscriptionTrialFromPlan      *bool                             `form:"subscription_trial_from_plan"`

	// This parameter is considered deprecated. Prefer using ApplicationFeeAmount
	ApplicationFee *int64 `form:"application_fee"`
}

// InvoiceListParams is the set of parameters that can be used when listing invoices.
// For more details see https://stripe.com/docs/api#list_customer_invoices.
type InvoiceListParams struct {
	ListParams   `form:"*"`
	Billing      *string           `form:"billing"`
	Customer     *string           `form:"customer"`
	Date         *int64            `form:"date"`
	DateRange    *RangeQueryParams `form:"date"`
	DueDate      *int64            `form:"due_date"`
	Subscription *string           `form:"subscription"`
}

// InvoiceLineListParams is the set of parameters that can be used when listing invoice line items.
// For more details see https://stripe.com/docs/api#invoice_lines.
type InvoiceLineListParams struct {
	ListParams `form:"*"`

	Customer *string `form:"customer"`

	// ID is the invoice ID to list invoice lines for.
	ID *string `form:"-"` // Goes in the URL

	Subscription *string `form:"subscription"`
}

// InvoiceFinalizeParams is the set of parameters that can be used when finalizing invoices.
type InvoiceFinalizeParams struct {
	Params      `form:"*"`
	AutoAdvance *bool `form:"auto_advance"`
}

// InvoiceMarkUncollectibleParams is the set of parameters that can be used when marking
// invoices as uncollectible.
type InvoiceMarkUncollectibleParams struct {
	Params `form:"*"`
}

// InvoicePayParams is the set of parameters that can be used when
// paying invoices. For more details, see:
// https://stripe.com/docs/api#pay_invoice.
type InvoicePayParams struct {
	Params        `form:"*"`
	Forgive       *bool   `form:"forgive"`
	PaidOutOfBand *bool   `form:"paid_out_of_band"`
	Source        *string `form:"source"`
}

// InvoiceSendParams is the set of parameters that can be used when sending invoices.
type InvoiceSendParams struct {
	Params `form:"*"`
}

// InvoiceVoidParams is the set of parameters that can be used when voiding invoices.
type InvoiceVoidParams struct {
	Params `form:"*"`
}

// Invoice is the resource representing a Stripe invoice.
// For more details see https://stripe.com/docs/api#invoice_object.
type Invoice struct {
	AmountDue                 int64                   `json:"amount_due"`
	AmountPaid                int64                   `json:"amount_paid"`
	AmountRemaining           int64                   `json:"amount_remaining"`
	ApplicationFeeAmount      int64                   `json:"application_fee_amount"`
	AttemptCount              int64                   `json:"attempt_count"`
	Attempted                 bool                    `json:"attempted"`
	AutoAdvance               bool                    `json:"auto_advance"`
	Billing                   InvoiceBilling          `json:"billing"`
	BillingReason             InvoiceBillingReason    `json:"billing_reason"`
	Charge                    *Charge                 `json:"charge"`
	Currency                  Currency                `json:"currency"`
	CustomFields              []*InvoiceCustomField   `json:"custom_fields"`
	Customer                  *Customer               `json:"customer"`
	Date                      int64                   `json:"date"`
	DefaultSource             *PaymentSource          `json:"default_source"`
	Description               string                  `json:"description"`
	Discount                  *Discount               `json:"discount"`
	DueDate                   int64                   `json:"due_date"`
	EndingBalance             int64                   `json:"ending_balance"`
	FinalizedAt               int64                   `json:"finalized_at"`
	Footer                    string                  `json:"footer"`
	HostedInvoiceURL          string                  `json:"hosted_invoice_url"`
	ID                        string                  `json:"id"`
	InvoicePDF                string                  `json:"invoice_pdf"`
	Lines                     *InvoiceLineList        `json:"lines"`
	Livemode                  bool                    `json:"livemode"`
	Metadata                  map[string]string       `json:"metadata"`
	NextPaymentAttempt        int64                   `json:"next_payment_attempt"`
	Number                    string                  `json:"number"`
	Paid                      bool                    `json:"paid"`
	PeriodEnd                 int64                   `json:"period_end"`
	PeriodStart               int64                   `json:"period_start"`
	ReceiptNumber             string                  `json:"receipt_number"`
	StartingBalance           int64                   `json:"starting_balance"`
	StatementDescriptor       string                  `json:"statement_descriptor"`
	Status                    InvoiceBillingStatus    `json:"status"`
	Subscription              string                  `json:"subscription"`
	SubscriptionProrationDate int64                   `json:"subscription_proration_date"`
	Subtotal                  int64                   `json:"subtotal"`
	Tax                       int64                   `json:"tax"`
	TaxPercent                float64                 `json:"tax_percent"`
	ThreasholdReason          *InvoiceThresholdReason `json:"threshold_reason"`
	Total                     int64                   `json:"total"`
	TransferData              *InvoiceTransferData    `json:"transfer_data"`
	WebhooksDeliveredAt       int64                   `json:"webhooks_delivered_at"`

	// This property is considered deprecated. Prefer using ApplicationFeeAmount
	ApplicationFee int64 `json:"application_fee"`
}

// InvoiceCustomField is a structure representing a custom field on an Invoice.
type InvoiceCustomField struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

// InvoiceThresholdReason is a structure representing a reason for a billing threshold.
type InvoiceThresholdReason struct {
	AmountGTE   int64                               `json:"amount_gte"`
	ItemReasons []*InvoiceThresholdReasonItemReason `json:"item_reasons"`
}

// InvoiceThresholdReasonItemReason is a structure representing the line items that
// triggered an invoice.
type InvoiceThresholdReasonItemReason struct {
	LineItemIDs []string `json:"line_item_ids"`
	UsageGTE    int64    `json:"usage_gte"`
}

// InvoiceList is a list of invoices as retrieved from a list endpoint.
type InvoiceList struct {
	ListMeta
	Data []*Invoice `json:"data"`
}

// InvoiceLine is the resource representing a Stripe invoice line item.
// For more details see https://stripe.com/docs/api#invoice_line_item_object.
type InvoiceLine struct {
	Amount           int64             `json:"amount"`
	Currency         Currency          `json:"currency"`
	Description      string            `json:"description"`
	Discountable     bool              `json:"discountable"`
	ID               string            `json:"id"`
	Livemode         bool              `json:"live_mode"`
	Metadata         map[string]string `json:"metadata"`
	Period           *Period           `json:"period"`
	Plan             *Plan             `json:"plan"`
	Proration        bool              `json:"proration"`
	Quantity         int64             `json:"quantity"`
	Subscription     string            `json:"subscription"`
	SubscriptionItem string            `json:"subscription_item"`
	Type             InvoiceLineType   `json:"type"`
}

// InvoiceTransferData represents the information for the transfer_data associated with an invoice.
type InvoiceTransferData struct {
	Destination *Account `json:"destination"`
}

// Period is a structure representing a start and end dates.
type Period struct {
	End   int64 `json:"end"`
	Start int64 `json:"start"`
}

// InvoiceLineList is a list object for invoice line items.
type InvoiceLineList struct {
	ListMeta
	Data []*InvoiceLine `json:"data"`
}

// UnmarshalJSON handles deserialization of an Invoice.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (i *Invoice) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		i.ID = id
		return nil
	}

	type invoice Invoice
	var v invoice
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*i = Invoice(v)
	return nil
}
<commit_msg>Make invoice items a slice, as per API spec<commit_after>package stripe

import "encoding/json"

// InvoiceLineType is the list of allowed values for the invoice line's type.
type InvoiceLineType string

// List of values that InvoiceLineType can take.
const (
	InvoiceLineTypeInvoiceItem  InvoiceLineType = "invoiceitem"
	InvoiceLineTypeSubscription InvoiceLineType = "subscription"
)

// InvoiceBilling is the type of billing method for this invoice.
type InvoiceBilling string

// List of values that InvoiceBilling can take.
const (
	InvoiceBillingChargeAutomatically InvoiceBilling = "charge_automatically"
	InvoiceBillingSendInvoice         InvoiceBilling = "send_invoice"
)

// InvoiceBillingReason is the reason why a given invoice was created
type InvoiceBillingReason string

// List of values that InvoiceBillingReason can take.
const (
	InvoiceBillingReasonManual                InvoiceBillingReason = "manual"
	InvoiceBillingReasonSubscription          InvoiceBillingReason = "subscription"
	InvoiceBillingReasonSubscriptionCreate    InvoiceBillingReason = "subscription_create"
	InvoiceBillingReasonSubscriptionCycle     InvoiceBillingReason = "subscription_cycle"
	InvoiceBillingReasonSubscriptionThreshold InvoiceBillingReason = "subscription_threshold"
	InvoiceBillingReasonSubscriptionUpdate    InvoiceBillingReason = "subscription_update"
	InvoiceBillingReasonUpcoming              InvoiceBillingReason = "upcoming"
)

// InvoiceBillingStatus is the reason why a given invoice was created
type InvoiceBillingStatus string

// List of values that InvoiceBillingStatus can take.
const (
	InvoiceBillingStatusDraft         InvoiceBillingStatus = "draft"
	InvoiceBillingStatusOpen          InvoiceBillingStatus = "open"
	InvoiceBillingStatusPaid          InvoiceBillingStatus = "paid"
	InvoiceBillingStatusUncollectible InvoiceBillingStatus = "uncollectible"
	InvoiceBillingStatusVoid          InvoiceBillingStatus = "void"
)

// InvoiceUpcomingInvoiceItemPeriodParams represents the period associated with that invoice item
type InvoiceUpcomingInvoiceItemPeriodParams struct {
	End   *int64 `form:"end"`
	Start *int64 `form:"start"`
}

// InvoiceUpcomingInvoiceItemParams is the set of parameters that can be used when adding or modifying
// invoice items on an upcoming invoice.
// For more details see https://stripe.com/docs/api#upcoming_invoice-invoice_items.
type InvoiceUpcomingInvoiceItemParams struct {
	Amount       *int64                                  `form:"amount"`
	Currency     *string                                 `form:"currency"`
	Description  *string                                 `form:"description"`
	Discountable *bool                                   `form:"discountable"`
	InvoiceItem  *string                                 `form:"invoiceitem"`
	Period       *InvoiceUpcomingInvoiceItemPeriodParams `form:"period"`
	Quantity     *int64                                  `form:"quantity"`
	UnitAmount   *int64                                  `form:"unit_amount"`
}

// InvoiceCustomFieldParams represents the parameters associated with one custom field on an invoice.
type InvoiceCustomFieldParams struct {
	Name  *string `form:"name"`
	Value *string `form:"value"`
}

// InvoiceTransferDataParams is the set of parameters allowed for the transfer_data hash.
type InvoiceTransferDataParams struct {
	Destination *string `form:"destination"`
}

// InvoiceParams is the set of parameters that can be used when creating or updating an invoice.
// For more details see https://stripe.com/docs/api#create_invoice, https://stripe.com/docs/api#update_invoice.
type InvoiceParams struct {
	Params               `form:"*"`
	AutoAdvance          *bool                       `form:"auto_advance"`
	ApplicationFeeAmount *int64                      `form:"application_fee_amount"`
	Billing              *string                     `form:"billing"`
	CustomFields         []*InvoiceCustomFieldParams `form:"custom_fields"`
	Customer             *string                     `form:"customer"`
	DaysUntilDue         *int64                      `form:"days_until_due"`
	DefaultSource        *string                     `form:"default_source"`
	Description          *string                     `form:"description"`
	DueDate              *int64                      `form:"due_date"`
	Footer               *string                     `form:"footer"`
	Paid                 *bool                       `form:"paid"`
	StatementDescriptor  *string                     `form:"statement_descriptor"`
	Subscription         *string                     `form:"subscription"`
	TaxPercent           *float64                    `form:"tax_percent"`
	TransferData         *InvoiceTransferDataParams  `form:"transfer_data"`

	// These are all for exclusive use by GetNext.

	Coupon                         *string                             `form:"coupon"`
	InvoiceItems                   []*InvoiceUpcomingInvoiceItemParams `form:"invoice_items"`
	SubscriptionBillingCycleAnchor *int64                              `form:"subscription_billing_cycle_anchor"`
	SubscriptionCancelAtPeriodEnd  *bool                               `form:"subscription_cancel_at_period_end"`
	SubscriptionItems              []*SubscriptionItemsParams          `form:"subscription_items"`
	SubscriptionPlan               *string                             `form:"subscription_plan"`
	SubscriptionProrate            *bool                               `form:"subscription_prorate"`
	SubscriptionProrationDate      *int64                              `form:"subscription_proration_date"`
	SubscriptionQuantity           *int64                              `form:"subscription_quantity"`
	SubscriptionTaxPercent         *float64                            `form:"subscription_tax_percent"`
	SubscriptionTrialEnd           *int64                              `form:"subscription_trial_end"`
	SubscriptionTrialFromPlan      *bool                               `form:"subscription_trial_from_plan"`

	// This parameter is considered deprecated. Prefer using ApplicationFeeAmount
	ApplicationFee *int64 `form:"application_fee"`
}

// InvoiceListParams is the set of parameters that can be used when listing invoices.
// For more details see https://stripe.com/docs/api#list_customer_invoices.
type InvoiceListParams struct {
	ListParams   `form:"*"`
	Billing      *string           `form:"billing"`
	Customer     *string           `form:"customer"`
	Date         *int64            `form:"date"`
	DateRange    *RangeQueryParams `form:"date"`
	DueDate      *int64            `form:"due_date"`
	Subscription *string           `form:"subscription"`
}

// InvoiceLineListParams is the set of parameters that can be used when listing invoice line items.
// For more details see https://stripe.com/docs/api#invoice_lines.
type InvoiceLineListParams struct {
	ListParams `form:"*"`

	Customer *string `form:"customer"`

	// ID is the invoice ID to list invoice lines for.
	ID *string `form:"-"` // Goes in the URL

	Subscription *string `form:"subscription"`
}

// InvoiceFinalizeParams is the set of parameters that can be used when finalizing invoices.
type InvoiceFinalizeParams struct {
	Params      `form:"*"`
	AutoAdvance *bool `form:"auto_advance"`
}

// InvoiceMarkUncollectibleParams is the set of parameters that can be used when marking
// invoices as uncollectible.
type InvoiceMarkUncollectibleParams struct {
	Params `form:"*"`
}

// InvoicePayParams is the set of parameters that can be used when
// paying invoices. For more details, see:
// https://stripe.com/docs/api#pay_invoice.
type InvoicePayParams struct {
	Params        `form:"*"`
	Forgive       *bool   `form:"forgive"`
	PaidOutOfBand *bool   `form:"paid_out_of_band"`
	Source        *string `form:"source"`
}

// InvoiceSendParams is the set of parameters that can be used when sending invoices.
type InvoiceSendParams struct {
	Params `form:"*"`
}

// InvoiceVoidParams is the set of parameters that can be used when voiding invoices.
type InvoiceVoidParams struct {
	Params `form:"*"`
}

// Invoice is the resource representing a Stripe invoice.
// For more details see https://stripe.com/docs/api#invoice_object.
type Invoice struct {
	AmountDue                 int64                   `json:"amount_due"`
	AmountPaid                int64                   `json:"amount_paid"`
	AmountRemaining           int64                   `json:"amount_remaining"`
	ApplicationFeeAmount      int64                   `json:"application_fee_amount"`
	AttemptCount              int64                   `json:"attempt_count"`
	Attempted                 bool                    `json:"attempted"`
	AutoAdvance               bool                    `json:"auto_advance"`
	Billing                   InvoiceBilling          `json:"billing"`
	BillingReason             InvoiceBillingReason    `json:"billing_reason"`
	Charge                    *Charge                 `json:"charge"`
	Currency                  Currency                `json:"currency"`
	CustomFields              []*InvoiceCustomField   `json:"custom_fields"`
	Customer                  *Customer               `json:"customer"`
	Date                      int64                   `json:"date"`
	DefaultSource             *PaymentSource          `json:"default_source"`
	Description               string                  `json:"description"`
	Discount                  *Discount               `json:"discount"`
	DueDate                   int64                   `json:"due_date"`
	EndingBalance             int64                   `json:"ending_balance"`
	FinalizedAt               int64                   `json:"finalized_at"`
	Footer                    string                  `json:"footer"`
	HostedInvoiceURL          string                  `json:"hosted_invoice_url"`
	ID                        string                  `json:"id"`
	InvoicePDF                string                  `json:"invoice_pdf"`
	Lines                     *InvoiceLineList        `json:"lines"`
	Livemode                  bool                    `json:"livemode"`
	Metadata                  map[string]string       `json:"metadata"`
	NextPaymentAttempt        int64                   `json:"next_payment_attempt"`
	Number                    string                  `json:"number"`
	Paid                      bool                    `json:"paid"`
	PeriodEnd                 int64                   `json:"period_end"`
	PeriodStart               int64                   `json:"period_start"`
	ReceiptNumber             string                  `json:"receipt_number"`
	StartingBalance           int64                   `json:"starting_balance"`
	StatementDescriptor       string                  `json:"statement_descriptor"`
	Status                    InvoiceBillingStatus    `json:"status"`
	Subscription              string                  `json:"subscription"`
	SubscriptionProrationDate int64                   `json:"subscription_proration_date"`
	Subtotal                  int64                   `json:"subtotal"`
	Tax                       int64                   `json:"tax"`
	TaxPercent                float64                 `json:"tax_percent"`
	ThreasholdReason          *InvoiceThresholdReason `json:"threshold_reason"`
	Total                     int64                   `json:"total"`
	TransferData              *InvoiceTransferData    `json:"transfer_data"`
	WebhooksDeliveredAt       int64                   `json:"webhooks_delivered_at"`

	// This property is considered deprecated. Prefer using ApplicationFeeAmount
	ApplicationFee int64 `json:"application_fee"`
}

// InvoiceCustomField is a structure representing a custom field on an Invoice.
type InvoiceCustomField struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

// InvoiceThresholdReason is a structure representing a reason for a billing threshold.
type InvoiceThresholdReason struct {
	AmountGTE   int64                               `json:"amount_gte"`
	ItemReasons []*InvoiceThresholdReasonItemReason `json:"item_reasons"`
}

// InvoiceThresholdReasonItemReason is a structure representing the line items that
// triggered an invoice.
type InvoiceThresholdReasonItemReason struct {
	LineItemIDs []string `json:"line_item_ids"`
	UsageGTE    int64    `json:"usage_gte"`
}

// InvoiceList is a list of invoices as retrieved from a list endpoint.
type InvoiceList struct {
	ListMeta
	Data []*Invoice `json:"data"`
}

// InvoiceLine is the resource representing a Stripe invoice line item.
// For more details see https://stripe.com/docs/api#invoice_line_item_object.
type InvoiceLine struct {
	Amount           int64             `json:"amount"`
	Currency         Currency          `json:"currency"`
	Description      string            `json:"description"`
	Discountable     bool              `json:"discountable"`
	ID               string            `json:"id"`
	Livemode         bool              `json:"live_mode"`
	Metadata         map[string]string `json:"metadata"`
	Period           *Period           `json:"period"`
	Plan             *Plan             `json:"plan"`
	Proration        bool              `json:"proration"`
	Quantity         int64             `json:"quantity"`
	Subscription     string            `json:"subscription"`
	SubscriptionItem string            `json:"subscription_item"`
	Type             InvoiceLineType   `json:"type"`
}

// InvoiceTransferData represents the information for the transfer_data associated with an invoice.
type InvoiceTransferData struct {
	Destination *Account `json:"destination"`
}

// Period is a structure representing a start and end dates.
type Period struct {
	End   int64 `json:"end"`
	Start int64 `json:"start"`
}

// InvoiceLineList is a list object for invoice line items.
type InvoiceLineList struct {
	ListMeta
	Data []*InvoiceLine `json:"data"`
}

// UnmarshalJSON handles deserialization of an Invoice.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (i *Invoice) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		i.ID = id
		return nil
	}

	type invoice Invoice
	var v invoice
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*i = Invoice(v)
	return nil
}
<|endoftext|>


<commit_before>package msglog

import (
	"github.com/davyxu/cellnet"
	"sync"
)

var (
	blockedMsgByID sync.Map
)

// 当前的某个消息ID是否被屏蔽
func IsBlockedMessageByID(msgid int) bool {

	_, ok := blockedMsgByID.Load(msgid)

	return ok
}

// 按指定规则(或消息名)屏蔽消息日志
func BlockMessageLog(nameRule string) (err error, matchCount int) {

	err = cellnet.MessageMetaVisit(nameRule, func(meta *cellnet.MessageMeta) bool {

		blockedMsgByID.Store(int(meta.ID), meta)
		matchCount++

		return true
	})

	return
}
<commit_msg>添加: 消息日志访问函数<commit_after>package msglog

import (
	"github.com/davyxu/cellnet"
	"sync"
)

var (
	blockedMsgByID sync.Map
)

// 当前的某个消息ID是否被屏蔽
func IsBlockedMessageByID(msgid int) bool {

	_, ok := blockedMsgByID.Load(msgid)

	return ok
}

// 按指定规则(或消息名)屏蔽消息日志, 需要使用完整消息名 例如 proto.MsgName
func BlockMessageLog(nameRule string) (err error, matchCount int) {

	err = cellnet.MessageMetaVisit(nameRule, func(meta *cellnet.MessageMeta) bool {

		blockedMsgByID.Store(int(meta.ID), meta)
		matchCount++

		return true
	})

	return
}

// 移除被屏蔽的消息
func RemoveBlockedMessage(nameRule string) (err error, matchCount int) {

	err = cellnet.MessageMetaVisit(nameRule, func(meta *cellnet.MessageMeta) bool {

		blockedMsgByID.Delete(int(meta.ID))
		matchCount++

		return true
	})

	return
}

// 遍历被屏蔽的消息
func VisitBlockedMessage(callback func(*cellnet.MessageMeta) bool) {

	blockedMsgByID.Range(func(key, value interface{}) bool {
		meta := value.(*cellnet.MessageMeta)

		return callback(meta)
	})

}
<|endoftext|>