<commit_before>// Copyright ©2012 The bíogo 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 sam

import (
	"bytes"
	"fmt"
)

// Cigar is a set of CIGAR operations.
type Cigar []CigarOp

// IsValid returns whether the CIGAR string is valid for a record of the given
// sequence length. Validity is defined by the sum of query consuming operations
// matching the given length, clipping operations only being present at the ends
// of alignments, and that CigarBack operations only result in query-consuming
// positions at or right of the start of the alignment.
func (c Cigar) IsValid(length int) bool {
	var pos int
	for i, co := range c {
		ct := co.Type()
		if ct == CigarHardClipped && i != 0 && i != len(c)-1 {
			return false
		}
		if ct == CigarSoftClipped && i != 0 && i != len(c)-1 {
			if c[i-1].Type() != CigarHardClipped && c[i+1].Type() != CigarHardClipped {
				return false
			}
		}
		con := ct.Consumes()
		if pos < 0 && con.Query != 0 {
			return false
		}
		length -= co.Len() * con.Query
		pos += co.Len() * con.Reference
	}
	return length == 0
}

// String returns the CIGAR string for c.
func (c Cigar) String() string {
	if len(c) == 0 {
		return "*"
	}
	var b bytes.Buffer
	for _, co := range c {
		fmt.Fprint(&b, co)
	}
	return b.String()
}

// Lengths returns the number of reference and read bases described by the Cigar.
func (c Cigar) Lengths() (ref, read int) {
	var con Consume
	for _, co := range c {
		con = co.Type().Consumes()
		if co.Type() != CigarBack {
			ref += co.Len() * con.Reference
		}
		read += co.Len() * con.Query
	}
	return ref, read
}

// CigarOp is a single CIGAR operation including the operation type and the
// length of the operation.
type CigarOp uint32

// NewCigarOp returns a CIGAR operation of the specified type with length n.
// Due to a limitation of the BAM format, CIGAR operation lengths are limited
// to 2^28-1, and NewCigarOp will panic if n is above this or negative.
func NewCigarOp(t CigarOpType, n int) CigarOp {
	if uint64(n) > 1<<28-1 {
		panic("sam: illegal CIGAR op length")
	}
	return CigarOp(t) | (CigarOp(n) << 4)
}

// Type returns the type of the CIGAR operation for the CigarOp.
func (co CigarOp) Type() CigarOpType { return CigarOpType(co & 0xf) }

// Len returns the number of positions affected by the CigarOp CIGAR operation.
func (co CigarOp) Len() int { return int(co >> 4) }

// String returns the string representation of the CigarOp
func (co CigarOp) String() string { return fmt.Sprintf("%d%s", co.Len(), co.Type().String()) }

// A CigarOpType represents the type of operation described by a CigarOp.
type CigarOpType byte

const (
	CigarMatch       CigarOpType = iota // Alignment match (can be a sequence match or mismatch).
	CigarInsertion                      // Insertion to the reference.
	CigarDeletion                       // Deletion from the reference.
	CigarSkipped                        // Skipped region from the reference.
	CigarSoftClipped                    // Soft clipping (clipped sequences present in SEQ).
	CigarHardClipped                    // Hard clipping (clipped sequences NOT present in SEQ).
	CigarPadded                         // Padding (silent deletion from padded reference).
	CigarEqual                          // Sequence match.
	CigarMismatch                       // Sequence mismatch.
	CigarBack                           // Skip backwards.
	lastCigar
)

var cigarOps = []string{"M", "I", "D", "N", "S", "H", "P", "=", "X", "B", "?"}

// Consumes returns the CIGAR operation alignment consumption characteristics for the CigarOpType.
//
// The Consume values for each of the CigarOpTypes is as follows:
//
//                    Query  Reference
//  CigarMatch          1        1
//  CigarInsertion      1        0
//  CigarDeletion       0        1
//  CigarSkipped        0        1
//  CigarSoftClipped    1        0
//  CigarHardClipped    0        0
//  CigarPadded         0        0
//  CigarEqual          1        1
//  CigarMismatch       1        1
//  CigarBack           0       -1
//
func (ct CigarOpType) Consumes() Consume { return consume[ct] }

// String returns the string representation of a CigarOpType.
func (ct CigarOpType) String() string {
	if ct < 0 || ct > lastCigar {
		ct = lastCigar
	}
	return cigarOps[ct]
}

// Consume describes how CIGAR operations consume alignment bases.
type Consume struct {
	Query, Reference int
}

// A few years ago, Complete Genomics (CG) proposed to add a new CIGAR
// operator 'B' for an operation of moving backward along the reference
// genome. It is the opposite of the 'N', the reference skip. In a later
// discussion on a separate issue, Fred expressed his preference to a
// negative reference skip which is equivalent to a positive 'B' operation.
// Now the SRA group from NCBI intends to archive the CG alignment in
// the SAM format and raises this request again. I think it may be the
// time to add this backward operation.
//
// The backward operation is designed to describe such an alignment:
//
// REF:: GCATACGATCGACTAGTCACGT
// READ: --ATACGATCGA----------
// READ: ---------CGACTAGTCAC--
//
// i.e. there is an overlap between two segments of a read, which is quite
// frequent in CG data. We are unable to fully describe such an alignment
// with the original CIGAR. In the current spec, we suggest using a CIGAR
// 18M and storing the overlap information in optional tags. This is a
// little clumsy and is not compressed well for the purpose of archiving.
// With 'B', the new CIGAR is "10M3B11M" with no other optional tags.
//
// Using "B" in this case is cleaner, but the major concern is that it breaks
// the compatibility and is also likely to complicate SNP calling and many
// other applications. As I think now, the solution is to implement a
// "remove_B()" routine in samtools. This routine collapses overlapping
// sequences, recalculates base quality in the overlap and gives a CIGAR
// without 'B'. For the example above, remove_B() gives CIGAR 18M. For SNP
// calling, we may call remove_B() immediately after the alignment loaded
// into memory. The downstream pileup engine does not need any changes. Other
// SNP callers can do the same. A new option will be added to "samtools view"
// as a way to remove 'B' operations on the command-line.
//
// The implementation of remove_B() may be quite complicated in the generic
// case - we may be dealing with a multiple-sequence alignment, but it should
// be straightforward in the simple cases such as the example above. Users may
// not need to care too much about how remove_B() is implemented.
//
// http://sourceforge.net/p/samtools/mailman/message/28463294/
var consume = []Consume{
	CigarMatch:       {Query: 1, Reference: 1},
	CigarInsertion:   {Query: 1, Reference: 0},
	CigarDeletion:    {Query: 0, Reference: 1},
	CigarSkipped:     {Query: 0, Reference: 1},
	CigarSoftClipped: {Query: 1, Reference: 0},
	CigarHardClipped: {Query: 0, Reference: 0},
	CigarPadded:      {Query: 0, Reference: 0},
	CigarEqual:       {Query: 1, Reference: 1},
	CigarMismatch:    {Query: 1, Reference: 1},
	CigarBack:        {Query: 0, Reference: -1}, // See notes above.
	lastCigar:        {},
}

var cigarOpTypeLookup [256]CigarOpType

func init() {
	for i := range cigarOpTypeLookup {
		cigarOpTypeLookup[i] = lastCigar
	}
	for op, c := range []byte{'M', 'I', 'D', 'N', 'S', 'H', 'P', '=', 'X', 'B'} {
		cigarOpTypeLookup[c] = CigarOpType(op)
	}
}

var powers = []int64{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12}

// atoi returns the integer interpretation of b which must be an ASCII decimal number representation.
func atoi(b []byte) (int, error) {
	if len(b) > len(powers) {
		return 0, fmt.Errorf("sam: integer overflow: %q", b)
	}
	var n int64
	k := len(b) - 1
	for i, v := range b {
		n += int64(v-'0') * powers[k-i]
		if int64(int(n)) != n {
			return 0, fmt.Errorf("sam: integer overflow: %q at %d", b, i)
		}
	}
	return int(n), nil
}

// ParseCigar returns a Cigar parsed from the provided byte slice.
// ParseCigar will break CIGAR operations longer than 2^28-1 into
// multiple operations summing to the same length.
func ParseCigar(b []byte) (Cigar, error) {
	if len(b) == 1 && b[0] == '*' {
		return nil, nil
	}
	var (
		c   Cigar
		op  CigarOpType
		n   int
		err error
	)
	for i := 0; i < len(b); i++ {
		for j := i; j < len(b); j++ {
			if b[j] < '0' || '9' < b[j] {
				n, err = atoi(b[i:j])
				if err != nil {
					return nil, err
				}
				op = cigarOpTypeLookup[b[j]]
				i = j
				break
			}
		}
		if op == lastCigar {
			return nil, fmt.Errorf("sam: failed to parse cigar string %q: unknown operation %q", b, op)
		}

		for {
			c = append(c, NewCigarOp(op, minInt(n, 1<<28-1)))
			n -= 1<<28 - 1
			if n <= 0 {
				break
			}
		}
	}
	fmt.Printf("%s\n", c)
	return c, nil
}

func minInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<commit_msg>sam: remove residual debug-checking print<commit_after>// Copyright ©2012 The bíogo 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 sam

import (
	"bytes"
	"fmt"
)

// Cigar is a set of CIGAR operations.
type Cigar []CigarOp

// IsValid returns whether the CIGAR string is valid for a record of the given
// sequence length. Validity is defined by the sum of query consuming operations
// matching the given length, clipping operations only being present at the ends
// of alignments, and that CigarBack operations only result in query-consuming
// positions at or right of the start of the alignment.
func (c Cigar) IsValid(length int) bool {
	var pos int
	for i, co := range c {
		ct := co.Type()
		if ct == CigarHardClipped && i != 0 && i != len(c)-1 {
			return false
		}
		if ct == CigarSoftClipped && i != 0 && i != len(c)-1 {
			if c[i-1].Type() != CigarHardClipped && c[i+1].Type() != CigarHardClipped {
				return false
			}
		}
		con := ct.Consumes()
		if pos < 0 && con.Query != 0 {
			return false
		}
		length -= co.Len() * con.Query
		pos += co.Len() * con.Reference
	}
	return length == 0
}

// String returns the CIGAR string for c.
func (c Cigar) String() string {
	if len(c) == 0 {
		return "*"
	}
	var b bytes.Buffer
	for _, co := range c {
		fmt.Fprint(&b, co)
	}
	return b.String()
}

// Lengths returns the number of reference and read bases described by the Cigar.
func (c Cigar) Lengths() (ref, read int) {
	var con Consume
	for _, co := range c {
		con = co.Type().Consumes()
		if co.Type() != CigarBack {
			ref += co.Len() * con.Reference
		}
		read += co.Len() * con.Query
	}
	return ref, read
}

// CigarOp is a single CIGAR operation including the operation type and the
// length of the operation.
type CigarOp uint32

// NewCigarOp returns a CIGAR operation of the specified type with length n.
// Due to a limitation of the BAM format, CIGAR operation lengths are limited
// to 2^28-1, and NewCigarOp will panic if n is above this or negative.
func NewCigarOp(t CigarOpType, n int) CigarOp {
	if uint64(n) > 1<<28-1 {
		panic("sam: illegal CIGAR op length")
	}
	return CigarOp(t) | (CigarOp(n) << 4)
}

// Type returns the type of the CIGAR operation for the CigarOp.
func (co CigarOp) Type() CigarOpType { return CigarOpType(co & 0xf) }

// Len returns the number of positions affected by the CigarOp CIGAR operation.
func (co CigarOp) Len() int { return int(co >> 4) }

// String returns the string representation of the CigarOp
func (co CigarOp) String() string { return fmt.Sprintf("%d%s", co.Len(), co.Type().String()) }

// A CigarOpType represents the type of operation described by a CigarOp.
type CigarOpType byte

const (
	CigarMatch       CigarOpType = iota // Alignment match (can be a sequence match or mismatch).
	CigarInsertion                      // Insertion to the reference.
	CigarDeletion                       // Deletion from the reference.
	CigarSkipped                        // Skipped region from the reference.
	CigarSoftClipped                    // Soft clipping (clipped sequences present in SEQ).
	CigarHardClipped                    // Hard clipping (clipped sequences NOT present in SEQ).
	CigarPadded                         // Padding (silent deletion from padded reference).
	CigarEqual                          // Sequence match.
	CigarMismatch                       // Sequence mismatch.
	CigarBack                           // Skip backwards.
	lastCigar
)

var cigarOps = []string{"M", "I", "D", "N", "S", "H", "P", "=", "X", "B", "?"}

// Consumes returns the CIGAR operation alignment consumption characteristics for the CigarOpType.
//
// The Consume values for each of the CigarOpTypes is as follows:
//
//                    Query  Reference
//  CigarMatch          1        1
//  CigarInsertion      1        0
//  CigarDeletion       0        1
//  CigarSkipped        0        1
//  CigarSoftClipped    1        0
//  CigarHardClipped    0        0
//  CigarPadded         0        0
//  CigarEqual          1        1
//  CigarMismatch       1        1
//  CigarBack           0       -1
//
func (ct CigarOpType) Consumes() Consume { return consume[ct] }

// String returns the string representation of a CigarOpType.
func (ct CigarOpType) String() string {
	if ct < 0 || ct > lastCigar {
		ct = lastCigar
	}
	return cigarOps[ct]
}

// Consume describes how CIGAR operations consume alignment bases.
type Consume struct {
	Query, Reference int
}

// A few years ago, Complete Genomics (CG) proposed to add a new CIGAR
// operator 'B' for an operation of moving backward along the reference
// genome. It is the opposite of the 'N', the reference skip. In a later
// discussion on a separate issue, Fred expressed his preference to a
// negative reference skip which is equivalent to a positive 'B' operation.
// Now the SRA group from NCBI intends to archive the CG alignment in
// the SAM format and raises this request again. I think it may be the
// time to add this backward operation.
//
// The backward operation is designed to describe such an alignment:
//
// REF:: GCATACGATCGACTAGTCACGT
// READ: --ATACGATCGA----------
// READ: ---------CGACTAGTCAC--
//
// i.e. there is an overlap between two segments of a read, which is quite
// frequent in CG data. We are unable to fully describe such an alignment
// with the original CIGAR. In the current spec, we suggest using a CIGAR
// 18M and storing the overlap information in optional tags. This is a
// little clumsy and is not compressed well for the purpose of archiving.
// With 'B', the new CIGAR is "10M3B11M" with no other optional tags.
//
// Using "B" in this case is cleaner, but the major concern is that it breaks
// the compatibility and is also likely to complicate SNP calling and many
// other applications. As I think now, the solution is to implement a
// "remove_B()" routine in samtools. This routine collapses overlapping
// sequences, recalculates base quality in the overlap and gives a CIGAR
// without 'B'. For the example above, remove_B() gives CIGAR 18M. For SNP
// calling, we may call remove_B() immediately after the alignment loaded
// into memory. The downstream pileup engine does not need any changes. Other
// SNP callers can do the same. A new option will be added to "samtools view"
// as a way to remove 'B' operations on the command-line.
//
// The implementation of remove_B() may be quite complicated in the generic
// case - we may be dealing with a multiple-sequence alignment, but it should
// be straightforward in the simple cases such as the example above. Users may
// not need to care too much about how remove_B() is implemented.
//
// http://sourceforge.net/p/samtools/mailman/message/28463294/
var consume = []Consume{
	CigarMatch:       {Query: 1, Reference: 1},
	CigarInsertion:   {Query: 1, Reference: 0},
	CigarDeletion:    {Query: 0, Reference: 1},
	CigarSkipped:     {Query: 0, Reference: 1},
	CigarSoftClipped: {Query: 1, Reference: 0},
	CigarHardClipped: {Query: 0, Reference: 0},
	CigarPadded:      {Query: 0, Reference: 0},
	CigarEqual:       {Query: 1, Reference: 1},
	CigarMismatch:    {Query: 1, Reference: 1},
	CigarBack:        {Query: 0, Reference: -1}, // See notes above.
	lastCigar:        {},
}

var cigarOpTypeLookup [256]CigarOpType

func init() {
	for i := range cigarOpTypeLookup {
		cigarOpTypeLookup[i] = lastCigar
	}
	for op, c := range []byte{'M', 'I', 'D', 'N', 'S', 'H', 'P', '=', 'X', 'B'} {
		cigarOpTypeLookup[c] = CigarOpType(op)
	}
}

var powers = []int64{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12}

// atoi returns the integer interpretation of b which must be an ASCII decimal number representation.
func atoi(b []byte) (int, error) {
	if len(b) > len(powers) {
		return 0, fmt.Errorf("sam: integer overflow: %q", b)
	}
	var n int64
	k := len(b) - 1
	for i, v := range b {
		n += int64(v-'0') * powers[k-i]
		if int64(int(n)) != n {
			return 0, fmt.Errorf("sam: integer overflow: %q at %d", b, i)
		}
	}
	return int(n), nil
}

// ParseCigar returns a Cigar parsed from the provided byte slice.
// ParseCigar will break CIGAR operations longer than 2^28-1 into
// multiple operations summing to the same length.
func ParseCigar(b []byte) (Cigar, error) {
	if len(b) == 1 && b[0] == '*' {
		return nil, nil
	}
	var (
		c   Cigar
		op  CigarOpType
		n   int
		err error
	)
	for i := 0; i < len(b); i++ {
		for j := i; j < len(b); j++ {
			if b[j] < '0' || '9' < b[j] {
				n, err = atoi(b[i:j])
				if err != nil {
					return nil, err
				}
				op = cigarOpTypeLookup[b[j]]
				i = j
				break
			}
		}
		if op == lastCigar {
			return nil, fmt.Errorf("sam: failed to parse cigar string %q: unknown operation %q", b, op)
		}

		for {
			c = append(c, NewCigarOp(op, minInt(n, 1<<28-1)))
			n -= 1<<28 - 1
			if n <= 0 {
				break
			}
		}
	}
	return c, nil
}

func minInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>// Int and BigInt objects

package py

import (
	"math"
	"math/big"
)

var IntType = NewType("int", "int(x=0) -> integer\nint(x, base=10) -> integer\n\nConvert a number or string to an integer, or return 0 if no arguments\nare given.  If x is a number, return x.__int__().  For floating point\nnumbers, this truncates towards zero.\n\nIf x is not a number or if base is given, then x must be a string,\nbytes, or bytearray instance representing an integer literal in the\ngiven base.  The literal can be preceded by '+' or '-' and be surrounded\nby whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.\nBase 0 means to interpret the base from the string as an integer literal.\n>>> int('0b100', base=0)\n4")

type Int int64

const (
	// Maximum possible Int
	IntMax = 1<<63 - 1
	// Minimum possible Int
	IntMin = -IntMax - 1
)

// Type of this Int object
func (o Int) Type() *Type {
	return IntType
}

type BigInt big.Int

var BigIntType = NewType("bigint", "Holds large integers")

// Type of this BigInt object
func (o *BigInt) Type() *Type {
	return BigIntType
}

// Make sure it satisfies the interface
var _ Object = (*BigInt)(nil)

// Arithmetic

// Convert an Object to an Int
//
// Retrurns ok as to whether the conversion worked or not
func convertToInt(other Object) (Int, bool) {
	switch b := other.(type) {
	case Int:
		return b, true
	case Bool:
		if b {
			return Int(1), true
		} else {
			return Int(0), true
		}
	}
	return 0, false
}

// FIXME overflow should promote to Long in all these functions

func (a Int) M__neg__() Object {
	return -a
}

func (a Int) M__pos__() Object {
	return a
}

func (a Int) M__abs__() Object {
	if a < 0 {
		return -a
	}
	return a
}

func (a Int) M__invert__() Object {
	return ^a
}

func (a Int) M__add__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a + b)
	}
	return NotImplemented
}

func (a Int) M__radd__(other Object) Object {
	return a.M__add__(other)
}

func (a Int) M__iadd__(other Object) Object {
	return a.M__add__(other)
}

func (a Int) M__sub__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a - b)
	}
	return NotImplemented
}

func (a Int) M__rsub__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b - a)
	}
	return NotImplemented
}

func (a Int) M__isub__(other Object) Object {
	return a.M__sub__(other)
}

func (a Int) M__mul__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a * b)
	}
	return NotImplemented
}

func (a Int) M__rmul__(other Object) Object {
	return a.M__mul__(other)
}

func (a Int) M__imul__(other Object) Object {
	return a.M__mul__(other)
}

func (a Int) M__truediv__(other Object) Object {
	return Float(a).M__truediv__(other)
}

func (a Int) M__rtruediv__(other Object) Object {
	return Float(a).M__rtruediv__(other)
}

func (a Int) M__itruediv__(other Object) Object {
	return Float(a).M__truediv__(other)
}

func (a Int) M__floordiv__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a / b)
	}
	return NotImplemented
}

func (a Int) M__rfloordiv__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b / a)
	}
	return NotImplemented
}

func (a Int) M__ifloordiv__(other Object) Object {
	return a.M__floordiv__(other)
}

func (a Int) M__mod__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a % b)
	}
	return NotImplemented
}

func (a Int) M__rmod__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b % a)
	}
	return NotImplemented
}

func (a Int) M__imod__(other Object) Object {
	return a.M__mod__(other)
}

func (a Int) M__divmod__(other Object) (Object, Object) {
	if b, ok := convertToInt(other); ok {
		return Int(a / b), Int(a % b)
	}
	return NotImplemented, None
}

func (a Int) M__rdivmod__(other Object) (Object, Object) {
	if b, ok := convertToInt(other); ok {
		return Int(b / a), Int(b % a)
	}
	return NotImplemented, None
}

// FIXME implement powmod...
func (a Int) M__pow__(other, modulus Object) Object {
	if modulus != None {
		return NotImplemented
	}
	if b, ok := convertToInt(other); ok {
		// FIXME possible loss of precision
		return Int(math.Pow(float64(a), float64(b)))
	}
	return NotImplemented
}

func (a Int) M__rpow__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		// FIXME possible loss of precision
		return Int(math.Pow(float64(b), float64(a)))
	}
	return NotImplemented
}

func (a Int) M__ipow__(other, modulus Object) Object {
	return a.M__pow__(other, modulus)
}

func (a Int) M__lshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(a << uint64(b))
	}
	return NotImplemented
}

func (a Int) M__rlshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(b << uint64(a))
	}
	return NotImplemented
}

func (a Int) M__ilshift__(other Object) Object {
	return a.M__floordiv__(other)
}

func (a Int) M__rshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(a >> uint64(b))
	}
	return NotImplemented
}

func (a Int) M__rrshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(b >> uint64(a))
	}
	return NotImplemented
}

func (a Int) M__irshift__(other Object) Object {
	return a.M__rshift__(other)
}

func (a Int) M__and__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a & b)
	}
	return NotImplemented
}

func (a Int) M__rand__(other Object) Object {
	return a.M__and__(other)
}

func (a Int) M__iand__(other Object) Object {
	return a.M__and__(other)
}

func (a Int) M__xor__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a ^ b)
	}
	return NotImplemented
}

func (a Int) M__rxor__(other Object) Object {
	return a.M__xor__(other)
}

func (a Int) M__ixor__(other Object) Object {
	return a.M__xor__(other)
}

func (a Int) M__or__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a | b)
	}
	return NotImplemented
}

func (a Int) M__ror__(other Object) Object {
	return a.M__or__(other)
}

func (a Int) M__ior__(other Object) Object {
	return a.M__or__(other)
}

func (a Int) M__bool__() Object {
	return NewBool(a != 0)
}

func (a Int) M__index__() Int {
	return a
}

func (a Int) M__int__() Object {
	return a
}

func (a Int) M__float__() Object {
	if r, ok := convertToFloat(a); ok {
		return r
	}
	panic("convertToFloat failed")
}

func (a Int) M__complex__() Object {
	if r, ok := convertToComplex(a); ok {
		return r
	}
	panic("convertToComplex failed")
}

func (a Int) M__round__(digits Object) Object {
	return Int(Float(a).M__round__(digits).(Float))
}

// Rich comparison

func (a Int) M__lt__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a < b)
	}
	return NotImplemented
}

func (a Int) M__le__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a <= b)
	}
	return NotImplemented
}

func (a Int) M__eq__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a == b)
	}
	return NotImplemented
}

func (a Int) M__ne__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a != b)
	}
	return NotImplemented
}

func (a Int) M__gt__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a > b)
	}
	return NotImplemented
}

func (a Int) M__ge__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a >= b)
	}
	return NotImplemented
}

// Check interface is satisfied
var _ floatArithmetic = Int(0)
var _ booleanArithmetic = Int(0)
var _ conversionBetweenTypes = Int(0)
var _ I__bool__ = Int(0)
var _ I__index__ = Int(0)
var _ richComparison = Int(0)
<commit_msg>Implement int()<commit_after>// Int and BigInt objects

package py

import (
	"math"
	"math/big"
	"strconv"
)

var IntType = ObjectType.NewType("int", `
int(x=0) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4`, IntNew, nil)

type Int int64

const (
	// Maximum possible Int
	IntMax = 1<<63 - 1
	// Minimum possible Int
	IntMin = -IntMax - 1
)

// Type of this Int object
func (o Int) Type() *Type {
	return IntType
}

type BigInt big.Int

var BigIntType = NewType("bigint", "Holds large integers")

// Type of this BigInt object
func (o *BigInt) Type() *Type {
	return BigIntType
}

// Make sure it satisfies the interface
var _ Object = (*BigInt)(nil)

// IntNew
func IntNew(metatype *Type, args Tuple, kwargs StringDict) Object {
	var xObj Object = Int(0)
	var baseObj Object = Int(10)
	ParseTupleAndKeywords(args, kwargs, "|OO:int", []string{"x", "base"}, &xObj, &baseObj)
	var res Int
	switch x := xObj.(type) {
	case Int:
		res = x
	case String:
		base := int(baseObj.(Int))
		// FIXME this isn't 100% python compatible but it is close!
		i, err := strconv.ParseInt(string(x), base, 64)
		if err != nil {
			panic(ExceptionNewf(ValueError, "invalid literal for int() with base %d: '%s'", base, string(x)))
		}
		res = Int(i)
	case Float:
		res = Int(x)
	default:
		var ok bool
		res, ok = convertToInt(x)
		if !ok {
			panic(ExceptionNewf(TypeError, "int() argument must be a string or a number, not 'tuple'"))
		}
	}
	return res
}

// Arithmetic

// Convert an Object to an Int
//
// Retrurns ok as to whether the conversion worked or not
func convertToInt(other Object) (Int, bool) {
	switch b := other.(type) {
	case Int:
		return b, true
	case Bool:
		if b {
			return Int(1), true
		} else {
			return Int(0), true
		}
	}
	return 0, false
}

// FIXME overflow should promote to Long in all these functions

func (a Int) M__neg__() Object {
	return -a
}

func (a Int) M__pos__() Object {
	return a
}

func (a Int) M__abs__() Object {
	if a < 0 {
		return -a
	}
	return a
}

func (a Int) M__invert__() Object {
	return ^a
}

func (a Int) M__add__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a + b)
	}
	return NotImplemented
}

func (a Int) M__radd__(other Object) Object {
	return a.M__add__(other)
}

func (a Int) M__iadd__(other Object) Object {
	return a.M__add__(other)
}

func (a Int) M__sub__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a - b)
	}
	return NotImplemented
}

func (a Int) M__rsub__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b - a)
	}
	return NotImplemented
}

func (a Int) M__isub__(other Object) Object {
	return a.M__sub__(other)
}

func (a Int) M__mul__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a * b)
	}
	return NotImplemented
}

func (a Int) M__rmul__(other Object) Object {
	return a.M__mul__(other)
}

func (a Int) M__imul__(other Object) Object {
	return a.M__mul__(other)
}

func (a Int) M__truediv__(other Object) Object {
	return Float(a).M__truediv__(other)
}

func (a Int) M__rtruediv__(other Object) Object {
	return Float(a).M__rtruediv__(other)
}

func (a Int) M__itruediv__(other Object) Object {
	return Float(a).M__truediv__(other)
}

func (a Int) M__floordiv__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a / b)
	}
	return NotImplemented
}

func (a Int) M__rfloordiv__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b / a)
	}
	return NotImplemented
}

func (a Int) M__ifloordiv__(other Object) Object {
	return a.M__floordiv__(other)
}

func (a Int) M__mod__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a % b)
	}
	return NotImplemented
}

func (a Int) M__rmod__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(b % a)
	}
	return NotImplemented
}

func (a Int) M__imod__(other Object) Object {
	return a.M__mod__(other)
}

func (a Int) M__divmod__(other Object) (Object, Object) {
	if b, ok := convertToInt(other); ok {
		return Int(a / b), Int(a % b)
	}
	return NotImplemented, None
}

func (a Int) M__rdivmod__(other Object) (Object, Object) {
	if b, ok := convertToInt(other); ok {
		return Int(b / a), Int(b % a)
	}
	return NotImplemented, None
}

// FIXME implement powmod...
func (a Int) M__pow__(other, modulus Object) Object {
	if modulus != None {
		return NotImplemented
	}
	if b, ok := convertToInt(other); ok {
		// FIXME possible loss of precision
		return Int(math.Pow(float64(a), float64(b)))
	}
	return NotImplemented
}

func (a Int) M__rpow__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		// FIXME possible loss of precision
		return Int(math.Pow(float64(b), float64(a)))
	}
	return NotImplemented
}

func (a Int) M__ipow__(other, modulus Object) Object {
	return a.M__pow__(other, modulus)
}

func (a Int) M__lshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(a << uint64(b))
	}
	return NotImplemented
}

func (a Int) M__rlshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(b << uint64(a))
	}
	return NotImplemented
}

func (a Int) M__ilshift__(other Object) Object {
	return a.M__floordiv__(other)
}

func (a Int) M__rshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(a >> uint64(b))
	}
	return NotImplemented
}

func (a Int) M__rrshift__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		if b < 0 {
			// FIXME should be ValueError
			panic("ValueError: negative shift count")
		}
		return Int(b >> uint64(a))
	}
	return NotImplemented
}

func (a Int) M__irshift__(other Object) Object {
	return a.M__rshift__(other)
}

func (a Int) M__and__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a & b)
	}
	return NotImplemented
}

func (a Int) M__rand__(other Object) Object {
	return a.M__and__(other)
}

func (a Int) M__iand__(other Object) Object {
	return a.M__and__(other)
}

func (a Int) M__xor__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a ^ b)
	}
	return NotImplemented
}

func (a Int) M__rxor__(other Object) Object {
	return a.M__xor__(other)
}

func (a Int) M__ixor__(other Object) Object {
	return a.M__xor__(other)
}

func (a Int) M__or__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return Int(a | b)
	}
	return NotImplemented
}

func (a Int) M__ror__(other Object) Object {
	return a.M__or__(other)
}

func (a Int) M__ior__(other Object) Object {
	return a.M__or__(other)
}

func (a Int) M__bool__() Object {
	return NewBool(a != 0)
}

func (a Int) M__index__() Int {
	return a
}

func (a Int) M__int__() Object {
	return a
}

func (a Int) M__float__() Object {
	if r, ok := convertToFloat(a); ok {
		return r
	}
	panic("convertToFloat failed")
}

func (a Int) M__complex__() Object {
	if r, ok := convertToComplex(a); ok {
		return r
	}
	panic("convertToComplex failed")
}

func (a Int) M__round__(digits Object) Object {
	return Int(Float(a).M__round__(digits).(Float))
}

// Rich comparison

func (a Int) M__lt__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a < b)
	}
	return NotImplemented
}

func (a Int) M__le__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a <= b)
	}
	return NotImplemented
}

func (a Int) M__eq__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a == b)
	}
	return NotImplemented
}

func (a Int) M__ne__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a != b)
	}
	return NotImplemented
}

func (a Int) M__gt__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a > b)
	}
	return NotImplemented
}

func (a Int) M__ge__(other Object) Object {
	if b, ok := convertToInt(other); ok {
		return NewBool(a >= b)
	}
	return NotImplemented
}

// Check interface is satisfied
var _ floatArithmetic = Int(0)
var _ booleanArithmetic = Int(0)
var _ conversionBetweenTypes = Int(0)
var _ I__bool__ = Int(0)
var _ I__index__ = Int(0)
var _ richComparison = Int(0)
<|endoftext|>


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

package mutate

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"strings"
	"time"

	"github.com/google/go-containerregistry/internal/gzip"
	v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/match"
	"github.com/google/go-containerregistry/pkg/v1/partial"
	"github.com/google/go-containerregistry/pkg/v1/tarball"
	"github.com/google/go-containerregistry/pkg/v1/types"
)

const whiteoutPrefix = ".wh."

// Addendum contains layers and history to be appended
// to a base image
type Addendum struct {
	Layer       v1.Layer
	History     v1.History
	URLs        []string
	Annotations map[string]string
	MediaType   types.MediaType
}

// AppendLayers applies layers to a base image.
func AppendLayers(base v1.Image, layers ...v1.Layer) (v1.Image, error) {
	additions := make([]Addendum, 0, len(layers))
	for _, layer := range layers {
		additions = append(additions, Addendum{Layer: layer})
	}

	return Append(base, additions...)
}

// Append will apply the list of addendums to the base image
func Append(base v1.Image, adds ...Addendum) (v1.Image, error) {
	if len(adds) == 0 {
		return base, nil
	}
	if err := validate(adds); err != nil {
		return nil, err
	}

	return &image{
		base: base,
		adds: adds,
	}, nil
}

// Appendable is an interface that represents something that can be appended
// to an ImageIndex. We need to be able to construct a v1.Descriptor in order
// to append something, and this is the minimum required information for that.
type Appendable interface {
	MediaType() (types.MediaType, error)
	Digest() (v1.Hash, error)
	Size() (int64, error)
}

// IndexAddendum represents an appendable thing and all the properties that
// we may want to override in the resulting v1.Descriptor.
type IndexAddendum struct {
	Add Appendable
	v1.Descriptor
}

// AppendManifests appends a manifest to the ImageIndex.
func AppendManifests(base v1.ImageIndex, adds ...IndexAddendum) v1.ImageIndex {
	return &index{
		base: base,
		adds: adds,
	}
}

// RemoveManifests removes any descriptors that match the match.Matcher.
func RemoveManifests(base v1.ImageIndex, matcher match.Matcher) v1.ImageIndex {
	return &index{
		base:   base,
		remove: matcher,
	}
}

// Config mutates the provided v1.Image to have the provided v1.Config
func Config(base v1.Image, cfg v1.Config) (v1.Image, error) {
	cf, err := base.ConfigFile()
	if err != nil {
		return nil, err
	}

	cf.Config = cfg

	return ConfigFile(base, cf)
}

// Annotatable represents a manifest that can carry annotations.
type Annotatable interface {
	partial.WithRawManifest
}

// Annotations mutates the annotations on an annotatable image or index manifest.
//
// The annotatable input is expected to be a v1.Image or v1.ImageIndex, and
// returns the same type. You can type-assert the result like so:
//
//     img := Annotations(empty.Image, map[string]string{
//         "foo": "bar",
//     }).(v1.Image)
//
// Or for an index:
//
//     idx := Annotations(empty.Index, map[string]string{
//         "foo": "bar",
//     }).(v1.ImageIndex)
//
// If the input Annotatable is not an Image or ImageIndex, the result will
// attempt to lazily annotate the raw manifest.
func Annotations(f Annotatable, anns map[string]string) Annotatable {
	if img, ok := f.(v1.Image); ok {
		return &image{
			base:        img,
			annotations: anns,
		}
	}
	if idx, ok := f.(v1.ImageIndex); ok {
		return &index{
			base:        idx,
			annotations: anns,
		}
	}
	return arbitraryRawManifest{f, anns}
}

type arbitraryRawManifest struct {
	a    Annotatable
	anns map[string]string
}

func (a arbitraryRawManifest) RawManifest() ([]byte, error) {
	b, err := a.a.RawManifest()
	if err != nil {
		return nil, err
	}
	var m map[string]interface{}
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, err
	}
	if ann, ok := m["annotations"]; ok {
		if annm, ok := ann.(map[string]string); ok {
			for k, v := range a.anns {
				annm[k] = v
			}
		} else {
			return nil, fmt.Errorf(".annotations is not a map: %T", ann)
		}
	} else {
		m["annotations"] = a.anns
	}
	return json.Marshal(m)
}

// ConfigFile mutates the provided v1.Image to have the provided v1.ConfigFile
func ConfigFile(base v1.Image, cfg *v1.ConfigFile) (v1.Image, error) {
	m, err := base.Manifest()
	if err != nil {
		return nil, err
	}

	image := &image{
		base:       base,
		manifest:   m.DeepCopy(),
		configFile: cfg,
	}

	return image, nil
}

// CreatedAt mutates the provided v1.Image to have the provided v1.Time
func CreatedAt(base v1.Image, created v1.Time) (v1.Image, error) {
	cf, err := base.ConfigFile()
	if err != nil {
		return nil, err
	}

	cfg := cf.DeepCopy()
	cfg.Created = created

	return ConfigFile(base, cfg)
}

// Extract takes an image and returns an io.ReadCloser containing the image's
// flattened filesystem.
//
// Callers can read the filesystem contents by passing the reader to
// tar.NewReader, or io.Copy it directly to some output.
//
// If a caller doesn't read the full contents, they should Close it to free up
// resources used during extraction.
func Extract(img v1.Image) io.ReadCloser {
	pr, pw := io.Pipe()

	go func() {
		// Close the writer with any errors encountered during
		// extraction. These errors will be returned by the reader end
		// on subsequent reads. If err == nil, the reader will return
		// EOF.
		pw.CloseWithError(extract(img, pw))
	}()

	return pr
}

// Adapted from https://github.com/google/containerregistry/blob/da03b395ccdc4e149e34fbb540483efce962dc64/client/v2_2/docker_image_.py#L816
func extract(img v1.Image, w io.Writer) error {
	tarWriter := tar.NewWriter(w)
	defer tarWriter.Close()

	fileMap := map[string]bool{}

	layers, err := img.Layers()
	if err != nil {
		return fmt.Errorf("retrieving image layers: %v", err)
	}
	// we iterate through the layers in reverse order because it makes handling
	// whiteout layers more efficient, since we can just keep track of the removed
	// files as we see .wh. layers and ignore those in previous layers.
	for i := len(layers) - 1; i >= 0; i-- {
		layer := layers[i]
		layerReader, err := layer.Uncompressed()
		if err != nil {
			return fmt.Errorf("reading layer contents: %v", err)
		}
		defer layerReader.Close()
		tarReader := tar.NewReader(layerReader)
		for {
			header, err := tarReader.Next()
			if err == io.EOF {
				break
			}
			if err != nil {
				return fmt.Errorf("reading tar: %v", err)
			}

			basename := filepath.Base(header.Name)
			dirname := filepath.Dir(header.Name)
			tombstone := strings.HasPrefix(basename, whiteoutPrefix)
			if tombstone {
				basename = basename[len(whiteoutPrefix):]
			}

			// check if we have seen value before
			// if we're checking a directory, don't filepath.Join names
			var name string
			if header.Typeflag == tar.TypeDir {
				name = header.Name
			} else {
				name = filepath.Join(dirname, basename)
			}

			if _, ok := fileMap[name]; ok {
				continue
			}

			// check for a whited out parent directory
			if inWhiteoutDir(fileMap, name) {
				continue
			}

			// mark file as handled. non-directory implicitly tombstones
			// any entries with a matching (or child) name
			fileMap[name] = tombstone || !(header.Typeflag == tar.TypeDir)
			if !tombstone {
				tarWriter.WriteHeader(header)
				if header.Size > 0 {
					if _, err := io.Copy(tarWriter, tarReader); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

func inWhiteoutDir(fileMap map[string]bool, file string) bool {
	for {
		if file == "" {
			break
		}
		dirname := filepath.Dir(file)
		if file == dirname {
			break
		}
		if val, ok := fileMap[dirname]; ok && val {
			return true
		}
		file = dirname
	}
	return false
}

// Time sets all timestamps in an image to the given timestamp.
func Time(img v1.Image, t time.Time) (v1.Image, error) {
	newImage := empty.Image

	layers, err := img.Layers()
	if err != nil {
		return nil, fmt.Errorf("getting image layers: %v", err)
	}

	// Strip away all timestamps from layers
	var newLayers []v1.Layer
	for _, layer := range layers {
		newLayer, err := layerTime(layer, t)
		if err != nil {
			return nil, fmt.Errorf("setting layer times: %v", err)
		}
		newLayers = append(newLayers, newLayer)
	}

	newImage, err = AppendLayers(newImage, newLayers...)
	if err != nil {
		return nil, fmt.Errorf("appending layers: %v", err)
	}

	ocf, err := img.ConfigFile()
	if err != nil {
		return nil, fmt.Errorf("getting original config file: %v", err)
	}

	cf, err := newImage.ConfigFile()
	if err != nil {
		return nil, fmt.Errorf("setting config file: %v", err)
	}

	cfg := cf.DeepCopy()

	// Copy basic config over
	cfg.Architecture = ocf.Architecture
	cfg.OS = ocf.OS
	cfg.OSVersion = ocf.OSVersion
	cfg.Config = ocf.Config

	// Strip away timestamps from the config file
	cfg.Created = v1.Time{Time: t}

	for _, h := range cfg.History {
		h.Created = v1.Time{Time: t}
	}

	return ConfigFile(newImage, cfg)
}

func layerTime(layer v1.Layer, t time.Time) (v1.Layer, error) {
	layerReader, err := layer.Uncompressed()
	if err != nil {
		return nil, fmt.Errorf("getting layer: %v", err)
	}
	defer layerReader.Close()
	w := new(bytes.Buffer)
	tarWriter := tar.NewWriter(w)
	defer tarWriter.Close()

	tarReader := tar.NewReader(layerReader)
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("reading layer: %v", err)
		}

		header.ModTime = t
		if err := tarWriter.WriteHeader(header); err != nil {
			return nil, fmt.Errorf("writing tar header: %v", err)
		}

		if header.Typeflag == tar.TypeReg {
			if _, err = io.Copy(tarWriter, tarReader); err != nil {
				return nil, fmt.Errorf("writing layer file: %v", err)
			}
		}
	}

	if err := tarWriter.Close(); err != nil {
		return nil, err
	}

	b := w.Bytes()
	// gzip the contents, then create the layer
	opener := func() (io.ReadCloser, error) {
		return gzip.ReadCloser(ioutil.NopCloser(bytes.NewReader(b))), nil
	}
	layer, err = tarball.LayerFromOpener(opener)
	if err != nil {
		return nil, fmt.Errorf("creating layer: %v", err)
	}

	return layer, nil
}

// Canonical is a helper function to combine Time and configFile
// to remove any randomness during a docker build.
func Canonical(img v1.Image) (v1.Image, error) {
	// Set all timestamps to 0
	created := time.Time{}
	img, err := Time(img, created)
	if err != nil {
		return nil, err
	}

	cf, err := img.ConfigFile()
	if err != nil {
		return nil, err
	}

	// Get rid of host-dependent random config
	cfg := cf.DeepCopy()

	cfg.Container = ""
	cfg.Config.Hostname = ""
	cfg.DockerVersion = ""

	return ConfigFile(img, cfg)
}

// MediaType modifies the MediaType() of the given image.
func MediaType(img v1.Image, mt types.MediaType) v1.Image {
	return &image{
		base:      img,
		mediaType: &mt,
	}
}

// IndexMediaType modifies the MediaType() of the given index.
func IndexMediaType(idx v1.ImageIndex, mt types.MediaType) v1.ImageIndex {
	return &index{
		base:      idx,
		mediaType: &mt,
	}
}
<commit_msg>Clean filepaths in mutate.Extract (#1106)<commit_after>// Copyright 2018 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mutate

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"strings"
	"time"

	"github.com/google/go-containerregistry/internal/gzip"
	v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/match"
	"github.com/google/go-containerregistry/pkg/v1/partial"
	"github.com/google/go-containerregistry/pkg/v1/tarball"
	"github.com/google/go-containerregistry/pkg/v1/types"
)

const whiteoutPrefix = ".wh."

// Addendum contains layers and history to be appended
// to a base image
type Addendum struct {
	Layer       v1.Layer
	History     v1.History
	URLs        []string
	Annotations map[string]string
	MediaType   types.MediaType
}

// AppendLayers applies layers to a base image.
func AppendLayers(base v1.Image, layers ...v1.Layer) (v1.Image, error) {
	additions := make([]Addendum, 0, len(layers))
	for _, layer := range layers {
		additions = append(additions, Addendum{Layer: layer})
	}

	return Append(base, additions...)
}

// Append will apply the list of addendums to the base image
func Append(base v1.Image, adds ...Addendum) (v1.Image, error) {
	if len(adds) == 0 {
		return base, nil
	}
	if err := validate(adds); err != nil {
		return nil, err
	}

	return &image{
		base: base,
		adds: adds,
	}, nil
}

// Appendable is an interface that represents something that can be appended
// to an ImageIndex. We need to be able to construct a v1.Descriptor in order
// to append something, and this is the minimum required information for that.
type Appendable interface {
	MediaType() (types.MediaType, error)
	Digest() (v1.Hash, error)
	Size() (int64, error)
}

// IndexAddendum represents an appendable thing and all the properties that
// we may want to override in the resulting v1.Descriptor.
type IndexAddendum struct {
	Add Appendable
	v1.Descriptor
}

// AppendManifests appends a manifest to the ImageIndex.
func AppendManifests(base v1.ImageIndex, adds ...IndexAddendum) v1.ImageIndex {
	return &index{
		base: base,
		adds: adds,
	}
}

// RemoveManifests removes any descriptors that match the match.Matcher.
func RemoveManifests(base v1.ImageIndex, matcher match.Matcher) v1.ImageIndex {
	return &index{
		base:   base,
		remove: matcher,
	}
}

// Config mutates the provided v1.Image to have the provided v1.Config
func Config(base v1.Image, cfg v1.Config) (v1.Image, error) {
	cf, err := base.ConfigFile()
	if err != nil {
		return nil, err
	}

	cf.Config = cfg

	return ConfigFile(base, cf)
}

// Annotatable represents a manifest that can carry annotations.
type Annotatable interface {
	partial.WithRawManifest
}

// Annotations mutates the annotations on an annotatable image or index manifest.
//
// The annotatable input is expected to be a v1.Image or v1.ImageIndex, and
// returns the same type. You can type-assert the result like so:
//
//     img := Annotations(empty.Image, map[string]string{
//         "foo": "bar",
//     }).(v1.Image)
//
// Or for an index:
//
//     idx := Annotations(empty.Index, map[string]string{
//         "foo": "bar",
//     }).(v1.ImageIndex)
//
// If the input Annotatable is not an Image or ImageIndex, the result will
// attempt to lazily annotate the raw manifest.
func Annotations(f Annotatable, anns map[string]string) Annotatable {
	if img, ok := f.(v1.Image); ok {
		return &image{
			base:        img,
			annotations: anns,
		}
	}
	if idx, ok := f.(v1.ImageIndex); ok {
		return &index{
			base:        idx,
			annotations: anns,
		}
	}
	return arbitraryRawManifest{f, anns}
}

type arbitraryRawManifest struct {
	a    Annotatable
	anns map[string]string
}

func (a arbitraryRawManifest) RawManifest() ([]byte, error) {
	b, err := a.a.RawManifest()
	if err != nil {
		return nil, err
	}
	var m map[string]interface{}
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, err
	}
	if ann, ok := m["annotations"]; ok {
		if annm, ok := ann.(map[string]string); ok {
			for k, v := range a.anns {
				annm[k] = v
			}
		} else {
			return nil, fmt.Errorf(".annotations is not a map: %T", ann)
		}
	} else {
		m["annotations"] = a.anns
	}
	return json.Marshal(m)
}

// ConfigFile mutates the provided v1.Image to have the provided v1.ConfigFile
func ConfigFile(base v1.Image, cfg *v1.ConfigFile) (v1.Image, error) {
	m, err := base.Manifest()
	if err != nil {
		return nil, err
	}

	image := &image{
		base:       base,
		manifest:   m.DeepCopy(),
		configFile: cfg,
	}

	return image, nil
}

// CreatedAt mutates the provided v1.Image to have the provided v1.Time
func CreatedAt(base v1.Image, created v1.Time) (v1.Image, error) {
	cf, err := base.ConfigFile()
	if err != nil {
		return nil, err
	}

	cfg := cf.DeepCopy()
	cfg.Created = created

	return ConfigFile(base, cfg)
}

// Extract takes an image and returns an io.ReadCloser containing the image's
// flattened filesystem.
//
// Callers can read the filesystem contents by passing the reader to
// tar.NewReader, or io.Copy it directly to some output.
//
// If a caller doesn't read the full contents, they should Close it to free up
// resources used during extraction.
func Extract(img v1.Image) io.ReadCloser {
	pr, pw := io.Pipe()

	go func() {
		// Close the writer with any errors encountered during
		// extraction. These errors will be returned by the reader end
		// on subsequent reads. If err == nil, the reader will return
		// EOF.
		pw.CloseWithError(extract(img, pw))
	}()

	return pr
}

// Adapted from https://github.com/google/containerregistry/blob/da03b395ccdc4e149e34fbb540483efce962dc64/client/v2_2/docker_image_.py#L816
func extract(img v1.Image, w io.Writer) error {
	tarWriter := tar.NewWriter(w)
	defer tarWriter.Close()

	fileMap := map[string]bool{}

	layers, err := img.Layers()
	if err != nil {
		return fmt.Errorf("retrieving image layers: %v", err)
	}
	// we iterate through the layers in reverse order because it makes handling
	// whiteout layers more efficient, since we can just keep track of the removed
	// files as we see .wh. layers and ignore those in previous layers.
	for i := len(layers) - 1; i >= 0; i-- {
		layer := layers[i]
		layerReader, err := layer.Uncompressed()
		if err != nil {
			return fmt.Errorf("reading layer contents: %v", err)
		}
		defer layerReader.Close()
		tarReader := tar.NewReader(layerReader)
		for {
			header, err := tarReader.Next()
			if err == io.EOF {
				break
			}
			if err != nil {
				return fmt.Errorf("reading tar: %v", err)
			}

			// Some tools prepend everything with "./", so if we don't Clean the
			// name, we may have duplicate entries, which angers tar-split.
			header.Name = filepath.Clean(header.Name)

			basename := filepath.Base(header.Name)
			dirname := filepath.Dir(header.Name)
			tombstone := strings.HasPrefix(basename, whiteoutPrefix)
			if tombstone {
				basename = basename[len(whiteoutPrefix):]
			}

			// check if we have seen value before
			// if we're checking a directory, don't filepath.Join names
			var name string
			if header.Typeflag == tar.TypeDir {
				name = header.Name
			} else {
				name = filepath.Join(dirname, basename)
			}

			if _, ok := fileMap[name]; ok {
				continue
			}

			// check for a whited out parent directory
			if inWhiteoutDir(fileMap, name) {
				continue
			}

			// mark file as handled. non-directory implicitly tombstones
			// any entries with a matching (or child) name
			fileMap[name] = tombstone || !(header.Typeflag == tar.TypeDir)
			if !tombstone {
				tarWriter.WriteHeader(header)
				if header.Size > 0 {
					if _, err := io.Copy(tarWriter, tarReader); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

func inWhiteoutDir(fileMap map[string]bool, file string) bool {
	for {
		if file == "" {
			break
		}
		dirname := filepath.Dir(file)
		if file == dirname {
			break
		}
		if val, ok := fileMap[dirname]; ok && val {
			return true
		}
		file = dirname
	}
	return false
}

// Time sets all timestamps in an image to the given timestamp.
func Time(img v1.Image, t time.Time) (v1.Image, error) {
	newImage := empty.Image

	layers, err := img.Layers()
	if err != nil {
		return nil, fmt.Errorf("getting image layers: %v", err)
	}

	// Strip away all timestamps from layers
	var newLayers []v1.Layer
	for _, layer := range layers {
		newLayer, err := layerTime(layer, t)
		if err != nil {
			return nil, fmt.Errorf("setting layer times: %v", err)
		}
		newLayers = append(newLayers, newLayer)
	}

	newImage, err = AppendLayers(newImage, newLayers...)
	if err != nil {
		return nil, fmt.Errorf("appending layers: %v", err)
	}

	ocf, err := img.ConfigFile()
	if err != nil {
		return nil, fmt.Errorf("getting original config file: %v", err)
	}

	cf, err := newImage.ConfigFile()
	if err != nil {
		return nil, fmt.Errorf("setting config file: %v", err)
	}

	cfg := cf.DeepCopy()

	// Copy basic config over
	cfg.Architecture = ocf.Architecture
	cfg.OS = ocf.OS
	cfg.OSVersion = ocf.OSVersion
	cfg.Config = ocf.Config

	// Strip away timestamps from the config file
	cfg.Created = v1.Time{Time: t}

	for _, h := range cfg.History {
		h.Created = v1.Time{Time: t}
	}

	return ConfigFile(newImage, cfg)
}

func layerTime(layer v1.Layer, t time.Time) (v1.Layer, error) {
	layerReader, err := layer.Uncompressed()
	if err != nil {
		return nil, fmt.Errorf("getting layer: %v", err)
	}
	defer layerReader.Close()
	w := new(bytes.Buffer)
	tarWriter := tar.NewWriter(w)
	defer tarWriter.Close()

	tarReader := tar.NewReader(layerReader)
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("reading layer: %v", err)
		}

		header.ModTime = t
		if err := tarWriter.WriteHeader(header); err != nil {
			return nil, fmt.Errorf("writing tar header: %v", err)
		}

		if header.Typeflag == tar.TypeReg {
			if _, err = io.Copy(tarWriter, tarReader); err != nil {
				return nil, fmt.Errorf("writing layer file: %v", err)
			}
		}
	}

	if err := tarWriter.Close(); err != nil {
		return nil, err
	}

	b := w.Bytes()
	// gzip the contents, then create the layer
	opener := func() (io.ReadCloser, error) {
		return gzip.ReadCloser(ioutil.NopCloser(bytes.NewReader(b))), nil
	}
	layer, err = tarball.LayerFromOpener(opener)
	if err != nil {
		return nil, fmt.Errorf("creating layer: %v", err)
	}

	return layer, nil
}

// Canonical is a helper function to combine Time and configFile
// to remove any randomness during a docker build.
func Canonical(img v1.Image) (v1.Image, error) {
	// Set all timestamps to 0
	created := time.Time{}
	img, err := Time(img, created)
	if err != nil {
		return nil, err
	}

	cf, err := img.ConfigFile()
	if err != nil {
		return nil, err
	}

	// Get rid of host-dependent random config
	cfg := cf.DeepCopy()

	cfg.Container = ""
	cfg.Config.Hostname = ""
	cfg.DockerVersion = ""

	return ConfigFile(img, cfg)
}

// MediaType modifies the MediaType() of the given image.
func MediaType(img v1.Image, mt types.MediaType) v1.Image {
	return &image{
		base:      img,
		mediaType: &mt,
	}
}

// IndexMediaType modifies the MediaType() of the given index.
func IndexMediaType(idx v1.ImageIndex, mt types.MediaType) v1.ImageIndex {
	return &index{
		base:      idx,
		mediaType: &mt,
	}
}
<|endoftext|>


<commit_before>package QesyDb

import (
	"database/sql"
	"fmt"
	"github.com/Qesy/QesyGo"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB
var OpenLog int = 0

type Model struct {
	Cond      interface{}
	Insert    map[string]string
	InsertArr []map[string]string
	Update    map[string]string
	Field     string
	Table     string
	Index     string
	Limit     interface{}
	Sort      string
	GroupBy   string
	IsDeug    int
	Tx        *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	//defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(3600)
	sqlDb.SetMaxIdleConns(600)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	QesyGo.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) Query(SqlStr string) ([]map[string]string, error) {
	ret, err := m.query(SqlStr)
	m.Clean()
	return ret, err
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	groupby := m.getGroupBy()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + groupby + sort + limit + ";"
	return m.query(sqlStr)
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	m.SetLimit([2]int{0, 1})
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsertBatch() (sql.Result, error) {
	insert := m.getSQLInsertArr()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) Exec(sqlStr string) (sql.Result, error) {
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok || m.Cond == nil {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			} else if isStrArrTmp, ok := v.([]string); ok {
				isStrArr := make([]string, len(isStrArrTmp))
				copy(isStrArr, isStrArrTmp)
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				if len(isStrArr) == 0 {
					continue
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			} else {
				return "WHERE "
			}
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return " WHERE "
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getGroupBy() string {
	if m.GroupBy != "" {
		return " GROUP BY " + m.GroupBy + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLInsertArr() string {
	fieldArr, valuesArr := []string{}, []string{}
	for k, _ := range m.InsertArr[0] {
		fieldArr = append(fieldArr, k)
	}
	for _, value := range m.InsertArr {
		var valueArr []string
		for _, v := range fieldArr {
			valueArr = append(valueArr, "'"+value[v]+"'")
		}
		valuesArr = append(valuesArr, "("+strings.Join(valueArr, ",")+")")
	}
	return "(" + strings.Join(fieldArr, ",") + ")" + " values " + strings.Join(valuesArr, ",")
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	if strArr, ok := m.Limit.([]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.InsertArr = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.GroupBy = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}

func logRecord(str string) {
	if OpenLog == 0 {
		return
	}
	QesyGo.Log(str, "error")
}

func (m *Model) query(sqlStr string) ([]map[string]string, error) {
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	resultsSlice := []map[string]string{}
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	}
	//defer stmt.Close()

	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}
	fields, err := rows.Columns()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}

	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return resultsSlice, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}
<commit_msg>update<commit_after>package QesyDb

import (
	"database/sql"
	"fmt"
	"github.com/Qesy/QesyGo"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var Db *sql.DB
var OpenLog int = 0

type Model struct {
	Cond      interface{}
	Insert    map[string]string
	InsertArr []map[string]string
	Update    map[string]string
	Field     string
	Table     string
	Index     string
	Limit     interface{}
	Sort      string
	GroupBy   string
	IsDeug    int
	Tx        *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string) {
	sqlDb, err := sql.Open("mysql", connStr)
	//defer sqlDb.Close()
	sqlDb.SetConnMaxLifetime(3600)
	sqlDb.SetMaxIdleConns(0)
	sqlDb.SetMaxOpenConns(600)
	if err != nil {
		log.Fatal("mysql connect error")
	}
	err = sqlDb.Ping()
	if err != nil {
		log.Fatal("mysql ping error")
	}
	QesyGo.Println("mysql connect sueccss")
	Db = sqlDb
}

func Begin() (*sql.Tx, error) {
	return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
	return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
	return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
	resultsSlice, _ := m.execSelect()
	retArr := map[string]map[string]string{}
	for _, v := range resultsSlice {
		if v[m.Index] == "" {
			continue
		}
		retArr[v[m.Index]] = v
	}
	m.Clean()
	return retArr, nil
}

func (m *Model) Query(SqlStr string) ([]map[string]string, error) {
	ret, err := m.query(SqlStr)
	m.Clean()
	return ret, err
}

func (m *Model) ExecSelect() ([]map[string]string, error) {
	ret, err := m.execSelect()
	m.Clean()
	return ret, err
}

// ExecSelect is a method with a sql.
func (m *Model) execSelect() ([]map[string]string, error) {
	cond := m.getSQLCond()
	field := m.getSQLField()
	sort := m.getSort()
	groupby := m.getGroupBy()
	limit := m.getSQLLimite()
	sqlStr := "SELECT " + field + " FROM " + m.Table + cond + groupby + sort + limit + ";"
	return m.query(sqlStr)
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
	m.SetLimit([2]int{0, 1})
	resultsSlice, err := m.ExecSelect()
	if len(resultsSlice) == 0 {
		return map[string]string{}, err
	}
	return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error) {
	updateStr := m.getSQLUpdate()
	condStr := m.getSQLCond()
	sqlStr := "UPDATE " + m.Table + " SET " + updateStr + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecInsertBatch() (sql.Result, error) {
	insert := m.getSQLInsertArr()
	sqlStr := "INSERT INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
	insert := m.getSQLInsert()
	sqlStr := "REPLACE INTO " + m.Table + " " + insert + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
	condStr := m.getSQLCond()
	sqlStr := "DELETE FROM " + m.Table + condStr + ";"
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func (m *Model) Exec(sqlStr string) (sql.Result, error) {
	var err error
	var stmt *sql.Stmt
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
	}
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return nil, err
	}
	result, err := stmt.Exec()
	m.Clean()
	return result, err
}

func GetLastInsertId(result sql.Result) (int64, error) {
	return result.LastInsertId()
}

func GetRowsAffected(result sql.Result) (int64, error) {
	return result.RowsAffected()
}

func (m *Model) getSQLCond() string {
	if str, ok := m.Cond.(string); ok || m.Cond == nil {
		return str
	}
	var strArr []string
	if arr, ok := m.Cond.(map[string]string); ok {
		var strArr []string
		for k, v := range arr {
			strArr = append(strArr, k+"='"+v+"'")
		}
		if len(strArr) == 0 {
			return ""
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	if arr, ok := m.Cond.(map[string]interface{}); ok {
		for k, v := range arr {
			if isStr, ok := v.(string); ok {
				strArr = append(strArr, k+"='"+isStr+"'")
			} else if isStrArrTmp, ok := v.([]string); ok {
				isStrArr := make([]string, len(isStrArrTmp))
				copy(isStrArr, isStrArrTmp)
				for k, v := range isStrArr {
					isStrArr[k] = "'" + v + "'"
				}
				if len(isStrArr) == 0 {
					continue
				}
				strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
			} else {
				return "WHERE "
			}
		}
		return " WHERE " + strings.Join(strArr, " && ")
	}
	return " WHERE "
}

func (m *Model) getSQLField() string {
	if m.Field != "" {
		return m.Field
	}
	return "*"
}

func (m *Model) getSort() string {
	if m.Sort != "" {
		return " ORDER BY " + m.Sort + " "
	}
	return ""
}

func (m *Model) getGroupBy() string {
	if m.GroupBy != "" {
		return " GROUP BY " + m.GroupBy + " "
	}
	return ""
}

func (m *Model) getSQLUpdate() string {
	var strArr []string
	for k, v := range m.Update {
		strArr = append(strArr, k+"='"+v+"'")
	}
	return strings.Join(strArr, ",")
}

func (m *Model) getSQLInsert() string {
	var fieldArr, valueArr []string
	for k, v := range m.Insert {
		fieldArr = append(fieldArr, k)
		valueArr = append(valueArr, "'"+v+"'")
	}
	return "(" + strings.Join(fieldArr, ",") + ") values (" + strings.Join(valueArr, ",") + ")"
}

func (m *Model) getSQLInsertArr() string {
	fieldArr, valuesArr := []string{}, []string{}
	for k, _ := range m.InsertArr[0] {
		fieldArr = append(fieldArr, k)
	}
	for _, value := range m.InsertArr {
		var valueArr []string
		for _, v := range fieldArr {
			valueArr = append(valueArr, "'"+value[v]+"'")
		}
		valuesArr = append(valuesArr, "("+strings.Join(valueArr, ",")+")")
	}
	return "(" + strings.Join(fieldArr, ",") + ")" + " values " + strings.Join(valuesArr, ",")
}

func (m *Model) getSQLLimite() string {
	if strArr, ok := m.Limit.([2]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	if strArr, ok := m.Limit.([]int); ok {
		return " LIMIT " + fmt.Sprintf("%d", strArr[0]) + ", " + fmt.Sprintf("%d", strArr[1])
	}
	return ""
}

func (m *Model) Clean() {
	m.Cond = nil
	m.Insert = nil
	m.InsertArr = nil
	m.Update = nil
	m.Field = ""
	m.Table = ""
	m.Index = ""
	m.Limit = nil
	m.Sort = ""
	m.GroupBy = ""
	m.IsDeug = 0
}

func (m *Model) Debug(sql string) {
	if m.IsDeug == 1 {
		fmt.Println(sql)
	}
}

func logRecord(str string) {
	if OpenLog == 0 {
		return
	}
	QesyGo.Log(str, "error")
}

func (m *Model) query(sqlStr string) ([]map[string]string, error) {
	m.Debug(sqlStr)
	var err error
	var stmt *sql.Stmt
	resultsSlice := []map[string]string{}
	if m.Tx == nil {
		stmt, err = Db.Prepare(sqlStr)
		defer stmt.Close()
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	} else {
		stmt, err = m.Tx.Prepare(sqlStr)
		if err != nil {
			logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
			return resultsSlice, err
		}
	}
	//defer stmt.Close()

	rows, err := stmt.Query()
	defer rows.Close()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}
	fields, err := rows.Columns()
	if err != nil {
		logRecord("ERR:" + err.Error() + "SQL:" + sqlStr)
		return resultsSlice, err
	}

	for rows.Next() {
		result := make(map[string]string)
		var scanResultContainers []interface{}
		for i := 0; i < len(fields); i++ {
			var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
		}
		if err := rows.Scan(scanResultContainers...); err != nil {
			return resultsSlice, err
		}
		for k, v := range fields {
			rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
			if rawValue.Interface() == nil {
				continue
			}
			rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
			var str string
			switch rawType.Kind() {
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				str = strconv.FormatInt(rawVal.Int(), 10)
				result[v] = str
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				str = strconv.FormatUint(rawVal.Uint(), 10)
				result[v] = str
			case reflect.Float32, reflect.Float64:
				str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
				result[v] = str
			case reflect.Slice:
				if rawType.Elem().Kind() == reflect.Uint8 {
					result[v] = string(rawVal.Interface().([]byte))
					break
				}
			case reflect.String:
				str = rawVal.String()
				result[v] = str
			case reflect.Struct:
				str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
				result[v] = str
			case reflect.Bool:
				if rawVal.Bool() {
					result[v] = "1"
				} else {
					result[v] = "0"
				}
			}
		}
		resultsSlice = append(resultsSlice, result)
	}
	return resultsSlice, nil
}
<|endoftext|>


<commit_before>package QesyDb

import(
    "database/sql"
    "fmt"
    "strings"
    "log"
    _"github.com/go-sql-driver/mysql"
    "reflect"
    "strconv"
    "time"
)

var Db *sql.DB

type Model struct{
    Cond interface{}
    Insert map[string]string
    Update map[string]string
    Field string
    Table string
    Index string
    Limit interface{}
    Sort string
    Fetch int
}

// Connect  is a method with a sql.
func Connect(connStr string){
    sqlDb, err := sql.Open("mysql", connStr)
    if(err != nil){
        log.Fatal("mysql connect error")
    }
    err = sqlDb.Ping()
    if(err != nil){
        log.Fatal("mysql ping error")
    }
	fmt.Println("mysql connect sueccss")
    Db = sqlDb
}

func Begin() (*sql.Tx, error) {
    return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
    return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
    return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
    resultsSlice, _ := m.ExecSelect()
    retArr := map[string]map[string]string{}
    for _, v := range resultsSlice{
        if v[m.Index] == "" {
            continue
        }
        retArr[v[m.Index]] = v
    }
    m.Clean()
    return retArr, nil
}

// ExecSelect is a method with a sql.
func (m *Model) ExecSelect() ([]map[string]string, error) {
    cond := m.getSQLCond()
    field := m.getSQLField()
    sort := m.getSort()
    limit := m.getSQLLimite()
    sql := "SELECT "+ field +" FROM "+m.Table+cond+sort+limit+";"
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    rows, err := stmt.Query()
    if(err != nil){
        return nil, err
    }
    defer rows.Close()
    fields, err := rows.Columns()
    if(err != nil){
        return nil, err
    }
    var resultsSlice []map[string]string
    for rows.Next(){
        result := make(map[string]string)
        var scanResultContainers []interface{}
        for i := 0; i < len(fields); i++ {
            var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
        }
        if err := rows.Scan(scanResultContainers...); err != nil {
			return nil, err
		}
        for k, v := range fields {
            rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
            if rawValue.Interface() == nil{
                continue
            }
            rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
            var str string
            switch rawType.Kind() {
                case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                    str = strconv.FormatInt(rawVal.Int(), 10)
                    result[v] = str
                case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
                    str = strconv.FormatUint(rawVal.Uint(), 10)
                    result[v] = str
                case reflect.Float32, reflect.Float64:
                    str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
                    result[v] = str
                case reflect.Slice:
                    if rawType.Elem().Kind() == reflect.Uint8 {
                        result[v] = string(rawVal.Interface().([]byte))
                        break
                    }
                case reflect.String:
                    str = rawVal.String()
                    result[v] = str
                case reflect.Struct:
                    str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
                    result[v] = str
                case reflect.Bool:
                    if rawVal.Bool() {
                        result[v] = "1"
                    } else {
                        result[v] = "0"
                    }
                }
            }
            resultsSlice = append(resultsSlice, result)
        }
        m.Clean()
        return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
    resultsSlice, err := m.ExecSelect()
    if len(resultsSlice) == 0{
        return nil, err
    }
    return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error){
    updateStr := m.getSQLUpdate()
    condStr := m.getSQLCond()
    sql := "UPDATE "+ m.Table +" SET "+ updateStr + condStr +";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
    insert := m.getSQLInsert()
    sql := "INSERT INTO "+m.Table+" "+insert+";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
    insert := m.getSQLInsert()
    sql := "REPLACE INTO "+m.Table+" "+insert+";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
    condStr := m.getSQLCond()
    sql := "DELETE FROM "+ m.Table + condStr +";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func GetLastInsertId(result sql.Result)(int64, error){
    return result.LastInsertId()
}

func GetRowsAffected(result sql.Result)(int64, error){
    return result.RowsAffected()
}

func (m *Model)getSQLCond() string {
    if str, ok := m.Cond.(string); ok{
        return str
    }
    var strArr []string
    if arr, ok := m.Cond.(map[string]string); ok{
        var strArr []string
        for k, v := range arr{
            strArr = append(strArr, k+"='"+v+"'")
        }
        return " WHERE "+ strings.Join(strArr, " && ")
    }
    if arr, ok := m.Cond.(map[string]interface{}); ok{
        for k, v := range arr{
            if isStr, ok := v.(string); ok{
                strArr = append(strArr, k+"='"+isStr+"'")
            }
            if isStrArr, ok := v.([]string); ok{
                for k, v := range isStrArr{
                    isStrArr[k] = "'"+v+"'"
                }
                strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
            }
        }
        return " WHERE "+ strings.Join(strArr, " && ")
    }
    return ""
}

func (m *Model)getSQLField() string {
    if m.Field != ""{
        return m.Field
    }
    return "*"
}

func (m *Model)getSort() string {
    if m.Sort != ""{
        return " ORDER BY "+m.Sort+" "
    }
    return ""
}

func (m *Model)getSQLUpdate() string {
    var strArr []string
    for k, v := range m.Update{
        strArr = append(strArr, k+"='"+v+"'")
    }
    return strings.Join(strArr, ",")
}

func (m *Model)getSQLInsert() string {
    var fieldArr, valueArr []string
    for k, v := range m.Insert{
        fieldArr = append(fieldArr, k)
        valueArr = append(valueArr, "'"+v+"'")
    }
    return "("+ strings.Join(fieldArr, ",") +") values ("+ strings.Join(valueArr, ",") +")"
}

func (m *Model)getSQLFatch() int {
    if(m.Fetch == 0){
        return 0
    }
    return 1
}

func (m *Model)getSQLLimite() string {
    if strArr, ok := m.Limit.([2]int); ok{
        return " LIMIT "+fmt.Sprintf("%d", strArr[0])+", "+fmt.Sprintf("%d", strArr[1])
    }
    return ""
}

func (m *Model)Clean() {
    m.Cond = nil
    m.Insert = nil
    m.Update = nil
    m.Field = ""
    m.Table = ""
    m.Index = ""
    m.Limit = nil
    m.Sort = ""
    m.Fetch = 0
}<commit_msg>fix bugs<commit_after>package QesyDb

import(
    "database/sql"
    "fmt"
    "strings"
    "log"
    _"github.com/go-sql-driver/mysql"
    "reflect"
    "strconv"
    "time"
)

var Db *sql.DB

type Model struct{
    Cond interface{}
    Insert map[string]string
    Update map[string]string
    Field string
    Table string
    Index string
    Limit interface{}
    Sort string
    Tx *sql.Tx
}

// Connect  is a method with a sql.
func Connect(connStr string){
    sqlDb, err := sql.Open("mysql", connStr)
    if(err != nil){
        log.Fatal("mysql connect error")
    }
    err = sqlDb.Ping()
    if(err != nil){
        log.Fatal("mysql ping error")
    }
	fmt.Println("mysql connect sueccss")
    Db = sqlDb
}

func Begin() (*sql.Tx, error) {
    return Db.Begin()
}

func Rollback(tx *sql.Tx) error {
    return tx.Rollback()
}

func Commit(tx *sql.Tx) error {
    return tx.Commit()
}

// ExecSelectIndex  is a method with a sql.
func (m *Model) ExecSelectIndex() (map[string]map[string]string, error) {
    resultsSlice, _ := m.ExecSelect()
    retArr := map[string]map[string]string{}
    for _, v := range resultsSlice{
        if v[m.Index] == "" {
            continue
        }
        retArr[v[m.Index]] = v
    }
    m.Clean()
    return retArr, nil
}

// ExecSelect is a method with a sql.
func (m *Model) ExecSelect() ([]map[string]string, error) {
    cond := m.getSQLCond()
    field := m.getSQLField()
    sort := m.getSort()
    limit := m.getSQLLimite()
    sql := "SELECT "+ field +" FROM "+m.Table+cond+sort+limit+";"
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    rows, err := stmt.Query()
    if(err != nil){
        return nil, err
    }
    defer rows.Close()
    fields, err := rows.Columns()
    if(err != nil){
        return nil, err
    }
    var resultsSlice []map[string]string
    for rows.Next(){
        result := make(map[string]string)
        var scanResultContainers []interface{}
        for i := 0; i < len(fields); i++ {
            var scanResultContainer interface{}
			scanResultContainers = append(scanResultContainers, &scanResultContainer)
        }
        if err := rows.Scan(scanResultContainers...); err != nil {
			return nil, err
		}
        for k, v := range fields {
            rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[k]))
            if rawValue.Interface() == nil{
                continue
            }
            rawType := reflect.TypeOf(rawValue.Interface())
			rawVal := reflect.ValueOf(rawValue.Interface())
            var str string
            switch rawType.Kind() {
                case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                    str = strconv.FormatInt(rawVal.Int(), 10)
                    result[v] = str
                case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
                    str = strconv.FormatUint(rawVal.Uint(), 10)
                    result[v] = str
                case reflect.Float32, reflect.Float64:
                    str = strconv.FormatFloat(rawVal.Float(), 'f', -1, 64)
                    result[v] = str
                case reflect.Slice:
                    if rawType.Elem().Kind() == reflect.Uint8 {
                        result[v] = string(rawVal.Interface().([]byte))
                        break
                    }
                case reflect.String:
                    str = rawVal.String()
                    result[v] = str
                case reflect.Struct:
                    str = rawVal.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
                    result[v] = str
                case reflect.Bool:
                    if rawVal.Bool() {
                        result[v] = "1"
                    } else {
                        result[v] = "0"
                    }
                }
            }
            resultsSlice = append(resultsSlice, result)
        }
        m.Clean()
        return resultsSlice, nil
}

func (m *Model) ExecSelectOne() (map[string]string, error) {
    resultsSlice, err := m.ExecSelect()
    if len(resultsSlice) == 0{
        return nil, err
    }
    return resultsSlice[0], nil
}

func (m *Model) ExecUpdate() (sql.Result, error){
    updateStr := m.getSQLUpdate()
    condStr := m.getSQLCond()
    sql := "UPDATE "+ m.Table +" SET "+ updateStr + condStr +";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecInsert() (sql.Result, error) {
    insert := m.getSQLInsert()
    sql := "INSERT INTO "+m.Table+" "+insert+";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecReplace() (sql.Result, error) {
    insert := m.getSQLInsert()
    sql := "REPLACE INTO "+m.Table+" "+insert+";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func (m *Model) ExecDelete() (sql.Result, error) {
    condStr := m.getSQLCond()
    sql := "DELETE FROM "+ m.Table + condStr +";";
    stmt, err := Db.Prepare(sql)
    if(err != nil){
        return nil, err
    }
    result, err := stmt.Exec()
    m.Clean()
    return result, err
}

func GetLastInsertId(result sql.Result)(int64, error){
    return result.LastInsertId()
}

func GetRowsAffected(result sql.Result)(int64, error){
    return result.RowsAffected()
}

func (m *Model)getSQLCond() string {
    if str, ok := m.Cond.(string); ok{
        return str
    }
    var strArr []string
    if arr, ok := m.Cond.(map[string]string); ok{
        var strArr []string
        for k, v := range arr{
            strArr = append(strArr, k+"='"+v+"'")
        }
        return " WHERE "+ strings.Join(strArr, " && ")
    }
    if arr, ok := m.Cond.(map[string]interface{}); ok{
        for k, v := range arr{
            if isStr, ok := v.(string); ok{
                strArr = append(strArr, k+"='"+isStr+"'")
            }
            if isStrArr, ok := v.([]string); ok{
                for k, v := range isStrArr{
                    isStrArr[k] = "'"+v+"'"
                }
                strArr = append(strArr, k+" in ("+strings.Join(isStrArr, ",")+")")
            }
        }
        return " WHERE "+ strings.Join(strArr, " && ")
    }
    return ""
}

func (m *Model)getSQLField() string {
    if m.Field != ""{
        return m.Field
    }
    return "*"
}

func (m *Model)getSort() string {
    if m.Sort != ""{
        return " ORDER BY "+m.Sort+" "
    }
    return ""
}

func (m *Model)getSQLUpdate() string {
    var strArr []string
    for k, v := range m.Update{
        strArr = append(strArr, k+"='"+v+"'")
    }
    return strings.Join(strArr, ",")
}

func (m *Model)getSQLInsert() string {
    var fieldArr, valueArr []string
    for k, v := range m.Insert{
        fieldArr = append(fieldArr, k)
        valueArr = append(valueArr, "'"+v+"'")
    }
    return "("+ strings.Join(fieldArr, ",") +") values ("+ strings.Join(valueArr, ",") +")"
}

func (m *Model)getSQLLimite() string {
    if strArr, ok := m.Limit.([2]int); ok{
        return " LIMIT "+fmt.Sprintf("%d", strArr[0])+", "+fmt.Sprintf("%d", strArr[1])
    }
    return ""
}

func (m *Model)Clean() {
    m.Cond = nil
    m.Insert = nil
    m.Update = nil
    m.Field = ""
    m.Table = ""
    m.Index = ""
    m.Limit = nil
    m.Sort = ""
}<|endoftext|>


<commit_before>package crypto

import (
	"crypto/aes"
	"crypto/cipher"
	crand "crypto/rand"
	"encoding/hex"
	"io"
	"sync"

	. "github.com/tendermint/tmlibs/common"
)

var gRandInfo *randInfo

func init() {
	gRandInfo = &randInfo{}
	gRandInfo.MixEntropy(randBytes(32)) // Init
}

// Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
// It is OK to call it multiple times.  It does not diminish security.
func MixEntropy(seedBytes []byte) {
	gRandInfo.MixEntropy(seedBytes)
}

// This only uses the OS's randomness
func randBytes(numBytes int) []byte {
	b := make([]byte, numBytes)
	_, err := crand.Read(b)
	if err != nil {
		PanicCrisis(err)
	}
	return b
}

// This uses the OS and the Seed(s).
func CRandBytes(numBytes int) []byte {
	b := make([]byte, numBytes)
	_, err := gRandInfo.Read(b)
	if err != nil {
		PanicCrisis(err)
	}
	return b
}

// RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
func CRandHex(numDigits int) string {
	return hex.EncodeToString(CRandBytes(numDigits / 2))
}

// Returns a crand.Reader mixed with user-supplied entropy
func CReader() io.Reader {
	return gRandInfo
}

//--------------------------------------------------------------------------------

type randInfo struct {
	mtx          sync.Mutex
	seedBytes    [32]byte
	cipherAES256 cipher.Block
	streamAES256 cipher.Stream
	reader       io.Reader
}

// You can call this as many times as you'd like.
// XXX TODO review
func (ri *randInfo) MixEntropy(seedBytes []byte) {
	ri.mtx.Lock()
	defer ri.mtx.Unlock()
	// Make new ri.seedBytes
	hashBytes := Sha256(seedBytes)
	hashBytes32 := [32]byte{}
	copy(hashBytes32[:], hashBytes)
	ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
	// Create new cipher.Block
	var err error
	ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
	if err != nil {
		PanicSanity("Error creating AES256 cipher: " + err.Error())
	}
	// Create new stream
	ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
	// Create new reader
	ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
}

func (ri *randInfo) Read(b []byte) (n int, err error) {
	ri.mtx.Lock()
	defer ri.mtx.Unlock()
	return ri.reader.Read(b)
}

func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
	for i, b := range bytesA {
		res[i] = b ^ bytesB[i]
	}
	return res
}
<commit_msg>CRandHex: fix up doc to mention length of digits<commit_after>package crypto

import (
	"crypto/aes"
	"crypto/cipher"
	crand "crypto/rand"
	"encoding/hex"
	"io"
	"sync"

	. "github.com/tendermint/tmlibs/common"
)

var gRandInfo *randInfo

func init() {
	gRandInfo = &randInfo{}
	gRandInfo.MixEntropy(randBytes(32)) // Init
}

// Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
// It is OK to call it multiple times.  It does not diminish security.
func MixEntropy(seedBytes []byte) {
	gRandInfo.MixEntropy(seedBytes)
}

// This only uses the OS's randomness
func randBytes(numBytes int) []byte {
	b := make([]byte, numBytes)
	_, err := crand.Read(b)
	if err != nil {
		PanicCrisis(err)
	}
	return b
}

// This uses the OS and the Seed(s).
func CRandBytes(numBytes int) []byte {
	b := make([]byte, numBytes)
	_, err := gRandInfo.Read(b)
	if err != nil {
		PanicCrisis(err)
	}
	return b
}

// CRandHex returns a hex encoded string that's floor(numDigits/2) * 2 long.
//
// Note: CRandHex(24) gives 96 bits of randomness that
// are usually strong enough for most purposes.
func CRandHex(numDigits int) string {
	return hex.EncodeToString(CRandBytes(numDigits / 2))
}

// Returns a crand.Reader mixed with user-supplied entropy
func CReader() io.Reader {
	return gRandInfo
}

//--------------------------------------------------------------------------------

type randInfo struct {
	mtx          sync.Mutex
	seedBytes    [32]byte
	cipherAES256 cipher.Block
	streamAES256 cipher.Stream
	reader       io.Reader
}

// You can call this as many times as you'd like.
// XXX TODO review
func (ri *randInfo) MixEntropy(seedBytes []byte) {
	ri.mtx.Lock()
	defer ri.mtx.Unlock()
	// Make new ri.seedBytes
	hashBytes := Sha256(seedBytes)
	hashBytes32 := [32]byte{}
	copy(hashBytes32[:], hashBytes)
	ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
	// Create new cipher.Block
	var err error
	ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
	if err != nil {
		PanicSanity("Error creating AES256 cipher: " + err.Error())
	}
	// Create new stream
	ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
	// Create new reader
	ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
}

func (ri *randInfo) Read(b []byte) (n int, err error) {
	ri.mtx.Lock()
	defer ri.mtx.Unlock()
	return ri.reader.Read(b)
}

func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
	for i, b := range bytesA {
		res[i] = b ^ bytesB[i]
	}
	return res
}
<|endoftext|>