<commit_before>package egoscale

// InstancePoolState represents the state of an Instance Pool.
type InstancePoolState string

const (
	// InstancePoolCreating creating state.
	InstancePoolCreating InstancePoolState = "creating"
	// InstancePoolRunning running state.
	InstancePoolRunning InstancePoolState = "running"
	// InstancePoolDestroying destroying state.
	InstancePoolDestroying InstancePoolState = "destroying"
	// InstancePoolScalingUp scaling up state.
	InstancePoolScalingUp InstancePoolState = "scaling-up"
	// InstancePoolScalingDown scaling down state.
	InstancePoolScalingDown InstancePoolState = "scaling-down"
)

// InstancePool represents an Instance Pool.
type InstancePool struct {
	ID                *UUID             `json:"id"`
	Name              string            `json:"name"`
	Description       string            `json:"description"`
	ServiceOfferingID *UUID             `json:"serviceofferingid"`
	TemplateID        *UUID             `json:"templateid"`
	ZoneID            *UUID             `json:"zoneid"`
	SecurityGroupIDs  []UUID            `json:"securitygroupids"`
	NetworkIDs        []UUID            `json:"networkids"`
	KeyPair           string            `json:"keypair"`
	UserData          string            `json:"userdata"`
	Size              int               `json:"size"`
	RootDiskSize      int               `json:"rootdisksize"`
	State             InstancePoolState `json:"state"`
	VirtualMachines   []VirtualMachine  `json:"virtualmachines"`
}

// CreateInstancePool represents an Instance Pool creation API request.
type CreateInstancePool struct {
	Name              string `json:"name"`
	Description       string `json:"description,omitempty"`
	ServiceOfferingID *UUID  `json:"serviceofferingid"`
	TemplateID        *UUID  `json:"templateid"`
	ZoneID            *UUID  `json:"zoneid"`
	SecurityGroupIDs  []UUID `json:"securitygroupids,omitempty"`
	NetworkIDs        []UUID `json:"networkids,omitempty"`
	KeyPair           string `json:"keypair,omitempty"`
	UserData          string `json:"userdata,omitempty"`
	Size              int    `json:"size"`
	RootDiskSize      int    `json:"rootdisksize,omitempty"`
	_                 bool   `name:"createInstancePool" description:"Create an Instance Pool"`
}

// CreateInstancePoolResponse represents an Instance Pool creation API response.
type CreateInstancePoolResponse struct {
	ID                *UUID             `json:"id"`
	Name              string            `json:"name"`
	Description       string            `json:"description"`
	ServiceOfferingID *UUID             `json:"serviceofferingid"`
	TemplateID        *UUID             `json:"templateid"`
	ZoneID            *UUID             `json:"zoneid"`
	SecurityGroupIDs  []UUID            `json:"securitygroupids"`
	NetworkIDs        []UUID            `json:"networkids"`
	KeyPair           string            `json:"keypair"`
	UserData          string            `json:"userdata"`
	Size              int64             `json:"size"`
	RootDiskSize      int               `json:"rootdisksize"`
	State             InstancePoolState `json:"state"`
}

// Response returns an empty structure to unmarshal an Instance Pool creation API response into.
func (CreateInstancePool) Response() interface{} {
	return new(CreateInstancePoolResponse)
}

// UpdateInstancePool represents an Instance Pool update API request.
type UpdateInstancePool struct {
	ID          *UUID  `json:"id"`
	ZoneID      *UUID  `json:"zoneid"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	TemplateID  *UUID  `json:"templateid,omitempty"`
	UserData    string `json:"userdata,omitempty"`
	_           bool   `name:"updateInstancePool" description:"Update an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool update API response into.
func (UpdateInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// ScaleInstancePool represents an Instance Pool scaling API request.
type ScaleInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	Size   int   `json:"size"`
	_      bool  `name:"scaleInstancePool" description:"Scale an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool scaling API response into.
func (ScaleInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// DestroyInstancePool represents an Instance Pool destruction API request.
type DestroyInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"destroyInstancePool" description:"Destroy an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool destruction API response into.
func (DestroyInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// GetInstancePool retrieves an Instance Pool's details.
type GetInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"getInstancePool" description:"Get an Instance Pool"`
}

// GetInstancePoolResponse get Instance Pool API response.
type GetInstancePoolResponse struct {
	Count         int
	InstancePools []InstancePool `json:"instancepool"`
}

// Response returns an empty structure to unmarshal an Instance Pool get API response into.
func (GetInstancePool) Response() interface{} {
	return new(GetInstancePoolResponse)
}

// ListInstancePools represents a list Instance Pool API request.
type ListInstancePools struct {
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"listInstancePools" description:"List Instance Pools"`
}

// ListInstancePoolsResponse represents a list Instance Pool API response.
type ListInstancePoolsResponse struct {
	Count         int
	InstancePools []InstancePool `json:"instancepool"`
}

// Response returns an empty structure to unmarshal an Instance Pool list API response into.
func (ListInstancePools) Response() interface{} {
	return new(ListInstancePoolsResponse)
}

// EvictInstancePoolMembers represents an Instance Pool members eviction API request.
type EvictInstancePoolMembers struct {
	ID        *UUID  `json:"id"`
	ZoneID    *UUID  `json:"zoneid"`
	MemberIDs []UUID `json:"memberids"`
	_         bool   `name:"evictInstancePoolMembers" description:"Evict some Instance Pool members"`
}

// Response returns an empty structure to unmarshal an Instance Pool members eviction API response into.
func (EvictInstancePoolMembers) Response() interface{} {
	return new(BooleanResponse)
}
<commit_msg>Instance Pools: add support for IPv6 (#446)<commit_after>package egoscale

// InstancePoolState represents the state of an Instance Pool.
type InstancePoolState string

const (
	// InstancePoolCreating creating state.
	InstancePoolCreating InstancePoolState = "creating"
	// InstancePoolRunning running state.
	InstancePoolRunning InstancePoolState = "running"
	// InstancePoolDestroying destroying state.
	InstancePoolDestroying InstancePoolState = "destroying"
	// InstancePoolScalingUp scaling up state.
	InstancePoolScalingUp InstancePoolState = "scaling-up"
	// InstancePoolScalingDown scaling down state.
	InstancePoolScalingDown InstancePoolState = "scaling-down"
)

// InstancePool represents an Instance Pool.
type InstancePool struct {
	ID                *UUID             `json:"id"`
	Name              string            `json:"name"`
	Description       string            `json:"description"`
	ServiceOfferingID *UUID             `json:"serviceofferingid"`
	TemplateID        *UUID             `json:"templateid"`
	ZoneID            *UUID             `json:"zoneid"`
	SecurityGroupIDs  []UUID            `json:"securitygroupids"`
	NetworkIDs        []UUID            `json:"networkids"`
	IPv6              bool              `json:"ipv6"`
	KeyPair           string            `json:"keypair"`
	UserData          string            `json:"userdata"`
	Size              int               `json:"size"`
	RootDiskSize      int               `json:"rootdisksize"`
	State             InstancePoolState `json:"state"`
	VirtualMachines   []VirtualMachine  `json:"virtualmachines"`
}

// CreateInstancePool represents an Instance Pool creation API request.
type CreateInstancePool struct {
	Name              string `json:"name"`
	Description       string `json:"description,omitempty"`
	ServiceOfferingID *UUID  `json:"serviceofferingid"`
	TemplateID        *UUID  `json:"templateid"`
	ZoneID            *UUID  `json:"zoneid"`
	SecurityGroupIDs  []UUID `json:"securitygroupids,omitempty"`
	NetworkIDs        []UUID `json:"networkids,omitempty"`
	IPv6              bool   `json:"ipv6"`
	KeyPair           string `json:"keypair,omitempty"`
	UserData          string `json:"userdata,omitempty"`
	Size              int    `json:"size"`
	RootDiskSize      int    `json:"rootdisksize,omitempty"`
	_                 bool   `name:"createInstancePool" description:"Create an Instance Pool"`
}

// CreateInstancePoolResponse represents an Instance Pool creation API response.
type CreateInstancePoolResponse struct {
	ID                *UUID             `json:"id"`
	Name              string            `json:"name"`
	Description       string            `json:"description"`
	ServiceOfferingID *UUID             `json:"serviceofferingid"`
	TemplateID        *UUID             `json:"templateid"`
	ZoneID            *UUID             `json:"zoneid"`
	SecurityGroupIDs  []UUID            `json:"securitygroupids"`
	NetworkIDs        []UUID            `json:"networkids"`
	IPv6              bool              `json:"ipv6"`
	KeyPair           string            `json:"keypair"`
	UserData          string            `json:"userdata"`
	Size              int64             `json:"size"`
	RootDiskSize      int               `json:"rootdisksize"`
	State             InstancePoolState `json:"state"`
}

// Response returns an empty structure to unmarshal an Instance Pool creation API response into.
func (CreateInstancePool) Response() interface{} {
	return new(CreateInstancePoolResponse)
}

// UpdateInstancePool represents an Instance Pool update API request.
type UpdateInstancePool struct {
	ID          *UUID  `json:"id"`
	ZoneID      *UUID  `json:"zoneid"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	TemplateID  *UUID  `json:"templateid,omitempty"`
	UserData    string `json:"userdata,omitempty"`
	IPv6        bool   `json:"ipv6"`
	_           bool   `name:"updateInstancePool" description:"Update an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool update API response into.
func (UpdateInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// ScaleInstancePool represents an Instance Pool scaling API request.
type ScaleInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	Size   int   `json:"size"`
	_      bool  `name:"scaleInstancePool" description:"Scale an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool scaling API response into.
func (ScaleInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// DestroyInstancePool represents an Instance Pool destruction API request.
type DestroyInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"destroyInstancePool" description:"Destroy an Instance Pool"`
}

// Response returns an empty structure to unmarshal an Instance Pool destruction API response into.
func (DestroyInstancePool) Response() interface{} {
	return new(BooleanResponse)
}

// GetInstancePool retrieves an Instance Pool's details.
type GetInstancePool struct {
	ID     *UUID `json:"id"`
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"getInstancePool" description:"Get an Instance Pool"`
}

// GetInstancePoolResponse get Instance Pool API response.
type GetInstancePoolResponse struct {
	Count         int
	InstancePools []InstancePool `json:"instancepool"`
}

// Response returns an empty structure to unmarshal an Instance Pool get API response into.
func (GetInstancePool) Response() interface{} {
	return new(GetInstancePoolResponse)
}

// ListInstancePools represents a list Instance Pool API request.
type ListInstancePools struct {
	ZoneID *UUID `json:"zoneid"`
	_      bool  `name:"listInstancePools" description:"List Instance Pools"`
}

// ListInstancePoolsResponse represents a list Instance Pool API response.
type ListInstancePoolsResponse struct {
	Count         int
	InstancePools []InstancePool `json:"instancepool"`
}

// Response returns an empty structure to unmarshal an Instance Pool list API response into.
func (ListInstancePools) Response() interface{} {
	return new(ListInstancePoolsResponse)
}

// EvictInstancePoolMembers represents an Instance Pool members eviction API request.
type EvictInstancePoolMembers struct {
	ID        *UUID  `json:"id"`
	ZoneID    *UUID  `json:"zoneid"`
	MemberIDs []UUID `json:"memberids"`
	_         bool   `name:"evictInstancePoolMembers" description:"Evict some Instance Pool members"`
}

// Response returns an empty structure to unmarshal an Instance Pool members eviction API response into.
func (EvictInstancePoolMembers) Response() interface{} {
	return new(BooleanResponse)
}
<|endoftext|>


<commit_before>package args

import (
	"flag"
	"github.com/unixpickle/gocube"
)

// Args stores the arguments which can be applied to pretty much any search.
type Args struct {
	scrambleStr string
	scramble    *gocube.CubieCube
}

// NewArgs creates a new Args object given a FlagSet.
// This will not automatically parse the FlagSet.
func NewArgs(f *flag.FlagSet) *Args {
	res := &Args{}
	f.StringVar(&res.scrambleStr, "scramble", "", "The WCA scramble.")
	return res
}

// Scramble gets the scramble from the arguments or reads it from standard
// input.
// The result is cached, so you may call Scramble() as many times as you wish.
func (a *Args) Scramble() (*gocube.CubieCube, error) {
	if a.scramble != nil {
		return a.scramble, nil
	} else if len(a.scrambleStr) > 0 {
		// Parse the scramble they used as an argument.
		moves, err := gocube.ParseMoves(a.scrambleStr)
		if err != nil {
			return nil, err
		}
		solved := gocube.SolvedCubieCube()
		a.scramble = &solved
		for _, move := range moves {
			a.scramble.Move(move)
		}
		return a.scramble, nil
	} else {
		// Input a scramble from the console.
		input, err := gocube.InputStickerCube()
		if err != nil {
			return nil, err
		}
		a.scramble, err = input.CubieCube()
		if err != nil {
			return nil, err
		}
		return a.scramble, nil
	}
}
<commit_msg>started working on new arguments<commit_after>package args

import (
	"flag"
	"github.com/unixpickle/gocube"
)

// Args stores the arguments which can be applied to pretty much any search.
type Args struct {
	scrambleStr string
	movesStr    string
	scramble    *gocube.CubieCube
	moves       []gocube.Move
	branch      *int
	maxDepth    *int
	minDepth    *int
}

// NewArgs creates a new Args object given a FlagSet.
// This will not automatically parse the FlagSet.
func NewArgs(f *flag.FlagSet) *Args {
	res := &Args{}
	f.StringVar(&res.scrambleStr, "scramble", "", "The scramble in WCA notation")
	f.StringVar(&res.movesStr, "moves", "", "The basis for the search")
	res.branch = f.Int("branch", 1, "The parallelization depth")
	res.maxDepth = f.Int("maxdepth", 20, "The maximum search depth")
	res.minDepth = f.Int("mindepth", 0, "The minimum search depth")
	return res
}

// Branch returns the branch depth argument.
func (a *Args) Branch() int {
	return *a.branch
}

// MaxDepth returns the maximum depth argument.
func (a *Args) MaxDepth() int {
	return *a.maxDepth
}

// MinDepth returns the minimum depth argument.
func (a *Args) MinDepth() int {
	return *a.minDepth
}

// Moves returns the basis moves.
func (a *Args) Moves() []gocube.Move {
	return a.moves
}

// Parse processes the supplied arguments and (possibly) asks the user for
// clarifying input.
// You should call this after calling parse on the FlagSet.
func (a *Args) Parse() error {
	// Create the scramble
	if len(a.scrambleStr) > 0 {
		// Parse the scramble they used as an argument.
		moves, err := gocube.ParseMoves(a.scrambleStr)
		if err != nil {
			return err
		}
		solved := gocube.SolvedCubieCube()
		a.scramble = &solved
		for _, move := range moves {
			a.scramble.Move(move)
		}
	} else {
		// Input a scramble from the console.
		input, err := gocube.InputStickerCube()
		if err != nil {
			return err
		}
		a.scramble, err = input.CubieCube()
		if err != nil {
			return err
		}
	}

	// Create the basis
	if len(a.movesStr) > 0 {
		// Parse the supplied basis
		var err error
		a.moves, err = gocube.ParseMoves(a.movesStr)
		if err != nil {
			return err
		}
	} else {
		// Order the default moves in terms of comfort.
		a.moves, _ = gocube.ParseMoves("R U L D R' U' L' D' R2 U2 L2 D2 " +
			"F B F' B' F2 B2")
	}

	return nil
}

// Scramble gets the scramble from the arguments.
func (a *Args) Scramble() gocube.CubieCube {
	return *a.scramble
}
<|endoftext|>


<commit_before>package fs

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/dotcloud/docker/future"
	_ "github.com/mattn/go-sqlite3"
	"github.com/shykes/gorp" //Forked to implement CreateTablesOpts
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"syscall"
	"time"
)

type Store struct {
	Root   string
	db     *sql.DB
	orm    *gorp.DbMap
	layers *LayerStore
}

type Archive io.Reader

func New(root string) (*Store, error) {
	isNewStore := true

	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	db, err := sql.Open("sqlite3", path.Join(root, "db"))
	if err != nil {
		return nil, err
	}
	orm := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
	orm.AddTableWithName(Image{}, "images").SetKeys(false, "Id")
	orm.AddTableWithName(Path{}, "paths").SetKeys(false, "Path", "Image")
	orm.AddTableWithName(Mountpoint{}, "mountpoints").SetKeys(false, "Root")
	orm.AddTableWithName(Tag{}, "tags").SetKeys(false, "TagName")
	if isNewStore {
		if err := orm.CreateTablesOpts(true); err != nil {
			return nil, err
		}
	}

	layers, err := NewLayerStore(path.Join(root, "layers"))
	if err != nil {
		return nil, err
	}
	return &Store{
		Root:   root,
		db:     db,
		orm:    orm,
		layers: layers,
	}, nil
}

func (store *Store) imageList(src []interface{}) []*Image {
	var images []*Image
	for _, i := range src {
		img := i.(*Image)
		img.store = store
		images = append(images, img)
	}
	return images
}

func (store *Store) Images() ([]*Image, error) {
	images, err := store.orm.Select(Image{}, "select * from images")
	if err != nil {
		return nil, err
	}
	return store.imageList(images), nil
}

func (store *Store) Paths() ([]string, error) {
	var paths []string
	rows, err := store.db.Query("select distinct Path from paths order by Path")
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var path string
		if err := rows.Scan(&path); err != nil {
			return nil, err
		}
		paths = append(paths, path)
	}
	return paths, nil
}

func (store *Store) List(pth string) ([]*Image, error) {
	pth = path.Clean(pth)
	images, err := store.orm.Select(Image{}, "select images.* from images, paths where Path=? and paths.Image=images.Id", pth)
	if err != nil {
		return nil, err
	}
	return store.imageList(images), nil
}

func (store *Store) Find(pth string) (*Image, error) {
	pth = path.Clean(pth)
	img, err := store.Get(pth)
	if err != nil {
		return nil, err
	} else if img != nil {
		return img, nil
	}

	images, err := store.orm.Select(Image{}, "select images.* from images, paths where Path=? and paths.Image=images.Id order by images.Created desc limit 1", pth)
	if err != nil {
		return nil, err
	} else if len(images) < 1 {
		return nil, nil
	}
	img = images[0].(*Image)
	img.store = store
	return img, nil
}

func (store *Store) Get(id string) (*Image, error) {
	img, err := store.orm.Get(Image{}, id)
	if img == nil {
		return nil, err
	}
	res := img.(*Image)
	res.store = store
	return res, err
}

func (store *Store) Create(layerData Archive, parent *Image, pth, comment string) (*Image, error) {
	// FIXME: actually do something with the layer...
	img := &Image{
		Id:      future.RandomId(),
		Comment: comment,
		Created: time.Now().Unix(),
		store:   store,
	}
	if parent != nil {
		img.Parent = parent.Id
	}
	// FIXME: we shouldn't have to pass os.Stderr to AddLayer()...
	// FIXME: Archive should contain compression info. For now we only support uncompressed.
	_, err := store.layers.AddLayer(img.Id, layerData)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Could not add layer: %s", err))
	}
	path := &Path{
		Path:  path.Clean(pth),
		Image: img.Id,
	}
	trans, err := store.orm.Begin()
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Could not begin transaction:", err))
	}
	if err := trans.Insert(img); err != nil {
		return nil, errors.New(fmt.Sprintf("Could not insert image info: %s", err))
	}
	if err := trans.Insert(path); err != nil {
		return nil, errors.New(fmt.Sprintf("Could not insert path info: %s", err))
	}
	if err := trans.Commit(); err != nil {
		return nil, errors.New(fmt.Sprintf("Could not commit transaction: %s", err))
	}
	return img, nil
}

func (store *Store) Register(image *Image, pth string) error {
	image.store = store
	// FIXME: import layer
	trans, err := store.orm.Begin()
	if err != nil {
		return err
	}
	trans.Insert(image)
	trans.Insert(&Path{Path: pth, Image: image.Id})
	return trans.Commit()
}

func (store *Store) Layers() []string {
	return store.layers.List()
}

type Image struct {
	Id      string
	Parent  string
	Comment string
	Created int64
	store   *Store `db:"-"`
}

func (image *Image) Copy(pth string) (*Image, error) {
	if err := image.store.orm.Insert(&Path{Path: pth, Image: image.Id}); err != nil {
		return nil, err
	}
	return image, nil
}

type Mountpoint struct {
	Image string
	Root  string
	Rw    string
	Store *Store `db:"-"`
}

func (image *Image) Mountpoint(root, rw string) (*Mountpoint, error) {
	mountpoint := &Mountpoint{
		Root:  path.Clean(root),
		Rw:    path.Clean(rw),
		Image: image.Id,
		Store: image.store,
	}
	if err := image.store.orm.Insert(mountpoint); err != nil {
		return nil, err
	}
	return mountpoint, nil
}

func (image *Image) layers() ([]string, error) {
	var list []string
	var err error
	currentImg := image
	for currentImg != nil {
		if layer := image.store.layers.Get(currentImg.Id); layer != "" {
			list = append(list, layer)
		} else {
			return list, fmt.Errorf("Layer not found for image %s", image.Id)
		}
		currentImg, err = currentImg.store.Get(currentImg.Parent)
		if err != nil {
			return list, fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	return list, nil
}

func (image *Image) Mountpoints() ([]*Mountpoint, error) {
	var mountpoints []*Mountpoint
	res, err := image.store.orm.Select(Mountpoint{}, "select * from mountpoints where Image=?", image.Id)
	if err != nil {
		return nil, err
	}
	for _, mp := range res {
		mountpoints = append(mountpoints, mp.(*Mountpoint))
	}
	return mountpoints, nil
}

func (image *Image) Mount(root, rw string) (*Mountpoint, error) {
	var mountpoint *Mountpoint
	if mp, err := image.store.FetchMountpoint(root, rw); err != nil {
		return nil, err
	} else if mp == nil {
		mountpoint, err = image.Mountpoint(root, rw)
		if err != nil {
			return nil, fmt.Errorf("Could not create mountpoint: %s", err)
		} else if mountpoint == nil {
			return nil, errors.New("No mountpoint created")
		}
	} else {
		mountpoint = mp
	}

	if err := mountpoint.createFolders(); err != nil {
		return nil, err
	}

	// FIXME: Now mount the layers
	rwBranch := fmt.Sprintf("%v=rw", mountpoint.Rw)
	roBranches := ""
	layers, err := image.layers()
	if err != nil {
		return nil, err
	}
	for _, layer := range layers {
		roBranches += fmt.Sprintf("%v=ro:", layer)
	}
	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
	if err := mount("none", mountpoint.Root, "aufs", 0, branches); err != nil {
		return mountpoint, err
	}
	if !mountpoint.Mounted() {
		return mountpoint, errors.New("Mount failed")
	}

	return mountpoint, nil
}

func (mp *Mountpoint) EnsureMounted() error {
	if mp.Mounted() {
		return nil
	}
	img, err := mp.Store.Get(mp.Image)
	if err != nil {
		return err
	}

	_, err = img.Mount(mp.Root, mp.Rw)
	return err
}

func (mp *Mountpoint) createFolders() error {
	if err := os.Mkdir(mp.Root, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := os.Mkdir(mp.Rw, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	return nil
}

func (mp *Mountpoint) Mounted() bool {
	root, err := os.Stat(mp.Root)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
		panic(err)
	}
	parent, err := os.Stat(filepath.Join(mp.Root, ".."))
	if err != nil {
		panic(err)
	}

	rootSt := root.Sys().(*syscall.Stat_t)
	parentSt := parent.Sys().(*syscall.Stat_t)
	return rootSt.Dev != parentSt.Dev
}

func (mp *Mountpoint) Umount() error {
	if !mp.Mounted() {
		return errors.New("Mountpoint doesn't seem to be mounted")
	}
	if err := syscall.Unmount(mp.Root, 0); err != nil {
		return fmt.Errorf("Unmount syscall failed: %v", err)
	}
	if mp.Mounted() {
		return fmt.Errorf("Umount: Filesystem still mounted after calling umount(%v)", mp.Root)
	}
	// Even though we just unmounted the filesystem, AUFS will prevent deleting the mntpoint
	// for some time. We'll just keep retrying until it succeeds.
	for retries := 0; retries < 1000; retries++ {
		err := os.Remove(mp.Root)
		if err == nil {
			// rm mntpoint succeeded
			return nil
		}
		if os.IsNotExist(err) {
			// mntpoint doesn't exist anymore. Success.
			return nil
		}
		// fmt.Printf("(%v) Remove %v returned: %v\n", retries, mp.Root, err)
		time.Sleep(10 * time.Millisecond)
	}
	return fmt.Errorf("Umount: Failed to umount %v", mp.Root)

}

func (mp *Mountpoint) Deregister() error {
	if mp.Mounted() {
		return errors.New("Mountpoint is currently mounted, can't deregister")
	}

	_, err := mp.Store.orm.Delete(mp)
	return err
}

func (store *Store) FetchMountpoint(root, rw string) (*Mountpoint, error) {
	res, err := store.orm.Select(Mountpoint{}, "select * from mountpoints where Root=? and Rw=?", root, rw)
	if err != nil {
		return nil, err
	} else if len(res) < 1 || res[0] == nil {
		return nil, nil
	}

	mp := res[0].(*Mountpoint)
	mp.Store = store
	return mp, nil
}

// OpenFile opens the named file for reading.
func (mp *Mountpoint) OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
	if err := mp.EnsureMounted(); err != nil {
		return nil, err
	}
	return os.OpenFile(filepath.Join(mp.Root, path), flag, perm)
}

// ReadDir reads the directory named by dirname, relative to the Mountpoint's root,
// and returns a list of sorted directory entries
func (mp *Mountpoint) ReadDir(dirname string) ([]os.FileInfo, error) {
	if err := mp.EnsureMounted(); err != nil {
		return nil, err
	}
	return ioutil.ReadDir(filepath.Join(mp.Root, dirname))
}

func (store *Store) AddTag(imageId, tagName string) error {
	if image, err := store.Get(imageId); err != nil {
		return err
	} else if image == nil {
		return errors.New("No image with ID " + imageId)
	}

	err2 := store.orm.Insert(&Tag{
		TagName: tagName,
		Image:   imageId,
	})

	return err2
}

func (store *Store) GetByTag(tagName string) (*Image, error) {
	res, err := store.orm.Get(Tag{}, tagName)
	if err != nil {
		return nil, err
	} else if res == nil {
		return nil, errors.New("No image associated to tag \"" + tagName + "\"")
	}

	tag := res.(*Tag)

	img, err2 := store.Get(tag.Image)
	if err2 != nil {
		return nil, err2
	} else if img == nil {
		return nil, errors.New("Tag was found but image seems to be inexistent.")
	}

	return img, nil
}

type Path struct {
	Path  string
	Image string
}

type Tag struct {
	TagName string
	Image   string
}
<commit_msg>Fix issue #32, aufs now take into consideration deleted files<commit_after>package fs

import (
	"database/sql"
	"fmt"
	"github.com/dotcloud/docker/future"
	_ "github.com/mattn/go-sqlite3"
	"github.com/shykes/gorp" //Forked to implement CreateTablesOpts
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"syscall"
	"time"
)

type Store struct {
	Root   string
	db     *sql.DB
	orm    *gorp.DbMap
	layers *LayerStore
}

type Archive io.Reader

func New(root string) (*Store, error) {
	isNewStore := true

	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	db, err := sql.Open("sqlite3", path.Join(root, "db"))
	if err != nil {
		return nil, err
	}
	orm := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
	orm.AddTableWithName(Image{}, "images").SetKeys(false, "Id")
	orm.AddTableWithName(Path{}, "paths").SetKeys(false, "Path", "Image")
	orm.AddTableWithName(Mountpoint{}, "mountpoints").SetKeys(false, "Root")
	orm.AddTableWithName(Tag{}, "tags").SetKeys(false, "TagName")
	if isNewStore {
		if err := orm.CreateTablesOpts(true); err != nil {
			return nil, err
		}
	}

	layers, err := NewLayerStore(path.Join(root, "layers"))
	if err != nil {
		return nil, err
	}
	return &Store{
		Root:   root,
		db:     db,
		orm:    orm,
		layers: layers,
	}, nil
}

func (store *Store) imageList(src []interface{}) []*Image {
	var images []*Image
	for _, i := range src {
		img := i.(*Image)
		img.store = store
		images = append(images, img)
	}
	return images
}

func (store *Store) Images() ([]*Image, error) {
	images, err := store.orm.Select(Image{}, "select * from images")
	if err != nil {
		return nil, err
	}
	return store.imageList(images), nil
}

func (store *Store) Paths() ([]string, error) {
	var paths []string
	rows, err := store.db.Query("select distinct Path from paths order by Path")
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var path string
		if err := rows.Scan(&path); err != nil {
			return nil, err
		}
		paths = append(paths, path)
	}
	return paths, nil
}

func (store *Store) List(pth string) ([]*Image, error) {
	pth = path.Clean(pth)
	images, err := store.orm.Select(Image{}, "select images.* from images, paths where Path=? and paths.Image=images.Id", pth)
	if err != nil {
		return nil, err
	}
	return store.imageList(images), nil
}

func (store *Store) Find(pth string) (*Image, error) {
	pth = path.Clean(pth)
	img, err := store.Get(pth)
	if err != nil {
		return nil, err
	} else if img != nil {
		return img, nil
	}

	images, err := store.orm.Select(Image{}, "select images.* from images, paths where Path=? and paths.Image=images.Id order by images.Created desc limit 1", pth)
	if err != nil {
		return nil, err
	} else if len(images) < 1 {
		return nil, nil
	}
	img = images[0].(*Image)
	img.store = store
	return img, nil
}

func (store *Store) Get(id string) (*Image, error) {
	img, err := store.orm.Get(Image{}, id)
	if img == nil {
		return nil, err
	}
	res := img.(*Image)
	res.store = store
	return res, err
}

func (store *Store) Create(layerData Archive, parent *Image, pth, comment string) (*Image, error) {
	// FIXME: actually do something with the layer...
	img := &Image{
		Id:      future.RandomId(),
		Comment: comment,
		Created: time.Now().Unix(),
		store:   store,
	}
	if parent != nil {
		img.Parent = parent.Id
	}
	// FIXME: we shouldn't have to pass os.Stderr to AddLayer()...
	// FIXME: Archive should contain compression info. For now we only support uncompressed.
	_, err := store.layers.AddLayer(img.Id, layerData)
	if err != nil {
		return nil, fmt.Errorf("Could not add layer: %s", err)
	}
	path := &Path{
		Path:  path.Clean(pth),
		Image: img.Id,
	}
	trans, err := store.orm.Begin()
	if err != nil {
		return nil, fmt.Errorf("Could not begin transaction: %s", err)
	}
	if err := trans.Insert(img); err != nil {
		return nil, fmt.Errorf("Could not insert image info: %s", err)
	}
	if err := trans.Insert(path); err != nil {
		return nil, fmt.Errorf("Could not insert path info: %s", err)
	}
	if err := trans.Commit(); err != nil {
		return nil, fmt.Errorf("Could not commit transaction: %s", err)
	}
	return img, nil
}

func (store *Store) Register(image *Image, pth string) error {
	image.store = store
	// FIXME: import layer
	trans, err := store.orm.Begin()
	if err != nil {
		return err
	}
	trans.Insert(image)
	trans.Insert(&Path{Path: pth, Image: image.Id})
	return trans.Commit()
}

func (store *Store) Layers() []string {
	return store.layers.List()
}

type Image struct {
	Id      string
	Parent  string
	Comment string
	Created int64
	store   *Store `db:"-"`
}

func (image *Image) Copy(pth string) (*Image, error) {
	if err := image.store.orm.Insert(&Path{Path: pth, Image: image.Id}); err != nil {
		return nil, err
	}
	return image, nil
}

type Mountpoint struct {
	Image string
	Root  string
	Rw    string
	Store *Store `db:"-"`
}

func (image *Image) Mountpoint(root, rw string) (*Mountpoint, error) {
	mountpoint := &Mountpoint{
		Root:  path.Clean(root),
		Rw:    path.Clean(rw),
		Image: image.Id,
		Store: image.store,
	}
	if err := image.store.orm.Insert(mountpoint); err != nil {
		return nil, err
	}
	return mountpoint, nil
}

func (image *Image) layers() ([]string, error) {
	var list []string
	var err error
	currentImg := image
	for currentImg != nil {
		if layer := image.store.layers.Get(currentImg.Id); layer != "" {
			list = append(list, layer)
		} else {
			return list, fmt.Errorf("Layer not found for image %s", image.Id)
		}
		currentImg, err = currentImg.store.Get(currentImg.Parent)
		if err != nil {
			return list, fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	if len(list) == 0 {
		return nil, fmt.Errorf("No layer found for image %s\n", image.Id)
	}
	return list, nil
}

func (image *Image) Mountpoints() ([]*Mountpoint, error) {
	var mountpoints []*Mountpoint
	res, err := image.store.orm.Select(Mountpoint{}, "select * from mountpoints where Image=?", image.Id)
	if err != nil {
		return nil, err
	}
	for _, mp := range res {
		mountpoints = append(mountpoints, mp.(*Mountpoint))
	}
	return mountpoints, nil
}

func (image *Image) Mount(root, rw string) (*Mountpoint, error) {
	var mountpoint *Mountpoint
	if mp, err := image.store.FetchMountpoint(root, rw); err != nil {
		return nil, err
	} else if mp == nil {
		mountpoint, err = image.Mountpoint(root, rw)
		if err != nil {
			return nil, fmt.Errorf("Could not create mountpoint: %s", err)
		} else if mountpoint == nil {
			return nil, fmt.Errorf("No mountpoint created")
		}
	} else {
		mountpoint = mp
	}

	if err := mountpoint.createFolders(); err != nil {
		return nil, err
	}

	// FIXME: Now mount the layers
	rwBranch := fmt.Sprintf("%v=rw", mountpoint.Rw)
	roBranches := ""
	layers, err := image.layers()
	if err != nil {
		return nil, err
	}
	for _, layer := range layers {
		roBranches += fmt.Sprintf("%v=ro:", layer)
	}
	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
	if err := mount("none", mountpoint.Root, "aufs", 0, branches); err != nil {
		return mountpoint, err
	}
	if !mountpoint.Mounted() {
		return mountpoint, fmt.Errorf("Mount failed")
	}

	// FIXME: Create tests for deletion
	// Retrieve the changeset from the parent and apply it to the container
	//  - Retrieve the changes
	changes, err := image.store.Changes(&Mountpoint{
		Image: image.Id,
		Root:  layers[0],
		Rw:    layers[0],
		Store: image.store})
	if err != nil {
		return nil, err
	}
	// Iterate on changes
	for _, c := range changes {
		// If there is a delete
		if c.Kind == ChangeDelete {
			// Make sure the directory exists
			file_path, file_name := path.Dir(c.Path), path.Base(c.Path)
			if err := os.MkdirAll(path.Join(mountpoint.Rw, file_path), 0755); err != nil {
				return nil, err
			}
			// And create the whiteout (we just need to create empty file, discard the return)
			if _, err := os.Create(path.Join(path.Join(mountpoint.Rw, file_path),
				".wh."+path.Base(file_name))); err != nil {
				return nil, err
			}
		}
	}
	return mountpoint, nil
}

func (mp *Mountpoint) EnsureMounted() error {
	if mp.Mounted() {
		return nil
	}
	img, err := mp.Store.Get(mp.Image)
	if err != nil {
		return err
	}

	_, err = img.Mount(mp.Root, mp.Rw)
	return err
}

func (mp *Mountpoint) createFolders() error {
	if err := os.Mkdir(mp.Root, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := os.Mkdir(mp.Rw, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	return nil
}

func (mp *Mountpoint) Mounted() bool {
	root, err := os.Stat(mp.Root)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
		panic(err)
	}
	parent, err := os.Stat(filepath.Join(mp.Root, ".."))
	if err != nil {
		panic(err)
	}

	rootSt := root.Sys().(*syscall.Stat_t)
	parentSt := parent.Sys().(*syscall.Stat_t)
	return rootSt.Dev != parentSt.Dev
}

func (mp *Mountpoint) Umount() error {
	if !mp.Mounted() {
		return fmt.Errorf("Mountpoint doesn't seem to be mounted")
	}
	if err := syscall.Unmount(mp.Root, 0); err != nil {
		return fmt.Errorf("Unmount syscall failed: %v", err)
	}
	if mp.Mounted() {
		return fmt.Errorf("Umount: Filesystem still mounted after calling umount(%v)", mp.Root)
	}
	// Even though we just unmounted the filesystem, AUFS will prevent deleting the mntpoint
	// for some time. We'll just keep retrying until it succeeds.
	for retries := 0; retries < 1000; retries++ {
		err := os.Remove(mp.Root)
		if err == nil {
			// rm mntpoint succeeded
			return nil
		}
		if os.IsNotExist(err) {
			// mntpoint doesn't exist anymore. Success.
			return nil
		}
		// fmt.Printf("(%v) Remove %v returned: %v\n", retries, mp.Root, err)
		time.Sleep(10 * time.Millisecond)
	}
	return fmt.Errorf("Umount: Failed to umount %v", mp.Root)

}

func (mp *Mountpoint) Deregister() error {
	if mp.Mounted() {
		return fmt.Errorf("Mountpoint is currently mounted, can't deregister")
	}

	_, err := mp.Store.orm.Delete(mp)
	return err
}

func (store *Store) FetchMountpoint(root, rw string) (*Mountpoint, error) {
	res, err := store.orm.Select(Mountpoint{}, "select * from mountpoints where Root=? and Rw=?", root, rw)
	if err != nil {
		return nil, err
	} else if len(res) < 1 || res[0] == nil {
		return nil, nil
	}

	mp := res[0].(*Mountpoint)
	mp.Store = store
	return mp, nil
}

// OpenFile opens the named file for reading.
func (mp *Mountpoint) OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
	if err := mp.EnsureMounted(); err != nil {
		return nil, err
	}
	return os.OpenFile(filepath.Join(mp.Root, path), flag, perm)
}

// ReadDir reads the directory named by dirname, relative to the Mountpoint's root,
// and returns a list of sorted directory entries
func (mp *Mountpoint) ReadDir(dirname string) ([]os.FileInfo, error) {
	if err := mp.EnsureMounted(); err != nil {
		return nil, err
	}
	return ioutil.ReadDir(filepath.Join(mp.Root, dirname))
}

func (store *Store) AddTag(imageId, tagName string) error {
	if image, err := store.Get(imageId); err != nil {
		return err
	} else if image == nil {
		return fmt.Errorf("No image with ID %s", imageId)
	}

	err2 := store.orm.Insert(&Tag{
		TagName: tagName,
		Image:   imageId,
	})

	return err2
}

func (store *Store) GetByTag(tagName string) (*Image, error) {
	res, err := store.orm.Get(Tag{}, tagName)
	if err != nil {
		return nil, err
	} else if res == nil {
		return nil, fmt.Errorf("No image associated to tag \"%s\"", tagName)
	}

	tag := res.(*Tag)

	img, err2 := store.Get(tag.Image)
	if err2 != nil {
		return nil, err2
	} else if img == nil {
		return nil, fmt.Errorf("Tag was found but image seems to be inexistent.")
	}

	return img, nil
}

type Path struct {
	Path  string
	Image string
}

type Tag struct {
	TagName string
	Image   string
}
<|endoftext|>


<commit_before>package susigo

import (
    "crypto/tls"
    "encoding/json"
    "log"
    "net"
    "strconv"
    "time"
)

type Callback func(map[string]interface{})

type Susi struct {
    conn       net.Conn
    encoder    *json.Encoder
    decoder    *json.Decoder
    callbacks  map[string]Callback
    consumers  map[string][]Callback
    processors map[string][]Callback
}

func NewSusi(addr, certFile, keyFile string) (*Susi, error) {
    susi := new(Susi)
    cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        return nil, err
    }
    conn, err := tls.Dial("tcp", addr, &tls.Config{
        Certificates:       []tls.Certificate{cert},
        InsecureSkipVerify: true,
    })
    if err != nil {
        return nil, err
    }
    susi.conn = conn
    susi.callbacks = make(map[string]Callback)
    susi.consumers = make(map[string][]Callback)
    susi.processors = make(map[string][]Callback)
    susi.encoder = json.NewEncoder(susi.conn)
    susi.decoder = json.NewDecoder(susi.conn)
    go susi.backend()
    return susi, nil
}

func (susi *Susi) Publish(topic string, payload interface{}, callback Callback) error {
    id := strconv.FormatInt(time.Now().UnixNano(), 10)
    packet := map[string]interface{}{
        "type": "publish",
        "data": map[string]interface{}{
            "topic":   topic,
            "payload": payload,
            "id":      id,
        },
    }
    susi.callbacks[id] = callback
    return susi.encoder.Encode(packet)
}

func (susi *Susi) RegisterConsumer(topic string, callback Callback) error {
    susi.consumers[topic] = append(susi.consumers[topic], callback)
    if len(susi.consumers[topic]) == 1 {
        packet := map[string]interface{}{
            "type": "registerConsumer",
            "data": map[string]interface{}{
                "topic": topic,
            },
        }
        return susi.encoder.Encode(packet)
    }
    return nil
}

func (susi *Susi) RegisterProcessor(topic string, callback Callback) error {
    susi.processors[topic] = append(susi.processors[topic], callback)
    if len(susi.processors[topic]) == 1 {
        packet := map[string]interface{}{
            "type": "registerProcessor",
            "data": map[string]interface{}{
                "topic": topic,
            },
        }
        return susi.encoder.Encode(packet)
    }
    return nil
}

func (susi *Susi) backend() {
    packet := make(map[string]interface{})
    for {
        err := susi.decoder.Decode(&packet)
        if err != nil {
            log.Println("Error reading from susi json decoder: ", err)
            continue
        }
        switch packet["type"] {
        case "ack":
            {
                event := packet["data"].(map[string]interface{})
                id := event["id"].(string)
                callback := susi.callbacks[id]
                callback(event)
                delete(susi.callbacks, id)
            }
        case "consumerEvent":
            {
                event := packet["data"].(map[string]interface{})
                topic := event["topic"].(string)
                consumers := susi.consumers[topic]
                for _, consumer := range consumers {
                    consumer(event)
                }
            }
        case "processorEvent":
            {
                event := packet["data"].(map[string]interface{})
                topic := event["topic"].(string)
                processors := susi.processors[topic]
                for _, processor := range processors {
                    processor(event)
                }
                packet["type"] = "ack"
                packet["data"] = event
                if err = susi.encoder.Encode(packet); err != nil {
                    log.Println("can not ack event back to susi: ", err)
                }
            }
        }
    }
}
<commit_msg>added unregister[Consumer|Processor];<commit_after>package susigo

import (
    "crypto/tls"
    "encoding/json"
    "errors"
    "log"
    "net"
    "strconv"
    "time"
)

type Callback func(map[string]interface{})

type Susi struct {
    conn       net.Conn
    encoder    *json.Encoder
    decoder    *json.Decoder
    callbacks  map[string]Callback
    consumers  map[string]map[int64]Callback
    processors map[string]map[int64]Callback
}

func NewSusi(addr, certFile, keyFile string) (*Susi, error) {
    susi := new(Susi)
    cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        return nil, err
    }
    conn, err := tls.Dial("tcp", addr, &tls.Config{
        Certificates:       []tls.Certificate{cert},
        InsecureSkipVerify: true,
    })
    if err != nil {
        return nil, err
    }
    susi.conn = conn
    susi.callbacks = make(map[string]Callback)
    susi.consumers = make(map[string]map[int64]Callback)
    susi.processors = make(map[string]map[int64]Callback)
    susi.encoder = json.NewEncoder(susi.conn)
    susi.decoder = json.NewDecoder(susi.conn)
    go susi.backend()
    return susi, nil
}

func (susi *Susi) Publish(topic string, payload interface{}, callback Callback) error {
    id := strconv.FormatInt(time.Now().UnixNano(), 10)
    packet := map[string]interface{}{
        "type": "publish",
        "data": map[string]interface{}{
            "topic":   topic,
            "payload": payload,
            "id":      id,
        },
    }
    susi.callbacks[id] = callback
    return susi.encoder.Encode(packet)
}

func (susi *Susi) RegisterConsumer(topic string, callback Callback) (int64, error) {
    if susi.consumers[topic] == nil {
        susi.consumers[topic] = make(map[int64]Callback)
    }
    consumers := susi.consumers[topic]
    id := time.Now().UnixNano()
    consumers[id] = callback
    if len(consumers) == 1 {
        packet := map[string]interface{}{
            "type": "registerConsumer",
            "data": map[string]interface{}{
                "topic": topic,
            },
        }
        return id, susi.encoder.Encode(packet)
    }
    return -1, nil
}

func (susi *Susi) RegisterProcessor(topic string, callback Callback) (int64, error) {
    if susi.processors[topic] == nil {
        susi.processors[topic] = make(map[int64]Callback)
    }
    processors := susi.processors[topic]
    id := time.Now().UnixNano()
    processors[id] = callback
    if len(processors) == 1 {
        packet := map[string]interface{}{
            "type": "registerProcessor",
            "data": map[string]interface{}{
                "topic": topic,
            },
        }
        return id, susi.encoder.Encode(packet)
    }
    return -1, nil
}

func (susi *Susi) UnregisterConsumer(id int64) error {
    for _, consumers := range susi.consumers {
        if topic, ok := consumers[id]; ok {
            delete(consumers, id)
            if len(consumers) == 0 {
                packet := map[string]interface{}{
                    "type": "unregisterConsumer",
                    "data": map[string]interface{}{
                        "topic": topic,
                    },
                }
                return susi.encoder.Encode(packet)
            } else {
                return nil
            }
        }
    }
    return errors.New("no such consumer")
}

func (susi *Susi) UnregisterProcessor(id int64) error {
    for _, processors := range susi.processors {
        if topic, ok := processors[id]; ok {
            delete(processors, id)
            if len(processors) == 0 {
                packet := map[string]interface{}{
                    "type": "unregisterProcessor",
                    "data": map[string]interface{}{
                        "topic": topic,
                    },
                }
                return susi.encoder.Encode(packet)
            } else {
                return nil
            }
        }
    }
    return errors.New("no such processor")
}

func (susi *Susi) backend() {
    packet := make(map[string]interface{})
    for {
        err := susi.decoder.Decode(&packet)
        if err != nil {
            log.Println("Error reading from susi json decoder: ", err)
            continue
        }
        switch packet["type"] {
        case "ack":
            {
                event := packet["data"].(map[string]interface{})
                id := event["id"].(string)
                callback := susi.callbacks[id]
                callback(event)
                delete(susi.callbacks, id)
            }
        case "consumerEvent":
            {
                event := packet["data"].(map[string]interface{})
                topic := event["topic"].(string)
                consumers := susi.consumers[topic]
                for _, consumer := range consumers {
                    consumer(event)
                }
            }
        case "processorEvent":
            {
                event := packet["data"].(map[string]interface{})
                topic := event["topic"].(string)
                processors := susi.processors[topic]
                for _, processor := range processors {
                    processor(event)
                }
                packet["type"] = "ack"
                packet["data"] = event
                if err = susi.encoder.Encode(packet); err != nil {
                    log.Println("can not ack event back to susi: ", err)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"os"
	"fmt"
	"net"
)

// This log writer sends output to a socket
type SysLogWriter chan *LogRecord

// This is the SocketLogWriter's output method
func (w SysLogWriter) LogWrite(rec *LogRecord) {
	w <- rec
}

func (w SysLogWriter) Close() {
	close(w)
}

func connectSyslogDaemon() (sock net.Conn, err os.Error) {
	logTypes := []string{"unixgram", "unix"}
	logPaths := []string{"/dev/log", "/var/run/syslog"}
	var raddr string
	for _, network := range logTypes {
		for _, path := range logPaths {
			raddr = path
			sock, err = net.Dial(network, raddr)
			if err != nil {
				continue
			} else {
				return
			}
		}
	}
	if err != nil {
		err = os.NewError("cannot connect to Syslog Daemon")
	}
	return
}

func NewSysLogWriter() (w SysLogWriter) {
	sock, err := connectSyslogDaemon()
	if err != nil {
		fmt.Fprintf(os.Stderr, "NewSysLogWriter: %s\n", err)
		return
	}
	w = SysLogWriter(make(chan *LogRecord, LogBufferLength))
	go func() {
		for rec := range w {
			fmt.Fprintf(sock, FormatLogRecord("%S:[%D %T]%L: %M", rec))
		}
	}()
	return
}
<commit_msg>close socket when done<commit_after>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"os"
	"fmt"
	"net"
)

// This log writer sends output to a socket
type SysLogWriter chan *LogRecord

// This is the SocketLogWriter's output method
func (w SysLogWriter) LogWrite(rec *LogRecord) {
	w <- rec
}

func (w SysLogWriter) Close() {
	close(w)
}

func connectSyslogDaemon() (sock net.Conn, err os.Error) {
	logTypes := []string{"unixgram", "unix"}
	logPaths := []string{"/dev/log", "/var/run/syslog"}
	var raddr string
	for _, network := range logTypes {
		for _, path := range logPaths {
			raddr = path
			sock, err = net.Dial(network, raddr)
			if err != nil {
				continue
			} else {
				return
			}
		}
	}
	if err != nil {
		err = os.NewError("cannot connect to Syslog Daemon")
	}
	return
}

func NewSysLogWriter() (w SysLogWriter) {
	sock, err := connectSyslogDaemon()
	if err != nil {
		fmt.Fprintf(os.Stderr, "NewSysLogWriter: %s\n", err)
		return
	}
	w = SysLogWriter(make(chan *LogRecord, LogBufferLength))
	go func() {
		defer func() {
			if sock != nil {
				sock.Close()
			}
		}()
		for rec := range w {
			fmt.Fprintf(sock, FormatLogRecord("%S:[%D %T]%L: %M", rec))
		}
	}()
	return
}
<|endoftext|>


<commit_before>package radius

import (
	"encoding/binary"
	"io"
)

var (

	// AccountingStart represents the start of RADIUS accounting session for a specific User
	AccountingStart = Attribute{AccountingStatusType, 6, fourOctet(1)}

	// AccountingStop represents the stop of a RADIUS accounting session for a specific USer
	AccountingStop = Attribute{AccountingStatusType, 6, fourOctet(2)}

	// The spec is NOT helpful on what these are for

	// ?
	InterimUpdate = Attribute{AccountingStatusType, 6, fourOctet(3)}

	// ?
	AccountingOn = Attribute{AccountingStatusType, 6, fourOctet(7)}

	// ?
	AccountingOff = Attribute{AccountingStatusType, 6, fourOctet(8)}

	UserRequest        = Attribute{AccountingTerminateCause, 6, fourOctet(1)}
	LostCarrier        = Attribute{AccountingTerminateCause, 6, fourOctet(2)}
	LostService        = Attribute{AccountingTerminateCause, 6, fourOctet(3)}
	IdleTimeout        = Attribute{AccountingTerminateCause, 6, fourOctet(4)}
	SessionTimeout     = Attribute{AccountingTerminateCause, 6, fourOctet(5)}
	AdminReset         = Attribute{AccountingTerminateCause, 6, fourOctet(6)}
	AdminReboot        = Attribute{AccountingTerminateCause, 6, fourOctet(7)}
	PortError          = Attribute{AccountingTerminateCause, 6, fourOctet(8)}
	NASError           = Attribute{AccountingTerminateCause, 6, fourOctet(9)}
	NASRequest         = Attribute{AccountingTerminateCause, 6, fourOctet(10)}
	NASReboot          = Attribute{AccountingTerminateCause, 6, fourOctet(11)}
	PortUnneeded       = Attribute{AccountingTerminateCause, 6, fourOctet(12)}
	PortPreempted      = Attribute{AccountingTerminateCause, 6, fourOctet(13)}
	PortSuspended      = Attribute{AccountingTerminateCause, 6, fourOctet(14)}
	ServiceUnavailable = Attribute{AccountingTerminateCause, 6, fourOctet(15)}
	Callback           = Attribute{AccountingTerminateCause, 6, fourOctet(16)}
	UserError          = Attribute{AccountingTerminateCause, 6, fourOctet(17)}
	HostRequest        = Attribute{AccountingTerminateCause, 6, fourOctet(18)}
)

// An AttributeValue is a value attached to an attribute
type AttributeValue Writer

// An Attribute is a Key-Value pair attached to a request or response
type Attribute struct {
	Type   AttributeType
	Length int8
	Values []Writer
}

// Write writes the attribute to the given writer
func (attr *Attribute) Write(w io.Writer) error {
	if err := attr.Type.Write(w); err != nil {
		return err
	}

	if err := binary.Write(w, binary.BigEndian, attr.Length); err != nil {
		return err
	}

	for _, v := range attr.Values {
		if err := v.Write(w); err != nil {
			return err
		}
	}

	return nil
}

// StringAttribute builds an attribute of length >= 3 with the given string
func StringAttribute(t AttributeType, str string) Attribute {
	return Attribute{t, int8(3 + len(str)), []Writer{stringWriter(str)}}
}

type stringWriter string

func (s stringWriter) Write(w io.Writer) error {
	_, err := w.Write([]byte(s))
	return err
}

// shortcut to represent a value as 4 octets
func fourOctet(i int) []Writer {
	return []Writer{
		WriterFunc(func(w io.Writer) error {
			return binary.Write(w, binary.BigEndian, int32(i))
		}),
	}
}
<commit_msg>Attribute - fix string attribute length<commit_after>package radius

import (
	"encoding/binary"
	"io"
)

var (

	// AccountingStart represents the start of RADIUS accounting session for a specific User
	AccountingStart = Attribute{AccountingStatusType, 6, fourOctet(1)}

	// AccountingStop represents the stop of a RADIUS accounting session for a specific USer
	AccountingStop = Attribute{AccountingStatusType, 6, fourOctet(2)}

	// The spec is NOT helpful on what these are for

	// ?
	InterimUpdate = Attribute{AccountingStatusType, 6, fourOctet(3)}

	// ?
	AccountingOn = Attribute{AccountingStatusType, 6, fourOctet(7)}

	// ?
	AccountingOff = Attribute{AccountingStatusType, 6, fourOctet(8)}

	UserRequest        = Attribute{AccountingTerminateCause, 6, fourOctet(1)}
	LostCarrier        = Attribute{AccountingTerminateCause, 6, fourOctet(2)}
	LostService        = Attribute{AccountingTerminateCause, 6, fourOctet(3)}
	IdleTimeout        = Attribute{AccountingTerminateCause, 6, fourOctet(4)}
	SessionTimeout     = Attribute{AccountingTerminateCause, 6, fourOctet(5)}
	AdminReset         = Attribute{AccountingTerminateCause, 6, fourOctet(6)}
	AdminReboot        = Attribute{AccountingTerminateCause, 6, fourOctet(7)}
	PortError          = Attribute{AccountingTerminateCause, 6, fourOctet(8)}
	NASError           = Attribute{AccountingTerminateCause, 6, fourOctet(9)}
	NASRequest         = Attribute{AccountingTerminateCause, 6, fourOctet(10)}
	NASReboot          = Attribute{AccountingTerminateCause, 6, fourOctet(11)}
	PortUnneeded       = Attribute{AccountingTerminateCause, 6, fourOctet(12)}
	PortPreempted      = Attribute{AccountingTerminateCause, 6, fourOctet(13)}
	PortSuspended      = Attribute{AccountingTerminateCause, 6, fourOctet(14)}
	ServiceUnavailable = Attribute{AccountingTerminateCause, 6, fourOctet(15)}
	Callback           = Attribute{AccountingTerminateCause, 6, fourOctet(16)}
	UserError          = Attribute{AccountingTerminateCause, 6, fourOctet(17)}
	HostRequest        = Attribute{AccountingTerminateCause, 6, fourOctet(18)}
)

// An AttributeValue is a value attached to an attribute
type AttributeValue Writer

// An Attribute is a Key-Value pair attached to a request or response
type Attribute struct {
	Type   AttributeType
	Length int8
	Values []Writer
}

// Write writes the attribute to the given writer
func (attr *Attribute) Write(w io.Writer) error {
	if err := attr.Type.Write(w); err != nil {
		return err
	}

	if err := binary.Write(w, binary.BigEndian, attr.Length); err != nil {
		return err
	}

	for _, v := range attr.Values {
		if err := v.Write(w); err != nil {
			return err
		}
	}

	return nil
}

// StringAttribute builds an attribute of length >= 3 with the given string
func StringAttribute(t AttributeType, str string) Attribute {
	return Attribute{t, int8(2 + len(str)), []Writer{stringWriter(str)}}
}

type stringWriter string

func (s stringWriter) Write(w io.Writer) error {
	_, err := w.Write([]byte(s))
	return err
}

// shortcut to represent a value as 4 octets
func fourOctet(i int) []Writer {
	return []Writer{
		WriterFunc(func(w io.Writer) error {
			return binary.Write(w, binary.BigEndian, int32(i))
		}),
	}
}
<|endoftext|>


<commit_before>package core

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"math"
	"math/big"
	"testing"
)

func Test_Authentication(t *testing.T) {
	auth := Authentication{}
	err := auth.createCrypto("testtest")
	if err != nil {
		t.Error("Expected no error:", err)
	}
	// create new auth with Secure of old one
	twoAuth := Authentication{Secure: auth.Secure, Nonce: auth.Nonce}
	err = twoAuth.loadCrypto("testtest")
	if err != nil {
		t.Error("Expected no error:", err)
	}
	if !sameKeys(auth.public, twoAuth.public) || !sameKeys(auth.private, twoAuth.private) {
		t.Error("Expected keys to match!")
	}
}

/*
Not really a test, more an example implementation of how challenge and response
should work.
*/
func Test_Challenge(t *testing.T) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// build a challenge
	bigNumber, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64-1))
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// convert back to int64
	number := bigNumber.Int64()
	// convert to data payload
	// NOTE: BAD DOC! binary.Size(number) does not return the correct number! Instead we use the maximum length to guarantee that the value will always fit...
	data := make([]byte, binary.MaxVarintLen64)
	_ = binary.PutVarint(data, number)
	// log.Println("GOLANG DEBUG: Size says we need", binary.Size(number), "bytes, but actually wrote", written, "!")
	// get a nonce
	nonce := auth.createNonce()
	// encrypt number with nonce
	encrypted, err := auth.Encrypt(data, nonce)
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// <-> ANSWER CHALLENGE <->
	// decrypt
	decrypted, err := auth.Decrypt(encrypted, nonce)
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// read number
	readNumber, err := binary.ReadVarint(bytes.NewBuffer(decrypted[:]))
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	if readNumber != number {
		t.Error("Expected numbers to match, got", readNumber, "instead of", number)
	}
}

func Benchmark_CreateAuthentication(b *testing.B) {
	for i := 0; i < b.N; i++ {
		auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
		if err != nil {
			b.Error("Error:", err)
		}
		_ = auth
	}
}

func Benchmark_Auth_Encrypt(b *testing.B) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Couldn't build auth:", err)
	}
	nonce := auth.createNonce()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		enc, err := auth.Encrypt([]byte("Add some random test here for now."), nonce)
		if err != nil {
			b.Error("Failed to encrypt:", err)
		}
		_ = enc
	}
}

func Benchmark_Auth_CreateNonce(b *testing.B) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Couldn't build auth:", err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = auth.createNonce()
	}
}

func sameKeys(a *[32]byte, b *[32]byte) bool {
	for i := 0; i < 32; i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<commit_msg>more benchmarks<commit_after>package core

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"io/ioutil"
	"math"
	"math/big"
	"testing"
)

func Test_Authentication(t *testing.T) {
	auth := Authentication{}
	err := auth.createCrypto("testtest")
	if err != nil {
		t.Error("Expected no error:", err)
	}
	// create new auth with Secure of old one
	twoAuth := Authentication{Secure: auth.Secure, Nonce: auth.Nonce}
	err = twoAuth.loadCrypto("testtest")
	if err != nil {
		t.Error("Expected no error:", err)
	}
	if !sameKeys(auth.public, twoAuth.public) || !sameKeys(auth.private, twoAuth.private) {
		t.Error("Expected keys to match!")
	}
}

/*
Not really a test, more an example implementation of how challenge and response
should work.
*/
func Test_Challenge(t *testing.T) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// build a challenge
	bigNumber, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64-1))
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// convert back to int64
	number := bigNumber.Int64()
	// convert to data payload
	// NOTE: BAD DOC! binary.Size(number) does not return the correct number! Instead we use the maximum length to guarantee that the value will always fit...
	data := make([]byte, binary.MaxVarintLen64)
	_ = binary.PutVarint(data, number)
	// log.Println("GOLANG DEBUG: Size says we need", binary.Size(number), "bytes, but actually wrote", written, "!")
	// get a nonce
	nonce := auth.createNonce()
	// encrypt number with nonce
	encrypted, err := auth.Encrypt(data, nonce)
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// <-> ANSWER CHALLENGE <->
	// decrypt
	decrypted, err := auth.Decrypt(encrypted, nonce)
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	// read number
	readNumber, err := binary.ReadVarint(bytes.NewBuffer(decrypted[:]))
	if err != nil {
		t.Fatal("Expected no errors:", err)
	}
	if readNumber != number {
		t.Error("Expected numbers to match, got", readNumber, "instead of", number)
	}
}

func Benchmark_CreateAuthentication(b *testing.B) {
	for i := 0; i < b.N; i++ {
		auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
		if err != nil {
			b.Error("Error:", err)
		}
		_ = auth
	}
}

func Benchmark_LoadAuthentication(b *testing.B) {
	path, _ := ioutil.TempDir("", "auth_bench")
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Creation failed:", err)
	}
	err = auth.StoreTo(path)
	if err != nil {
		b.Fatal("Store failed:", err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := loadAuthenticationFrom(path, "hunter2")
		if err != nil {
			b.Error("Failed to load:", err)
		}
	}
}

func Benchmark_Auth_Encrypt(b *testing.B) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Couldn't build auth:", err)
	}
	nonce := auth.createNonce()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		enc, err := auth.Encrypt([]byte("Add some random test here for now."), nonce)
		if err != nil {
			b.Error("Failed to encrypt:", err)
		}
		_ = enc
	}
}

func Benchmark_Auth_Decrypt(b *testing.B) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Couldn't build auth:", err)
	}
	data := []byte("Add some random test here for now.")
	nonce := auth.createNonce()
	enc, err := auth.Encrypt(data, nonce)
	if err != nil {
		b.Fatal("Couldn't encrypt:", err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		clear, err := auth.Decrypt(enc, nonce)
		if err != nil {
			b.Error("Failed to decrypt:", err)
		}
		if 0 != bytes.Compare(clear, data) {
			b.Error("Enc and dec are different!")
		}
	}
}

func Benchmark_Auth_CreateNonce(b *testing.B) {
	auth, err := createAuthentication("/path", "dirname", "username", "hunter2")
	if err != nil {
		b.Fatal("Couldn't build auth:", err)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = auth.createNonce()
	}
}

func sameKeys(a *[32]byte, b *[32]byte) bool {
	for i := 0; i < 32; i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package libtorrent

// #cgo pkg-config: libtorrent-rasterbar openssl
// #cgo darwin LDFLAGS: -lm -lstdc++
// #cgo linux LDFLAGS: -lm -lstdc++ -ldl -lrt
// #cgo windows CXXFLAGS: -DIPV6_TCLASS=39 -O0 -g
// #cgo windows LDFLAGS: -static-libgcc -static-libstdc++
import "C"
<commit_msg>Remove debug flags in cgo<commit_after>package libtorrent

// #cgo pkg-config: libtorrent-rasterbar openssl
// #cgo darwin LDFLAGS: -lm -lstdc++
// #cgo linux LDFLAGS: -lm -lstdc++ -ldl -lrt
// #cgo windows CXXFLAGS: -DIPV6_TCLASS=39
// #cgo windows LDFLAGS: -static-libgcc -static-libstdc++
import "C"
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/cloudfoundry/cli/plugin"
	"github.com/xchapter7x/autopilot/application_repo"
	"github.com/xchapter7x/autopilot/rewind"
)

var ActionList []rewind.Action

func fatalIf(err error) {
	if err != nil {
		fmt.Fprintln(os.Stdout, "error:", err)
		os.Exit(1)
	}
}

func appExists(output []string, appName string) bool {
	for _, app := range output {
		if strings.Contains(app, appName) {
			return true
		}
	}
	return false
}

func main() {
	plugin.Start(&AutopilotPlugin{})
}

//AutopilotPlugin - the object implementing the plugin for zdd
type AutopilotPlugin struct{}

//Run - required command of a plugin (entry point)
func (plugin AutopilotPlugin) Run(cliConnection plugin.CliConnection, args []string) {

	var err error
	appRepo := application_repo.NewApplicationRepo(cliConnection)

	if args[0] == "push-zdd" && len(args) == 1 {
		err = appRepo.PushApplication([]string{"push", "-h"})
		fatalIf(err)
		return
	}

	appName, argList := ParseArgs(args)
	venerableAppName := appName + "-venerable"

	output, err := appRepo.ListApplicationsWithOutput()
	fatalIf(err)

	if appNotFound(output, appName) {
		fmt.Printf("\n%s not found! Using cf push.\n\n", appName)
		err := appRepo.PushApplication(argList)
		fatalIf(err)

		fmt.Printf("\nYour application has successfully been pushed!\n\n")
		return
	}

	actions := rewind.Actions{
		Actions: []rewind.Action{
			// rename
			{
				Forward: func() error {
					return appRepo.RenameApplication(appName, venerableAppName)
				},
			},

			// push
			{
				Forward: func() error {
					return appRepo.PushApplication(argList)
				},
				ReversePrevious: func() error {
					appRepo.DeleteApplication(appName)
					return appRepo.RenameApplication(venerableAppName, appName)
				},
			},

			// delete
			{
				Forward: func() error {
					return appRepo.DeleteApplication(venerableAppName)
				},
			},

func (plugin AutopilotPlugin) getPushAction(argList []string) rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.PushApplication(argList)
		},
		RewindFailureMessage: "Oh no. Something's gone wrong. I've tried to roll back but you should check to see if everything is OK.",
	}
}

	err = actions.Execute()
	fatalIf(err)
func (plugin AutopilotPlugin) addReversePrevious(action *rewind.Action) {
	action.ReversePrevious = func() error {
		plugin.appRepo.DeleteApplication(plugin.appName)

	fmt.Printf("\nA new version of your application has successfully been pushed!\n\n")
		return plugin.appRepo.RenameApplication(plugin.venerableAppName, plugin.appName)
	}
}

	err = appRepo.ListApplications()
	fatalIf(err)
func (plugin AutopilotPlugin) getRenameAction() rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.RenameApplication(plugin.appName, plugin.venerableAppName)
		},
	}
}

func (plugin AutopilotPlugin) getDeleteAction() rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.DeleteApplication(plugin.venerableAppName)
		},
	}
}

//GetMetadata - required command of plugin (returns meta data about plugin)
func (AutopilotPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "push-zero-downtime-deployment",
		Commands: []plugin.Command{
			{
				Name:     "push-zdd",
				HelpText: "Perform a zero-downtime push of an application over the top of an old one",
			},
		},
	}
}

//ParseArgs - parse given cli arguments
func ParseArgs(args []string) (string, []string) {
	args[0] = "push"
	appName := args[1]
	return appName, args
}

//ErrNoManifest - error to return when there is no manifest if required
var ErrNoManifest = errors.New("a manifest is required to push this application")

func getAppList(appRepo *application_repo.ApplicationRepo) []string {
	output, err := appRepo.ListApplicationsWithOutput()
	fatalIf(err)
	return output
}
<commit_msg>add appName and venerableAppName as properties on AutoPilotPlugin<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/cloudfoundry/cli/plugin"
	"github.com/xchapter7x/autopilot/application_repo"
	"github.com/xchapter7x/autopilot/rewind"
)

var ActionList []rewind.Action

func fatalIf(err error) {
	if err != nil {
		fmt.Fprintln(os.Stdout, "error:", err)
		os.Exit(1)
	}
}

func appExists(output []string, appName string) bool {
	for _, app := range output {
		if strings.Contains(app, appName) {
			return true
		}
	}
	return false
}

func main() {
	plugin.Start(&AutopilotPlugin{})
}

//AutopilotPlugin - the object implementing the plugin for zdd
type AutopilotPlugin struct {
	appRepo          *application_repo.ApplicationRepo
	appName          string
	venerableAppName string
}

//Run - required command of a plugin (entry point)
func (plugin AutopilotPlugin) Run(cliConnection plugin.CliConnection, args []string) {

	var err error
	plugin.appRepo = application_repo.NewApplicationRepo(cliConnection)

	if args[0] == "push-zdd" && len(args) == 1 {
		err = plugin.appRepo.PushApplication([]string{"push", "-h"})
		fatalIf(err)
		return
	}

	appName, argList := ParseArgs(args)
	plugin.appName = appName
	plugin.venerableAppName = appName + "-venerable"

	output, err := appRepo.ListApplicationsWithOutput()
	fatalIf(err)

	if appNotFound(output, appName) {
		fmt.Printf("\n%s not found! Using cf push.\n\n", appName)
		err := appRepo.PushApplication(argList)
		fatalIf(err)

		fmt.Printf("\nYour application has successfully been pushed!\n\n")
		return
	}

	actions := rewind.Actions{
		Actions: []rewind.Action{
			// rename
			{
				Forward: func() error {
					return appRepo.RenameApplication(appName, venerableAppName)
				},
			},

			// push
			{
				Forward: func() error {
					return appRepo.PushApplication(argList)
				},
				ReversePrevious: func() error {
					appRepo.DeleteApplication(appName)
					return appRepo.RenameApplication(venerableAppName, appName)
				},
			},

			// delete
			{
				Forward: func() error {
					return appRepo.DeleteApplication(venerableAppName)
				},
			},

func (plugin AutopilotPlugin) getPushAction(argList []string) rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.PushApplication(argList)
		},
		RewindFailureMessage: "Oh no. Something's gone wrong. I've tried to roll back but you should check to see if everything is OK.",
	}
}

	err = actions.Execute()
	fatalIf(err)
func (plugin AutopilotPlugin) addReversePrevious(action *rewind.Action) {
	action.ReversePrevious = func() error {
		plugin.appRepo.DeleteApplication(plugin.appName)

	fmt.Printf("\nA new version of your application has successfully been pushed!\n\n")
		return plugin.appRepo.RenameApplication(plugin.venerableAppName, plugin.appName)
	}
}

	err = appRepo.ListApplications()
	fatalIf(err)
func (plugin AutopilotPlugin) getRenameAction() rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.RenameApplication(plugin.appName, plugin.venerableAppName)
		},
	}
}

func (plugin AutopilotPlugin) getDeleteAction() rewind.Action {
	return rewind.Action{
		Forward: func() error {
			return plugin.appRepo.DeleteApplication(plugin.venerableAppName)
		},
	}
}

//GetMetadata - required command of plugin (returns meta data about plugin)
func (AutopilotPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "push-zero-downtime-deployment",
		Commands: []plugin.Command{
			{
				Name:     "push-zdd",
				HelpText: "Perform a zero-downtime push of an application over the top of an old one",
			},
		},
	}
}

//ParseArgs - parse given cli arguments
func ParseArgs(args []string) (string, []string) {
	args[0] = "push"
	appName := args[1]
	return appName, args
}

//ErrNoManifest - error to return when there is no manifest if required
var ErrNoManifest = errors.New("a manifest is required to push this application")

func getAppList(appRepo *application_repo.ApplicationRepo) []string {
	output, err := appRepo.ListApplicationsWithOutput()
	fatalIf(err)
	return output
}
<|endoftext|>


<commit_before>package query

import (
	"fmt"
	"sort"
	"strings"

	"github.com/jacksontj/dataman/src/router_node/sharding"
)

// Encapsulate a result from the datastore
type Result struct {
	Return []map[string]interface{} `json:"return"`
	// TODO: make a list of errors!
	Error string `json:"error,omitempty"`
	// TODO: pointer to the right thing
	ValidationError interface{}            `json:"validation_error,omitempty"`
	Meta            map[string]interface{} `json:"meta,omitempty"`
}

func (r *Result) Sort(keys []string, reverseList []bool) {
	if r.Return != nil {
		Sort(keys, reverseList, r.Return)
	}
}

// TODO: decide if we want to support globs, right now we give the entire sub-record
// if the parent is projected. Globs would only be useful if we want to do something
// like `a.b.*.c.d` where it would give you some subfields of a variety of fields--
// which seems not terribly helpful for structured data
func (r *Result) Project(fields []string) {
	// TODO: do this in the underlying datasource so we can get a partial select
	projectionFields := make([][]string, len(fields))
	for i, fieldName := range fields {
		projectionFields[i] = strings.Split(fieldName, ".")
	}

	for i, returnRow := range r.Return {
		projectedResult := make(map[string]interface{})
		for _, fieldNameParts := range projectionFields {
			if len(fieldNameParts) == 1 {
				tmpVal, ok := returnRow[fieldNameParts[0]]
				if ok {
					projectedResult[fieldNameParts[0]] = tmpVal
				}
			} else {
				dstTmp := projectedResult
				srcTmp := returnRow
				for _, fieldNamePart := range fieldNameParts[:len(fieldNameParts)-1] {
					_, ok := dstTmp[fieldNamePart]
					if !ok {
						dstTmp[fieldNamePart] = make(map[string]interface{})
					}
					dstTmp = dstTmp[fieldNamePart].(map[string]interface{})
					srcTmp = srcTmp[fieldNamePart].(map[string]interface{})
				}
				// Now we are on the last hop-- just copy the value over
				tmpVal, ok := srcTmp[fieldNameParts[len(fieldNameParts)-1]]
				if ok {
					dstTmp[fieldNameParts[len(fieldNameParts)-1]] = tmpVal
				}
			}
		}
		r.Return[i] = projectedResult
	}
}

// Merge multiple results together
func MergeResult(pkeyFields []string, numResults int, results chan *Result) *Result {
	// Fast-path single results
	if numResults == 1 {
		r := <-results
		return r
	}

	pkeyFieldParts := make([][]string, len(pkeyFields))
	for i, pkeyField := range pkeyFields {
		pkeyFieldParts[i] = strings.Split(pkeyField, ".")
	}

	// We want to make sure we don't duplicate return entries
	ids := make(map[uint64]struct{})

	combinedResult := &Result{
		Return: make([]map[string]interface{}, 0),
		Meta:   make(map[string]interface{}),
	}

	recievedResults := 0
	for result := range results {
		if result.Error != "" {
			combinedResult.Error += "\n" + result.Error
		}
		// TODO: merge meta
		if len(combinedResult.Meta) == 0 {
			combinedResult.Meta = result.Meta
		}

		for _, resultReturn := range result.Return {

			pkeyFields := make([]interface{}, len(pkeyFieldParts))
			var ok bool
			for i, pkeyField := range pkeyFieldParts {
				pkeyFields[i], ok = GetValue(resultReturn, pkeyField)
				if !ok {
					// TODO: something else?
					panic("Missing pkey in response!!!")
				}
			}
			pkey, err := (sharding.HashMethod(sharding.SHA256).Get())(sharding.CombineKeys(pkeyFields))
			if err != nil {
				panic(fmt.Sprintf("MergeResult doesn't know how to hash pkey: %v", err))
			}
			if _, ok := ids[pkey]; !ok {
				ids[pkey] = struct{}{}
				combinedResult.Return = append(combinedResult.Return, resultReturn)
			}
		}
		recievedResults++
		if recievedResults == numResults {
			break
		}
	}

	return combinedResult
}

func GetValue(value map[string]interface{}, nameParts []string) (interface{}, bool) {
	val, ok := value[nameParts[0]]
	if !ok {
		return nil, ok
	}

	for _, namePart := range nameParts[1:] {
		typedVal, ok := val.(map[string]interface{})
		if !ok {
			return nil, ok
		}
		val, ok = typedVal[namePart]
		if !ok {
			return nil, ok
		}
	}
	return val, true
}

func SetValue(value map[string]interface{}, newValue interface{}, nameParts []string) interface{} {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	val.(map[string]interface{})[nameParts[len(nameParts)-1]] = newValue

	return val
}

func DelValue(value map[string]interface{}, nameParts []string) bool {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	_, ok := val.(map[string]interface{})[nameParts[len(nameParts)-1]]
	if ok {
		delete(val.(map[string]interface{}), nameParts[len(nameParts)-1])
	}
	return ok
}

func PopValue(value map[string]interface{}, nameParts []string) (interface{}, bool) {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	tmp, ok := val.(map[string]interface{})[nameParts[len(nameParts)-1]]
	if ok {
		delete(val.(map[string]interface{}), nameParts[len(nameParts)-1])
	}
	return tmp, ok
}

func FlattenResult(m map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range m {
		switch typedV := v.(type) {
		case map[string]interface{}:
			// get the submap as a flattened thing
			subMap := FlattenResult(typedV)
			for subK, subV := range subMap {
				result[k+"."+subK] = subV
			}
		default:
			result[k] = v
		}
	}
	return result
}

// TODO: change map[string]interface to a `Record` struct type
// sort the given data by the given keys
func Sort(sortKeys []string, reverseList []bool, data []map[string]interface{}) {
	splitSortKeys := make([][]string, len(sortKeys))
	for i, sortKey := range sortKeys {
		splitSortKeys[i] = strings.Split(sortKey, ".")
	}

	less := func(i, j int) (l bool) {
		var reverse bool
		defer func() {
			if reverse {
				l = !l
			}
		}()
		for sortKeyIdx, keyParts := range splitSortKeys {
			reverse = reverseList[sortKeyIdx]
			// TODO: record could (and should) point at the CollectionFields which will tell us types
			iVal, _ := GetValue(data[i], keyParts)
			jVal, _ := GetValue(data[j], keyParts)
			switch iValTyped := iVal.(type) {
			case string:
				jValTyped := jVal.(string)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case int:
				jValTyped := jVal.(int)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case int64:
				jValTyped := jVal.(int64)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case float64:
				jValTyped := jVal.(float64)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case bool:
				jValTyped := jVal.(bool)
				if iValTyped != jValTyped {
					l = !iValTyped && jValTyped
					return
				}
			// TODO: return error? At this point if all return false, I'm not sure what happens
			default:
				panic("Unknown type")
				l = false
				return

			}
		}
		l = false
		return
	}
	sort.Slice(data, less)
}
<commit_msg>Clean up error combining (don't lead with a newline)<commit_after>package query

import (
	"fmt"
	"sort"
	"strings"

	"github.com/jacksontj/dataman/src/router_node/sharding"
)

// Encapsulate a result from the datastore
type Result struct {
	Return []map[string]interface{} `json:"return"`
	// TODO: make a list of errors!
	Error string `json:"error,omitempty"`
	// TODO: pointer to the right thing
	ValidationError interface{}            `json:"validation_error,omitempty"`
	Meta            map[string]interface{} `json:"meta,omitempty"`
}

func (r *Result) Sort(keys []string, reverseList []bool) {
	if r.Return != nil {
		Sort(keys, reverseList, r.Return)
	}
}

// TODO: decide if we want to support globs, right now we give the entire sub-record
// if the parent is projected. Globs would only be useful if we want to do something
// like `a.b.*.c.d` where it would give you some subfields of a variety of fields--
// which seems not terribly helpful for structured data
func (r *Result) Project(fields []string) {
	// TODO: do this in the underlying datasource so we can get a partial select
	projectionFields := make([][]string, len(fields))
	for i, fieldName := range fields {
		projectionFields[i] = strings.Split(fieldName, ".")
	}

	for i, returnRow := range r.Return {
		projectedResult := make(map[string]interface{})
		for _, fieldNameParts := range projectionFields {
			if len(fieldNameParts) == 1 {
				tmpVal, ok := returnRow[fieldNameParts[0]]
				if ok {
					projectedResult[fieldNameParts[0]] = tmpVal
				}
			} else {
				dstTmp := projectedResult
				srcTmp := returnRow
				for _, fieldNamePart := range fieldNameParts[:len(fieldNameParts)-1] {
					_, ok := dstTmp[fieldNamePart]
					if !ok {
						dstTmp[fieldNamePart] = make(map[string]interface{})
					}
					dstTmp = dstTmp[fieldNamePart].(map[string]interface{})
					srcTmp = srcTmp[fieldNamePart].(map[string]interface{})
				}
				// Now we are on the last hop-- just copy the value over
				tmpVal, ok := srcTmp[fieldNameParts[len(fieldNameParts)-1]]
				if ok {
					dstTmp[fieldNameParts[len(fieldNameParts)-1]] = tmpVal
				}
			}
		}
		r.Return[i] = projectedResult
	}
}

// Merge multiple results together
func MergeResult(pkeyFields []string, numResults int, results chan *Result) *Result {
	// Fast-path single results
	if numResults == 1 {
		r := <-results
		return r
	}

	pkeyFieldParts := make([][]string, len(pkeyFields))
	for i, pkeyField := range pkeyFields {
		pkeyFieldParts[i] = strings.Split(pkeyField, ".")
	}

	// We want to make sure we don't duplicate return entries
	ids := make(map[uint64]struct{})

	combinedResult := &Result{
		Return: make([]map[string]interface{}, 0),
		Meta:   make(map[string]interface{}),
	}

	recievedResults := 0
	for result := range results {
		if result.Error != "" {
			// If there was one before, add this to the list
			if combinedResult.Error != "" {
				combinedResult.Error += "\n"
			}
			combinedResult.Error += result.Error
		}
		// TODO: merge meta
		if len(combinedResult.Meta) == 0 {
			combinedResult.Meta = result.Meta
		}

		for _, resultReturn := range result.Return {

			pkeyFields := make([]interface{}, len(pkeyFieldParts))
			var ok bool
			for i, pkeyField := range pkeyFieldParts {
				pkeyFields[i], ok = GetValue(resultReturn, pkeyField)
				if !ok {
					// TODO: something else?
					panic("Missing pkey in response!!!")
				}
			}
			pkey, err := (sharding.HashMethod(sharding.SHA256).Get())(sharding.CombineKeys(pkeyFields))
			if err != nil {
				panic(fmt.Sprintf("MergeResult doesn't know how to hash pkey: %v", err))
			}
			if _, ok := ids[pkey]; !ok {
				ids[pkey] = struct{}{}
				combinedResult.Return = append(combinedResult.Return, resultReturn)
			}
		}
		recievedResults++
		if recievedResults == numResults {
			break
		}
	}

	return combinedResult
}

func GetValue(value map[string]interface{}, nameParts []string) (interface{}, bool) {
	val, ok := value[nameParts[0]]
	if !ok {
		return nil, ok
	}

	for _, namePart := range nameParts[1:] {
		typedVal, ok := val.(map[string]interface{})
		if !ok {
			return nil, ok
		}
		val, ok = typedVal[namePart]
		if !ok {
			return nil, ok
		}
	}
	return val, true
}

func SetValue(value map[string]interface{}, newValue interface{}, nameParts []string) interface{} {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	val.(map[string]interface{})[nameParts[len(nameParts)-1]] = newValue

	return val
}

func DelValue(value map[string]interface{}, nameParts []string) bool {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	_, ok := val.(map[string]interface{})[nameParts[len(nameParts)-1]]
	if ok {
		delete(val.(map[string]interface{}), nameParts[len(nameParts)-1])
	}
	return ok
}

func PopValue(value map[string]interface{}, nameParts []string) (interface{}, bool) {
	var val interface{}
	if len(nameParts) > 1 {
		val = value[nameParts[0]]
		for _, namePart := range nameParts[1 : len(nameParts)-1] {
			val = val.(map[string]interface{})[namePart]
		}

	} else {
		val = value
	}

	tmp, ok := val.(map[string]interface{})[nameParts[len(nameParts)-1]]
	if ok {
		delete(val.(map[string]interface{}), nameParts[len(nameParts)-1])
	}
	return tmp, ok
}

func FlattenResult(m map[string]interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	for k, v := range m {
		switch typedV := v.(type) {
		case map[string]interface{}:
			// get the submap as a flattened thing
			subMap := FlattenResult(typedV)
			for subK, subV := range subMap {
				result[k+"."+subK] = subV
			}
		default:
			result[k] = v
		}
	}
	return result
}

// TODO: change map[string]interface to a `Record` struct type
// sort the given data by the given keys
func Sort(sortKeys []string, reverseList []bool, data []map[string]interface{}) {
	splitSortKeys := make([][]string, len(sortKeys))
	for i, sortKey := range sortKeys {
		splitSortKeys[i] = strings.Split(sortKey, ".")
	}

	less := func(i, j int) (l bool) {
		var reverse bool
		defer func() {
			if reverse {
				l = !l
			}
		}()
		for sortKeyIdx, keyParts := range splitSortKeys {
			reverse = reverseList[sortKeyIdx]
			// TODO: record could (and should) point at the CollectionFields which will tell us types
			iVal, _ := GetValue(data[i], keyParts)
			jVal, _ := GetValue(data[j], keyParts)
			switch iValTyped := iVal.(type) {
			case string:
				jValTyped := jVal.(string)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case int:
				jValTyped := jVal.(int)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case int64:
				jValTyped := jVal.(int64)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case float64:
				jValTyped := jVal.(float64)
				if iValTyped != jValTyped {
					l = iValTyped < jValTyped
					return
				}
			case bool:
				jValTyped := jVal.(bool)
				if iValTyped != jValTyped {
					l = !iValTyped && jValTyped
					return
				}
			// TODO: return error? At this point if all return false, I'm not sure what happens
			default:
				panic("Unknown type")
				l = false
				return

			}
		}
		l = false
		return
	}
	sort.Slice(data, less)
}
<|endoftext|>


<commit_before>package telego

import (
	"strings"

	"github.com/Syfaro/telegram-bot-api"
)

type Bot struct {
	Api      *tgbotapi.BotAPI
	handlers map[string]func(string, tgbotapi.Update)
}

func NewBot(token string) (*Bot, error) {
	api, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		return nil, err
	}
	return &Bot{Api: api}, nil
}

func (b *Bot) AddHandler(command string, handler func(string, tgbotapi.Update)) {
	b.handlers[command] = handler
}

func (b *Bot) Run() {
	ucfg := tgbotapi.NewUpdate(0)
	ucfg.Timeout = 60
	err := b.Api.UpdatesChan(ucfg)
	// читаем обновления из канала
	for {
		select {
		case update := <-b.Api.Updates:
			text := strings.SplitN(update.Message.Text, ' ', 2)
			handler, ok := b.handlers[text[0]]
			if ok {
				handler(text[1], update)
			}
		}
	}
}
<commit_msg>sending message<commit_after>package telego

import (
	"strings"

	"github.com/Syfaro/telegram-bot-api"
)

type Bot struct {
	Api      *tgbotapi.BotAPI
	handlers map[string]func(string, tgbotapi.Update) string
}

func NewBot(token string) (*Bot, error) {
	api, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		return nil, err
	}
	return &Bot{Api: api, handlers: map[string]func(string, tgbotapi.Update) string{}}, nil
}

func (b *Bot) AddHandler(command string, handler func(string, tgbotapi.Update) string) {
	b.handlers[command] = handler
}

func (b *Bot) Run() {
	ucfg := tgbotapi.NewUpdate(0)
	ucfg.Timeout = 60
	b.Api.UpdatesChan(ucfg)
	for {
		select {
		case update := <-b.Api.Updates:
			text := strings.SplitN(update.Message.Text, " ", 2)
			handler, ok := b.handlers[text[0]]
			if ok {
				params := ""
				if len(text) > 1 {
					params = text[1]
				}
				msg_text := handler(params, update)
				if msg_text != "" {
					chat_id := update.Message.Chat.ID
					msg := tgbotapi.NewMessage(chat_id, msg_text)
					b.Api.SendMessage(msg)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package list

import (
	"fmt"
	"strings"
	"testing"

	"github.com/gotgenes/getignore/testutils"
)

const contentsBodyTemplate = `{
  "sha": "be962308a6efb6d27446d13ee05b74948e616a01",
  "url": "https://api.github.com/repos/github/gitignore/git/trees/be962308a6efb6d27446d13ee05b74948e616a01",
  "tree": [
%v
  ],
  "truncated": false
 }`

func TestGetFileNamesFromGitHubJSONNoTreeContents(t *testing.T) {
	assertReturnsExpectedFileNames(t, "", nil)
}

func TestGetFileNamesFromGitHubJSON(t *testing.T) {
	treeContents := `
    {
      "path": "Global/Vim.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "42e7afc100512b21af0a3339fe851d21e3ee4ed5",
      "size": 147,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/42e7afc100512b21af0a3339fe851d21e3ee4ed5"
    },
    {
      "path": "Go.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "a1338d68517ee2ad6ee11214b201e5958cb2bbc3",
      "size": 275,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/a1338d68517ee2ad6ee11214b201e5958cb2bbc3"
    }`
	assertReturnsExpectedFileNames(t, treeContents, []string{"Global/Vim.gitignore", "Go.gitignore"})
}

func TestGetFileNamesFromGitHubJSONIgnoresDirectories(t *testing.T) {
	treeContents := `
    {
      "path": ".github",
      "mode": "040000",
      "type": "tree",
      "sha": "0b994405766547cfaeaf5e45a176947336926c23",
      "url": "https://api.github.com/repos/github/gitignore/git/trees/0b994405766547cfaeaf5e45a176947336926c23"
    },
    {
      "path": "Global/Vim.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "42e7afc100512b21af0a3339fe851d21e3ee4ed5",
      "size": 147,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/42e7afc100512b21af0a3339fe851d21e3ee4ed5"
    },
    {
      "path": "Go.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "a1338d68517ee2ad6ee11214b201e5958cb2bbc3",
      "size": 275,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/a1338d68517ee2ad6ee11214b201e5958cb2bbc3"
    }`
	assertReturnsExpectedFileNames(t, treeContents, []string{"Global/Vim.gitignore", "Go.gitignore"})
}

func TestGetFileNamesFromGitHubJSONReturnsDecodeError(t *testing.T) {
	assertReturnsError(
		t,
		`}"path": "Go.gitignore", "type": "blob"`,
		"invalid character '}' looking for beginning of value")
}

func TestGetFileNamesFromGitHubJSONReturnsUnmarshallError(t *testing.T) {
	assertReturnsError(
		t,
		`{"path": "Go.gitignore", "type": 1}`,
		"json: cannot unmarshal number into Go struct field fileInfo.Type of type string")
}

func assertReturnsExpectedFileNames(t *testing.T, treeContents string, expectedFileNames []string) {
	contents := fmt.Sprintf(contentsBodyTemplate, treeContents)
	responseBody := strings.NewReader(contents)
	fileNames, _ := getFileNamesFromGitTreeJSON(responseBody)
	testutils.AssertDeepEqual(t, fileNames, expectedFileNames)
}

func assertReturnsError(t *testing.T, treeContents string, expectedErrorMessage string) {
	contents := fmt.Sprintf(contentsBodyTemplate, treeContents)
	responseBody := strings.NewReader(contents)
	_, err := getFileNamesFromGitTreeJSON(responseBody)
	testutils.AssertDeepEqual(t, err.Error(), expectedErrorMessage)
}

func TestFilterBySuffix(t *testing.T) {
	assertReturnsFilteredFileNames(t, nil, "", nil)
	assertReturnsFilteredFileNames(
		t,
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"},
		"",
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"})
	assertReturnsFilteredFileNames(
		t,
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"},
		".gitignore",
		[]string{"Global/Vim.gitignore", "Go.gitignore"})
}

func assertReturnsFilteredFileNames(t *testing.T, fileNames []string, suffix string, expectedFileNames []string) {
	testutils.AssertDeepEqual(t, filterBySuffix(fileNames, suffix), expectedFileNames)
}
<commit_msg>Fix tests broken after rename<commit_after>package list

import (
	"fmt"
	"strings"
	"testing"

	"github.com/gotgenes/getignore/testutils"
)

const contentsBodyTemplate = `{
  "sha": "be962308a6efb6d27446d13ee05b74948e616a01",
  "url": "https://api.github.com/repos/github/gitignore/git/trees/be962308a6efb6d27446d13ee05b74948e616a01",
  "tree": [
%v
  ],
  "truncated": false
 }`

func TestParseGitTreeToFileNamesNoTreeContents(t *testing.T) {
	assertReturnsExpectedFileNames(t, "", nil)
}

func TestParseGitTreeToFileNames(t *testing.T) {
	treeContents := `
    {
      "path": "Global/Vim.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "42e7afc100512b21af0a3339fe851d21e3ee4ed5",
      "size": 147,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/42e7afc100512b21af0a3339fe851d21e3ee4ed5"
    },
    {
      "path": "Go.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "a1338d68517ee2ad6ee11214b201e5958cb2bbc3",
      "size": 275,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/a1338d68517ee2ad6ee11214b201e5958cb2bbc3"
    }`
	assertReturnsExpectedFileNames(t, treeContents, []string{"Global/Vim.gitignore", "Go.gitignore"})
}

func TestParseGitTreeToFileNamesIgnoresDirectories(t *testing.T) {
	treeContents := `
    {
      "path": ".github",
      "mode": "040000",
      "type": "tree",
      "sha": "0b994405766547cfaeaf5e45a176947336926c23",
      "url": "https://api.github.com/repos/github/gitignore/git/trees/0b994405766547cfaeaf5e45a176947336926c23"
    },
    {
      "path": "Global/Vim.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "42e7afc100512b21af0a3339fe851d21e3ee4ed5",
      "size": 147,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/42e7afc100512b21af0a3339fe851d21e3ee4ed5"
    },
    {
      "path": "Go.gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "a1338d68517ee2ad6ee11214b201e5958cb2bbc3",
      "size": 275,
      "url": "https://api.github.com/repos/github/gitignore/git/blobs/a1338d68517ee2ad6ee11214b201e5958cb2bbc3"
    }`
	assertReturnsExpectedFileNames(t, treeContents, []string{"Global/Vim.gitignore", "Go.gitignore"})
}

func TestParseGitTreeToFileNamesReturnsDecodeError(t *testing.T) {
	assertReturnsError(
		t,
		`}"path": "Go.gitignore", "type": "blob"`,
		"invalid character '}' looking for beginning of value")
}

func TestParseGitTreeToFileNamesReturnsUnmarshallError(t *testing.T) {
	assertReturnsError(
		t,
		`{"path": "Go.gitignore", "type": 1}`,
		"json: cannot unmarshal number into Go struct field fileInfo.Type of type string")
}

func assertReturnsExpectedFileNames(t *testing.T, treeContents string, expectedFileNames []string) {
	contents := fmt.Sprintf(contentsBodyTemplate, treeContents)
	responseBody := strings.NewReader(contents)
	fileNames, _ := parseGitTreeToFileNames(responseBody)
	testutils.AssertDeepEqual(t, fileNames, expectedFileNames)
}

func assertReturnsError(t *testing.T, treeContents string, expectedErrorMessage string) {
	contents := fmt.Sprintf(contentsBodyTemplate, treeContents)
	responseBody := strings.NewReader(contents)
	_, err := parseGitTreeToFileNames(responseBody)
	testutils.AssertDeepEqual(t, err.Error(), expectedErrorMessage)
}

func TestFilterBySuffix(t *testing.T) {
	assertReturnsFilteredFileNames(t, nil, "", nil)
	assertReturnsFilteredFileNames(
		t,
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"},
		"",
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"})
	assertReturnsFilteredFileNames(
		t,
		[]string{"Foo", "Global/Vim.gitignore", "Go.gitignore", "Ignoreme"},
		".gitignore",
		[]string{"Global/Vim.gitignore", "Go.gitignore"})
}

func assertReturnsFilteredFileNames(t *testing.T, fileNames []string, suffix string, expectedFileNames []string) {
	testutils.AssertDeepEqual(t, filterBySuffix(fileNames, suffix), expectedFileNames)
}
<|endoftext|>