<commit_before>/*
Package zgok provides a simple library to create a single binary with asset files in Go (Golang).

Example:

	package main

	import (
		"net/http"
		"github.com/srtkkou/zgok"
		"os"
	)

	func main() {
		zfs, err := zgok.RestoreFileSystem(os.Args[0])
		if err != nil {
			panic(err)
		}
		assetServer := zfs.FileServer("web/public")
		http.Handle("/assets/", http.StripPrefix("/assets/", assetServer))
		http.ListenAndServe(":8080", nil)
	}
*/
package zgok

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	APP   = "zgok" // Application name.
	MAJOR = 0      // Major version.
	MINOR = 0      // Minor version.
	REV   = 1      // Revision.
)

// Get version string.
func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d", APP, MAJOR, MINOR, REV)
}

// File system interface.
// Implements [net/http.FileSystem]
type FileSystem interface {
	AddFile(file File)
	GetFile(path string) (File, error)
	ReadFile(path string) ([]byte, error)
	ReadFileString(path string) (string, error)
	Paths() []string
	SubFileSystem(rootPath string) (FileSystem, error)
	Signature() Signature
	SetSignature(signature Signature)
	String() string
	Open(name string) (http.File, error)     // Implements [net/http.FileSystem.Open]
	FileServer(basePath string) http.Handler // Get a static file server.
}

// Zgok file system.
type zgokFileSystem struct {
	signature Signature       // Zgok signature.
	rootPath  string          // Root path of the file system.
	fileMap   map[string]File // Map of files.
}

// Create a new file system.
func NewFileSystem() FileSystem {
	return &zgokFileSystem{
		signature: nil,
		rootPath:  APP,
		fileMap:   make(map[string]File),
	}
}

// Restore file system.
func RestoreFileSystem(path string) (FileSystem, error) {
	// Get bytes of exe file.
	exeBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	// Restore signature.
	sigOffset := len(exeBytes) - SIGNATURE_BYTE_SIZE
	sigBytes := exeBytes[sigOffset:]
	signature, err := RestoreSignature(sigBytes)
	if err != nil {
		return nil, err
	}
	// Unzip zip section.
	zipOffset := signature.ExeSize()
	zipBytes := exeBytes[zipOffset:sigOffset]
	unzipper := NewUnzipper(&zipBytes)
	zfs, err := unzipper.Unzip()
	if err != nil {
		return nil, err
	}
	// Set signature.
	zfs.SetSignature(signature)
	return zfs, nil
}

// Add file to file system.
func (zfs *zgokFileSystem) AddFile(file File) {
	key := filepath.ToSlash(file.Path())
	zfs.fileMap[key] = file
}

// Get file from file system.
func (zfs *zgokFileSystem) GetFile(path string) (File, error) {
	key := filepath.ToSlash(filepath.Join(zfs.rootPath, path))
	file, exists := zfs.fileMap[key]
	if !exists {
		return nil, errors.New("File doesn't exist.")
	}
	return file, nil
}

// Get the content of file in bytes from file system.
func (zfs *zgokFileSystem) ReadFile(path string) ([]byte, error) {
	file, err := zfs.GetFile(path)
	if err != nil {
		return []byte{}, nil
	}
	return file.Bytes(), nil
}

// Get the content of file in string from file system.
func (zfs *zgokFileSystem) ReadFileString(path string) (string, error) {
	bytes, err := zfs.ReadFile(path)
	if err != nil {
		return "", nil
	}
	str := string(bytes)
	return str, nil
}

// Get all the paths stored in the file system.
func (zfs *zgokFileSystem) Paths() []string {
	paths := []string{}
	prefix := zfs.rootPath + "/"
	for key := range zfs.fileMap {
		if strings.HasPrefix(key, prefix) {
			relPath := strings.TrimPrefix(key, prefix)
			paths = append(paths, relPath)
		}
	}
	sort.Strings(paths)
	return paths
}

// Get a sub file system.
func (zfs *zgokFileSystem) SubFileSystem(rootPath string) (FileSystem, error) {
	// Check root path.
	if strings.Contains(rootPath, "..") {
		return nil, errors.New("No double dots [..] are allowed in root path.")
	}
	// Initialize sub file system.
	newRootPath := filepath.ToSlash(filepath.Join(zfs.rootPath, rootPath))
	subFs := &zgokFileSystem{
		signature: zfs.signature,
		rootPath:  newRootPath,
		fileMap:   make(map[string]File),
	}
	// Add all the sets matching the new root path.
	for key, value := range zfs.fileMap {
		if key[0:len(newRootPath)] == newRootPath {
			subFs.fileMap[key] = value
		}
	}
	return subFs, nil
}

// Get signature.
func (zfs *zgokFileSystem) Signature() Signature {
	return zfs.signature
}

// Set signature.
func (zfs *zgokFileSystem) SetSignature(signature Signature) {
	zfs.signature = signature
}

// Get string.
func (zfs *zgokFileSystem) String() string {
	return zfs.Signature().String()
}

// Open the file.
// Implements [net/http.FileSystem.Open]
func (zfs *zgokFileSystem) Open(name string) (http.File, error) {
	path := strings.TrimLeft(name, "/")
	file, err := zfs.GetFile(path)
	if err != nil {
		// Return an abstract directory.
		dir := &zgokFile{
			fileInfo: zgokFileInfo{
				name: filepath.Base(path),
				mode: os.ModeDir | os.ModePerm,
			},
		}
		return dir, nil
	}
	// Set a new file reader
	file.SetNewReader()
	return file, nil
}

// File interface.
type File interface {
	SetPath(path string)                          // Set file path.
	Path() string                                 // Get file path.
	SetFileInfo(fileInfo os.FileInfo)             // Set file info.
	FileInfo() os.FileInfo                        // Get file info.
	SetBytes(content []byte)                      // Set content bytes.
	Bytes() []byte                                // Get content bytes.
	SetNewReader()                                // Set a new reader.
	Close() error                                 // Implements [net/http.File.Close]
	Read(p []byte) (int, error)                   // Implements [net/http.File.Read]
	Readdir(count int) ([]os.FileInfo, error)     // Implements [net/http.File.Readdir]
	Seek(offset int64, whence int) (int64, error) // Implements [net/http.File.Seek]
	Stat() (os.FileInfo, error)                   // Implements [net/http.File.Stat]
}

// Zgok file.
type zgokFile struct {
	path     string        // Path of the file.
	fileInfo os.FileInfo   // File info.
	content  []byte        // Content of the file.
	reader   *bytes.Reader // File reader.
}

// Create a new zgok file.
func NewZgokFile() File {
	return &zgokFile{}
}

// Set file path.
func (zf *zgokFile) SetPath(path string) {
	zf.path = strings.Replace(path, `\`, "/", -1)
}

// Get file path.
func (zf *zgokFile) Path() string {
	return zf.path
}

// Set file info.
func (zf *zgokFile) SetFileInfo(fileInfo os.FileInfo) {
	zf.fileInfo = fileInfo
}

// Get file info.
func (zf *zgokFile) FileInfo() os.FileInfo {
	return zf.fileInfo
}

// Set content bytes.
func (zf *zgokFile) SetBytes(content []byte) {
	zf.content = content
}

// Get content bytes.
func (zf *zgokFile) Bytes() []byte {
	return zf.content
}

// Set a new reader.
func (zf *zgokFile) SetNewReader() {
	reader := bytes.NewReader(zf.content)
	zf.reader = reader
}

// Close file.
// Implements [net/http.File.Close]
func (zf *zgokFile) Close() error {
	return nil
}

// Read file.
// Implements [net/http.File.Read]
func (zf *zgokFile) Read(p []byte) (int, error) {
	return zf.reader.Read(p)
}

// Read directories.
// Implements [net/http.File.Readdir]
func (zf *zgokFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("Readdir is not allowed.")
}

// Seek file.
// Implements [net/http.File.Seek]
func (zf *zgokFile) Seek(offset int64, whence int) (int64, error) {
	return zf.reader.Seek(offset, whence)
}

// Get file info.
// Implements [net/http.File.Stat]
func (zf *zgokFile) Stat() (os.FileInfo, error) {
	return zf.fileInfo, nil
}

// Zgok file info.
// Implements [os.FileInfo]
type zgokFileInfo struct {
	name    string      // File name.
	size    int64       // Size of the file.
	mode    os.FileMode // File mode.
	modTime time.Time   // Modified time of the file.
}

// Get name.
// Implements [os.FileInfo.Name]
func (i zgokFileInfo) Name() string {
	return i.name
}

// Get size.
// Implements [os.FileInfo.Size]
func (i zgokFileInfo) Size() int64 {
	return i.size
}

// Get mode.
// Implements [os.FileInfo.Mode]
func (i zgokFileInfo) Mode() os.FileMode {
	return i.mode
}

// Get modified time.
// Implements [os.FileInfo.ModTime]
func (i zgokFileInfo) ModTime() time.Time {
	return i.modTime
}

// Check if it is a directory.
// Implements [os.FileInfo.IsDir]
func (i zgokFileInfo) IsDir() bool {
	return i.mode.IsDir()
}

// Get sys information. (Only returns nil.)
// Implements [os.FileInfo.Sys]
func (i zgokFileInfo) Sys() interface{} {
	return nil
}
<commit_msg>[BugFix] Fixed bug in zgok that zfs.ReadFile/ReadFileString was returning nil even on error.<commit_after>/*
Package zgok provides a simple library to create a single binary with asset files in Go (Golang).

Example:

	package main

	import (
		"net/http"
		"github.com/srtkkou/zgok"
		"os"
	)

	func main() {
		zfs, err := zgok.RestoreFileSystem(os.Args[0])
		if err != nil {
			panic(err)
		}
		assetServer := zfs.FileServer("web/public")
		http.Handle("/assets/", http.StripPrefix("/assets/", assetServer))
		http.ListenAndServe(":8080", nil)
	}
*/
package zgok

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	APP   = "zgok" // Application name.
	MAJOR = 0      // Major version.
	MINOR = 0      // Minor version.
	REV   = 1      // Revision.
)

// Get version string.
func Version() string {
	return fmt.Sprintf("%s-%d.%d.%d", APP, MAJOR, MINOR, REV)
}

// File system interface.
// Implements [net/http.FileSystem]
type FileSystem interface {
	AddFile(file File)
	GetFile(path string) (File, error)
	ReadFile(path string) ([]byte, error)
	ReadFileString(path string) (string, error)
	Paths() []string
	SubFileSystem(rootPath string) (FileSystem, error)
	Signature() Signature
	SetSignature(signature Signature)
	String() string
	Open(name string) (http.File, error)     // Implements [net/http.FileSystem.Open]
	FileServer(basePath string) http.Handler // Get a static file server.
}

// Zgok file system.
type zgokFileSystem struct {
	signature Signature       // Zgok signature.
	rootPath  string          // Root path of the file system.
	fileMap   map[string]File // Map of files.
}

// Create a new file system.
func NewFileSystem() FileSystem {
	return &zgokFileSystem{
		signature: nil,
		rootPath:  APP,
		fileMap:   make(map[string]File),
	}
}

// Restore file system.
func RestoreFileSystem(path string) (FileSystem, error) {
	// Get bytes of exe file.
	exeBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	// Restore signature.
	sigOffset := len(exeBytes) - SIGNATURE_BYTE_SIZE
	sigBytes := exeBytes[sigOffset:]
	signature, err := RestoreSignature(sigBytes)
	if err != nil {
		return nil, err
	}
	// Unzip zip section.
	zipOffset := signature.ExeSize()
	zipBytes := exeBytes[zipOffset:sigOffset]
	unzipper := NewUnzipper(&zipBytes)
	zfs, err := unzipper.Unzip()
	if err != nil {
		return nil, err
	}
	// Set signature.
	zfs.SetSignature(signature)
	return zfs, nil
}

// Add file to file system.
func (zfs *zgokFileSystem) AddFile(file File) {
	key := filepath.ToSlash(file.Path())
	zfs.fileMap[key] = file
}

// Get file from file system.
func (zfs *zgokFileSystem) GetFile(path string) (File, error) {
	key := filepath.ToSlash(filepath.Join(zfs.rootPath, path))
	file, exists := zfs.fileMap[key]
	if !exists {
		return nil, errors.New("File doesn't exist.")
	}
	return file, nil
}

// Get the content of file in bytes from file system.
func (zfs *zgokFileSystem) ReadFile(path string) ([]byte, error) {
	file, err := zfs.GetFile(path)
	if err != nil {
		return []byte{}, err
	}
	return file.Bytes(), nil
}

// Get the content of file in string from file system.
func (zfs *zgokFileSystem) ReadFileString(path string) (string, error) {
	bytes, err := zfs.ReadFile(path)
	if err != nil {
		return "", err
	}
	str := string(bytes)
	return str, nil
}

// Get all the paths stored in the file system.
func (zfs *zgokFileSystem) Paths() []string {
	paths := []string{}
	prefix := zfs.rootPath + "/"
	for key := range zfs.fileMap {
		if strings.HasPrefix(key, prefix) {
			relPath := strings.TrimPrefix(key, prefix)
			paths = append(paths, relPath)
		}
	}
	sort.Strings(paths)
	return paths
}

// Get a sub file system.
func (zfs *zgokFileSystem) SubFileSystem(rootPath string) (FileSystem, error) {
	// Check root path.
	if strings.Contains(rootPath, "..") {
		return nil, errors.New("No double dots [..] are allowed in root path.")
	}
	// Initialize sub file system.
	newRootPath := filepath.ToSlash(filepath.Join(zfs.rootPath, rootPath))
	subFs := &zgokFileSystem{
		signature: zfs.signature,
		rootPath:  newRootPath,
		fileMap:   make(map[string]File),
	}
	// Add all the sets matching the new root path.
	for key, value := range zfs.fileMap {
		if key[0:len(newRootPath)] == newRootPath {
			subFs.fileMap[key] = value
		}
	}
	return subFs, nil
}

// Get signature.
func (zfs *zgokFileSystem) Signature() Signature {
	return zfs.signature
}

// Set signature.
func (zfs *zgokFileSystem) SetSignature(signature Signature) {
	zfs.signature = signature
}

// Get string.
func (zfs *zgokFileSystem) String() string {
	return zfs.Signature().String()
}

// Open the file.
// Implements [net/http.FileSystem.Open]
func (zfs *zgokFileSystem) Open(name string) (http.File, error) {
	path := strings.TrimLeft(name, "/")
	file, err := zfs.GetFile(path)
	if err != nil {
		// Return an abstract directory.
		dir := &zgokFile{
			fileInfo: zgokFileInfo{
				name: filepath.Base(path),
				mode: os.ModeDir | os.ModePerm,
			},
		}
		return dir, nil
	}
	// Set a new file reader
	file.SetNewReader()
	return file, nil
}

// File interface.
type File interface {
	SetPath(path string)                          // Set file path.
	Path() string                                 // Get file path.
	SetFileInfo(fileInfo os.FileInfo)             // Set file info.
	FileInfo() os.FileInfo                        // Get file info.
	SetBytes(content []byte)                      // Set content bytes.
	Bytes() []byte                                // Get content bytes.
	SetNewReader()                                // Set a new reader.
	Close() error                                 // Implements [net/http.File.Close]
	Read(p []byte) (int, error)                   // Implements [net/http.File.Read]
	Readdir(count int) ([]os.FileInfo, error)     // Implements [net/http.File.Readdir]
	Seek(offset int64, whence int) (int64, error) // Implements [net/http.File.Seek]
	Stat() (os.FileInfo, error)                   // Implements [net/http.File.Stat]
}

// Zgok file.
type zgokFile struct {
	path     string        // Path of the file.
	fileInfo os.FileInfo   // File info.
	content  []byte        // Content of the file.
	reader   *bytes.Reader // File reader.
}

// Create a new zgok file.
func NewZgokFile() File {
	return &zgokFile{}
}

// Set file path.
func (zf *zgokFile) SetPath(path string) {
	zf.path = strings.Replace(path, `\`, "/", -1)
}

// Get file path.
func (zf *zgokFile) Path() string {
	return zf.path
}

// Set file info.
func (zf *zgokFile) SetFileInfo(fileInfo os.FileInfo) {
	zf.fileInfo = fileInfo
}

// Get file info.
func (zf *zgokFile) FileInfo() os.FileInfo {
	return zf.fileInfo
}

// Set content bytes.
func (zf *zgokFile) SetBytes(content []byte) {
	zf.content = content
}

// Get content bytes.
func (zf *zgokFile) Bytes() []byte {
	return zf.content
}

// Set a new reader.
func (zf *zgokFile) SetNewReader() {
	reader := bytes.NewReader(zf.content)
	zf.reader = reader
}

// Close file.
// Implements [net/http.File.Close]
func (zf *zgokFile) Close() error {
	return nil
}

// Read file.
// Implements [net/http.File.Read]
func (zf *zgokFile) Read(p []byte) (int, error) {
	return zf.reader.Read(p)
}

// Read directories.
// Implements [net/http.File.Readdir]
func (zf *zgokFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, errors.New("Readdir is not allowed.")
}

// Seek file.
// Implements [net/http.File.Seek]
func (zf *zgokFile) Seek(offset int64, whence int) (int64, error) {
	return zf.reader.Seek(offset, whence)
}

// Get file info.
// Implements [net/http.File.Stat]
func (zf *zgokFile) Stat() (os.FileInfo, error) {
	return zf.fileInfo, nil
}

// Zgok file info.
// Implements [os.FileInfo]
type zgokFileInfo struct {
	name    string      // File name.
	size    int64       // Size of the file.
	mode    os.FileMode // File mode.
	modTime time.Time   // Modified time of the file.
}

// Get name.
// Implements [os.FileInfo.Name]
func (i zgokFileInfo) Name() string {
	return i.name
}

// Get size.
// Implements [os.FileInfo.Size]
func (i zgokFileInfo) Size() int64 {
	return i.size
}

// Get mode.
// Implements [os.FileInfo.Mode]
func (i zgokFileInfo) Mode() os.FileMode {
	return i.mode
}

// Get modified time.
// Implements [os.FileInfo.ModTime]
func (i zgokFileInfo) ModTime() time.Time {
	return i.modTime
}

// Check if it is a directory.
// Implements [os.FileInfo.IsDir]
func (i zgokFileInfo) IsDir() bool {
	return i.mode.IsDir()
}

// Get sys information. (Only returns nil.)
// Implements [os.FileInfo.Sys]
func (i zgokFileInfo) Sys() interface{} {
	return nil
}
<|endoftext|>


<commit_before>package dns

// A structure for handling zone data

import (
	"github.com/miekg/radix"
)

type Zone struct {
	Name         string // Name of the zone
	*radix.Radix        // Zone data
}

type ZoneData struct {
	Name       string          // Domain name for this node
	RR         map[uint16][]RR // Map of the RR type to the RR
	Signatures []*RR_RRSIG     // DNSSEC signatures
	Glue       bool            // True if the A and AAAA record are glue
}

// New ...
func New(name string) *Zone {
	z := new(Zone)
	z.Name = name
	z.Radix = radix.New()
	return z
}

func (z *Zone) Insert(r RR) {
	zd := z.Radix.Find(r.Header().Name)
	if zd == nil {
		zd := new(ZoneData)
		zd.Name = r.Header().Name
		switch t := r.Header().Rrtype; t {
		case TypeRRSIG:
			zd.Signatures = append(zd.Signatures, r.(*RR_RRSIG))
		default:
			zd.RR[t] = append(zd.RR[t], r)
		}
		z.Radix.Insert(r.Header().Name, zd)
		return
	}
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		zd.(*ZoneData).Signatures = append(zd.(*ZoneData).Signatures, r.(*RR_RRSIG))
	default:
		zd.(*ZoneData).RR[t] = append(zd.(*ZoneData).RR[t], r)
	}
	// TODO(mg): Glue
	return
}

func (z *Zone) Remove(r RR) {

}
<commit_msg>initialize better<commit_after>package dns

// A structure for handling zone data

import (
	"github.com/miekg/radix"
)

type Zone struct {
	Name         string // Name of the zone
	*radix.Radix        // Zone data
}

type ZoneData struct {
	Name       string          // Domain name for this node
	RR         map[uint16][]RR // Map of the RR type to the RR
	Signatures []*RR_RRSIG     // DNSSEC signatures
	Glue       bool            // True if the A and AAAA record are glue
}

// New ...
func NewZone(name string) *Zone {
	z := new(Zone)
	z.Name = name
	z.Radix = radix.New()
	return z
}

func (z *Zone) Insert(r RR) {
	zd := z.Radix.Find(r.Header().Name)
	if zd == nil {
		zd := new(ZoneData)
		zd.Name = r.Header().Name
		zd.RR = make(map[uint16][]RR)
		zd.Signatures = make([]*RR_RRSIG, 0)
		switch t := r.Header().Rrtype; t {
		case TypeRRSIG:
			zd.Signatures = append(zd.Signatures, r.(*RR_RRSIG))
		default:
			zd.RR[t] = append(zd.RR[t], r)
		}
		z.Radix.Insert(r.Header().Name, zd)
		return
	}
	switch t := r.Header().Rrtype; t {
	case TypeRRSIG:
		zd.(*ZoneData).Signatures = append(zd.(*ZoneData).Signatures, r.(*RR_RRSIG))
	default:
		zd.(*ZoneData).RR[t] = append(zd.(*ZoneData).RR[t], r)
	}
	// TODO(mg): Glue
	return
}

func (z *Zone) Remove(r RR) {

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"strconv"
	"strings"

	"github.com/jmhodges/levigo"
)

/* Keys stored in LevelDB for zsets
 *
 * MetadataKey | key = ZCardValue | count of members uint32
 *
 * For each member:
 * ZSetKey   | key length uint32 | key | member = score float64
 * ZScoreKey | key length uint32 | key | score float64 | member = empty
 */

func Zadd(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	if (len(args)-1)%2 != 0 {
		return fmt.Errorf("wrong number of arguments for 'zadd' command")
	}
	return zadd(args, wb, false)
}

func Zincrby(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zadd(args, wb, true)
}

func zadd(args [][]byte, wb *levigo.WriteBatch, incr bool) cmdReply {
	var newMembers uint32
	var score float64
	scoreBytes := make([]byte, 8)

	// Iterate through each of the score/member pairs
	for i := 1; i < len(args); i += 2 {
		var err error
		score, err = strconv.ParseFloat(string(args[i]), 64)
		if err != nil {
			return fmt.Errorf("'%s' is not a valid float", string(args[1]))
		}

		// Check if the member exists
		setKey := zsetKey(args[0], args[i+1])
		res, err := DB.Get(DefaultReadOptions, setKey)
		if err != nil {
			return err
		}

		if res != nil { // We got a score from the db, so the member already exists
			if len(res) != 8 {
				return InvalidDataError
			}
			actualScore := math.Float64frombits(binary.BigEndian.Uint64(res))
			if incr { // this is a ZINCRBY, so increment the score
				score += actualScore
			}
			if score == actualScore { // Member already exists with the same score, do nothing
				continue
			}

			// Delete score key for member
			wb.Delete(zscoreKey(args[0], args[i+1], actualScore))
		} else { // No score found, we're adding a new member
			newMembers++
		}

		// Store the set and score keys
		binary.BigEndian.PutUint64(scoreBytes, math.Float64bits(score))
		wb.Put(setKey, scoreBytes)
		wb.Put(zscoreKey(args[0], args[i+1], score), []byte{}) // The score key is only used for sorting, the value is empty
	}

	// Update the set metadata with the new cardinality
	if newMembers > 0 {
		card, err := zcard(args[0])
		if err != nil {
			return err
		}
		res := make([]byte, 5)
		res[0] = ZCardValue

		// Increment the cardinality
		binary.BigEndian.PutUint32(res[1:], card+newMembers)
		wb.Put(metaKey(args[0]), res)
	}

	if incr { // This is a ZINCRBY, return the new score
		return ftoa(score)
	}
	return newMembers
}

func Zscore(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	res, err := DB.Get(DefaultReadOptions, zsetKey(args[0], args[1]))
	if err != nil {
		return err
	}
	if res == nil {
		return nil
	}
	if len(res) != 8 {
		return InvalidDataError
	}

	return ftoa(btof(res))
}

func Zcard(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	c, err := zcard(args[0])
	if err != nil {
		return err
	}
	return c
}

func zcard(key []byte) (uint32, error) {
	res, err := DB.Get(DefaultReadOptions, metaKey(key))
	if err != nil {
		return 0, err
	}
	if res == nil {
		return 0, nil
	}
	if len(res) > 0 && res[0] != ZCardValue {
		return 0, InvalidKeyTypeError
	}
	if len(res) < 5 {
		return 0, InvalidDataError
	}
	return binary.BigEndian.Uint32(res[1:]), nil
}

func Zrem(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	card, err := zcard(args[0])
	if err != nil {
		return err
	}
	if card == 0 {
		return 0
	}

	var deleted uint32
	// Delete each of the members
	for _, member := range args[1:] {
		setKey := zsetKey(args[0], member)
		res, err := DB.Get(DefaultReadOptions, setKey)
		if err != nil {
			return nil
		}
		if res == nil {
			continue
		}
		if len(res) != 8 {
			return InvalidDataError
		}

		score := btof(res)
		wb.Delete(setKey)
		wb.Delete(zscoreKey(args[0], member, score))
		deleted++
	}
	if deleted == card { // We deleted all of the members, so delete the meta key
		wb.Delete(metaKey(args[0]))
	} else if deleted > 0 { // Decrement the cardinality
		data := make([]byte, 5)
		data[0] = ZCardValue

		// Increment the cardinality
		binary.BigEndian.PutUint32(data[1:], card-deleted)
		wb.Put(metaKey(args[0]), data)
	}

	return deleted
}

func Zrange(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zrange(args, false)
}

func Zrevrange(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zrange(args, true)
}

func zrange(args [][]byte, reverse bool) cmdReply {
	count, err := zcard(args[0])
	if err != nil {
		return err
	}
	if count == 0 {
		return []cmdReply{}
	}

	start, err := strconv.ParseInt(string(args[1]), 10, 64)
	end, err2 := strconv.ParseInt(string(args[2]), 10, 64)
	if err != nil || err2 != nil {
		return fmt.Errorf("value is not an integer or out of range")
	}

	// if the index is negative, it is counting from the end,
	// so add it to the length to get the absolute index
	if start < 0 {
		start += int64(count)
	}
	if end < 0 {
		end += int64(count)
	}

	if end > int64(count) { // limit the end to the last member
		end = int64(count) - 1
	}
	// the start comes after the end, so we're not going to find anything
	if start > end {
		return []cmdReply{}
	}

	var withscores bool
	items := end + 1 - start
	if len(args) >= 4 {
		if strings.ToLower(string(args[3])) != "withscores" || len(args) > 4 {
			return SyntaxError
		}
		withscores = true
		items *= 2
	}
	res := make([]cmdReply, 0, items)

	it := DB.NewIterator(DefaultReadOptions)
	defer it.Close()

	var i int64
	iterKey := zscoreIterKey(args[0])
	if reverse {
		iterKey = lastIterKey(iterKey)
	}
	for it.Seek(iterKey); it.Valid() && i <= end; i++ {
		if reverse {
			it.Prev()
		}
		if i >= start {
			score, member := parseZscoreKey(it.Key(), len(args[0]))
			res = append(res, member)
			if withscores {
				res = append(res, ftoa(score))
			}
		}
		if !reverse {
			it.Next()
		}
	}

	return res
}

func DelZset(key []byte, wb *levigo.WriteBatch) {
	// TODO: count keys to verify everything works as expected?
	it := DB.NewIterator(DefaultReadOptions)
	defer it.Close()
	iterKey := zsetIterKey(key)
	for it.Seek(iterKey); it.Valid(); it.Next() {
		k, v := it.Key(), it.Value()
		// If the prefix of the current key doesn't match the iteration key,
		// we have reached the end of the zset
		if !bytes.Equal(iterKey, k[:len(iterKey)]) {
			break
		}
		wb.Delete(k)
		wb.Delete(zscoreKey(key, k[len(iterKey):], btof(v)))
	}
}

// ZSetKey | key length uint32 | key | member
func zsetKey(k, member []byte) []byte {
	key := make([]byte, 5+len(k)+len(member))
	key[0] = ZSetKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	copy(key[5+len(k):], member)
	return key
}

// zsetKey without the member
func zsetIterKey(k []byte) []byte {
	key := make([]byte, 5+len(k))
	key[0] = ZSetKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	return key
}

// ZScoreKey | key length uint32 | key | score float64 | member
func zscoreKey(k, member []byte, score float64) []byte {
	key := make([]byte, 13+len(k)+len(member))
	key[0] = ZScoreKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	writeByteSortableFloat(key[5+len(k):], score)
	copy(key[13+len(k):], member)
	return key
}

// zscoreKey without the score or member
func zscoreIterKey(k []byte) []byte {
	key := make([]byte, 5+len(k))
	key[0] = ZScoreKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	return key
}

func parseZscoreKey(b []byte, keyLen int) (float64, []byte) {
	return readByteSortableFloat(b[keyLen+5:]), b[keyLen+13:]
}

func btof(b []byte) float64 {
	return math.Float64frombits(binary.BigEndian.Uint64(b))
}

func ftoa(f float64) []byte {
	b := []byte(strconv.FormatFloat(f, 'g', -1, 64))
	if len(b) > 1 && b[1] == 'I' { // -Inf/+Inf to lowercase
		b[1] = 'i'
	}
	if b[0] == 'N' { // NaN to lowercase
		b[0], b[2] = 'n', 'n'
	}
	if b[0] == '+' { // +inf to inf
		b = b[1:]
	}

	return b
}

// To get a key that will sort *after* the given prefix, we increment the last
// byte that is not 0xff and return a new byte slice truncated after the byte
// that was incremented
func lastIterKey(k []byte) []byte {
	for i := len(k) - 1; i >= 0; i-- {
		if k[i] == 0xff {
			continue
		}
		k[i] += 1
		return k[:i+1]
	}
	panic("not reached")
}

/* Natural sorting of floating point numbers
 *
 * ENCODING
 * If the number is positive, flip the sign (first bit to 1)
 * Else the number is negative, flip all the bits
 *
 * DECODING
 * If the first byte is >= 0x80 (0b10000000), decode float, flip the sign
 * Else flip all the bits, decode float
 */

func writeByteSortableFloat(b []byte, f float64) {
	if math.Signbit(f) {
		binary.BigEndian.PutUint64(b, math.Float64bits(f))
		for i, v := range b[:8] {
			b[i] = v ^ 255
		}
	} else {
		binary.BigEndian.PutUint64(b, math.Float64bits(-f))
	}
}

func readByteSortableFloat(b []byte) float64 {
	if b[0] < 0x80 {
		for i, v := range b[:8] {
			b[i] = v ^ 255
		}
		return math.Float64frombits(binary.BigEndian.Uint64(b))
	}
	return -math.Float64frombits(binary.BigEndian.Uint64(b))
}

// ZCOUNT
// ZINTERSTORE
// ZUNIONSTORE
// ZREVRANGEBYSCORE
// ZRANGEBYSCORE
// ZRANK
// ZREMRANGEBYRANK
// ZREMRANGEBYSCORE
// ZREVRANK
<commit_msg>Simplify withscores flag<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"strconv"

	"github.com/jmhodges/levigo"
)

/* Keys stored in LevelDB for zsets
 *
 * MetadataKey | key = ZCardValue | count of members uint32
 *
 * For each member:
 * ZSetKey   | key length uint32 | key | member = score float64
 * ZScoreKey | key length uint32 | key | score float64 | member = empty
 */

func Zadd(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	if (len(args)-1)%2 != 0 {
		return fmt.Errorf("wrong number of arguments for 'zadd' command")
	}
	return zadd(args, wb, false)
}

func Zincrby(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zadd(args, wb, true)
}

func zadd(args [][]byte, wb *levigo.WriteBatch, incr bool) cmdReply {
	var newMembers uint32
	var score float64
	scoreBytes := make([]byte, 8)

	// Iterate through each of the score/member pairs
	for i := 1; i < len(args); i += 2 {
		var err error
		score, err = strconv.ParseFloat(string(args[i]), 64)
		if err != nil {
			return fmt.Errorf("'%s' is not a valid float", string(args[1]))
		}

		// Check if the member exists
		setKey := zsetKey(args[0], args[i+1])
		res, err := DB.Get(DefaultReadOptions, setKey)
		if err != nil {
			return err
		}

		if res != nil { // We got a score from the db, so the member already exists
			if len(res) != 8 {
				return InvalidDataError
			}
			actualScore := math.Float64frombits(binary.BigEndian.Uint64(res))
			if incr { // this is a ZINCRBY, so increment the score
				score += actualScore
			}
			if score == actualScore { // Member already exists with the same score, do nothing
				continue
			}

			// Delete score key for member
			wb.Delete(zscoreKey(args[0], args[i+1], actualScore))
		} else { // No score found, we're adding a new member
			newMembers++
		}

		// Store the set and score keys
		binary.BigEndian.PutUint64(scoreBytes, math.Float64bits(score))
		wb.Put(setKey, scoreBytes)
		wb.Put(zscoreKey(args[0], args[i+1], score), []byte{}) // The score key is only used for sorting, the value is empty
	}

	// Update the set metadata with the new cardinality
	if newMembers > 0 {
		card, err := zcard(args[0])
		if err != nil {
			return err
		}
		res := make([]byte, 5)
		res[0] = ZCardValue

		// Increment the cardinality
		binary.BigEndian.PutUint32(res[1:], card+newMembers)
		wb.Put(metaKey(args[0]), res)
	}

	if incr { // This is a ZINCRBY, return the new score
		return ftoa(score)
	}
	return newMembers
}

func Zscore(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	res, err := DB.Get(DefaultReadOptions, zsetKey(args[0], args[1]))
	if err != nil {
		return err
	}
	if res == nil {
		return nil
	}
	if len(res) != 8 {
		return InvalidDataError
	}

	return ftoa(btof(res))
}

func Zcard(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	c, err := zcard(args[0])
	if err != nil {
		return err
	}
	return c
}

func zcard(key []byte) (uint32, error) {
	res, err := DB.Get(DefaultReadOptions, metaKey(key))
	if err != nil {
		return 0, err
	}
	if res == nil {
		return 0, nil
	}
	if len(res) > 0 && res[0] != ZCardValue {
		return 0, InvalidKeyTypeError
	}
	if len(res) < 5 {
		return 0, InvalidDataError
	}
	return binary.BigEndian.Uint32(res[1:]), nil
}

func Zrem(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	card, err := zcard(args[0])
	if err != nil {
		return err
	}
	if card == 0 {
		return 0
	}

	var deleted uint32
	// Delete each of the members
	for _, member := range args[1:] {
		setKey := zsetKey(args[0], member)
		res, err := DB.Get(DefaultReadOptions, setKey)
		if err != nil {
			return nil
		}
		if res == nil {
			continue
		}
		if len(res) != 8 {
			return InvalidDataError
		}

		score := btof(res)
		wb.Delete(setKey)
		wb.Delete(zscoreKey(args[0], member, score))
		deleted++
	}
	if deleted == card { // We deleted all of the members, so delete the meta key
		wb.Delete(metaKey(args[0]))
	} else if deleted > 0 { // Decrement the cardinality
		data := make([]byte, 5)
		data[0] = ZCardValue

		// Increment the cardinality
		binary.BigEndian.PutUint32(data[1:], card-deleted)
		wb.Put(metaKey(args[0]), data)
	}

	return deleted
}

func Zrange(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zrange(args, false)
}

func Zrevrange(args [][]byte, wb *levigo.WriteBatch) cmdReply {
	return zrange(args, true)
}

func zrange(args [][]byte, reverse bool) cmdReply {
	count, err := zcard(args[0])
	if err != nil {
		return err
	}
	if count == 0 {
		return []cmdReply{}
	}

	start, err := strconv.ParseInt(string(args[1]), 10, 64)
	end, err2 := strconv.ParseInt(string(args[2]), 10, 64)
	if err != nil || err2 != nil {
		return fmt.Errorf("value is not an integer or out of range")
	}

	// if the index is negative, it is counting from the end,
	// so add it to the length to get the absolute index
	if start < 0 {
		start += int64(count)
	}
	if end < 0 {
		end += int64(count)
	}

	if end > int64(count) { // limit the end to the last member
		end = int64(count) - 1
	}
	// the start comes after the end, so we're not going to find anything
	if start > end {
		return []cmdReply{}
	}

	var withscores bool
	items := end + 1 - start
	if len(args) >= 4 {
		if len(args[3]) != 10 || len(args) > 4 { // withscores flag
			return SyntaxError
		}
		withscores = true
		items *= 2
	}
	res := make([]cmdReply, 0, items)

	it := DB.NewIterator(DefaultReadOptions)
	defer it.Close()

	var i int64
	iterKey := zscoreIterKey(args[0])
	if reverse {
		iterKey = lastIterKey(iterKey)
	}
	for it.Seek(iterKey); it.Valid() && i <= end; i++ {
		if reverse {
			it.Prev()
		}
		if i >= start {
			score, member := parseZscoreKey(it.Key(), len(args[0]))
			res = append(res, member)
			if withscores {
				res = append(res, ftoa(score))
			}
		}
		if !reverse {
			it.Next()
		}
	}

	return res
}

func DelZset(key []byte, wb *levigo.WriteBatch) {
	// TODO: count keys to verify everything works as expected?
	it := DB.NewIterator(DefaultReadOptions)
	defer it.Close()
	iterKey := zsetIterKey(key)
	for it.Seek(iterKey); it.Valid(); it.Next() {
		k, v := it.Key(), it.Value()
		// If the prefix of the current key doesn't match the iteration key,
		// we have reached the end of the zset
		if !bytes.Equal(iterKey, k[:len(iterKey)]) {
			break
		}
		wb.Delete(k)
		wb.Delete(zscoreKey(key, k[len(iterKey):], btof(v)))
	}
}

// ZSetKey | key length uint32 | key | member
func zsetKey(k, member []byte) []byte {
	key := make([]byte, 5+len(k)+len(member))
	key[0] = ZSetKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	copy(key[5+len(k):], member)
	return key
}

// zsetKey without the member
func zsetIterKey(k []byte) []byte {
	key := make([]byte, 5+len(k))
	key[0] = ZSetKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	return key
}

// ZScoreKey | key length uint32 | key | score float64 | member
func zscoreKey(k, member []byte, score float64) []byte {
	key := make([]byte, 13+len(k)+len(member))
	key[0] = ZScoreKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	writeByteSortableFloat(key[5+len(k):], score)
	copy(key[13+len(k):], member)
	return key
}

// zscoreKey without the score or member
func zscoreIterKey(k []byte) []byte {
	key := make([]byte, 5+len(k))
	key[0] = ZScoreKey
	binary.BigEndian.PutUint32(key[1:], uint32(len(k)))
	copy(key[5:], k)
	return key
}

func parseZscoreKey(b []byte, keyLen int) (float64, []byte) {
	return readByteSortableFloat(b[keyLen+5:]), b[keyLen+13:]
}

func btof(b []byte) float64 {
	return math.Float64frombits(binary.BigEndian.Uint64(b))
}

func ftoa(f float64) []byte {
	b := []byte(strconv.FormatFloat(f, 'g', -1, 64))
	if len(b) > 1 && b[1] == 'I' { // -Inf/+Inf to lowercase
		b[1] = 'i'
	}
	if b[0] == 'N' { // NaN to lowercase
		b[0], b[2] = 'n', 'n'
	}
	if b[0] == '+' { // +inf to inf
		b = b[1:]
	}

	return b
}

// To get a key that will sort *after* the given prefix, we increment the last
// byte that is not 0xff and return a new byte slice truncated after the byte
// that was incremented
func lastIterKey(k []byte) []byte {
	for i := len(k) - 1; i >= 0; i-- {
		if k[i] == 0xff {
			continue
		}
		k[i] += 1
		return k[:i+1]
	}
	panic("not reached")
}

/* Natural sorting of floating point numbers
 *
 * ENCODING
 * If the number is positive, flip the sign (first bit to 1)
 * Else the number is negative, flip all the bits
 *
 * DECODING
 * If the first byte is >= 0x80 (0b10000000), decode float, flip the sign
 * Else flip all the bits, decode float
 */

func writeByteSortableFloat(b []byte, f float64) {
	if math.Signbit(f) {
		binary.BigEndian.PutUint64(b, math.Float64bits(f))
		for i, v := range b[:8] {
			b[i] = v ^ 255
		}
	} else {
		binary.BigEndian.PutUint64(b, math.Float64bits(-f))
	}
}

func readByteSortableFloat(b []byte) float64 {
	if b[0] < 0x80 {
		for i, v := range b[:8] {
			b[i] = v ^ 255
		}
		return math.Float64frombits(binary.BigEndian.Uint64(b))
	}
	return -math.Float64frombits(binary.BigEndian.Uint64(b))
}

// ZCOUNT
// ZINTERSTORE
// ZUNIONSTORE
// ZREVRANGEBYSCORE
// ZRANGEBYSCORE
// ZRANK
// ZREMRANGEBYRANK
// ZREMRANGEBYSCORE
// ZREVRANK
<|endoftext|>


<commit_before>package empire // import "github.com/remind101/empire/empire"

import (
	"net/url"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/mattes/migrate/migrate"
	"github.com/remind101/empire/empire/pkg/container"
)

// A function to return the current time. It can be useful to stub this out in
// tests.
var Now = func() time.Time {
	return time.Now().UTC()
}

// DefaultOptions is a default Options instance that can be passed when
// intializing a new Empire.
var DefaultOptions = Options{}

// DockerOptions is a set of options to configure a docker api client.
type DockerOptions struct {
	// The default docker organization to use.
	Organization string

	// The unix socket to connect to the docker api.
	Socket string

	// Path to a certificate to use for TLS connections.
	CertPath string

	// A set of docker registry credentials.
	Auth *docker.AuthConfigurations
}

// FleetOptions is a set of options to configure a fleet api client.
type FleetOptions struct {
	// The location of the fleet api.
	API string
}

// Options is provided to New to configure the Empire services.
type Options struct {
	Docker DockerOptions
	Fleet  FleetOptions

	Secret string

	// Database connection string.
	DB string
}

// Empire is a context object that contains a collection of services.
type Empire struct {
	*Store

	*AccessTokensService
	*AppsService
	*ConfigsService
	DeploysService
	*JobsService
	*JobStatesService
	*Manager
	*ReleasesService
	*SlugsService
}

// New returns a new Empire instance.
func New(options Options) (*Empire, error) {
	db, err := newDB(options.DB)
	if err != nil {
		return nil, err
	}

	store := &Store{db: db}

	scheduler, err := newScheduler(options.Fleet.API)
	if err != nil {
		return nil, err
	}

	extractor, err := NewExtractor(
		options.Docker.Socket,
		options.Docker.CertPath,
		options.Docker.Auth,
	)
	if err != nil {
		return nil, err
	}

	accessTokens := &AccessTokensService{
		Secret: []byte(options.Secret),
	}

	configs := &ConfigsService{
		store: store,
	}

	jobs := &JobsService{
		store:     store,
		scheduler: scheduler,
	}

	jobStates := &JobStatesService{
		store:     store,
		scheduler: scheduler,
	}

	apps := &AppsService{
		store:       store,
		JobsService: jobs,
	}

	manager := &Manager{
		JobsService: jobs,
		store:       store,
	}

	releases := &ReleasesService{
		store:   store,
		manager: manager,
	}

	slugs := &SlugsService{
		store:     store,
		extractor: extractor,
	}

	imageDeployer := &imageDeployer{
		AppsService:     apps,
		ConfigsService:  configs,
		SlugsService:    slugs,
		ReleasesService: releases,
	}

	commitDeployer := &commitDeployer{
		Organization:  options.Docker.Organization,
		ImageDeployer: imageDeployer,
		appsService:   apps,
	}

	return &Empire{
		Store:               store,
		AccessTokensService: accessTokens,
		AppsService:         apps,
		ConfigsService:      configs,
		DeploysService:      commitDeployer,
		JobsService:         jobs,
		JobStatesService:    jobStates,
		Manager:             manager,
		SlugsService:        slugs,
		ReleasesService:     releases,
	}, nil
}

func (e *Empire) AppsDestroy(app *App) error {
	return e.AppsService.AppsDestroy(app)
}

// Migrate runs the migrations.
func Migrate(db, path string) ([]error, bool) {
	return migrate.UpSync(db, path)
}

// ValidationError is returned when a model is not valid.
type ValidationError struct {
	Err error
}

func (e *ValidationError) Error() string {
	return e.Err.Error()
}

// key used to store context values from within this package.
type key int

const (
	UserKey key = 0
)

func newScheduler(fleetURL string) (container.Scheduler, error) {
	if fleetURL == "fake" {
		return container.NewFakeScheduler(), nil
	}

	u, err := url.Parse(fleetURL)
	if err != nil {
		return nil, err
	}

	return container.NewFleetScheduler(u)
}
<commit_msg>Provide methods on Empire.<commit_after>package empire // import "github.com/remind101/empire/empire"

import (
	"net/url"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/mattes/migrate/migrate"
	"github.com/remind101/empire/empire/pkg/container"
)

// A function to return the current time. It can be useful to stub this out in
// tests.
var Now = func() time.Time {
	return time.Now().UTC()
}

// DefaultOptions is a default Options instance that can be passed when
// intializing a new Empire.
var DefaultOptions = Options{}

// DockerOptions is a set of options to configure a docker api client.
type DockerOptions struct {
	// The default docker organization to use.
	Organization string

	// The unix socket to connect to the docker api.
	Socket string

	// Path to a certificate to use for TLS connections.
	CertPath string

	// A set of docker registry credentials.
	Auth *docker.AuthConfigurations
}

// FleetOptions is a set of options to configure a fleet api client.
type FleetOptions struct {
	// The location of the fleet api.
	API string
}

// Options is provided to New to configure the Empire services.
type Options struct {
	Docker DockerOptions
	Fleet  FleetOptions

	Secret string

	// Database connection string.
	DB string
}

// Empire is a context object that contains a collection of services.
type Empire struct {
	Store *Store

	AccessTokens *AccessTokensService
	Apps         *AppsService
	Configs      *ConfigsService
	JobStates    *JobStatesService
	Manager      *Manager
	Releases     *ReleasesService
	Slugs        *SlugsService

	DeploysService
}

// New returns a new Empire instance.
func New(options Options) (*Empire, error) {
	db, err := newDB(options.DB)
	if err != nil {
		return nil, err
	}

	store := &Store{db: db}

	scheduler, err := newScheduler(options.Fleet.API)
	if err != nil {
		return nil, err
	}

	extractor, err := NewExtractor(
		options.Docker.Socket,
		options.Docker.CertPath,
		options.Docker.Auth,
	)
	if err != nil {
		return nil, err
	}

	accessTokens := &AccessTokensService{
		Secret: []byte(options.Secret),
	}

	configs := &ConfigsService{
		store: store,
	}

	jobs := &JobsService{
		store:     store,
		scheduler: scheduler,
	}

	jobStates := &JobStatesService{
		store:     store,
		scheduler: scheduler,
	}

	apps := &AppsService{
		store:       store,
		JobsService: jobs,
	}

	manager := &Manager{
		JobsService: jobs,
		store:       store,
	}

	releases := &ReleasesService{
		store:   store,
		manager: manager,
	}

	slugs := &SlugsService{
		store:     store,
		extractor: extractor,
	}

	imageDeployer := &imageDeployer{
		AppsService:     apps,
		ConfigsService:  configs,
		SlugsService:    slugs,
		ReleasesService: releases,
	}

	commitDeployer := &commitDeployer{
		Organization:  options.Docker.Organization,
		ImageDeployer: imageDeployer,
		appsService:   apps,
	}

	return &Empire{
		Store:          store,
		AccessTokens:   accessTokens,
		Apps:           apps,
		Configs:        configs,
		DeploysService: commitDeployer,
		JobStates:      jobStates,
		Manager:        manager,
		Slugs:          slugs,
		Releases:       releases,
	}, nil
}

// AccessTokensFind finds an access token.
func (e *Empire) AccessTokensFind(token string) (*AccessToken, error) {
	return e.AccessTokens.AccessTokensFind(token)
}

// AccessTokensCreate creates a new AccessToken.
func (e *Empire) AccessTokensCreate(accessToken *AccessToken) (*AccessToken, error) {
	return e.AccessTokens.AccessTokensCreate(accessToken)
}

// AppsAll returns all Apps.
func (e *Empire) AppsAll() ([]*App, error) {
	return e.Store.AppsAll()
}

// AppsCreate creates a new app.
func (e *Empire) AppsCreate(app *App) (*App, error) {
	return e.Store.AppsCreate(app)
}

// AppsFind finds an app by name.
func (e *Empire) AppsFind(name string) (*App, error) {
	return e.Store.AppsFind(name)
}

// AppsDestroy destroys the app.
func (e *Empire) AppsDestroy(app *App) error {
	return e.Apps.AppsDestroy(app)
}

// ConfigsCurrent returns the current Config for a given app.
func (e *Empire) ConfigsCurrent(app *App) (*Config, error) {
	return e.Configs.ConfigsCurrent(app)
}

// ConfigsApply applies the new config vars to the apps current Config,
// returning a new Config.
func (e *Empire) ConfigsApply(app *App, vars Vars) (*Config, error) {
	return e.Configs.ConfigsApply(app, vars)
}

// ConfigsFind finds a Config by id.
func (e *Empire) ConfigsFind(id string) (*Config, error) {
	return e.Store.ConfigsFind(id)
}

// JobStatesByApp returns the JobStates for the given app.
func (e *Empire) JobStatesByApp(app *App) ([]*JobState, error) {
	return e.JobStates.JobStatesByApp(app)
}

// ProcessesAll returns all processes for a given Release.
func (e *Empire) ProcessesAll(release *Release) (Formation, error) {
	return e.Store.ProcessesAll(release)
}

// ReleasesCreate creates a new release for an app.
func (e *Empire) ReleasesCreate(app *App, config *Config, slug *Slug, desc string) (*Release, error) {
	return e.Releases.ReleasesCreate(app, config, slug, desc)
}

// ReleasesFindByApp returns all Releases for a given App.
func (e *Empire) ReleasesFindByApp(app *App) ([]*Release, error) {
	return e.Store.ReleasesFindByApp(app)
}

// ReleasesFindByAppAndVersion finds a specific Release for a given App.
func (e *Empire) ReleasesFindByAppAndVersion(app *App, version int) (*Release, error) {
	return e.Store.ReleasesFindByAppAndVersion(app, version)
}

// ReleasesLast returns the last release for an App.
func (e *Empire) ReleasesLast(app *App) (*Release, error) {
	return e.Store.ReleasesLast(app)
}

// ScaleRelease scales the processes in a release.
func (e *Empire) ScaleRelease(release *Release, config *Config, slug *Slug, formation Formation, qm ProcessQuantityMap) error {
	return e.Manager.ScaleRelease(release, config, slug, formation, qm)
}

// SlugsFind finds a slug by id.
func (e *Empire) SlugsFind(id string) (*Slug, error) {
	return e.Store.SlugsFind(id)
}

// Reset resets empire.
func (e *Empire) Reset() error {
	return e.Store.Reset()
}

// Migrate runs the migrations.
func Migrate(db, path string) ([]error, bool) {
	return migrate.UpSync(db, path)
}

// ValidationError is returned when a model is not valid.
type ValidationError struct {
	Err error
}

func (e *ValidationError) Error() string {
	return e.Err.Error()
}

// key used to store context values from within this package.
type key int

const (
	UserKey key = 0
)

func newScheduler(fleetURL string) (container.Scheduler, error) {
	if fleetURL == "fake" {
		return container.NewFakeScheduler(), nil
	}

	u, err := url.Parse(fleetURL)
	if err != nil {
		return nil, err
	}

	return container.NewFleetScheduler(u)
}
<|endoftext|>


<commit_before>// Copyright 2016 Yury Kozyrev

package encoding

import (
	"compress/flate"
	"io"
	"compress/gzip"
)

type EncoderDeflate struct {}
func (_ *EncoderDeflate) GetName() (string){ return "deflate" }
func (_ *EncoderDeflate) NewWriter(w io.Writer, level int) (ew io.Writer){
	if level < 1 || level > 11{
		level = 1
	}
	ew, _ = flate.NewWriter(w, level)
	return
}

var _ Encoder = (*EncoderDeflate)(nil)

type EncoderGzip struct {}
func (_ *EncoderGzip) GetName() (string){ return "gzip" }
func (_ *EncoderGzip) NewWriter(w io.Writer, level int) (ew io.Writer){
	if level < 1 || level > 11{
		level = 1
	}
	ew, _ = gzip.NewWriterLevel(w, level)
	return
}

var _ Encoder = (*EncoderGzip)(nil)

<commit_msg>Update gzip.go<commit_after>// Copyright 2016 Yury Kozyrev

package encoding

import (
	"github.com/klauspost/compress/flate"
	"io"
	"github.com/klauspost/compress/gzip"
)

type EncoderDeflate struct {}
func (_ *EncoderDeflate) GetName() (string){ return "deflate" }
func (_ *EncoderDeflate) NewWriter(w io.Writer, level int) (ew io.Writer){
	if level < 1 || level > 11{
		level = 1
	}
	ew, _ = flate.NewWriter(w, level)
	return
}

var _ Encoder = (*EncoderDeflate)(nil)

type EncoderGzip struct {}
func (_ *EncoderGzip) GetName() (string){ return "gzip" }
func (_ *EncoderGzip) NewWriter(w io.Writer, level int) (ew io.Writer){
	if level < 1 || level > 11{
		level = 1
	}
	ew, _ = gzip.NewWriterLevel(w, level)
	return
}

var _ Encoder = (*EncoderGzip)(nil)

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
)

var (
	bashPath    string
	debugging   = false
	erroring    = false
	maxprocs    = 4
	testPattern = regexp.MustCompile(`test[/\\]test-([a-z\-]+)\.sh$`)
)

func mainIntegration() {
	if len(os.Getenv("DEBUG")) > 0 {
		debugging = true
	}

	setBash()

	if maxprocs < 1 {
		maxprocs = 1
	}

	files := testFiles()

	if len(files) == 0 {
		fmt.Println("no tests to run")
		os.Exit(1)
	}

	var wg sync.WaitGroup
	tests := make(chan string, len(files))
	output := make(chan string, len(files))

	for _, file := range files {
		tests <- file
	}

	go printOutput(output)
	for i := 0; i < maxprocs; i++ {
		wg.Add(1)
		go worker(tests, output, &wg)
	}

	close(tests)
	wg.Wait()
	close(output)
	printOutput(output)

	if erroring {
		os.Exit(1)
	}
}

func runTest(output chan string, test string) {
	out, err := exec.Command(bashPath, test).CombinedOutput()
	if err != nil {
		erroring = true
	}

	output <- strings.TrimSpace(string(out))
}

func printOutput(output <-chan string) {
	for {
		select {
		case out, ok := <-output:
			if !ok {
				return
			}

			fmt.Println(out)
		}
	}
}

func worker(tests <-chan string, output chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case testname, ok := <-tests:
			if !ok {
				return
			}
			runTest(output, testname)
		}
	}
}

func testFiles() []string {
	if len(os.Args) < 4 {
		return allTestFiles()
	}

	fileMap := make(map[string]bool)
	for _, file := range allTestFiles() {
		fileMap[file] = true
	}

	files := make([]string, 0, len(os.Args)-3)
	for _, arg := range os.Args {
		fullname := "test/test-" + arg + ".sh"
		if fileMap[fullname] {
			files = append(files, fullname)
		}
	}

	return files
}

func allTestFiles() []string {
	files := make([]string, 0, 100)
	filepath.Walk("test", func(path string, info os.FileInfo, err error) error {
		if debugging {
			fmt.Println("FOUND:", path)
		}
		if err != nil || info.IsDir() || !testPattern.MatchString(path) {
			return nil
		}

		if debugging {
			fmt.Println("MATCHING:", path)
		}
		files = append(files, path)
		return nil
	})
	return files
}

func setBash() {
	out, err := exec.Command("which", "bash").Output()
	if err != nil {
		fmt.Println("Unable to find bash:", err)
		os.Exit(1)
	}

	bashPath = strings.TrimSpace(string(out))
	if debugging {
		fmt.Println("Using", bashPath)
	}
}
<commit_msg>Fix running integration tests on Windows<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"
)

var (
	bashPath    string
	debugging   = false
	erroring    = false
	maxprocs    = 4
	testPattern = regexp.MustCompile(`test[/\\]test-([a-z\-]+)\.sh$`)
)

func mainIntegration() {
	if len(os.Getenv("DEBUG")) > 0 {
		debugging = true
	}

	setBash()

	if maxprocs < 1 {
		maxprocs = 1
	}

	files := testFiles()

	if len(files) == 0 {
		fmt.Println("no tests to run")
		os.Exit(1)
	}

	var wg sync.WaitGroup
	tests := make(chan string, len(files))
	output := make(chan string, len(files))

	for _, file := range files {
		tests <- file
	}

	go printOutput(output)
	for i := 0; i < maxprocs; i++ {
		wg.Add(1)
		go worker(tests, output, &wg)
	}

	close(tests)
	wg.Wait()
	close(output)
	printOutput(output)

	if erroring {
		os.Exit(1)
	}
}

func runTest(output chan string, test string) {
	out, err := exec.Command(bashPath, test).CombinedOutput()
	if err != nil {
		if debugging {
			fmt.Println("Error:", err)
		}
		erroring = true
	}

	output <- strings.TrimSpace(string(out))
}

func printOutput(output <-chan string) {
	for {
		select {
		case out, ok := <-output:
			if !ok {
				return
			}

			fmt.Println(out)
		}
	}
}

func worker(tests <-chan string, output chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case testname, ok := <-tests:
			if !ok {
				return
			}
			runTest(output, testname)
		}
	}
}

func testFiles() []string {
	if len(os.Args) < 4 {
		return allTestFiles()
	}

	fileMap := make(map[string]bool)
	for _, file := range allTestFiles() {
		fileMap[file] = true
	}

	files := make([]string, 0, len(os.Args)-3)
	for _, arg := range os.Args {
		fullname := "test/test-" + arg + ".sh"
		if fileMap[fullname] {
			files = append(files, fullname)
		}
	}

	return files
}

func allTestFiles() []string {
	files := make([]string, 0, 100)
	filepath.Walk("test", func(path string, info os.FileInfo, err error) error {
		if debugging {
			fmt.Println("FOUND:", path)
		}
		if err != nil || info.IsDir() || !testPattern.MatchString(path) {
			return nil
		}

		if debugging {
			fmt.Println("MATCHING:", path)
		}
		files = append(files, path)
		return nil
	})
	return files
}

func setBash() {
	findcmd := "which"
	if runtime.GOOS == "windows" {
		// Can't use paths returned from which even if it's on PATH in Windows
		// Because our Go binary is a separate Windows app & not MinGW, it
		// can't understand paths like '/usr/bin/bash', needs Windows version
		findcmd = "where"
	}
	out, err := exec.Command(findcmd, "bash").Output()
	if err != nil {
		fmt.Println("Unable to find bash:", err)
		os.Exit(1)
	}

	bashPath = strings.TrimSpace(string(out))
	if debugging {
		fmt.Println("Using", bashPath)
	}

	// Test
	_, err = exec.Command(bashPath, "--version").CombinedOutput()
	if err != nil {
		fmt.Println("Error calling bash:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

func main() {
	Log("main.start")

	databaseUrl := DatabaseUrl()
	libratoAuth := LibratoAuth()
	queryInterval := QueryInterval()
	queryFiles := QueryFiles()

	metricBatches := make(chan []interface{}, 10)
	queryTicks := make(chan QueryFile, 10)

	go MonitorStart(queryTicks, metricBatches, MonitorInterval)
	go LibratoStart(libratoAuth, metricBatches)
	go PostgresStart(databaseUrl, queryTicks, QueryTimeout, metricBatches)
	go SchedulerStart(queryFiles, queryInterval, queryTicks)

	wait := make(chan bool)
	<-wait
}
<commit_msg>Inline<commit_after>package main

func main() {
	Log("main.start")

	databaseUrl := DatabaseUrl()
	libratoAuth := LibratoAuth()
	queryInterval := QueryInterval()
	queryFiles := QueryFiles()

	metricBatches := make(chan []interface{}, 10)
	queryTicks := make(chan QueryFile, 10)

	go MonitorStart(queryTicks, metricBatches, MonitorInterval)
	go LibratoStart(libratoAuth, metricBatches)
	go PostgresStart(databaseUrl, queryTicks, QueryTimeout, metricBatches)
	go SchedulerStart(queryFiles, queryInterval, queryTicks)

	<-make(chan bool)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/miekg/dns"
	"net"
	"strconv"
	"strings"
)

// we put the names in the reverse domain
// bla.blie.skydns.local becomes
// local/skydns/blie/bla/srv where we put the rdata
// last element must be A AAAA or SRV

func toValue(rr dns.RR) string {
	switch x := rr.(type) {
	case *dns.A:
		return x.A.String()
	case *dns.AAAA:
		return x.AAAA.String()
	case *dns.SRV:
		return strconv.Itoa(int(x.Priority)) + " " +
			strconv.Itoa(int(x.Weight)) + " " +
			strconv.Itoa(int(x.Port)) + " " + dns.Name(x.Target).String()
	}
	return ""
}

func toKey(s string) string {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	return strings.Join(l, "/")
}

func parseA(v string) (net.IP, error)    { return net.ParseIP(v).To4(), nil }
func parseAAAA(v string) (net.IP, error) { return net.ParseIP(v).To16(), nil }
func parseSRV(v string) (uint16, uint16, uint16, string, error) {
	p := strings.Split(v, " ")
	prio, _ := strconv.Atoi(p[0])
	weight, _ := strconv.Atoi(p[1])
	port, _ := strconv.Atoi(p[2])
	return uint16(prio), uint16(weight), uint16(port), p[3], nil
}
<commit_msg>Some more stuff<commit_after>package main

import (
	"github.com/miekg/dns"
	"net"
	"strconv"
	"strings"
)

// we put the names in the reverse domain
// bla.blie.skydns.local becomes
// local/skydns/blie/bla/srv where we put the rdata
// last element must be A AAAA or SRV

func toValue(rr dns.RR) string {
	switch x := rr.(type) {
	case *dns.A:
		return x.A.String()
	case *dns.AAAA:
		return x.AAAA.String()
	case *dns.SRV:
		return strconv.Itoa(int(x.Priority)) + " " +
			strconv.Itoa(int(x.Weight)) + " " +
			strconv.Itoa(int(x.Port)) + " " + dns.Name(x.Target).String()
	}
	return ""
}

func toKey(s string) string {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	// TODO(miek): escape slashes in s.
	return strings.Join(l, "/")
}

func parseA(v string) (net.IP, error)    { return net.ParseIP(v).To4(), nil }
func parseAAAA(v string) (net.IP, error) { return net.ParseIP(v).To16(), nil }
func parseSRV(v string) (uint16, uint16, uint16, string, error) {
	p := strings.Split(v, " ")
	prio, _ := strconv.Atoi(p[0])
	weight, _ := strconv.Atoi(p[1])
	port, _ := strconv.Atoi(p[2])
	return uint16(prio), uint16(weight), uint16(port), p[3], nil
}

// Convert a DNS question to a etcd key. If the questions looks
// like service.staging.skydns.local SRV, the resulting key
// will by /local/skydns/staging/service/SRV .
func QuestionToKey(q string, t uint16) string {
	return "/" + toKey(q) + "/" + dns.TypeToString[t]
}
<|endoftext|>


<commit_before>package xlsx

import (
	"archive/zip"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strconv"
)

// File is a high level structure providing a slice of Sheet structs
// to the user.
type File struct {
	worksheets     map[string]*zip.File
	numFmtRefTable map[int]xlsxNumFmt
	referenceTable *RefTable
	Date1904       bool
	styles         *xlsxStyles
	Sheets       []*Sheet
	Sheet        map[string]*Sheet
}

// Create a new File
func NewFile() (file *File) {
	file = &File{};
	file.Sheet = make(map[string]*Sheet)
	file.Sheets = make([]*Sheet, 0)
	return
}

// OpenFile() take the name of an XLSX file and returns a populated
// xlsx.File struct for it.
func OpenFile(filename string) (*File, error) {
	var f *zip.ReadCloser
	f, err := zip.OpenReader(filename)
	if err != nil {
		return nil, err
	}
	return ReadZip(f)
}

// Save the File to an xlsx file at the provided path.
func (f *File) Save(path string) (err error) {
	var parts map[string]string
	var target *os.File
	var zipWriter *zip.Writer

	parts, err = f.MarshallParts()
	if err != nil {
		return
	}

	target, err = os.Create(path)
	if err != nil {
		return
	}

	zipWriter = zip.NewWriter(target)

	for partName, part := range parts {
		var writer io.Writer
		writer, err = zipWriter.Create(partName)
		if err != nil {
			return
		}
		_, err = writer.Write([]byte(part))
		if err != nil {
			return
		}
	}
	err = zipWriter.Close()
	if err != nil {
		return
	}

	return target.Close()
}

// Add a new Sheet, with the provided name, to a File
func (f *File) AddSheet(sheetName string) (sheet *Sheet) {
	sheet = &Sheet{}
	f.Sheet[sheetName] = sheet
	f.Sheets = append(f.Sheets, sheet)
	return sheet
}

func (f *File) makeWorkbook() xlsxWorkbook {
	var workbook xlsxWorkbook
	workbook = xlsxWorkbook{}
	workbook.FileVersion = xlsxFileVersion{}
	workbook.FileVersion.AppName = "Go XLSX"
	workbook.WorkbookPr = xlsxWorkbookPr{BackupFile: false}
	workbook.BookViews = xlsxBookViews{}
	workbook.BookViews.WorkBookView = make([]xlsxWorkBookView, 1)
	workbook.BookViews.WorkBookView[0] = xlsxWorkBookView{}
	workbook.Sheets = xlsxSheets{}
	workbook.Sheets.Sheet = make([]xlsxSheet, len(f.Sheets))
	return workbook
}

// Construct a map of file name to XML content representing the file
// in terms of the structure of an XLSX file.
func (f *File) MarshallParts() (map[string]string, error) {
	var parts map[string]string
	var refTable *RefTable = NewSharedStringRefTable()
	var workbookRels WorkBookRels = make(WorkBookRels)
	var err error
	var workbook xlsxWorkbook
	var types xlsxTypes = MakeDefaultContentTypes()

	marshal := func(thing interface{}) (string, error) {
		body, err := xml.MarshalIndent(thing, "  ", "  ")
		if err != nil {
			return "", err
		}
		return xml.Header + string(body), nil
	}

	parts = make(map[string]string)
	workbook = f.makeWorkbook()
	sheetIndex := 1

	for sheetName, sheet := range f.Sheet {
		xSheet := sheet.makeXLSXSheet(refTable)
		rId := fmt.Sprintf("rId%d", sheetIndex)
		sheetId := strconv.Itoa(sheetIndex)
		sheetPath := fmt.Sprintf("worksheets/sheet%d.xml", sheetIndex)
		partName := "xl/" + sheetPath
		types.Overrides = append(
			types.Overrides,
			xlsxOverride{
				PartName: partName,
				ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"})
		workbookRels[rId] = sheetPath
		workbook.Sheets.Sheet[sheetIndex - 1] = xlsxSheet{
			Name: sheetName,
			SheetId: sheetId,
			Id: rId}
		parts[partName], err = marshal(xSheet)
		if err != nil {
			return parts, err
		}
		sheetIndex++
	}

	parts["xl/workbook.xml"], err = marshal(workbook)
	if err != nil {
		return parts, err
	}

	parts["_rels/.rels"] = `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
  <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
  <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
</Relationships>`

	parts["docProps/app.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <TotalTime>0</TotalTime>
  <Application>Go XLSX</Application>
</Properties>`

	// TODO - do this properly, modification and revision information
	parts["docProps/core.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></cp:coreProperties>`

	xSST := refTable.makeXLSXSST()
	parts["xl/sharedStrings.xml"], err = marshal(xSST)
	if err != nil {
		return parts, err
	}

	xWRel := workbookRels.MakeXLSXWorkbookRels()

	parts["xl/_rels/workbook.xml.rels"], err = marshal(xWRel)
	if err != nil {
		return parts, err
	}

	parts["[Content_Types].xml"], err = marshal(types)
	if err != nil {
		return parts, err
	}

	parts["xl/styles.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
</styleSheet>`

	return parts, nil
}
<commit_msg>- Use File.Sheets for iteration in File.MarshalParts instead of File.Sheet, to   maintain stable ordering of sheets (this stops random test failures)<commit_after>package xlsx

import (
	"archive/zip"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strconv"
)

// File is a high level structure providing a slice of Sheet structs
// to the user.
type File struct {
	worksheets     map[string]*zip.File
	numFmtRefTable map[int]xlsxNumFmt
	referenceTable *RefTable
	Date1904       bool
	styles         *xlsxStyles
	Sheets       []*Sheet
	Sheet        map[string]*Sheet
}

// Create a new File
func NewFile() (file *File) {
	file = &File{};
	file.Sheet = make(map[string]*Sheet)
	file.Sheets = make([]*Sheet, 0)
	return
}

// OpenFile() take the name of an XLSX file and returns a populated
// xlsx.File struct for it.
func OpenFile(filename string) (*File, error) {
	var f *zip.ReadCloser
	f, err := zip.OpenReader(filename)
	if err != nil {
		return nil, err
	}
	return ReadZip(f)
}

// Save the File to an xlsx file at the provided path.
func (f *File) Save(path string) (err error) {
	var parts map[string]string
	var target *os.File
	var zipWriter *zip.Writer

	parts, err = f.MarshallParts()
	if err != nil {
		return
	}

	target, err = os.Create(path)
	if err != nil {
		return
	}

	zipWriter = zip.NewWriter(target)

	for partName, part := range parts {
		var writer io.Writer
		writer, err = zipWriter.Create(partName)
		if err != nil {
			return
		}
		_, err = writer.Write([]byte(part))
		if err != nil {
			return
		}
	}
	err = zipWriter.Close()
	if err != nil {
		return
	}

	return target.Close()
}

// Add a new Sheet, with the provided name, to a File
func (f *File) AddSheet(sheetName string) (sheet *Sheet) {
	sheet = &Sheet{Name: sheetName}
	f.Sheet[sheetName] = sheet
	f.Sheets = append(f.Sheets, sheet)
	return sheet
}

func (f *File) makeWorkbook() xlsxWorkbook {
	var workbook xlsxWorkbook
	workbook = xlsxWorkbook{}
	workbook.FileVersion = xlsxFileVersion{}
	workbook.FileVersion.AppName = "Go XLSX"
	workbook.WorkbookPr = xlsxWorkbookPr{BackupFile: false}
	workbook.BookViews = xlsxBookViews{}
	workbook.BookViews.WorkBookView = make([]xlsxWorkBookView, 1)
	workbook.BookViews.WorkBookView[0] = xlsxWorkBookView{}
	workbook.Sheets = xlsxSheets{}
	workbook.Sheets.Sheet = make([]xlsxSheet, len(f.Sheets))
	return workbook
}

// Construct a map of file name to XML content representing the file
// in terms of the structure of an XLSX file.
func (f *File) MarshallParts() (map[string]string, error) {
	var parts map[string]string
	var refTable *RefTable = NewSharedStringRefTable()
	var workbookRels WorkBookRels = make(WorkBookRels)
	var err error
	var workbook xlsxWorkbook
	var types xlsxTypes = MakeDefaultContentTypes()

	marshal := func(thing interface{}) (string, error) {
		body, err := xml.MarshalIndent(thing, "  ", "  ")
		if err != nil {
			return "", err
		}
		return xml.Header + string(body), nil
	}

	parts = make(map[string]string)
	workbook = f.makeWorkbook()
	sheetIndex := 1

	for _, sheet := range f.Sheets {
		xSheet := sheet.makeXLSXSheet(refTable)
		rId := fmt.Sprintf("rId%d", sheetIndex)
		sheetId := strconv.Itoa(sheetIndex)
		sheetPath := fmt.Sprintf("worksheets/sheet%d.xml", sheetIndex)
		partName := "xl/" + sheetPath
		types.Overrides = append(
			types.Overrides,
			xlsxOverride{
				PartName: partName,
				ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"})
		workbookRels[rId] = sheetPath
		workbook.Sheets.Sheet[sheetIndex - 1] = xlsxSheet{
			Name: sheet.Name,
			SheetId: sheetId,
			Id: rId}
		parts[partName], err = marshal(xSheet)
		if err != nil {
			return parts, err
		}
		sheetIndex++
	}

	parts["xl/workbook.xml"], err = marshal(workbook)
	if err != nil {
		return parts, err
	}

	parts["_rels/.rels"] = `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
  <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
  <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
</Relationships>`

	parts["docProps/app.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <TotalTime>0</TotalTime>
  <Application>Go XLSX</Application>
</Properties>`

	// TODO - do this properly, modification and revision information
	parts["docProps/core.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></cp:coreProperties>`

	xSST := refTable.makeXLSXSST()
	parts["xl/sharedStrings.xml"], err = marshal(xSST)
	if err != nil {
		return parts, err
	}

	xWRel := workbookRels.MakeXLSXWorkbookRels()

	parts["xl/_rels/workbook.xml.rels"], err = marshal(xWRel)
	if err != nil {
		return parts, err
	}

	parts["[Content_Types].xml"], err = marshal(types)
	if err != nil {
		return parts, err
	}

	parts["xl/styles.xml"] = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
</styleSheet>`

	return parts, nil
}
<|endoftext|>


<commit_before>package flow

import (
	"bytes"
	"fmt"
	"os"
	"os/signal"
	"path"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	pkgPath      = reflect.TypeOf(Flow{}).PkgPath()
	DefaultDebug = false
)

type debugInfo struct {
	Time     string
	FileInfo string
	Stack    string
	Info     string
}

func (d *debugInfo) String() string {
	return d.Stack + " - " + d.Info
}

type Flow struct {
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32
	exited   int32
	onClose  []func()
	id       uintptr

	mutex   sync.Mutex
	debug   []debugInfo
	printed int32
}

func NewEx(n int) *Flow {
	f := &Flow{
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.appendDebug("init")
	if n > 0 {
		f.Add(n)
	}
	return f
}

func New() *Flow {
	return NewEx(0)
}

func (f *Flow) WaitNotify(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	case <-f.IsClose():
		return false
	}
}

func (f *Flow) MarkExit() bool {
	return atomic.CompareAndSwapInt32(&f.exited, 0, 1)
}

func (f *Flow) IsExit() bool {
	return atomic.LoadInt32(&f.exited) == 1
}

func (f *Flow) GetDebug() []byte {
	buf := bytes.NewBuffer(nil)
	var stackML, fileML, timeML int
	for _, d := range f.debug {
		if stackML < len(d.Stack) {
			stackML = len(d.Stack)
		}
		if fileML < len(d.FileInfo) {
			fileML = len(d.FileInfo)
		}
		if timeML < len(d.Time) {
			timeML = len(d.Time)
		}
	}
	fill := func(a string, n int) string {
		return a + strings.Repeat(" ", n-len(a))
	}
	buf.WriteString("\n")
	for _, d := range f.debug {
		buf.WriteString(fmt.Sprintf("%v %v %v - %v\n",
			fill(d.Time, timeML),
			fill(d.FileInfo, fileML),
			fill(d.Stack, stackML), d.Info,
		))
	}
	return buf.Bytes()
}

func (f *Flow) printDebug() {
	println(string(f.GetDebug()))
}

func (f *Flow) appendDebug(info string) {
	pc, fp, line, _ := runtime.Caller(f.getCaller())
	name := runtime.FuncForPC(pc).Name()
	f.debug = append(f.debug, debugInfo{
		Time:     time.Now().Format("02 15:04:05"),
		FileInfo: fmt.Sprintf("%v:%v", path.Base(fp), line),
		Stack:    path.Base(name),
		Info:     info,
	})
}

func (f *Flow) SetOnClose(exit func()) *Flow {
	if f.IsClosed() {
		f.appendDebug("set close after closed")
		exit()
		return f
	}

	f.onClose = []func(){exit}
	return f
}

func (f *Flow) AddOnClose(exit func()) *Flow {
	if f.IsClosed() {
		f.appendDebug("add close after closed")
		exit()
		return f
	}

	f.onClose = append(f.onClose, exit)
	return f
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) Tick(t *time.Ticker) bool {
	select {
	case <-t.C:
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) ForkTo(ref **Flow, exit func()) {
	*ref = f.Fork(0).AddOnClose(exit)
}

func (f *Flow) Fork(n int) *Flow {
	f2 := NewEx(n)
	f2.Parent = f
	// TODO(chzyer): test it !
	f2.errChan = f.errChan
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2

	if f.IsClosed() {
		f.appendDebug("fork when closed")
		// stop-wait
		// ->fork
		// done
		f2.Stop()
	}

	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	f.appendDebug("close")
	f.close()
}

func (f *Flow) close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}
	f.appendDebug("stop")

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
	if len(f.onClose) > 0 {
		go func() {
			for _, f := range f.onClose {
				f()
			}
		}()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	ref := atomic.AddInt32(f.ref, int32(n))
	f.appendDebug(fmt.Sprintf("add: %v, ref: %v", n, ref))
	f.wg.Add(n)
}

func (f *Flow) getCaller() int {
	for i := 0; ; i++ {
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}
		f := runtime.FuncForPC(pc).Name()
		if !strings.HasPrefix(f, pkgPath) {
			return i - 1
		}
	}
	return 0
}

func (f *Flow) getRef() int32 {
	return atomic.LoadInt32(f.ref)
}

func (f *Flow) Done() {
	f.wg.Done()
	ref := atomic.AddInt32(f.ref, -1)
	f.appendDebug(fmt.Sprintf("done, ref: %v", ref))
	if ref == 0 {
		f.Stop()
	}
}

func (f *Flow) DoneAndClose() {
	f.wg.Done()
	ref := atomic.AddInt32(f.ref, -1)
	f.appendDebug(fmt.Sprintf("done and close, ref: %v", ref))
	f.Stop()
}

func (f *Flow) wait() {
	f.appendDebug("wait")

	done := make(chan struct{})
	printed := int32(0)
	if DefaultDebug && atomic.CompareAndSwapInt32(&f.printed, 0, 1) {
		go func() {
			select {
			case <-done:
				return
			case <-time.After(1000 * time.Millisecond):
				f.printDebug()
				atomic.StoreInt32(&printed, 1)
			}
		}()
	}
	<-f.stopChan
	f.wg.Wait()
	close(done)
	if atomic.LoadInt32(&printed) == 1 {
		println(fmt.Sprint(&f) + " - exit")
	}

	if f.Parent != nil {
		f.Parent.Done()
		f.Parent = nil
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
		f.appendDebug("got closed")
	case <-signalChan:
		f.appendDebug("got signal")
		f.Stop()
	case err = <-f.errChan:
		f.appendDebug(fmt.Sprintf("got error: %v", err))

		if err != nil {
			f.Stop()
		}
	}

	go func() {
		<-signalChan
		// force close
		println("force close")
		os.Exit(1)
	}()

	f.wait()
	return err
}
<commit_msg>fix ForkTo error<commit_after>package flow

import (
	"bytes"
	"fmt"
	"os"
	"os/signal"
	"path"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	pkgPath      = reflect.TypeOf(Flow{}).PkgPath()
	DefaultDebug = false
)

type debugInfo struct {
	Time     string
	FileInfo string
	Stack    string
	Info     string
}

func (d *debugInfo) String() string {
	return d.Stack + " - " + d.Info
}

type Flow struct {
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32
	exited   int32
	onClose  []func()
	id       uintptr

	mutex   sync.Mutex
	debug   []debugInfo
	printed int32
}

func NewEx(n int) *Flow {
	f := &Flow{
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.appendDebug("init")
	if n > 0 {
		f.Add(n)
	}
	return f
}

func New() *Flow {
	return NewEx(0)
}

func (f *Flow) WaitNotify(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	case <-f.IsClose():
		return false
	}
}

func (f *Flow) MarkExit() bool {
	return atomic.CompareAndSwapInt32(&f.exited, 0, 1)
}

func (f *Flow) IsExit() bool {
	return atomic.LoadInt32(&f.exited) == 1
}

func (f *Flow) GetDebug() []byte {
	buf := bytes.NewBuffer(nil)
	var stackML, fileML, timeML int
	for _, d := range f.debug {
		if stackML < len(d.Stack) {
			stackML = len(d.Stack)
		}
		if fileML < len(d.FileInfo) {
			fileML = len(d.FileInfo)
		}
		if timeML < len(d.Time) {
			timeML = len(d.Time)
		}
	}
	fill := func(a string, n int) string {
		return a + strings.Repeat(" ", n-len(a))
	}
	buf.WriteString("\n")
	for _, d := range f.debug {
		buf.WriteString(fmt.Sprintf("%v %v %v - %v\n",
			fill(d.Time, timeML),
			fill(d.FileInfo, fileML),
			fill(d.Stack, stackML), d.Info,
		))
	}
	return buf.Bytes()
}

func (f *Flow) printDebug() {
	println(string(f.GetDebug()))
}

func (f *Flow) appendDebug(info string) {
	pc, fp, line, _ := runtime.Caller(f.getCaller())
	name := runtime.FuncForPC(pc).Name()
	f.debug = append(f.debug, debugInfo{
		Time:     time.Now().Format("02 15:04:05"),
		FileInfo: fmt.Sprintf("%v:%v", path.Base(fp), line),
		Stack:    path.Base(name),
		Info:     info,
	})
}

func (f *Flow) SetOnClose(exit func()) *Flow {
	if f.IsClosed() {
		f.appendDebug("set close after closed")
		exit()
		return f
	}

	f.onClose = []func(){exit}
	return f
}

func (f *Flow) AddOnClose(exit func()) *Flow {
	if f.IsClosed() {
		f.appendDebug("add close after closed")
		exit()
		return f
	}

	f.onClose = append(f.onClose, exit)
	return f
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) Tick(t *time.Ticker) bool {
	select {
	case <-t.C:
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) ForkTo(ref **Flow, exit func()) {
	child := f.Fork(0)
	*ref = child
	child.AddOnClose(exit)
}

func (f *Flow) Fork(n int) *Flow {
	f2 := NewEx(n)
	f2.Parent = f
	// TODO(chzyer): test it !
	f2.errChan = f.errChan
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2

	if f.IsClosed() {
		f.appendDebug("fork when closed")
		// stop-wait
		// ->fork
		// done
		f2.Stop()
	}

	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	f.appendDebug("close")
	f.close()
}

func (f *Flow) close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}
	f.appendDebug("stop")

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
	if len(f.onClose) > 0 {
		go func() {
			for _, f := range f.onClose {
				f()
			}
		}()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	ref := atomic.AddInt32(f.ref, int32(n))
	f.appendDebug(fmt.Sprintf("add: %v, ref: %v", n, ref))
	f.wg.Add(n)
}

func (f *Flow) getCaller() int {
	for i := 0; ; i++ {
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}
		f := runtime.FuncForPC(pc).Name()
		if !strings.HasPrefix(f, pkgPath) {
			return i - 1
		}
	}
	return 0
}

func (f *Flow) getRef() int32 {
	return atomic.LoadInt32(f.ref)
}

func (f *Flow) Done() {
	f.wg.Done()
	ref := atomic.AddInt32(f.ref, -1)
	f.appendDebug(fmt.Sprintf("done, ref: %v", ref))
	if ref == 0 {
		f.Stop()
	}
}

func (f *Flow) DoneAndClose() {
	f.wg.Done()
	ref := atomic.AddInt32(f.ref, -1)
	f.appendDebug(fmt.Sprintf("done and close, ref: %v", ref))
	f.Stop()
}

func (f *Flow) wait() {
	f.appendDebug("wait")

	done := make(chan struct{})
	printed := int32(0)
	if DefaultDebug && atomic.CompareAndSwapInt32(&f.printed, 0, 1) {
		go func() {
			select {
			case <-done:
				return
			case <-time.After(1000 * time.Millisecond):
				f.printDebug()
				atomic.StoreInt32(&printed, 1)
			}
		}()
	}
	<-f.stopChan
	f.wg.Wait()
	close(done)
	if atomic.LoadInt32(&printed) == 1 {
		println(fmt.Sprint(&f) + " - exit")
	}

	if f.Parent != nil {
		f.Parent.Done()
		f.Parent = nil
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
		f.appendDebug("got closed")
	case <-signalChan:
		f.appendDebug("got signal")
		f.Stop()
	case err = <-f.errChan:
		f.appendDebug(fmt.Sprintf("got error: %v", err))

		if err != nil {
			f.Stop()
		}
	}

	go func() {
		<-signalChan
		// force close
		println("force close")
		os.Exit(1)
	}()

	f.wait()
	return err
}
<|endoftext|>


<commit_before>package plans

import (
	"sort"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/configs/configschema"
	"github.com/zclconf/go-cty/cty"
)

// Plan is the top-level type representing a planned set of changes.
//
// A plan is a summary of the set of changes required to move from a current
// state to a goal state derived from configuration. The described changes
// are not applied directly, but contain an approximation of the final
// result that will be completed during apply by resolving any values that
// cannot be predicted.
//
// A plan must always be accompanied by the state and configuration it was
// built from, since the plan does not itself include all of the information
// required to make the changes indicated.
type Plan struct {
	VariableValues  map[string]DynamicValue
	Changes         *Changes
	TargetAddrs     []addrs.Targetable
	ProviderSHA256s map[string][]byte
	Backend         Backend
}

// Backend represents the backend-related configuration and other data as it
// existed when a plan was created.
type Backend struct {
	// Type is the type of backend that the plan will apply against.
	Type string

	// Config is the configuration of the backend, whose schema is decided by
	// the backend Type.
	Config DynamicValue

	// Workspace is the name of the workspace that was active when the plan
	// was created. It is illegal to apply a plan created for one workspace
	// to the state of another workspace.
	// (This constraint is already enforced by the statefile lineage mechanism,
	// but storing this explicitly allows us to return a better error message
	// in the situation where the user has the wrong workspace selected.)
	Workspace string
}

func NewBackend(typeName string, config cty.Value, configSchema *configschema.Block, workspaceName string) (*Backend, error) {
	dv, err := NewDynamicValue(config, configSchema.ImpliedType())
	if err != nil {
		return nil, err
	}

	return &Backend{
		Type:      typeName,
		Config:    dv,
		Workspace: workspaceName,
	}, nil
}

// ProviderAddrs returns a list of all of the provider configuration addresses
// referenced throughout the receiving plan.
//
// The result is de-duplicated so that each distinct address appears only once.
func (p *Plan) ProviderAddrs() []addrs.AbsProviderConfig {
	if p == nil || p.Changes == nil {
		return nil
	}

	m := map[string]addrs.AbsProviderConfig{}
	for _, rc := range p.Changes.Resources {
		m[rc.ProviderAddr.String()] = rc.ProviderAddr
	}
	if len(m) == 0 {
		return nil
	}

	// This is mainly just so we'll get stable results for testing purposes.
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	ret := make([]addrs.AbsProviderConfig, len(keys))
	for i, key := range keys {
		ret[i] = m[key]
	}

	return ret
}
<commit_msg>add state to plans.Plan<commit_after>package plans

import (
	"sort"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/configs/configschema"
	"github.com/hashicorp/terraform/states"
	"github.com/zclconf/go-cty/cty"
)

// Plan is the top-level type representing a planned set of changes.
//
// A plan is a summary of the set of changes required to move from a current
// state to a goal state derived from configuration. The described changes
// are not applied directly, but contain an approximation of the final
// result that will be completed during apply by resolving any values that
// cannot be predicted.
//
// A plan must always be accompanied by the configuration it was built from,
// since the plan does not itself include all of the information required to
// make the changes indicated.
type Plan struct {
	VariableValues  map[string]DynamicValue
	Changes         *Changes
	TargetAddrs     []addrs.Targetable
	ProviderSHA256s map[string][]byte
	Backend         Backend
	State           *states.State
}

// Backend represents the backend-related configuration and other data as it
// existed when a plan was created.
type Backend struct {
	// Type is the type of backend that the plan will apply against.
	Type string

	// Config is the configuration of the backend, whose schema is decided by
	// the backend Type.
	Config DynamicValue

	// Workspace is the name of the workspace that was active when the plan
	// was created. It is illegal to apply a plan created for one workspace
	// to the state of another workspace.
	// (This constraint is already enforced by the statefile lineage mechanism,
	// but storing this explicitly allows us to return a better error message
	// in the situation where the user has the wrong workspace selected.)
	Workspace string
}

func NewBackend(typeName string, config cty.Value, configSchema *configschema.Block, workspaceName string) (*Backend, error) {
	dv, err := NewDynamicValue(config, configSchema.ImpliedType())
	if err != nil {
		return nil, err
	}

	return &Backend{
		Type:      typeName,
		Config:    dv,
		Workspace: workspaceName,
	}, nil
}

// ProviderAddrs returns a list of all of the provider configuration addresses
// referenced throughout the receiving plan.
//
// The result is de-duplicated so that each distinct address appears only once.
func (p *Plan) ProviderAddrs() []addrs.AbsProviderConfig {
	if p == nil || p.Changes == nil {
		return nil
	}

	m := map[string]addrs.AbsProviderConfig{}
	for _, rc := range p.Changes.Resources {
		m[rc.ProviderAddr.String()] = rc.ProviderAddr
	}
	if len(m) == 0 {
		return nil
	}

	// This is mainly just so we'll get stable results for testing purposes.
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	ret := make([]addrs.AbsProviderConfig, len(keys))
	for i, key := range keys {
		ret[i] = m[key]
	}

	return ret
}
<|endoftext|>