<commit_before>package mmm

import (
	"reflect"
	"syscall"
	"unsafe"
)

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

// Error represents an error within the mmm package.
type Error string

// Error implements the built-in error interface.
func (e Error) Error() string {
	return string(e)
}

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

// MemChunk represents a chunk of manually allocated memory.
type MemChunk struct {
	chunkSize uintptr
	objSize   uintptr

	bytes []byte
}

// NbObjects returns the number of objects in the chunk.
func (mc MemChunk) NbObjects() uint {
	return uint(mc.chunkSize / mc.objSize)
}

// Index returns the i-th object of the chunk as an unsafe pointer.
//
// This will panic if `i` is out of bounds.
func (mc MemChunk) Index(i int) unsafe.Pointer {
	return unsafe.Pointer(&(mc.bytes[uintptr(i)*mc.objSize]))
}

// Delete frees the memory chunk.
func (mc *MemChunk) Delete() error {
	err := syscall.Munmap(mc.bytes)
	if err != nil {
		return err
	}

	mc.chunkSize = 0
	mc.objSize = 1
	mc.bytes = nil

	return nil
}

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

// NewMemChunk returns a new memory chunk.
//
// `v`'s memory representation will be used as a template for the newly
// allocated memory. All pointers will be flattened. All data will be copied.
// `n` is the number of `v`-like objects the memory chunk can contain (i.e.,
// sizeof(chunk) = sizeof(v) * n).
func NewMemChunk(v interface{}, n uint) (MemChunk, error) {
	if n == 0 {
		return MemChunk{}, Error("`n` must be > 0")
	}

	size := reflect.ValueOf(v).Type().Size()
	bytes, err := syscall.Mmap(
		0, 0, int(size*uintptr(n)),
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS,
	)
	if err != nil {
		return MemChunk{}, err
	}

	for i := uint(0); i < n; i++ {
		if err := BytesOf(v, bytes[i*uint(size):]); err != nil {
			return MemChunk{}, err
		}
	}

	return MemChunk{
		chunkSize: size * uintptr(n),
		objSize:   size,
		bytes:     bytes,
	}, nil
}
<commit_msg>MemChunk.Index now builds and returns an interface<commit_after>package mmm

import (
	"encoding/binary"
	"reflect"
	"syscall"
	"unsafe"
)

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

// Error represents an error within the mmm package.
type Error string

// Error implements the built-in error interface.
func (e Error) Error() string {
	return string(e)
}

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

// MemChunk represents a chunk of manually allocated memory.
type MemChunk struct {
	chunkSize uintptr
	objSize   uintptr

	itf       interface{}
	byteOrder binary.ByteOrder
	bytes     []byte
}

// NbObjects returns the number of objects in the chunk.
func (mc MemChunk) NbObjects() uint {
	return uint(mc.chunkSize / mc.objSize)
}

// Index returns the i-th object of the chunk as an interface.
//
// This will panic if `i` is out of bounds.
func (mc MemChunk) Index(i int) interface{} {
	itf := mc.itf
	itfBytes := ((*[unsafe.Sizeof(itf)]byte)(unsafe.Pointer(&itf)))

	dataPtr := uintptr(unsafe.Pointer(&(mc.bytes[uintptr(i)*mc.objSize])))

	ptrSize := unsafe.Sizeof(uintptr(0))
	itfLen := uintptr(len(itfBytes)) - ptrSize

	switch ptrSize {
	case unsafe.Sizeof(uint8(0)):
		itfBytes[itfLen] = byte(dataPtr)
	case unsafe.Sizeof(uint16(0)):
		mc.byteOrder.PutUint16(itfBytes[itfLen:], uint16(dataPtr))
	case unsafe.Sizeof(uint32(0)):
		mc.byteOrder.PutUint32(itfBytes[itfLen:], uint32(dataPtr))
	case unsafe.Sizeof(uint64(0)):
		mc.byteOrder.PutUint64(itfBytes[itfLen:], uint64(dataPtr))
	}

	return itf
}

// Delete frees the memory chunk.
func (mc *MemChunk) Delete() error {
	err := syscall.Munmap(mc.bytes)
	if err != nil {
		return err
	}

	mc.chunkSize = 0
	mc.objSize = 1
	mc.bytes = nil

	return nil
}

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

// NewMemChunk returns a new memory chunk.
//
// `v`'s memory representation will be used as a template for the newly
// allocated memory. All pointers will be flattened. All data will be copied.
// `n` is the number of `v`-like objects the memory chunk can contain (i.e.,
// sizeof(chunk) = sizeof(v) * n).
func NewMemChunk(v interface{}, n uint) (MemChunk, error) {
	if n == 0 {
		return MemChunk{}, Error("`n` must be > 0")
	}

	size := reflect.ValueOf(v).Type().Size()
	bytes, err := syscall.Mmap(
		0, 0, int(size*uintptr(n)),
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS,
	)
	if err != nil {
		return MemChunk{}, err
	}

	for i := uint(0); i < n; i++ {
		if err := BytesOf(v, bytes[i*uint(size):]); err != nil {
			return MemChunk{}, err
		}
	}

	return MemChunk{
		chunkSize: size * uintptr(n),
		objSize:   size,

		itf:       reflect.ValueOf(v).Interface(),
		byteOrder: Endianness(),
		bytes:     bytes,
	}, nil
}

func Endianness() binary.ByteOrder {
	var byteOrder binary.ByteOrder = binary.LittleEndian
	var i int = 0x1
	if ((*[unsafe.Sizeof(uintptr(0))]byte)(unsafe.Pointer(&i)))[0] == 0 {
		byteOrder = binary.BigEndian
	}

	return byteOrder
}
<|endoftext|>


<commit_before>// Copyright © 2015 Clement 'cmc' Rey <cr.rey.clement@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package mmm

import (
	"reflect"
	"runtime"
	"syscall"
	"unsafe"
)

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

// Error represents an error within the mmm package.
type Error string

// Error implements the built-in error interface.
func (e Error) Error() string {
	return string(e)
}

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

// MemChunk represents a chunk of manually allocated memory.
type MemChunk struct {
	chunkSize uintptr
	objSize   uintptr

	arr   reflect.Value
	bytes []byte
}

// NbObjects returns the number of objects in the chunk.
func (mc MemChunk) NbObjects() uint {
	return uint(mc.chunkSize / mc.objSize)
}

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

// Read returns the i-th object of the chunk as an interface.
//
// mmm doesn't provide synchronization of reads and writes on a MemChunk: it's
// entirely up to you to decide how you want to manage thread-safety.
//
// This will panic if `i` is out of bounds.
func (mc *MemChunk) Read(i int) interface{} {
	return mc.arr.Index(i).Interface()
}

// Write writes the passed value to the i-th object of the chunk.
//
// It returns the passed value.
//
// mmm doesn't provide synchronization of reads and writes on a MemChunk: it's
// entirely up to you to decide how you want to manage thread-safety.
//
// This will panic if `i` is out of bounds, or if `v` is of a different type than
// the other objects in the chunk. Or if anything went wrong.
func (mc *MemChunk) Write(i int, v interface{}) interface{} {
	// panic if `v` is of a different type
	if reflect.TypeOf(v) != mc.arr.Type().Elem() {
		panic("illegal value")
	}
	// copies `v`'s byte representation to index `i`
	if err := BytesOf(v, mc.bytes[uintptr(i)*mc.objSize:]); err != nil {
		panic(err)
	}

	return v
}

// Pointer returns a pointer to the i-th object of the chunk.
//
// It returns uintptr instead of unsafe.Pointer so that code using mmm
// cannot obtain unsafe.Pointers without importing the unsafe package
// explicitly.
//
// This will panic if `i` is out of bounds.
func (mc MemChunk) Pointer(i int) uintptr {
	return uintptr(unsafe.Pointer(&(mc.bytes[uintptr(i)*mc.objSize])))
}

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

// NewMemChunk returns a new memory chunk.
//
// Supported types:
// interfaces,
// arrays,
// structs,
// numerics and boolean (bool/int/uint/float/complex and their variants),
// unsafe.Pointer,
// and any possible combination of the above.
//
// `v`'s memory representation will be used as a template for the newly
// allocated memory. All data will be copied.
// `n` is the number of `v`-like objects the memory chunk can contain (i.e.,
// sizeof(chunk) = sizeof(v) * n).
func NewMemChunk(v interface{}, n uint) (MemChunk, error) {
	if n == 0 {
		return MemChunk{}, Error("`n` must be > 0")
	}
	if _, err := TypeOf(v); err != nil {
		return MemChunk{}, err
	}

	t := reflect.TypeOf(v)
	size := t.Size()
	bytes, err := syscall.Mmap(
		0, 0, int(size*uintptr(n)),
		syscall.PROT_READ|syscall.PROT_WRITE,
		mmapFlags,
	)
	if err != nil {
		return MemChunk{}, err
	}

	for i := uintptr(0); i < uintptr(n); i++ {
		if err := BytesOf(v, bytes[i*size:]); err != nil {
			return MemChunk{}, err
		}
	}

	// create an array of type t, backed by the mmap'd memory
	arr := reflect.Zero(reflect.ArrayOf(int(n), t)).Interface()
	(*[2]uintptr)(unsafe.Pointer(&arr))[1] = uintptr(unsafe.Pointer(&bytes[0]))

	ret := MemChunk{
		chunkSize: size * uintptr(n),
		objSize:   size,

		arr:   reflect.ValueOf(arr),
		bytes: bytes,
	}

	// set a finalizer to free the chunk's memory when it would normally be
	// garbage collected
	runtime.SetFinalizer(&ret, func(chunk *MemChunk) {
		if chunk.bytes != nil {
			chunk.Delete()
		}
	})

	return ret, nil
}

// Delete frees the memory chunk.
func (mc *MemChunk) Delete() error {
	err := syscall.Munmap(mc.bytes)
	if err != nil {
		return err
	}

	mc.chunkSize = 0
	mc.objSize = 1
	mc.bytes = nil

	return nil
}
<commit_msg>use reflect.MakeSlice instead of ArrayOf<commit_after>// Copyright © 2015 Clement 'cmc' Rey <cr.rey.clement@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package mmm

import (
	"reflect"
	"runtime"
	"syscall"
	"unsafe"
)

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

// Error represents an error within the mmm package.
type Error string

// Error implements the built-in error interface.
func (e Error) Error() string {
	return string(e)
}

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

// MemChunk represents a chunk of manually allocated memory.
type MemChunk struct {
	chunkSize uintptr
	objSize   uintptr

	slice reflect.Value
	bytes []byte
}

// NbObjects returns the number of objects in the chunk.
func (mc MemChunk) NbObjects() uint {
	return uint(mc.chunkSize / mc.objSize)
}

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

// Read returns the i-th object of the chunk as an interface.
//
// mmm doesn't provide synchronization of reads and writes on a MemChunk: it's
// entirely up to you to decide how you want to manage thread-safety.
//
// This will panic if `i` is out of bounds.
func (mc *MemChunk) Read(i int) interface{} {
	return mc.slice.Index(i).Interface()
}

// Write writes the passed value to the i-th object of the chunk.
//
// It returns the passed value.
//
// mmm doesn't provide synchronization of reads and writes on a MemChunk: it's
// entirely up to you to decide how you want to manage thread-safety.
//
// This will panic if `i` is out of bounds, or if `v` is of a different type than
// the other objects in the chunk. Or if anything went wrong.
func (mc *MemChunk) Write(i int, v interface{}) interface{} {
	// panic if `v` is of a different type
	val := reflect.ValueOf(v)
	if val.Type() != mc.slice.Type().Elem() {
		panic("illegal value")
	}
	mc.slice.Index(i).Set(val)
	return v
}

// Pointer returns a pointer to the i-th object of the chunk.
//
// It returns uintptr instead of unsafe.Pointer so that code using mmm
// cannot obtain unsafe.Pointers without importing the unsafe package
// explicitly.
//
// This will panic if `i` is out of bounds.
func (mc MemChunk) Pointer(i int) uintptr {
	return uintptr(unsafe.Pointer(&(mc.bytes[uintptr(i)*mc.objSize])))
}

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

// NewMemChunk returns a new memory chunk.
//
// Supported types:
// interfaces,
// arrays,
// structs,
// numerics and boolean (bool/int/uint/float/complex and their variants),
// unsafe.Pointer,
// and any possible combination of the above.
//
// `v`'s memory representation will be used as a template for the newly
// allocated memory. All data will be copied.
// `n` is the number of `v`-like objects the memory chunk can contain (i.e.,
// sizeof(chunk) = sizeof(v) * n).
func NewMemChunk(v interface{}, n uint) (MemChunk, error) {
	if n == 0 {
		return MemChunk{}, Error("`n` must be > 0")
	}
	if _, err := TypeOf(v); err != nil {
		return MemChunk{}, err
	}

	t := reflect.TypeOf(v)
	size := t.Size()
	bytes, err := syscall.Mmap(
		0, 0, int(size*uintptr(n)),
		syscall.PROT_READ|syscall.PROT_WRITE,
		mmapFlags,
	)
	if err != nil {
		return MemChunk{}, err
	}

	for i := uintptr(0); i < uintptr(n); i++ {
		if err := BytesOf(v, bytes[i*size:]); err != nil {
			return MemChunk{}, err
		}
	}

	// create a slice of type t, backed by the mmap'd memory
	slice := reflect.MakeSlice(reflect.SliceOf(t), int(n), int(n)).Interface()
	type sliceInternals struct {
		data uintptr
		_len uintptr
		_cap uintptr
	}
	si := (*sliceInternals)((*[2]unsafe.Pointer)(unsafe.Pointer(&slice))[1])
	si.data = uintptr(unsafe.Pointer(&bytes[0]))

	ret := MemChunk{
		chunkSize: size * uintptr(n),
		objSize:   size,

		slice: reflect.ValueOf(slice),
		bytes: bytes,
	}

	// set a finalizer to free the chunk's memory when it would normally be
	// garbage collected
	runtime.SetFinalizer(&ret, func(chunk *MemChunk) {
		if chunk.bytes != nil {
			chunk.Delete()
		}
	})

	return ret, nil
}

// Delete frees the memory chunk.
func (mc *MemChunk) Delete() error {
	err := syscall.Munmap(mc.bytes)
	if err != nil {
		return err
	}

	mc.chunkSize = 0
	mc.objSize = 1
	mc.bytes = nil

	return nil
}
<|endoftext|>


<commit_before>package logtap

import (
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/pagodabox/golang-hatchet"
	"net/http"
	"strconv"
)

// HistoricalDrain matches the drain interface
type HistoricalDrain struct {
	port string
	max  int
	log  hatchet.Logger
	db   *bolt.DB
	deploy []string
}

// NewHistoricalDrain returns a new instance of a HistoricalDrain
func NewHistoricalDrain(port string, file string, max int) *HistoricalDrain {
	db, err := bolt.Open(file, 0644, nil)
	if err != nil {
		db, err = bolt.Open("./bolt.db", 0644, nil)
	}
	return &HistoricalDrain{
		port: port,
		max:  max,
		db:   db,
	}
}

// allow us to clear history of the deploy logs
func (h *HistoricalDrain) ClearDeploy() {
	h.deploy = []string{}
}

// Start starts the http listener.
// The listener on every request returns a json hash of logs of some arbitrary size
// default size is 100
func (h *HistoricalDrain) Start() {
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/logtap/system", h.handlerSystem)
		mux.HandleFunc("/logtap/deploy", h.handlerDeploy)
		err := http.ListenAndServe(":"+h.port, mux)
		if err != nil {
			h.log.Error("[LOGTAP]"+err.Error())
		}
	}()
}

// Handle deploys that come into this drain
// deploy logs should stay relatively short and should be cleared out easily
func (h *HistoricalDrain) handlerDeploy(w http.ResponseWriter, r *http.Request) {
	for _, msg := range h.deploy {
		fmt.Fprintf(w, "%s\n", msg)
	}
}

// handlerSystem handles any web request with any path and returns logs
// this makes it so a client that talks to pagodabox's logvac
// can communicate with this system
func (h *HistoricalDrain) handlerSystem(w http.ResponseWriter, r *http.Request) {
	var limit int64
	if i, err := strconv.ParseInt(r.FormValue("limit"), 10, 64); err == nil {
		limit = i
	} else {
		limit = 10000
	}
	h.log.Debug("[LOGTAP][handler] limit: %d", limit)
	h.db.View(func(tx *bolt.Tx) error {
		// Create a new bucket.
		b := tx.Bucket([]byte("log"))
		c := b.Cursor()

		// move the curser along so we can start dropping logs
		// in the right order at the right place
		if int64(b.Stats().KeyN) > limit {
			c.First()
			move_forward := int64(b.Stats().KeyN) - limit
			for i := int64(1); i < move_forward; i++ {
				c.Next()
			}
		} else {
			c.First()
		}

		for k, v := c.Next(); k != nil; k, v = c.Next() {
			fmt.Fprintf(w, "%s - %s", k, v)
		}

		return nil
	})

}

// SetLogger really allows the logtap main struct
// to assign its own logger to the historical drain
func (h *HistoricalDrain) SetLogger(l hatchet.Logger) {
	h.log = l
}

// Write is used to implement the interface and do
// type switching
func (h *HistoricalDrain) Write(msg Message) {
  switch msg.Type {
  case "deploy":
  	h.WriteDeploy(msg)
  default :
    h.WriteSystem(msg)
  }
}

// Write deploy logs to the deploy array.
// much quicker and better at handling deploy logs
func (h *HistoricalDrain) WriteDeploy(msg Message) {
	h.deploy = append(h.deploy, (msg.Time.String()+" - "+msg.Content))
}

// WriteSyslog drops data into a capped collection of logs
// if we hit the limit the last log item will be removed from the beginning
func (h *HistoricalDrain) WriteSystem(msg Message) {
	h.log.Debug("[LOGTAP][Historical][write] message: (%s)%s", msg.Time.String(), msg.Content)
	h.db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte("log"))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}
		err = bucket.Put([]byte(msg.Time.String()), []byte(msg.Content))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}

		if bucket.Stats().KeyN > h.max {
			delete_count := bucket.Stats().KeyN - h.max
			c := bucket.Cursor()
			for i := 0; i < delete_count; i++ {
				c.First()
				c.Delete()
			}
		}

		return nil
	})

}
<commit_msg>make the historical drain handle both admin and system logs<commit_after>package logtap

import (
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/pagodabox/golang-hatchet"
	"net/http"
	"strconv"
)

// HistoricalDrain matches the drain interface
type HistoricalDrain struct {
	port string
	max  int
	log  hatchet.Logger
	db   *bolt.DB
	deploy []string
}

// NewHistoricalDrain returns a new instance of a HistoricalDrain
func NewHistoricalDrain(port string, file string, max int) *HistoricalDrain {
	db, err := bolt.Open(file, 0644, nil)
	if err != nil {
		db, err = bolt.Open("./bolt.db", 0644, nil)
	}
	return &HistoricalDrain{
		port: port,
		max:  max,
		db:   db,
	}
}

// allow us to clear history of the deploy logs
func (h *HistoricalDrain) ClearDeploy() {
	h.deploy = []string{}
}

// Start starts the http listener.
// The listener on every request returns a json hash of logs of some arbitrary size
// default size is 100
func (h *HistoricalDrain) Start() {
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/logtap/system", h.handlerSystem)
		mux.HandleFunc("/logtap/admin", h.handlerAdmin)
		mux.HandleFunc("/logtap/deploy", h.handlerDeploy)
		err := http.ListenAndServe(":"+h.port, mux)
		if err != nil {
			h.log.Error("[LOGTAP]"+err.Error())
		}
	}()
}

// Handle deploys that come into this drain
// deploy logs should stay relatively short and should be cleared out easily
func (h *HistoricalDrain) handlerDeploy(w http.ResponseWriter, r *http.Request) {
	for _, msg := range h.deploy {
		fmt.Fprintf(w, "%s\n", msg)
	}
}

// handlerSystem handles any web request with any path and returns logs
// this makes it so a client that talks to pagodabox's logvac
// can communicate with this system
func (h *HistoricalDrain) handlerAdmin(w http.ResponseWriter, r *http.Request) {
	var limit int64
	if i, err := strconv.ParseInt(r.FormValue("limit"), 10, 64); err == nil {
		limit = i
	} else {
		limit = 10000
	}
	h.log.Debug("[LOGTAP][handler] limit: %d", limit)
	h.db.View(func(tx *bolt.Tx) error {
		// Create a new bucket.
		b := tx.Bucket([]byte("admin"))
		c := b.Cursor()

		// move the curser along so we can start dropping logs
		// in the right order at the right place
		if int64(b.Stats().KeyN) > limit {
			c.First()
			move_forward := int64(b.Stats().KeyN) - limit
			for i := int64(1); i < move_forward; i++ {
				c.Next()
			}
		} else {
			c.First()
		}

		for k, v := c.Next(); k != nil; k, v = c.Next() {
			fmt.Fprintf(w, "%s - %s", k, v)
		}

		return nil
	})

}
// handlerSystem handles any web request with any path and returns logs
// this makes it so a client that talks to pagodabox's logvac
// can communicate with this system
func (h *HistoricalDrain) handlerSystem(w http.ResponseWriter, r *http.Request) {
	var limit int64
	if i, err := strconv.ParseInt(r.FormValue("limit"), 10, 64); err == nil {
		limit = i
	} else {
		limit = 10000
	}
	h.log.Debug("[LOGTAP][handler] limit: %d", limit)
	h.db.View(func(tx *bolt.Tx) error {
		// Create a new bucket.
		b := tx.Bucket([]byte("system"))
		c := b.Cursor()

		// move the curser along so we can start dropping logs
		// in the right order at the right place
		if int64(b.Stats().KeyN) > limit {
			c.First()
			move_forward := int64(b.Stats().KeyN) - limit
			for i := int64(1); i < move_forward; i++ {
				c.Next()
			}
		} else {
			c.First()
		}

		for k, v := c.Next(); k != nil; k, v = c.Next() {
			fmt.Fprintf(w, "%s - %s", k, v)
		}

		return nil
	})

}

// SetLogger really allows the logtap main struct
// to assign its own logger to the historical drain
func (h *HistoricalDrain) SetLogger(l hatchet.Logger) {
	h.log = l
}

// Write is used to implement the interface and do
// type switching
func (h *HistoricalDrain) Write(msg Message) {
  switch msg.Type {
  case "deploy":
  	h.WriteDeploy(msg)
  case "admin":
  	h.WriteAdmin(msg)
  default :
    h.WriteSystem(msg)
  }
}

// Write deploy logs to the deploy array.
// much quicker and better at handling deploy logs
func (h *HistoricalDrain) WriteDeploy(msg Message) {
	h.deploy = append(h.deploy, (msg.Time.String()+" - "+msg.Content))
}

// WriteSyslog drops data into a capped collection of logs
// if we hit the limit the last log item will be removed from the beginning
func (h *HistoricalDrain) WriteAdmin(msg Message) {
	h.log.Debug("[LOGTAP][Historical][write] message: (%s)%s", msg.Time.String(), msg.Content)
	h.db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte("admin"))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}
		err = bucket.Put([]byte(msg.Time.String()), []byte(msg.Content))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}

		if bucket.Stats().KeyN > h.max {
			delete_count := bucket.Stats().KeyN - h.max
			c := bucket.Cursor()
			for i := 0; i < delete_count; i++ {
				c.First()
				c.Delete()
			}
		}

		return nil
	})

}
// WriteSyslog drops data into a capped collection of logs
// if we hit the limit the last log item will be removed from the beginning
func (h *HistoricalDrain) WriteSystem(msg Message) {
	h.log.Debug("[LOGTAP][Historical][write] message: (%s)%s", msg.Time.String(), msg.Content)
	h.db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte("system"))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}
		err = bucket.Put([]byte(msg.Time.String()), []byte(msg.Content))
		if err != nil {
			h.log.Error("[LOGTAP][Historical][write]" + err.Error())
			return err
		}

		if bucket.Stats().KeyN > h.max {
			delete_count := bucket.Stats().KeyN - h.max
			c := bucket.Cursor()
			for i := 0; i < delete_count; i++ {
				c.First()
				c.Delete()
			}
		}

		return nil
	})

}
<|endoftext|>


<commit_before>package xmpp

import (
	"encoding/xml"
	"fmt"
	"strings"
)

const (
	NsMUC     = "http://jabber.org/protocol/muc"
	NsMUCUser = "http://jabber.org/protocol/muc#user"
)

type Status struct {
	XMLName xml.Name `xml:"status"`
	Code    string   `xml:"code,attr"`
}

type Item struct {
	XMLName xml.Name `xml:"item"`
	// owner, admin, member, outcast, none
	Affiliation string `xml:"affiliation,attr,omitempty"`
	// moderator, participant, visitor, none
	Role string `xml:"role,attr,omitempty"`
	JID  string `xml:"jid,attr,omitempty"`
	Nick string `xml:"nick,attr,omitempty"`
}

type X struct {
	XMLName  xml.Name `xml:"http://jabber.org/protocol/muc#user x"`
	Items    []Item   `xml:"item,omitempty"`
	Statuses []Status `xml:"status,omitempty"`
	Decline  Reason   `xml:"decline,omitempty"`
	Invite   Reason   `xml:"invite,omitempty"`
	Destroy  XDestroy `xml:"destroy,omitempty"`
	Password string   `xml:"password,omitempty"`
}

type Photo struct {
	XMLName xml.Name `xml:"vcard-temp:x:update x"`
	Photo   string   `xml:"photo,omitempty"`
}

type Reason struct {
	From   string `xml:"from,attr,omitempty"`
	To     string `xml:"to,attr,omitempty"`
	Reason string `xml:"reason,omitempty"`
}

type XDestroy struct {
	JID    string `xml:"jid,attr,omitempty"`
	Reason string `xml:"reason,omitempty"`
}

// http://xmpp.org/extensions/xep-0045.html
// <presence />
type MUCPresence struct {
	XMLName xml.Name `xml:"presence"`
	Lang    string   `xml:"lang,attr,omitempty"`
	From    string   `xml:"from,attr,omitempty"`
	To      string   `xml:"to,attr,omitempty"`
	Id      string   `xml:"id.attr,omitempty"`
	Type    string   `xml:"type,attr,omitempty"`

	X     []X   `xml:"http://jabber.org/protocol/muc#user x,omitempty"`
	Photo Photo `xml:"vcard-temp:x:update x"` // http://xmpp.org/extensions/xep-0153.html

	Show     string       `xml:"show,omitempty"`   // away, chat, dnd, xa
	Status   string       `xml:"status,omitempty"` // sb []clientText
	Priority string       `xml:"priority,omitempty"`
	Caps     *ClientCaps  `xml:"c"`
	Error    *ClientError `xml:"error"`
}

// JoinMUC joins to a given conference with nick and optional password
// http://xmpp.org/extensions/xep-0045.html#bizrules-presence
func (c *Conn) JoinMUC(to, nick, password string) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	// remove resource from jid
	parts := strings.SplitN(to, "/", 2)
	to = parts[0]
	if len(nick) == 0 {
		if len(parts) == 2 {
			nick = parts[1]
		} else { // if nick empty & bare jid, set nick to login
			nick = strings.SplitN(c.jid, "@", 2)[0]
		}
	}
	var pass string
	if len(password) > 0 {
		pass = "<password>" + password + "</password>"
	}
	stanza := fmt.Sprintf("<presence from='%s' to='%s/%s'>"+
		"\n  <x xmlns='%s'>"+
		"\n    <history maxchars='0' />"+
		"\n    "+pass+
		"\n  </x>"+
		"\n</presence>",
		xmlEscape(c.jid), xmlEscape(to), xmlEscape(nick), NsMUC)
	_, err := fmt.Fprintf(c.out, stanza)
	return err
}

// SendMUC sends a message to the given conference with specified type (chat or groupchat).
func (c *Conn) SendMUC(to, typ, msg string) error {
	if typ == "" {
		typ = "groupchat"
	}
	cookie := c.getCookie()
	stanza := fmt.Sprintf("<message from='%s' to='%s' type='%s' id='%x'>%s</message>",
		xmlEscape(c.jid), xmlEscape(to), xmlEscape(typ), cookie, xmlEscape(msg))
	_, err := fmt.Fprintf(c.out, stanza)
	return err
}
<commit_msg>API: GetAffilRole() and IsCode()<commit_after>package xmpp

import (
	"encoding/xml"
	"errors"
	"fmt"
	"strings"
)

const (
	NsMUC     = "http://jabber.org/protocol/muc"
	NsMUCUser = "http://jabber.org/protocol/muc#user"
)

type Status struct {
	// XMLName xml.Name `xml:"status"`
	Code string `xml:"code,attr"`
}

type Item struct {
	// XMLName xml.Name `xml:"item"`
	// owner, admin, member, outcast, none
	Affil string `xml:"affiliation,attr,omitempty"`
	// moderator, participant, visitor, none
	Role string `xml:"role,attr,omitempty"`
	JID  string `xml:"jid,attr,omitempty"`
	Nick string `xml:"nick,attr,omitempty"`
}

type X struct {
	XMLName  xml.Name `xml:"http://jabber.org/protocol/muc#user x"`
	Items    []Item   `xml:"item,omitempty"`
	Statuses []Status `xml:"status,omitempty"`
	Decline  Reason   `xml:"decline,omitempty"`
	Invite   Reason   `xml:"invite,omitempty"`
	Destroy  XDestroy `xml:"destroy,omitempty"`
	Password string   `xml:"password,omitempty"`
}

type Photo struct {
	XMLName xml.Name `xml:"vcard-temp:x:update x"`
	Photo   string   `xml:"photo,omitempty"`
}

type Reason struct {
	From   string `xml:"from,attr,omitempty"`
	To     string `xml:"to,attr,omitempty"`
	Reason string `xml:"reason,omitempty"`
}

type XDestroy struct {
	JID    string `xml:"jid,attr,omitempty"`
	Reason string `xml:"reason,omitempty"`
}

// http://xmpp.org/extensions/xep-0045.html
// <presence />
type MUCPresence struct {
	XMLName xml.Name `xml:"presence"`
	Lang    string   `xml:"lang,attr,omitempty"`
	From    string   `xml:"from,attr,omitempty"`
	To      string   `xml:"to,attr,omitempty"`
	Id      string   `xml:"id.attr,omitempty"`
	Type    string   `xml:"type,attr,omitempty"`

	X     []X   `xml:"http://jabber.org/protocol/muc#user x,omitempty"`
	Photo Photo `xml:"vcard-temp:x:update x"` // http://xmpp.org/extensions/xep-0153.html

	Show     string       `xml:"show,omitempty"`   // away, chat, dnd, xa
	Status   string       `xml:"status,omitempty"` // sb []clientText
	Priority string       `xml:"priority,omitempty"`
	Caps     *ClientCaps  `xml:"c"`
	Error    *ClientError `xml:"error"`
}

// IsCode checks if MUCPresence contains given code
func (p *MUCPresence) IsCode(code string) bool {
	if len(p.X) == 0 {
		return false
	}
	for _, x := range p.X {
		for _, xs := range x.Statuses {
			if xs.Code == code {
				return true
			}
		}
	}
	return false
}

func (p *MUCPresence) GetAffilRole() (affil, role string, err error) {
	if len(p.X) == 0 {
		return "", "", errors.New("no <x /> subitem!")
	}
	for _, x := range p.X {
		for _, xi := range x.Items {
			affil = xi.Affil
			role = xi.Role
			return
		}
	}
	return "", "", errors.New("no affil/role info")
}

// JoinMUC joins to a given conference with nick and optional password
// http://xmpp.org/extensions/xep-0045.html#bizrules-presence
func (c *Conn) JoinMUC(to, nick, password string) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	// remove resource from jid
	parts := strings.SplitN(to, "/", 2)
	to = parts[0]
	if len(nick) == 0 {
		if len(parts) == 2 {
			nick = parts[1]
		} else { // if nick empty & bare jid, set nick to login
			nick = strings.SplitN(c.jid, "@", 2)[0]
		}
	}
	var pass string
	if len(password) > 0 {
		pass = "<password>" + password + "</password>"
	}
	stanza := fmt.Sprintf("<presence from='%s' to='%s/%s'>"+
		"\n  <x xmlns='%s'>"+
		"\n    <history maxchars='0' />"+
		"\n    "+pass+
		"\n  </x>"+
		"\n</presence>",
		xmlEscape(c.jid), xmlEscape(to), xmlEscape(nick), NsMUC)
	_, err := fmt.Fprintf(c.out, stanza)
	return err
}

// SendMUC sends a message to the given conference with specified type (chat or groupchat).
func (c *Conn) SendMUC(to, typ, msg string) error {
	if typ == "" {
		typ = "groupchat"
	}
	cookie := c.getCookie()
	stanza := fmt.Sprintf("<message from='%s' to='%s' type='%s' id='%x'>%s</message>",
		xmlEscape(c.jid), xmlEscape(to), xmlEscape(typ), cookie, xmlEscape(msg))
	_, err := fmt.Fprintf(c.out, stanza)
	return err
}
<|endoftext|>


<commit_before>package buildah

import (
	"context"
	"fmt"
	"math/rand"
	"strings"

	"github.com/containers/buildah/util"
	"github.com/containers/image/pkg/sysregistries"
	is "github.com/containers/image/storage"
	"github.com/containers/image/transports"
	"github.com/containers/image/transports/alltransports"
	"github.com/containers/image/types"
	"github.com/containers/storage"
	"github.com/openshift/imagebuilder"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// BaseImageFakeName is the "name" of a source image which we interpret
	// as "no image".
	BaseImageFakeName = imagebuilder.NoBaseImageSpecifier
)

func pullAndFindImage(ctx context.Context, store storage.Store, transport string, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) {
	pullOptions := PullOptions{
		ReportWriter:  options.ReportWriter,
		Store:         store,
		SystemContext: options.SystemContext,
		BlobDirectory: options.PullBlobDirectory,
	}
	ref, err := pullImage(ctx, store, transport, imageName, pullOptions, sc)
	if err != nil {
		logrus.Debugf("error pulling image %q: %v", imageName, err)
		return nil, nil, err
	}
	img, err := is.Transport.GetStoreImage(store, ref)
	if err != nil {
		logrus.Debugf("error reading pulled image %q: %v", imageName, err)
		return nil, nil, errors.Wrapf(err, "error locating image %q in local storage", transports.ImageName(ref))
	}
	return img, ref, nil
}

func getImageName(name string, img *storage.Image) string {
	imageName := name
	if len(img.Names) > 0 {
		imageName = img.Names[0]
		// When the image used by the container is a tagged image
		// the container name might be set to the original image instead of
		// the image given in the "from" command line.
		// This loop is supposed to fix this.
		for _, n := range img.Names {
			if strings.Contains(n, name) {
				imageName = n
				break
			}
		}
	}
	return imageName
}

func imageNamePrefix(imageName string) string {
	prefix := imageName
	s := strings.Split(imageName, "/")
	if len(s) > 0 {
		prefix = s[len(s)-1]
	}
	s = strings.Split(prefix, ":")
	if len(s) > 0 {
		prefix = s[0]
	}
	s = strings.Split(prefix, "@")
	if len(s) > 0 {
		prefix = s[0]
	}
	return prefix
}

func newContainerIDMappingOptions(idmapOptions *IDMappingOptions) storage.IDMappingOptions {
	var options storage.IDMappingOptions
	if idmapOptions != nil {
		options.HostUIDMapping = idmapOptions.HostUIDMapping
		options.HostGIDMapping = idmapOptions.HostGIDMapping
		uidmap, gidmap := convertRuntimeIDMaps(idmapOptions.UIDMap, idmapOptions.GIDMap)
		if len(uidmap) > 0 && len(gidmap) > 0 {
			options.UIDMap = uidmap
			options.GIDMap = gidmap
		} else {
			options.HostUIDMapping = true
			options.HostGIDMapping = true
		}
	}
	return options
}

func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) {
	type failure struct {
		resolvedImageName string
		err               error
	}
	candidates, transport, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store)
	if err != nil {
		return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage)
	}

	failures := []failure{}
	for _, image := range candidates {
		if transport == "" {
			img, err := store.Image(image)
			if err != nil {
				logrus.Debugf("error looking up known-local image %q: %v", image, err)
				failures = append(failures, failure{resolvedImageName: image, err: err})
				continue
			}
			ref, err := is.Transport.ParseStoreReference(store, img.ID)
			if err != nil {
				return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID)
			}
			return ref, transport, img, nil
		}

		if options.PullPolicy == PullAlways {
			pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
			if err != nil {
				logrus.Debugf("unable to pull and read image %q: %v", image, err)
				failures = append(failures, failure{resolvedImageName: image, err: err})
				continue
			}
			return pulledReference, transport, pulledImg, nil
		}

		srcRef, err := alltransports.ParseImageName(image)
		if err != nil {
			if transport == "" {
				logrus.Debugf("error parsing image name %q: %v", image, err)
				failures = append(failures, failure{
					resolvedImageName: image,
					err:               errors.Wrapf(err, "error parsing image name"),
				})
				continue
			}
			logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, transport, err)

			trans := transport
			if transport != util.DefaultTransport {
				trans = trans + ":"
			}
			srcRef2, err := alltransports.ParseImageName(trans + image)
			if err != nil {
				logrus.Debugf("error parsing image name %q: %v", transport+image, err)
				failures = append(failures, failure{
					resolvedImageName: image,
					err:               errors.Wrapf(err, "error parsing attempted image name %q", transport+image),
				})
				continue
			}
			srcRef = srcRef2
		}

		destImage, err := localImageNameForReference(ctx, store, srcRef, options.FromImage)
		if err != nil {
			return nil, "", nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef))
		}
		if destImage == "" {
			return nil, "", nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef))
		}

		ref, err := is.Transport.ParseStoreReference(store, destImage)
		if err != nil {
			return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", destImage)
		}
		img, err := is.Transport.GetStoreImage(store, ref)
		if err == nil {
			return ref, transport, img, nil
		}

		if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing {
			logrus.Debugf("no such image %q: %v", transports.ImageName(ref), err)
			failures = append(failures, failure{
				resolvedImageName: image,
				err:               fmt.Errorf("no such image %q", transports.ImageName(ref)),
			})
			continue
		}

		pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
		if err != nil {
			logrus.Debugf("unable to pull and read image %q: %v", image, err)
			failures = append(failures, failure{resolvedImageName: image, err: err})
			continue
		}
		return pulledReference, transport, pulledImg, nil
	}

	if len(failures) != len(candidates) {
		return nil, "", nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures)
	}

	registriesConfPath := sysregistries.RegistriesConfPath(systemContext)
	switch len(failures) {
	case 0:
		if searchRegistriesWereUsedButEmpty {
			return nil, "", nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath)
		}
		return nil, "", nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage)

	case 1:
		err := failures[0].err
		if failures[0].resolvedImageName != options.FromImage {
			err = errors.Wrapf(err, "while pulling %q as %q", options.FromImage, failures[0].resolvedImageName)
		}
		if searchRegistriesWereUsedButEmpty {
			err = errors.Wrapf(err, "(image name %q is a short name and no search registries are defined in %s)", options.FromImage, registriesConfPath)
		}
		return nil, "", nil, err

	default:
		// NOTE: a multi-line error string:
		e := fmt.Sprintf("The following failures happened while trying to pull image specified by %q based on search registries in %s:", options.FromImage, registriesConfPath)
		for _, f := range failures {
			e = e + fmt.Sprintf("\n* %q: %s", f.resolvedImageName, f.err.Error())
		}
		return nil, "", nil, errors.New(e)
	}
}

func containerNameExist(name string, containers []storage.Container) bool {
	for _, container := range containers {
		for _, cname := range container.Names {
			if cname == name {
				return true
			}
		}
	}
	return false
}

func findUnusedContainer(name string, containers []storage.Container) string {
	suffix := 1
	tmpName := name
	for containerNameExist(tmpName, containers) {
		tmpName = fmt.Sprintf("%s-%d", name, suffix)
		suffix++
	}
	return tmpName
}

func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) {
	var (
		ref types.ImageReference
		img *storage.Image
		err error
	)
	if options.FromImage == BaseImageFakeName {
		options.FromImage = ""
	}

	systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath)

	if options.FromImage != "" && options.FromImage != "scratch" {
		ref, _, img, err = resolveImage(ctx, systemContext, store, options)
		if err != nil {
			return nil, err
		}
	}
	image := options.FromImage
	imageID := ""
	topLayer := ""
	if img != nil {
		image = getImageName(imageNamePrefix(image), img)
		imageID = img.ID
		topLayer = img.TopLayer
	}
	var src types.ImageCloser
	if ref != nil {
		src, err = ref.NewImage(ctx, systemContext)
		if err != nil {
			return nil, errors.Wrapf(err, "error instantiating image for %q", transports.ImageName(ref))
		}
		defer src.Close()
	}

	name := "working-container"
	if options.Container != "" {
		name = options.Container
	} else {
		if image != "" {
			name = imageNamePrefix(image) + "-" + name
		}
	}
	var container *storage.Container
	tmpName := name
	if options.Container == "" {
		containers, err := store.Containers()
		if err != nil {
			return nil, errors.Wrapf(err, "unable to check for container names")
		}
		tmpName = findUnusedContainer(tmpName, containers)
	}

	conflict := 100
	for {
		coptions := storage.ContainerOptions{
			LabelOpts:        options.CommonBuildOpts.LabelOpts,
			IDMappingOptions: newContainerIDMappingOptions(options.IDMappingOptions),
		}
		container, err = store.CreateContainer("", []string{tmpName}, imageID, "", "", &coptions)
		if err == nil {
			name = tmpName
			break
		}
		if errors.Cause(err) != storage.ErrDuplicateName || options.Container != "" {
			return nil, errors.Wrapf(err, "error creating container")
		}
		tmpName = fmt.Sprintf("%s-%d", name, rand.Int()%conflict)
		conflict = conflict * 10
	}
	defer func() {
		if err != nil {
			if err2 := store.DeleteContainer(container.ID); err2 != nil {
				logrus.Errorf("error deleting container %q: %v", container.ID, err2)
			}
		}
	}()

	uidmap, gidmap := convertStorageIDMaps(container.UIDMap, container.GIDMap)

	defaultNamespaceOptions, err := DefaultNamespaceOptions()
	if err != nil {
		return nil, err
	}

	namespaceOptions := defaultNamespaceOptions
	namespaceOptions.AddOrReplace(options.NamespaceOptions...)

	builder := &Builder{
		store:                 store,
		Type:                  containerType,
		FromImage:             image,
		FromImageID:           imageID,
		Container:             name,
		ContainerID:           container.ID,
		ImageAnnotations:      map[string]string{},
		ImageCreatedBy:        "",
		ProcessLabel:          container.ProcessLabel(),
		MountLabel:            container.MountLabel(),
		DefaultMountsFilePath: options.DefaultMountsFilePath,
		Isolation:             options.Isolation,
		NamespaceOptions:      namespaceOptions,
		ConfigureNetwork:      options.ConfigureNetwork,
		CNIPluginPath:         options.CNIPluginPath,
		CNIConfigDir:          options.CNIConfigDir,
		IDMappingOptions: IDMappingOptions{
			HostUIDMapping: len(uidmap) == 0,
			HostGIDMapping: len(uidmap) == 0,
			UIDMap:         uidmap,
			GIDMap:         gidmap,
		},
		AddCapabilities:  copyStringSlice(options.AddCapabilities),
		DropCapabilities: copyStringSlice(options.DropCapabilities),
		CommonBuildOpts:  options.CommonBuildOpts,
		TopLayer:         topLayer,
		Args:             options.Args,
		Format:           options.Format,
	}

	if options.Mount {
		_, err = builder.Mount(container.MountLabel())
		if err != nil {
			return nil, errors.Wrapf(err, "error mounting build container %q", builder.ContainerID)
		}
	}

	if err := builder.initConfig(ctx, src); err != nil {
		return nil, errors.Wrapf(err, "error preparing image configuration")
	}
	err = builder.Save()
	if err != nil {
		return nil, errors.Wrapf(err, "error saving builder state for container %q", builder.ContainerID)
	}

	return builder, nil
}
<commit_msg>Remove 'transport == ""' handling from the pull path<commit_after>package buildah

import (
	"context"
	"fmt"
	"math/rand"
	"strings"

	"github.com/containers/buildah/util"
	"github.com/containers/image/pkg/sysregistries"
	is "github.com/containers/image/storage"
	"github.com/containers/image/transports"
	"github.com/containers/image/transports/alltransports"
	"github.com/containers/image/types"
	"github.com/containers/storage"
	"github.com/openshift/imagebuilder"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// BaseImageFakeName is the "name" of a source image which we interpret
	// as "no image".
	BaseImageFakeName = imagebuilder.NoBaseImageSpecifier
)

func pullAndFindImage(ctx context.Context, store storage.Store, transport string, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) {
	pullOptions := PullOptions{
		ReportWriter:  options.ReportWriter,
		Store:         store,
		SystemContext: options.SystemContext,
		BlobDirectory: options.PullBlobDirectory,
	}
	ref, err := pullImage(ctx, store, transport, imageName, pullOptions, sc)
	if err != nil {
		logrus.Debugf("error pulling image %q: %v", imageName, err)
		return nil, nil, err
	}
	img, err := is.Transport.GetStoreImage(store, ref)
	if err != nil {
		logrus.Debugf("error reading pulled image %q: %v", imageName, err)
		return nil, nil, errors.Wrapf(err, "error locating image %q in local storage", transports.ImageName(ref))
	}
	return img, ref, nil
}

func getImageName(name string, img *storage.Image) string {
	imageName := name
	if len(img.Names) > 0 {
		imageName = img.Names[0]
		// When the image used by the container is a tagged image
		// the container name might be set to the original image instead of
		// the image given in the "from" command line.
		// This loop is supposed to fix this.
		for _, n := range img.Names {
			if strings.Contains(n, name) {
				imageName = n
				break
			}
		}
	}
	return imageName
}

func imageNamePrefix(imageName string) string {
	prefix := imageName
	s := strings.Split(imageName, "/")
	if len(s) > 0 {
		prefix = s[len(s)-1]
	}
	s = strings.Split(prefix, ":")
	if len(s) > 0 {
		prefix = s[0]
	}
	s = strings.Split(prefix, "@")
	if len(s) > 0 {
		prefix = s[0]
	}
	return prefix
}

func newContainerIDMappingOptions(idmapOptions *IDMappingOptions) storage.IDMappingOptions {
	var options storage.IDMappingOptions
	if idmapOptions != nil {
		options.HostUIDMapping = idmapOptions.HostUIDMapping
		options.HostGIDMapping = idmapOptions.HostGIDMapping
		uidmap, gidmap := convertRuntimeIDMaps(idmapOptions.UIDMap, idmapOptions.GIDMap)
		if len(uidmap) > 0 && len(gidmap) > 0 {
			options.UIDMap = uidmap
			options.GIDMap = gidmap
		} else {
			options.HostUIDMapping = true
			options.HostGIDMapping = true
		}
	}
	return options
}

func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) {
	type failure struct {
		resolvedImageName string
		err               error
	}
	candidates, transport, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store)
	if err != nil {
		return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage)
	}

	failures := []failure{}
	for _, image := range candidates {
		if transport == "" {
			img, err := store.Image(image)
			if err != nil {
				logrus.Debugf("error looking up known-local image %q: %v", image, err)
				failures = append(failures, failure{resolvedImageName: image, err: err})
				continue
			}
			ref, err := is.Transport.ParseStoreReference(store, img.ID)
			if err != nil {
				return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID)
			}
			return ref, transport, img, nil
		}

		if options.PullPolicy == PullAlways {
			pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
			if err != nil {
				logrus.Debugf("unable to pull and read image %q: %v", image, err)
				failures = append(failures, failure{resolvedImageName: image, err: err})
				continue
			}
			return pulledReference, transport, pulledImg, nil
		}

		srcRef, err := alltransports.ParseImageName(image)
		if err != nil {
			logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, transport, err)

			trans := transport
			if transport != util.DefaultTransport {
				trans = trans + ":"
			}
			srcRef2, err := alltransports.ParseImageName(trans + image)
			if err != nil {
				logrus.Debugf("error parsing image name %q: %v", transport+image, err)
				failures = append(failures, failure{
					resolvedImageName: image,
					err:               errors.Wrapf(err, "error parsing attempted image name %q", transport+image),
				})
				continue
			}
			srcRef = srcRef2
		}

		destImage, err := localImageNameForReference(ctx, store, srcRef, options.FromImage)
		if err != nil {
			return nil, "", nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef))
		}
		if destImage == "" {
			return nil, "", nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef))
		}

		ref, err := is.Transport.ParseStoreReference(store, destImage)
		if err != nil {
			return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", destImage)
		}
		img, err := is.Transport.GetStoreImage(store, ref)
		if err == nil {
			return ref, transport, img, nil
		}

		if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing {
			logrus.Debugf("no such image %q: %v", transports.ImageName(ref), err)
			failures = append(failures, failure{
				resolvedImageName: image,
				err:               fmt.Errorf("no such image %q", transports.ImageName(ref)),
			})
			continue
		}

		pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext)
		if err != nil {
			logrus.Debugf("unable to pull and read image %q: %v", image, err)
			failures = append(failures, failure{resolvedImageName: image, err: err})
			continue
		}
		return pulledReference, transport, pulledImg, nil
	}

	if len(failures) != len(candidates) {
		return nil, "", nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures)
	}

	registriesConfPath := sysregistries.RegistriesConfPath(systemContext)
	switch len(failures) {
	case 0:
		if searchRegistriesWereUsedButEmpty {
			return nil, "", nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath)
		}
		return nil, "", nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage)

	case 1:
		err := failures[0].err
		if failures[0].resolvedImageName != options.FromImage {
			err = errors.Wrapf(err, "while pulling %q as %q", options.FromImage, failures[0].resolvedImageName)
		}
		if searchRegistriesWereUsedButEmpty {
			err = errors.Wrapf(err, "(image name %q is a short name and no search registries are defined in %s)", options.FromImage, registriesConfPath)
		}
		return nil, "", nil, err

	default:
		// NOTE: a multi-line error string:
		e := fmt.Sprintf("The following failures happened while trying to pull image specified by %q based on search registries in %s:", options.FromImage, registriesConfPath)
		for _, f := range failures {
			e = e + fmt.Sprintf("\n* %q: %s", f.resolvedImageName, f.err.Error())
		}
		return nil, "", nil, errors.New(e)
	}
}

func containerNameExist(name string, containers []storage.Container) bool {
	for _, container := range containers {
		for _, cname := range container.Names {
			if cname == name {
				return true
			}
		}
	}
	return false
}

func findUnusedContainer(name string, containers []storage.Container) string {
	suffix := 1
	tmpName := name
	for containerNameExist(tmpName, containers) {
		tmpName = fmt.Sprintf("%s-%d", name, suffix)
		suffix++
	}
	return tmpName
}

func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) {
	var (
		ref types.ImageReference
		img *storage.Image
		err error
	)
	if options.FromImage == BaseImageFakeName {
		options.FromImage = ""
	}

	systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath)

	if options.FromImage != "" && options.FromImage != "scratch" {
		ref, _, img, err = resolveImage(ctx, systemContext, store, options)
		if err != nil {
			return nil, err
		}
	}
	image := options.FromImage
	imageID := ""
	topLayer := ""
	if img != nil {
		image = getImageName(imageNamePrefix(image), img)
		imageID = img.ID
		topLayer = img.TopLayer
	}
	var src types.ImageCloser
	if ref != nil {
		src, err = ref.NewImage(ctx, systemContext)
		if err != nil {
			return nil, errors.Wrapf(err, "error instantiating image for %q", transports.ImageName(ref))
		}
		defer src.Close()
	}

	name := "working-container"
	if options.Container != "" {
		name = options.Container
	} else {
		if image != "" {
			name = imageNamePrefix(image) + "-" + name
		}
	}
	var container *storage.Container
	tmpName := name
	if options.Container == "" {
		containers, err := store.Containers()
		if err != nil {
			return nil, errors.Wrapf(err, "unable to check for container names")
		}
		tmpName = findUnusedContainer(tmpName, containers)
	}

	conflict := 100
	for {
		coptions := storage.ContainerOptions{
			LabelOpts:        options.CommonBuildOpts.LabelOpts,
			IDMappingOptions: newContainerIDMappingOptions(options.IDMappingOptions),
		}
		container, err = store.CreateContainer("", []string{tmpName}, imageID, "", "", &coptions)
		if err == nil {
			name = tmpName
			break
		}
		if errors.Cause(err) != storage.ErrDuplicateName || options.Container != "" {
			return nil, errors.Wrapf(err, "error creating container")
		}
		tmpName = fmt.Sprintf("%s-%d", name, rand.Int()%conflict)
		conflict = conflict * 10
	}
	defer func() {
		if err != nil {
			if err2 := store.DeleteContainer(container.ID); err2 != nil {
				logrus.Errorf("error deleting container %q: %v", container.ID, err2)
			}
		}
	}()

	uidmap, gidmap := convertStorageIDMaps(container.UIDMap, container.GIDMap)

	defaultNamespaceOptions, err := DefaultNamespaceOptions()
	if err != nil {
		return nil, err
	}

	namespaceOptions := defaultNamespaceOptions
	namespaceOptions.AddOrReplace(options.NamespaceOptions...)

	builder := &Builder{
		store:                 store,
		Type:                  containerType,
		FromImage:             image,
		FromImageID:           imageID,
		Container:             name,
		ContainerID:           container.ID,
		ImageAnnotations:      map[string]string{},
		ImageCreatedBy:        "",
		ProcessLabel:          container.ProcessLabel(),
		MountLabel:            container.MountLabel(),
		DefaultMountsFilePath: options.DefaultMountsFilePath,
		Isolation:             options.Isolation,
		NamespaceOptions:      namespaceOptions,
		ConfigureNetwork:      options.ConfigureNetwork,
		CNIPluginPath:         options.CNIPluginPath,
		CNIConfigDir:          options.CNIConfigDir,
		IDMappingOptions: IDMappingOptions{
			HostUIDMapping: len(uidmap) == 0,
			HostGIDMapping: len(uidmap) == 0,
			UIDMap:         uidmap,
			GIDMap:         gidmap,
		},
		AddCapabilities:  copyStringSlice(options.AddCapabilities),
		DropCapabilities: copyStringSlice(options.DropCapabilities),
		CommonBuildOpts:  options.CommonBuildOpts,
		TopLayer:         topLayer,
		Args:             options.Args,
		Format:           options.Format,
	}

	if options.Mount {
		_, err = builder.Mount(container.MountLabel())
		if err != nil {
			return nil, errors.Wrapf(err, "error mounting build container %q", builder.ContainerID)
		}
	}

	if err := builder.initConfig(ctx, src); err != nil {
		return nil, errors.Wrapf(err, "error preparing image configuration")
	}
	err = builder.Save()
	if err != nil {
		return nil, errors.Wrapf(err, "error saving builder state for container %q", builder.ContainerID)
	}

	return builder, nil
}
<|endoftext|>


<commit_before>package nut

import (
	"archive/zip"
	"bytes"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"sort"
	"strings"
)

// Check package for errors and return them.
func CheckPackage(pack *build.Package) (errors []string) {
	// check name
	if strings.HasPrefix(pack.Name, "_") {
		errors = append(errors, `Package name should not starts with "_".`)
	}
	if strings.HasSuffix(pack.Name, "_test") {
		errors = append(errors, `Package name should not ends with "_test".`)
	}

	// check doc summary
	r := regexp.MustCompile(fmt.Sprintf(`Package %s .+\.`, pack.Name))
	if !r.MatchString(pack.Doc) {
		errors = append(errors, fmt.Sprintf(`Package summary in code should be in form "Package %s ... ."`, pack.Name))
	}

	return
}

// Describes nut – a Go package with associated meta-information.
type Nut struct {
	Spec
	build.Package
}

// Check nut for errors and return them. Calls Spec.Check() and CheckPackage().
func (nut *Nut) Check() (errors []string) {
	errors = nut.Spec.Check()
	errors = append(errors, CheckPackage(&nut.Package)...)
	return
}

// Returns canonical filename in format <name>-<version>.nut
func (nut *Nut) FileName() string {
	return fmt.Sprintf("%s-%s.nut", nut.Name, nut.Version)
}

// Code "Nut.ReadFrom()" will call Nut.Spec.ReadFrom(), while programmer likely wanted to call NutFile.ReadFrom().
// This method (with weird incompatible signature) is defined to prevent this typical error.
func (nut *Nut) ReadFrom(Do, Not, Call bool) (do, not, call bool) {
	panic("Nut.ReadFrom() called: call Nut.Spec.ReadFrom() or NutFile.ReadFrom()")
}

// Describes .nut file (a ZIP archive).
type NutFile struct {
	Nut
	Reader *zip.Reader
}

// ReadFrom reads nut from r until EOF.
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read is also returned.
// Implements io.ReaderFrom.
func (nf *NutFile) ReadFrom(r io.Reader) (n int64, err error) {
	var b []byte
	b, err = ioutil.ReadAll(r)
	n = int64(len(b))
	if err != nil {
		return
	}

	nf.Reader, err = zip.NewReader(bytes.NewReader(b), n)
	if err != nil {
		return
	}

	// read spec (typically the last file)
	var specReader io.ReadCloser
	for i := len(nf.Reader.File) - 1; i >= 0; i-- {
		file := nf.Reader.File[i]
		if file.Name == SpecFileName {
			specReader, err = file.Open()
			if err != nil {
				return
			}
			defer func() {
				e := specReader.Close()
				if err == nil { // don't hide original error
					err = e
				}
			}()
			break
		}
	}
	if specReader == nil {
		err = fmt.Errorf("NutFile.ReadFrom: %q not found", SpecFileName)
		return
	}
	spec := &nf.Spec
	_, err = spec.ReadFrom(specReader)
	if err != nil {
		return
	}

	// read package
	pack, err := nf.context().ImportDir(".", 0)
	nf.Package = *pack
	return
}

// byName implements sort.Interface.
type byName []os.FileInfo

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

// Returns build.Context for given nut.
// Returned value may be used to call normal context methods Import and ImportDir
// to extract information about package in nut without unpacking it: name, doc, dependencies.
func (nf *NutFile) context() (ctxt *build.Context) {
	ctxt = new(build.Context)
	*ctxt = build.Default

	// FIXME path is ignored (multi-package nuts are not supported yet)
	ctxt.ReadDir = func(path string) (fi []os.FileInfo, err error) {
		// log.Printf("nf.ReadDir %q", path)

		fi = make([]os.FileInfo, len(nf.Reader.File))
		for i, f := range nf.Reader.File {
			fi[i] = f.FileInfo()
		}
		sort.Sort(byName(fi))
		return fi, nil
	}

	ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
		// log.Printf("nf.OpenFile %q", path)

		for _, f := range nf.Reader.File {
			if f.Name == path {
				return f.Open()
			}
		}

		return nil, fmt.Errorf("NutFile.Context.OpenFile: %q not found", path)
	}

	return
}
<commit_msg>Package name should be lower case.<commit_after>package nut

import (
	"archive/zip"
	"bytes"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"sort"
	"strings"
)

// Check package for errors and return them.
func CheckPackage(pack *build.Package) (errors []string) {
	// check name
	if strings.ToLower(pack.Name) != pack.Name {
		errors = append(errors, `Package name should be lower case.`)
	}
	if strings.HasPrefix(pack.Name, "_") {
		errors = append(errors, `Package name should not starts with "_".`)
	}
	if strings.HasSuffix(pack.Name, "_test") {
		errors = append(errors, `Package name should not ends with "_test".`)
	}

	// check doc summary
	r := regexp.MustCompile(fmt.Sprintf(`Package %s .+\.`, pack.Name))
	if !r.MatchString(pack.Doc) {
		errors = append(errors, fmt.Sprintf(`Package summary in code should be in form "Package %s ... ."`, pack.Name))
	}

	return
}

// Describes nut – a Go package with associated meta-information.
type Nut struct {
	Spec
	build.Package
}

// Check nut for errors and return them. Calls Spec.Check() and CheckPackage().
func (nut *Nut) Check() (errors []string) {
	errors = nut.Spec.Check()
	errors = append(errors, CheckPackage(&nut.Package)...)
	return
}

// Returns canonical filename in format <name>-<version>.nut
func (nut *Nut) FileName() string {
	return fmt.Sprintf("%s-%s.nut", nut.Name, nut.Version)
}

// Code "Nut.ReadFrom()" will call Nut.Spec.ReadFrom(), while programmer likely wanted to call NutFile.ReadFrom().
// This method (with weird incompatible signature) is defined to prevent this typical error.
func (nut *Nut) ReadFrom(Do, Not, Call bool) (do, not, call bool) {
	panic("Nut.ReadFrom() called: call Nut.Spec.ReadFrom() or NutFile.ReadFrom()")
}

// Describes .nut file (a ZIP archive).
type NutFile struct {
	Nut
	Reader *zip.Reader
}

// ReadFrom reads nut from r until EOF.
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read is also returned.
// Implements io.ReaderFrom.
func (nf *NutFile) ReadFrom(r io.Reader) (n int64, err error) {
	var b []byte
	b, err = ioutil.ReadAll(r)
	n = int64(len(b))
	if err != nil {
		return
	}

	nf.Reader, err = zip.NewReader(bytes.NewReader(b), n)
	if err != nil {
		return
	}

	// read spec (typically the last file)
	var specReader io.ReadCloser
	for i := len(nf.Reader.File) - 1; i >= 0; i-- {
		file := nf.Reader.File[i]
		if file.Name == SpecFileName {
			specReader, err = file.Open()
			if err != nil {
				return
			}
			defer func() {
				e := specReader.Close()
				if err == nil { // don't hide original error
					err = e
				}
			}()
			break
		}
	}
	if specReader == nil {
		err = fmt.Errorf("NutFile.ReadFrom: %q not found", SpecFileName)
		return
	}
	spec := &nf.Spec
	_, err = spec.ReadFrom(specReader)
	if err != nil {
		return
	}

	// read package
	pack, err := nf.context().ImportDir(".", 0)
	nf.Package = *pack
	return
}

// byName implements sort.Interface.
type byName []os.FileInfo

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

// Returns build.Context for given nut.
// Returned value may be used to call normal context methods Import and ImportDir
// to extract information about package in nut without unpacking it: name, doc, dependencies.
func (nf *NutFile) context() (ctxt *build.Context) {
	ctxt = new(build.Context)
	*ctxt = build.Default

	// FIXME path is ignored (multi-package nuts are not supported yet)
	ctxt.ReadDir = func(path string) (fi []os.FileInfo, err error) {
		// log.Printf("nf.ReadDir %q", path)

		fi = make([]os.FileInfo, len(nf.Reader.File))
		for i, f := range nf.Reader.File {
			fi[i] = f.FileInfo()
		}
		sort.Sort(byName(fi))
		return fi, nil
	}

	ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
		// log.Printf("nf.OpenFile %q", path)

		for _, f := range nf.Reader.File {
			if f.Name == path {
				return f.Open()
			}
		}

		return nil, fmt.Errorf("NutFile.Context.OpenFile: %q not found", path)
	}

	return
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>

extern int _go_git_odb_foreach(git_odb *db, void *payload);
extern void _go_git_odb_backend_free(git_odb_backend *backend);
*/
import "C"
import (
	"reflect"
	"runtime"
	"unsafe"
	"fmt"
)

type Odb struct {
	ptr *C.git_odb
}

type OdbBackend struct {
	ptr *C.git_odb_backend
}

func NewOdb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_new(&odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) {
	backend = &OdbBackend{ptr}
	return backend
}

func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_add_backend(v.ptr, backend.ptr, C.int(priority))
	if ret < 0 {
		backend.Free()
		return MakeGitError(ret)
	}
	return nil
}

func (v *Odb) Exists(oid *Oid) bool {
	ret := C.git_odb_exists(v.ptr, oid.toC())
	return ret != 0
}

func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
	oid = new(Oid)
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(hdr.Data), C.size_t(hdr.Len), C.git_otype(otype))

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
	obj = new(OdbObject)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(obj, (*OdbObject).Free)
	return obj, nil
}

type OdbForEachCallback func(id *Oid) error

type foreachData struct {
	callback OdbForEachCallback
	err      error
}

//export odbForEachCb
func odbForEachCb(id *C.git_oid, handle unsafe.Pointer) int {
	data, ok := pointerHandles.Get(handle).(*foreachData)

	if !ok {
		panic("could not retrieve handle")
	}

	err := data.callback(newOidFromC(id))
	fmt.Println("err %v", err)
	if err != nil {
		fmt.Println("returning EUSER")
		data.err = err
		return C.GIT_EUSER
	}

	return 0
}

func (v *Odb) ForEach(callback OdbForEachCallback) error {
	data := foreachData{
		callback: callback,
		err:      nil,
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	handle := pointerHandles.Track(&data)
	defer pointerHandles.Untrack(handle)

	ret := C._go_git_odb_foreach(v.ptr, handle)
	fmt.Println("ret %v", ret);
	if ret == C.GIT_EUSER {
		return data.err
	} else if ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

// Hash determines the object-ID (sha1) of a data buffer.
func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
	oid = new(Oid)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := unsafe.Pointer(header.Data)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	return oid, nil
}

// NewReadStream opens a read stream from the ODB. Reading from it will give you the
// contents of the object.
func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
	stream := new(OdbReadStream)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC())
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(stream, (*OdbReadStream).Free)
	return stream, nil
}

// NewWriteStream opens a write stream to the ODB, which allows you to
// create a new object in the database. The size and type must be
// known in advance
func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, error) {
	stream := new(OdbWriteStream)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(stream, (*OdbWriteStream).Free)
	return stream, nil
}

func (v *OdbBackend) Free() {
	C._go_git_odb_backend_free(v.ptr)
}

type OdbObject struct {
	ptr *C.git_odb_object
}

func (v *OdbObject) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_object_free(v.ptr)
}

func (object *OdbObject) Id() (oid *Oid) {
	return newOidFromC(C.git_odb_object_id(object.ptr))
}

func (object *OdbObject) Len() (len uint64) {
	return uint64(C.git_odb_object_size(object.ptr))
}

func (object *OdbObject) Data() (data []byte) {
	var c_blob unsafe.Pointer = C.git_odb_object_data(object.ptr)
	var blob []byte

	len := int(C.git_odb_object_size(object.ptr))

	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&blob)))
	sliceHeader.Cap = len
	sliceHeader.Len = len
	sliceHeader.Data = uintptr(c_blob)

	return blob
}

type OdbReadStream struct {
	ptr *C.git_odb_stream
}

// Read reads from the stream
func (stream *OdbReadStream) Read(data []byte) (int, error) {
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := (*C.char)(unsafe.Pointer(header.Data))
	size := C.size_t(header.Cap)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_read(stream.ptr, ptr, size)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}

	header.Len = int(ret)

	return len(data), nil
}

// Close is a dummy function in order to implement the Closer and
// ReadCloser interfaces
func (stream *OdbReadStream) Close() error {
	return nil
}

func (stream *OdbReadStream) Free() {
	runtime.SetFinalizer(stream, nil)
	C.git_odb_stream_free(stream.ptr)
}

type OdbWriteStream struct {
	ptr *C.git_odb_stream
	Id  Oid
}

// Write writes to the stream
func (stream *OdbWriteStream) Write(data []byte) (int, error) {
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := (*C.char)(unsafe.Pointer(header.Data))
	size := C.size_t(header.Len)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_write(stream.ptr, ptr, size)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}

	return len(data), nil
}

// Close signals that all the data has been written and stores the
// resulting object id in the stream's Id field.
func (stream *OdbWriteStream) Close() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr)
	if ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (stream *OdbWriteStream) Free() {
	runtime.SetFinalizer(stream, nil)
	C.git_odb_stream_free(stream.ptr)
}
<commit_msg>odb: remove debug fmt.Printlns<commit_after>package git

/*
#include <git2.h>

extern int _go_git_odb_foreach(git_odb *db, void *payload);
extern void _go_git_odb_backend_free(git_odb_backend *backend);
*/
import "C"
import (
	"reflect"
	"runtime"
	"unsafe"
)

type Odb struct {
	ptr *C.git_odb
}

type OdbBackend struct {
	ptr *C.git_odb_backend
}

func NewOdb() (odb *Odb, err error) {
	odb = new(Odb)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_new(&odb.ptr)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(odb, (*Odb).Free)
	return odb, nil
}

func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) {
	backend = &OdbBackend{ptr}
	return backend
}

func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_add_backend(v.ptr, backend.ptr, C.int(priority))
	if ret < 0 {
		backend.Free()
		return MakeGitError(ret)
	}
	return nil
}

func (v *Odb) Exists(oid *Oid) bool {
	ret := C.git_odb_exists(v.ptr, oid.toC())
	return ret != 0
}

func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
	oid = new(Oid)
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(hdr.Data), C.size_t(hdr.Len), C.git_otype(otype))

	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	return oid, nil
}

func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
	obj = new(OdbObject)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(obj, (*OdbObject).Free)
	return obj, nil
}

type OdbForEachCallback func(id *Oid) error

type foreachData struct {
	callback OdbForEachCallback
	err      error
}

//export odbForEachCb
func odbForEachCb(id *C.git_oid, handle unsafe.Pointer) int {
	data, ok := pointerHandles.Get(handle).(*foreachData)

	if !ok {
		panic("could not retrieve handle")
	}

	err := data.callback(newOidFromC(id))
	if err != nil {
		data.err = err
		return C.GIT_EUSER
	}

	return 0
}

func (v *Odb) ForEach(callback OdbForEachCallback) error {
	data := foreachData{
		callback: callback,
		err:      nil,
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	handle := pointerHandles.Track(&data)
	defer pointerHandles.Untrack(handle)

	ret := C._go_git_odb_foreach(v.ptr, handle)
	if ret == C.GIT_EUSER {
		return data.err
	} else if ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

// Hash determines the object-ID (sha1) of a data buffer.
func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
	oid = new(Oid)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := unsafe.Pointer(header.Data)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	return oid, nil
}

// NewReadStream opens a read stream from the ODB. Reading from it will give you the
// contents of the object.
func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
	stream := new(OdbReadStream)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC())
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(stream, (*OdbReadStream).Free)
	return stream, nil
}

// NewWriteStream opens a write stream to the ODB, which allows you to
// create a new object in the database. The size and type must be
// known in advance
func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, error) {
	stream := new(OdbWriteStream)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
	if ret < 0 {
		return nil, MakeGitError(ret)
	}

	runtime.SetFinalizer(stream, (*OdbWriteStream).Free)
	return stream, nil
}

func (v *OdbBackend) Free() {
	C._go_git_odb_backend_free(v.ptr)
}

type OdbObject struct {
	ptr *C.git_odb_object
}

func (v *OdbObject) Free() {
	runtime.SetFinalizer(v, nil)
	C.git_odb_object_free(v.ptr)
}

func (object *OdbObject) Id() (oid *Oid) {
	return newOidFromC(C.git_odb_object_id(object.ptr))
}

func (object *OdbObject) Len() (len uint64) {
	return uint64(C.git_odb_object_size(object.ptr))
}

func (object *OdbObject) Data() (data []byte) {
	var c_blob unsafe.Pointer = C.git_odb_object_data(object.ptr)
	var blob []byte

	len := int(C.git_odb_object_size(object.ptr))

	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&blob)))
	sliceHeader.Cap = len
	sliceHeader.Len = len
	sliceHeader.Data = uintptr(c_blob)

	return blob
}

type OdbReadStream struct {
	ptr *C.git_odb_stream
}

// Read reads from the stream
func (stream *OdbReadStream) Read(data []byte) (int, error) {
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := (*C.char)(unsafe.Pointer(header.Data))
	size := C.size_t(header.Cap)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_read(stream.ptr, ptr, size)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}

	header.Len = int(ret)

	return len(data), nil
}

// Close is a dummy function in order to implement the Closer and
// ReadCloser interfaces
func (stream *OdbReadStream) Close() error {
	return nil
}

func (stream *OdbReadStream) Free() {
	runtime.SetFinalizer(stream, nil)
	C.git_odb_stream_free(stream.ptr)
}

type OdbWriteStream struct {
	ptr *C.git_odb_stream
	Id  Oid
}

// Write writes to the stream
func (stream *OdbWriteStream) Write(data []byte) (int, error) {
	header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
	ptr := (*C.char)(unsafe.Pointer(header.Data))
	size := C.size_t(header.Len)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_write(stream.ptr, ptr, size)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}

	return len(data), nil
}

// Close signals that all the data has been written and stores the
// resulting object id in the stream's Id field.
func (stream *OdbWriteStream) Close() error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr)
	if ret < 0 {
		return MakeGitError(ret)
	}

	return nil
}

func (stream *OdbWriteStream) Free() {
	runtime.SetFinalizer(stream, nil)
	C.git_odb_stream_free(stream.ptr)
}
<|endoftext|>


<commit_before>package model

import (
	"context"
	"fmt"
	"strings"
	"sync/atomic"

	"github.com/flimzy/kivik"
	"github.com/flimzy/log"
	"github.com/pkg/errors"
)

func (r *Repo) remoteDSN(name string) string {
	dsn := r.remote.DSN()
	if strings.HasSuffix(dsn, "/") {
		return dsn + name
	}
	return dsn + "/" + name
}

// Sync performs a bi-directional sync.
func (r *Repo) Sync(ctx context.Context) error {
	u, err := r.CurrentUser()
	if err != nil {
		return err
	}
	udbName := "user-" + u
	rdb := r.remoteDSN(udbName)

	var docsWritten, docsRead int32

	// local to remote
	if err := replicate(ctx, r.local, rdb, udbName, &docsWritten); err != nil {
		return errors.Wrap(err, "sync local to remote")
	}

	// remote to local
	if err := replicate(ctx, r.local, udbName, rdb, &docsRead); err != nil {
		return errors.Wrap(err, "sync remote to local")
	}

	if err := r.syncBundles(ctx, &docsRead, &docsWritten); err != nil {
		return errors.Wrap(err, "bundle sync")
	}

	log.Debugf("Synced %d docs from server, %d to server\n", docsRead, docsWritten)
	return nil
}

type clientReplicator interface {
	Replicate(context.Context, string, string, ...kivik.Options) (*kivik.Replication, error)
}

func dbDSN(db clientNamer) string {
	dsn := db.Client().DSN()
	dbName := db.Name()
	if dsn != "" && !strings.HasSuffix(dsn, "/") {
		return dsn + "/" + dbName
	}
	return dsn + dbName
}

func replicate(ctx context.Context, client clientReplicator, target, source string, count *int32) error {
	defer profile(fmt.Sprintf("replicate %s -> %s", source, target))()
	replication, err := client.Replicate(ctx, target, source)
	if err != nil {
		return err
	}
	c, err := processReplication(ctx, replication)
	atomic.AddInt32(count, c)
	return err
}

type replication interface {
	IsActive() bool
	Update(context.Context) error
	Delete(context.Context) error
	Err() error
	DocsWritten() int64
}

func processReplication(ctx context.Context, rep replication) (int32, error) {
	// Just wait until the replication is complete
	// TODO: Visual updates
	for rep.IsActive() {
		if err := rep.Update(ctx); err != nil {
			_ = rep.Delete(ctx)
			return int32(rep.DocsWritten()), err
		}
	}
	return int32(rep.DocsWritten()), rep.Err()
}

func (r *Repo) syncBundles(ctx context.Context, reads, writes *int32) error {
	defer profile("syncBundles")()
	udb, err := r.userDB(ctx)
	if err != nil {
		return err
	}
	log.Debugf("Reading bundles from user database...\n")
	rows, err := udb.Find(context.TODO(), map[string]interface{}{
		"selector": map[string]string{"type": "bundle"},
		"fields":   []string{"_id"},
	})
	if err != nil {
		return errors.Wrap(err, "failed to sync bundles")
	}

	var bundles []string
	for rows.Next() {
		var result struct {
			ID string `json:"_id"`
		}
		if err := rows.ScanDoc(&result); err != nil {
			return errors.Wrapf(err, "failed to scan bundle %s", rows.ID())
		}
		bundles = append(bundles, result.ID)
	}
	log.Debugf("bundles = %v\n", bundles)
	for _, bundle := range bundles {
		log.Debugf("Bundle %s", bundle)
		rdb := r.remoteDSN(bundle)
		if err := r.remote.CreateDB(ctx, bundle); err != nil {
			return err
		}
		if err := replicate(ctx, r.local, rdb, bundle, writes); err != nil {
			return errors.Wrap(err, "bundle push")
		}
		if err := replicate(ctx, r.local, bundle, rdb, reads); err != nil {
			return errors.Wrap(err, "bundle pull")
		}
	}
	return nil
}

/*
func SyncReviews(local, remote *repo.DB) (int32, error) {
	u, err := repo.CurrentUser()
	if err != nil {
		return 0, err
	}
	host := util.CouchHost()
	ldb, err := util.ReviewsSyncDbs()
	if err != nil {
		return 0, err
	}
	if ldb == nil {
		return 0, nil
	}
	before, err := ldb.Info()
	if err != nil {
		return 0, err
	}
	if before.DocCount == 0 {
		// Nothing at all to sync
		return 0, nil
	}
	rdb, err := repo.NewDB(host + "/" + u.MasterReviewsDBName())
	if err != nil {
		return 0, err
	}
	revsSynced, err := Sync(ldb, rdb)
	if err != nil {
		return 0, err
	}
	after, err := ldb.Info()
	if err != nil {
		return revsSynced, err
	}
	if before.DocCount != after.DocCount || before.UpdateSeq != after.UpdateSeq {
		log.Debugf("ReviewsDb content changed during sync. Refusing to delete.\n")
		return revsSynced, nil
	}
	log.Debugf("Ready to zap %s\n", after.DBName)
	err = util.ZapReviewsDb(ldb)
	return revsSynced, err
}
*/
<commit_msg>Don't abort the sync if the bundle exists<commit_after>package model

import (
	"context"
	"fmt"
	"strings"
	"sync/atomic"

	"github.com/flimzy/kivik"
	"github.com/flimzy/log"
	"github.com/pkg/errors"
)

func (r *Repo) remoteDSN(name string) string {
	dsn := r.remote.DSN()
	if strings.HasSuffix(dsn, "/") {
		return dsn + name
	}
	return dsn + "/" + name
}

// Sync performs a bi-directional sync.
func (r *Repo) Sync(ctx context.Context) error {
	u, err := r.CurrentUser()
	if err != nil {
		return err
	}
	udbName := "user-" + u
	rdb := r.remoteDSN(udbName)

	var docsWritten, docsRead int32

	// local to remote
	if err := replicate(ctx, r.local, rdb, udbName, &docsWritten); err != nil {
		return errors.Wrap(err, "sync local to remote")
	}

	// remote to local
	if err := replicate(ctx, r.local, udbName, rdb, &docsRead); err != nil {
		return errors.Wrap(err, "sync remote to local")
	}

	if err := r.syncBundles(ctx, &docsRead, &docsWritten); err != nil {
		return errors.Wrap(err, "bundle sync")
	}

	log.Debugf("Synced %d docs from server, %d to server\n", docsRead, docsWritten)
	return nil
}

type clientReplicator interface {
	Replicate(context.Context, string, string, ...kivik.Options) (*kivik.Replication, error)
}

func dbDSN(db clientNamer) string {
	dsn := db.Client().DSN()
	dbName := db.Name()
	if dsn != "" && !strings.HasSuffix(dsn, "/") {
		return dsn + "/" + dbName
	}
	return dsn + dbName
}

func replicate(ctx context.Context, client clientReplicator, target, source string, count *int32) error {
	defer profile(fmt.Sprintf("replicate %s -> %s", source, target))()
	replication, err := client.Replicate(ctx, target, source)
	if err != nil {
		return err
	}
	c, err := processReplication(ctx, replication)
	atomic.AddInt32(count, c)
	return err
}

type replication interface {
	IsActive() bool
	Update(context.Context) error
	Delete(context.Context) error
	Err() error
	DocsWritten() int64
}

func processReplication(ctx context.Context, rep replication) (int32, error) {
	// Just wait until the replication is complete
	// TODO: Visual updates
	for rep.IsActive() {
		if err := rep.Update(ctx); err != nil {
			_ = rep.Delete(ctx)
			return int32(rep.DocsWritten()), err
		}
	}
	return int32(rep.DocsWritten()), rep.Err()
}

func (r *Repo) syncBundles(ctx context.Context, reads, writes *int32) error {
	defer profile("syncBundles")()
	udb, err := r.userDB(ctx)
	if err != nil {
		return err
	}
	log.Debugf("Reading bundles from user database...\n")
	rows, err := udb.Find(context.TODO(), map[string]interface{}{
		"selector": map[string]string{"type": "bundle"},
		"fields":   []string{"_id"},
	})
	if err != nil {
		return errors.Wrap(err, "failed to sync bundles")
	}

	var bundles []string
	for rows.Next() {
		var result struct {
			ID string `json:"_id"`
		}
		if err := rows.ScanDoc(&result); err != nil {
			return errors.Wrapf(err, "failed to scan bundle %s", rows.ID())
		}
		bundles = append(bundles, result.ID)
	}
	log.Debugf("bundles = %v\n", bundles)
	for _, bundle := range bundles {
		rdb := r.remoteDSN(bundle)
		if err := r.remote.CreateDB(ctx, bundle); err != nil && kivik.StatusCode(err) != kivik.StatusPreconditionFailed {
			return err
		}
		if err := replicate(ctx, r.local, rdb, bundle, writes); err != nil {
			return errors.Wrap(err, "bundle push")
		}
		if err := replicate(ctx, r.local, bundle, rdb, reads); err != nil {
			return errors.Wrap(err, "bundle pull")
		}
	}
	return nil
}

/*
func SyncReviews(local, remote *repo.DB) (int32, error) {
	u, err := repo.CurrentUser()
	if err != nil {
		return 0, err
	}
	host := util.CouchHost()
	ldb, err := util.ReviewsSyncDbs()
	if err != nil {
		return 0, err
	}
	if ldb == nil {
		return 0, nil
	}
	before, err := ldb.Info()
	if err != nil {
		return 0, err
	}
	if before.DocCount == 0 {
		// Nothing at all to sync
		return 0, nil
	}
	rdb, err := repo.NewDB(host + "/" + u.MasterReviewsDBName())
	if err != nil {
		return 0, err
	}
	revsSynced, err := Sync(ldb, rdb)
	if err != nil {
		return 0, err
	}
	after, err := ldb.Info()
	if err != nil {
		return revsSynced, err
	}
	if before.DocCount != after.DocCount || before.UpdateSeq != after.UpdateSeq {
		log.Debugf("ReviewsDb content changed during sync. Refusing to delete.\n")
		return revsSynced, nil
	}
	log.Debugf("Ready to zap %s\n", after.DBName)
	err = util.ZapReviewsDb(ldb)
	return revsSynced, err
}
*/
<|endoftext|>


<commit_before>package model

import (
	"time"
)

type User struct {
	ID              uint      `gorm:"column:user_id;primary_key"`
	Username        string    `gorm:"column:username"`
	Password        string    `gorm:"column:password"`
	Email           string    `gorm:"column:email"`
	Status          int       `gorm:"column:status"`
	CreatedAt       time.Time `gorm:"column:created_at"`
	UpdatedAt       time.Time `gorm:"column:updated_at"`
	Token           string    `gorm:"column:api_token"`
	TokenExpiration time.Time `gorm:"column:api_token_expiry"`
	Language        string    `gorm:"column:language"`

	// TODO: move this to PublicUser
	LikingCount int    `json:"likingCount" gorm:"-"`
	LikedCount  int    `json:"likedCount" gorm:"-"`
	Likings     []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
	Liked       []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`

	MD5      string    `json:"md5"` // Hash of email address, used for Gravatar
	Torrents []Torrent `gorm:"ForeignKey:UploaderID"`
}

// Returns the total size of memory recursively allocated for this struct
func (u User) Size() (s int) {
	s += 4 + // ints
		6*2 + // string pointers
		4*3 + //time.Time
		3*2 + // arrays
		// string arrays
		len(u.Username) + len(u.Password) + len(u.Email) + len(u.Token) + len(u.MD5) + len(u.Language)
	s *= 8

	// Ignoring foreign key users. Fuck them.

	return
}

type PublicUser struct {
	User *User
}

// different users following eachother
type UserFollows struct {
	UserID     uint `gorm:"column:user_id"`
	FollowerID uint `gorm:"column:following"`
}

type UserUploadsOld struct {
	Username  string `gorm:"column:username"`
	TorrentId uint   `gorm:"column:torrent_id"`
}

func (c UserUploadsOld) TableName() string {
	// TODO: rename this in db
	return "user_uploads_old"
}
<commit_msg>Rename md5 column again<commit_after>package model

import (
	"time"
)

type User struct {
	ID              uint      `gorm:"column:user_id;primary_key"`
	Username        string    `gorm:"column:username"`
	Password        string    `gorm:"column:password"`
	Email           string    `gorm:"column:email"`
	Status          int       `gorm:"column:status"`
	CreatedAt       time.Time `gorm:"column:created_at"`
	UpdatedAt       time.Time `gorm:"column:updated_at"`
	Token           string    `gorm:"column:api_token"`
	TokenExpiration time.Time `gorm:"column:api_token_expiry"`
	Language        string    `gorm:"column:language"`

	// TODO: move this to PublicUser
	LikingCount int    `json:"likingCount" gorm:"-"`
	LikedCount  int    `json:"likedCount" gorm:"-"`
	Likings     []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
	Liked       []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`

	MD5      string    `json:"md5" gorm:"column:md5"` // Hash of email address, used for Gravatar
	Torrents []Torrent `gorm:"ForeignKey:UploaderID"`
}

// Returns the total size of memory recursively allocated for this struct
func (u User) Size() (s int) {
	s += 4 + // ints
		6*2 + // string pointers
		4*3 + //time.Time
		3*2 + // arrays
		// string arrays
		len(u.Username) + len(u.Password) + len(u.Email) + len(u.Token) + len(u.MD5) + len(u.Language)
	s *= 8

	// Ignoring foreign key users. Fuck them.

	return
}

type PublicUser struct {
	User *User
}

// different users following eachother
type UserFollows struct {
	UserID     uint `gorm:"column:user_id"`
	FollowerID uint `gorm:"column:following"`
}

type UserUploadsOld struct {
	Username  string `gorm:"column:username"`
	TorrentId uint   `gorm:"column:torrent_id"`
}

func (c UserUploadsOld) TableName() string {
	// TODO: rename this in db
	return "user_uploads_old"
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

type infiniteNewLineReader struct{}

// Read fills the buffer with newlines.
func (r infiniteNewLineReader) Read(b []byte) (int, error) {
	for i := range b {
		b[i] = '\n'
	}
	return len(b), nil
}

// TestObtain test the user data acquisition phase of the cli.
func TestObtain(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	exfg, _ := cli.Obtain(infiniteNewLineReader{})
	assert.NotNil(t, exfg)
}

type faultyReader struct{}

// Read always fails.
func (r faultyReader) Read(b []byte) (int, error) {
	return 0, errors.New("error")
}

// TestObtainWithErrorReading test error handling.
func TestObtainWithErrorReading(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	_, err := cli.Obtain(faultyReader{})
	assert.Error(t, err)
}

// TestWrite test the configuration write phase of the cli.
func TestWrite(t *testing.T) {
	tf, err := ioutil.TempFile("", "test_fritzctl.yml.")
	assert.NoError(t, err)
	defer tf.Close()
	defer os.Remove(tf.Name())
	extendedCfg := ExtendedConfig{}
	extendedCfg.file = tf.Name()
	err = extendedCfg.Write()
	assert.NoError(t, err)
}

// TestWriteAndRead test the configuration write with subsequent re-read.
func TestWriteAndRead(t *testing.T) {
	tf, err := ioutil.TempFile("", "test_fritzctl.yml.")
	assert.NoError(t, err)
	defer tf.Close()
	defer os.Remove(tf.Name())
	extendedCfg := ExtendedConfig{fritzCfg: Config{Net: new(Net), Login: new(Login), Pki: new(Pki)}}
	extendedCfg.file = tf.Name()
	err = extendedCfg.Write()
	assert.NoError(t, err)
	re, err := New(tf.Name())
	assert.NoError(t, err)
	assert.NotNil(t, re)
	assert.Equal(t, *extendedCfg.fritzCfg.Net, *re.Net)
	assert.Equal(t, *extendedCfg.fritzCfg.Login, *re.Login)
	assert.Equal(t, *extendedCfg.fritzCfg.Pki, *re.Pki)
}

// TestWriteWithIOError test the write phase of the cli with error.
func TestWriteWithIOError(t *testing.T) {
	extendedCfg := ExtendedConfig{file: `/root/*/"/?/:/a/b/c/no/such/file/or/directory/cfg.yml`}
	err := extendedCfg.Write()
	assert.Error(t, err)
}

// TestGreet tests the greeting.
func TestGreet(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	assert.NotPanics(t, func() {
		cli.Greet()
	})
}

// TestDefaultConfigFileLoc asserts the default config file behavior.
func TestDefaultConfigFileLoc(t *testing.T) {
	c := cliConfigurer{}
	assert.NotEmpty(t,
		c.defaultConfigLocation(func(file string) (string, error) { return "/path/to/folder/" + file, nil }))
	assert.NotEmpty(t,
		c.defaultConfigLocation(func(file string) (string, error) { return "", errors.New("didn't work") }))
}
<commit_msg>Fix test: use an empty filename to make sure config cannot be written<commit_after>package config

import (
	"errors"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

type infiniteNewLineReader struct{}

// Read fills the buffer with newlines.
func (r infiniteNewLineReader) Read(b []byte) (int, error) {
	for i := range b {
		b[i] = '\n'
	}
	return len(b), nil
}

// TestObtain test the user data acquisition phase of the cli.
func TestObtain(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	exfg, _ := cli.Obtain(infiniteNewLineReader{})
	assert.NotNil(t, exfg)
}

type faultyReader struct{}

// Read always fails.
func (r faultyReader) Read(b []byte) (int, error) {
	return 0, errors.New("error")
}

// TestObtainWithErrorReading test error handling.
func TestObtainWithErrorReading(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	_, err := cli.Obtain(faultyReader{})
	assert.Error(t, err)
}

// TestWrite test the configuration write phase of the cli.
func TestWrite(t *testing.T) {
	tf, err := ioutil.TempFile("", "test_fritzctl.yml.")
	assert.NoError(t, err)
	defer tf.Close()
	defer os.Remove(tf.Name())
	extendedCfg := ExtendedConfig{}
	extendedCfg.file = tf.Name()
	err = extendedCfg.Write()
	assert.NoError(t, err)
}

// TestWriteAndRead test the configuration write with subsequent re-read.
func TestWriteAndRead(t *testing.T) {
	tf, err := ioutil.TempFile("", "test_fritzctl.yml.")
	assert.NoError(t, err)
	defer tf.Close()
	defer os.Remove(tf.Name())
	extendedCfg := ExtendedConfig{fritzCfg: Config{Net: new(Net), Login: new(Login), Pki: new(Pki)}}
	extendedCfg.file = tf.Name()
	err = extendedCfg.Write()
	assert.NoError(t, err)
	re, err := New(tf.Name())
	assert.NoError(t, err)
	assert.NotNil(t, re)
	assert.Equal(t, *extendedCfg.fritzCfg.Net, *re.Net)
	assert.Equal(t, *extendedCfg.fritzCfg.Login, *re.Login)
	assert.Equal(t, *extendedCfg.fritzCfg.Pki, *re.Pki)
}

// TestWriteWithIOError test the write phase of the cli with error.
func TestWriteWithIOError(t *testing.T) {
	extendedCfg := ExtendedConfig{file: ""}
	err := extendedCfg.Write()
	assert.Error(t, err)
}

// TestGreet tests the greeting.
func TestGreet(t *testing.T) {
	cli := NewConfigurer().(*cliConfigurer)
	assert.NotPanics(t, func() {
		cli.Greet()
	})
}

// TestDefaultConfigFileLoc asserts the default config file behavior.
func TestDefaultConfigFileLoc(t *testing.T) {
	c := cliConfigurer{}
	assert.NotEmpty(t,
		c.defaultConfigLocation(func(file string) (string, error) { return "/path/to/folder/" + file, nil }))
	assert.NotEmpty(t,
		c.defaultConfigLocation(func(file string) (string, error) { return "", errors.New("didn't work") }))
}
<|endoftext|>


<commit_before>package paa

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

//go:generate stringer -type=PaaType
type PaaType uint16

const (
	DXT1          PaaType = 0xFF01
	DXT2          PaaType = 0xFF02
	DXT3          PaaType = 0xFF03
	DXT4          PaaType = 0xFF04
	DXT5          PaaType = 0xFF05
	RGBA4444      PaaType = 0x4444
	RGBA5551      PaaType = 0x5551
	RGBA8888      PaaType = 0x8888
	GrayWithAlpha PaaType = 0x8080
)

func (p PaaType) IsValid() bool {
	switch p {
	case DXT1:
		return true
	case DXT2:
		return true
	case DXT3:
		return true
	case DXT4:
		return true
	case DXT5:
		return true
	case RGBA4444:
		return true
	case RGBA5551:
		return true
	case RGBA8888:
		return true
	case GrayWithAlpha:
		return true
	}

	return false
}

func ReadPaa(r io.Reader) ([]Tagg, error) {
	reader := bufio.NewReader(r)

	// Read the file magic
	var magic PaaType
	err := binary.Read(reader, binary.LittleEndian, &magic)

	if err != nil {
		return nil, fmt.Errorf("An error occurred: %s", err)
	}

	if !magic.IsValid() {
		return nil, fmt.Errorf("Invalid or unknown PAA type 0x%X", uint16(magic))
	}

	taggs := []Tagg{}
	for {
		// Read in a new tagg
		tagg := Tagg{}

		signature := make([]byte, 4)
		_, err := reader.Read(signature)

		if err != nil {
			return nil, err
		}

		reverse(&signature)

		tagg.signature = string(signature)

		if tagg.Signature() != TaggSignature {
			return nil, fmt.Errorf("Invalid TAGG signature (expected TAGG, got \"%s\"", tagg.Signature())
		}

		// Read the tag name
		taggType := make([]byte, 4)
		_, err = reader.Read(taggType)
		if err != nil {
			return nil, err
		}

		reverse(&taggType)

		tagg.name = string(taggType)

		// Read the length of the data
		err = binary.Read(reader, binary.LittleEndian, &tagg.dataLength)
		if err != nil {
			return nil, err
		}

		// Read in the data. The data is a bunch of 32-bit integers, and the length is the length
		// of the raw byte buffer I guess
		tagg.data = make([]int32, tagg.dataLength/4)

		var data int32
		for i := range tagg.data {
			err := binary.Read(reader, binary.LittleEndian, &data)
			if err != nil {
				return nil, err
			}

			tagg.data[i] = data
		}

		taggs = append(taggs, tagg)

		if tagg.Name() == OFFS {
			break
		}
	}

	return taggs, nil
}
<commit_msg>Fix unclosed paren<commit_after>package paa

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

//go:generate stringer -type=PaaType
type PaaType uint16

const (
	DXT1          PaaType = 0xFF01
	DXT2          PaaType = 0xFF02
	DXT3          PaaType = 0xFF03
	DXT4          PaaType = 0xFF04
	DXT5          PaaType = 0xFF05
	RGBA4444      PaaType = 0x4444
	RGBA5551      PaaType = 0x5551
	RGBA8888      PaaType = 0x8888
	GrayWithAlpha PaaType = 0x8080
)

func (p PaaType) IsValid() bool {
	switch p {
	case DXT1:
		return true
	case DXT2:
		return true
	case DXT3:
		return true
	case DXT4:
		return true
	case DXT5:
		return true
	case RGBA4444:
		return true
	case RGBA5551:
		return true
	case RGBA8888:
		return true
	case GrayWithAlpha:
		return true
	}

	return false
}

func ReadPaa(r io.Reader) ([]Tagg, error) {
	reader := bufio.NewReader(r)

	// Read the file magic
	var magic PaaType
	err := binary.Read(reader, binary.LittleEndian, &magic)

	if err != nil {
		return nil, fmt.Errorf("An error occurred: %s", err)
	}

	if !magic.IsValid() {
		return nil, fmt.Errorf("Invalid or unknown PAA type 0x%X", uint16(magic))
	}

	taggs := []Tagg{}
	for {
		// Read in a new tagg
		tagg := Tagg{}

		signature := make([]byte, 4)
		_, err := reader.Read(signature)

		if err != nil {
			return nil, err
		}

		reverse(&signature)

		tagg.signature = string(signature)

		if tagg.Signature() != TaggSignature {
			return nil, fmt.Errorf("Invalid TAGG signature (expected TAGG, got \"%s\")", tagg.Signature())
		}

		// Read the tag name
		taggType := make([]byte, 4)
		_, err = reader.Read(taggType)
		if err != nil {
			return nil, err
		}

		reverse(&taggType)

		tagg.name = string(taggType)

		// Read the length of the data
		err = binary.Read(reader, binary.LittleEndian, &tagg.dataLength)
		if err != nil {
			return nil, err
		}

		// Read in the data. The data is a bunch of 32-bit integers, and the length is the length
		// of the raw byte buffer I guess
		tagg.data = make([]int32, tagg.dataLength/4)

		var data int32
		for i := range tagg.data {
			err := binary.Read(reader, binary.LittleEndian, &data)
			if err != nil {
				return nil, err
			}

			tagg.data[i] = data
		}

		taggs = append(taggs, tagg)

		if tagg.Name() == OFFS {
			break
		}
	}

	return taggs, nil
}
<|endoftext|>