<commit_before>package wavs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/gordonklaus/portaudio"
	log "github.com/sirupsen/logrus"
	"github.com/youpy/go-wav"
)

const (
	WAVS = "./wavs"
	BUF  = 128
)

type Wavs struct {
	wavs    map[string]*wavFile
	stream  *portaudio.Stream
	stopAll chan struct{}
}

type wavFile struct {
	name      string
	buf       []float32
	length    int
	active    chan struct{}
	remaining int
}

func InitWavs() *Wavs {
	err := portaudio.Initialize()
	if err != nil {
		panic(err)
	}

	files, _ := ioutil.ReadDir(WAVS)

	wavs := &Wavs{
		wavs:    map[string]*wavFile{},
		stopAll: make(chan struct{}),
	}

	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".wav") {
			wavs.wavs[f.Name()] = initWav(f)
		}
	}

	wavs.stream, err = portaudio.OpenDefaultStream(0, 1, 44100, BUF, wavs.cb)
	if err != nil {
		panic(err)
	}
	err = wavs.stream.Start()
	if err != nil {
		panic(err)
	}

	return wavs
}

func initWav(f os.FileInfo) *wavFile {
	file, _ := os.Open(WAVS + "/" + f.Name())
	reader := wav.NewReader(file)
	defer file.Close()

	buf := make([]float32, f.Size())
	loc := 0
	for {
		samples, err := reader.ReadSamples()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				panic(fmt.Sprintf("ReadSamples failed on file %s with error: %s", f.Name(), err))
			}
		}

		for _, sample := range samples {
			buf[loc] = float32(reader.FloatValue(sample, 0))
			loc += 1
		}
	}

	w := wavFile{
		name:   f.Name(),
		buf:    make([]float32, loc),
		length: loc,
		active: make(chan struct{}),
	}
	copy(w.buf, buf[:])

	return &w
}

func (w *Wavs) cb(output [][]float32) {
	for _, wv := range w.wavs {
		select {
		case <-wv.active:
			wv.remaining = wv.length
		default:
		}
	}

	select {
	case <-w.stopAll:
		for _, wv := range w.wavs {
			wv.remaining = 0
		}
	default:
	}

	out := make([]float32, BUF)
	for _, wv := range w.wavs {
		for i := 0; i < BUF; i++ {
			if wv.remaining > i {
				// TODO: do this correctly
				// add dynamic range compressor
				out[i] += wv.buf[wv.length-wv.remaining+i]
			}
		}
		wv.remaining -= BUF
	}
	copy(output[0], out)
}

func (w *Wavs) Play(name string) {
	wav, ok := w.wavs[name]
	if !ok {
		log.Debugf("Unknown wav file: %s", name)
		return
	}

	wav.active <- struct{}{}
}

func (w *Wavs) StopAll() {
	w.stopAll <- struct{}{}
}

func (w *Wavs) Durations() map[string]time.Duration {
	durations := map[string]time.Duration{}

	for name, wav := range w.wavs {
		durations[name] = time.Duration(float64(wav.length)/44.1) * time.Millisecond
	}

	return durations
}

func (w *Wavs) Close() {
	w.stream.Stop()
	w.stream.Close()
	portaudio.Terminate()

	log.Debugf("Wavs Closed")
}
<commit_msg>fix racey out of range panic<commit_after>package wavs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/gordonklaus/portaudio"
	log "github.com/sirupsen/logrus"
	"github.com/youpy/go-wav"
)

const (
	WAVS = "./wavs"
	BUF  = 128
)

type Wavs struct {
	wavs    map[string]*wavFile
	stream  *portaudio.Stream
	stopAll chan struct{}
}

type wavFile struct {
	name      string
	buf       []float32
	length    int
	active    chan struct{}
	remaining int
}

func InitWavs() *Wavs {
	err := portaudio.Initialize()
	if err != nil {
		panic(err)
	}

	files, _ := ioutil.ReadDir(WAVS)

	wavs := &Wavs{
		wavs:    map[string]*wavFile{},
		stopAll: make(chan struct{}),
	}

	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".wav") {
			wavs.wavs[f.Name()] = initWav(f)
		}
	}

	wavs.stream, err = portaudio.OpenDefaultStream(0, 1, 44100, BUF, wavs.cb)
	if err != nil {
		panic(err)
	}
	err = wavs.stream.Start()
	if err != nil {
		panic(err)
	}

	return wavs
}

func initWav(f os.FileInfo) *wavFile {
	file, _ := os.Open(WAVS + "/" + f.Name())
	reader := wav.NewReader(file)
	defer file.Close()

	buf := make([]float32, f.Size())
	loc := 0
	for {
		samples, err := reader.ReadSamples()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				panic(fmt.Sprintf("ReadSamples failed on file %s with error: %s", f.Name(), err))
			}
		}

		for _, sample := range samples {
			buf[loc] = float32(reader.FloatValue(sample, 0))
			loc += 1
		}
	}

	w := wavFile{
		name:   f.Name(),
		buf:    make([]float32, loc),
		length: loc,
		active: make(chan struct{}),
	}
	copy(w.buf, buf[:])

	return &w
}

func (w *Wavs) cb(output [][]float32) {
	for _, wv := range w.wavs {
		select {
		case <-wv.active:
			wv.remaining = wv.length
		default:
		}
	}

	select {
	case <-w.stopAll:
		for _, wv := range w.wavs {
			wv.remaining = 0
		}
	default:
	}

	out := make([]float32, BUF)
	for _, wv := range w.wavs {
		for i := 0; i < BUF; i++ {
			loc := wv.length - wv.remaining + i
			if loc >= 0 && loc < len(wv.buf) {
				// TODO: do this correctly
				// add dynamic range compressor
				out[i] += wv.buf[wv.length-wv.remaining+i]
			}
		}
		wv.remaining -= BUF
	}
	copy(output[0], out)
}

func (w *Wavs) Play(name string) {
	wav, ok := w.wavs[name]
	if !ok {
		log.Debugf("Unknown wav file: %s", name)
		return
	}

	wav.active <- struct{}{}
}

func (w *Wavs) StopAll() {
	w.stopAll <- struct{}{}
}

func (w *Wavs) Durations() map[string]time.Duration {
	durations := map[string]time.Duration{}

	for name, wav := range w.wavs {
		durations[name] = time.Duration(float64(wav.length)/44.1) * time.Millisecond
	}

	return durations
}

func (w *Wavs) Close() {
	w.stream.Stop()
	w.stream.Close()
	portaudio.Terminate()

	log.Debugf("Wavs Closed")
}
<|endoftext|>


<commit_before>package dsig

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	_ "crypto/sha1"
	_ "crypto/sha256"
	"encoding/base64"
	"errors"

	"github.com/beevik/etree"
)

type SigningContext struct {
	Hash        crypto.Hash
	KeyStore    X509KeyStore
	IdAttribute string
	Prefix      string
}

func NewDefaultSigningContext(ks X509KeyStore) *SigningContext {
	return &SigningContext{
		Hash:        crypto.SHA256,
		KeyStore:    ks,
		IdAttribute: DefaultIdAttr,
		Prefix:      DefaultPrefix,
	}
}

func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) {

	doc := etree.CreateDocument(canonicalHack(el))
	doc.WriteSettings = etree.WriteSettings{
		CanonicalAttrVal: true,
		CanonicalEndTags: true,
		CanonicalText:    true,
	}

	hash := ctx.Hash.New()
	_, err := doc.WriteTo(hash)
	if err != nil {
		return nil, err
	}

	return hash.Sum(nil), nil
}

func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) {
	digestAlgorithmIdentifier, ok := digestAlgorithmIdentifiers[ctx.Hash]
	if !ok {
		return nil, errors.New("unsupported hash mechanism")
	}

	signatureMethodIdentifier, ok := signatureMethodIdentifiers[ctx.Hash]
	if !ok {
		return nil, errors.New("unsupported signature method")
	}

	digest, err := ctx.digest(el)
	if err != nil {
		return nil, err
	}

	signedInfo := &etree.Element{
		Tag:   SignedInfoTag,
		Space: ctx.Prefix,
	}

	// /SignedInfo/CanonicalizationMethod
	canonicalizationMethod := ctx.createNamespacedElement(signedInfo, CanonicalizationMethodTag)
	canonicalizationMethod.CreateAttr(AlgorithmAttr, CanonicalXML11AlgorithmId)

	// /SignedInfo/SignatureMethod
	signatureMethod := ctx.createNamespacedElement(signedInfo, SignatureMethodTag)
	signatureMethod.CreateAttr(AlgorithmAttr, signatureMethodIdentifier)

	// /SignedInfo/Reference
	reference := ctx.createNamespacedElement(signedInfo, ReferenceTag)

	dataId := el.SelectAttrValue(DefaultIdAttr, "")
	if dataId == "" {
		return nil, errors.New("Missing data ID")
	}

	reference.CreateAttr(URIAttr, "#"+dataId)

	// /SignedInfo/Reference/Transforms
	transforms := ctx.createNamespacedElement(reference, TransformsTag)
	if enveloped {
		envelopedTransform := ctx.createNamespacedElement(transforms, TransformTag)
		envelopedTransform.CreateAttr(AlgorithmAttr, EnvelopedSignatureAltorithmId)
	}
	canonicalizationAlgorithm := ctx.createNamespacedElement(transforms, TransformTag)
	canonicalizationAlgorithm.CreateAttr(AlgorithmAttr, CanonicalXML11AlgorithmId)

	// /SignedInfo/Reference/DigestMethod
	digestMethod := ctx.createNamespacedElement(reference, DigestMethodTag)
	digestMethod.CreateAttr(AlgorithmAttr, digestAlgorithmIdentifier)

	// /SignedInfo/Reference/DigestValue
	digestValue := ctx.createNamespacedElement(reference, DigestValueTag)
	digestValue.SetText(base64.StdEncoding.EncodeToString(digest))

	return signedInfo, nil
}

func (ctx *SigningContext) constructSignature(el *etree.Element, enveloped bool) (*etree.Element, error) {
	signedInfo, err := ctx.constructSignedInfo(el, enveloped)
	if err != nil {
		return nil, err
	}

	sig := &etree.Element{
		Tag:   SignatureTag,
		Space: ctx.Prefix,
	}

	xmlns := "xmlns"
	if ctx.Prefix != "" {
		xmlns += ":" + ctx.Prefix
	}

	sig.CreateAttr(xmlns, Namespace)

	sig.Child = append(sig.Child, signedInfo)

	digest, err := ctx.digest(signedInfo)
	if err != nil {
		return nil, err
	}

	key, cert, err := ctx.KeyStore.GetKeyPair()
	if err != nil {
		return nil, err
	}

	rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest)
	if err != nil {
		return nil, err
	}

	signatureValue := ctx.createNamespacedElement(sig, SignatureValueTag)
	signatureValue.SetText(base64.StdEncoding.EncodeToString(rawSignature))

	keyInfo := ctx.createNamespacedElement(sig, KeyInfoTag)
	x509Data := ctx.createNamespacedElement(keyInfo, X509DataTag)
	x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag)
	x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert))

	return sig, nil
}

func (ctx *SigningContext) createNamespacedElement(el *etree.Element, tag string) *etree.Element {
	child := el.CreateElement(tag)
	child.Space = ctx.Prefix
	return child
}

func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, error) {
	sig, err := ctx.constructSignature(el, true)
	if err != nil {
		return nil, err
	}

	ret := el.Copy()
	ret.Child = append(ret.Child, sig)

	return ret, nil
}
<commit_msg>sign.go: removed accidental whitespace addition<commit_after>package dsig

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	_ "crypto/sha1"
	_ "crypto/sha256"
	"encoding/base64"
	"errors"

	"github.com/beevik/etree"
)

type SigningContext struct {
	Hash        crypto.Hash
	KeyStore    X509KeyStore
	IdAttribute string
	Prefix      string
}

func NewDefaultSigningContext(ks X509KeyStore) *SigningContext {
	return &SigningContext{
		Hash:        crypto.SHA256,
		KeyStore:    ks,
		IdAttribute: DefaultIdAttr,
		Prefix:      DefaultPrefix,
	}
}

func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) {
	doc := etree.CreateDocument(canonicalHack(el))
	doc.WriteSettings = etree.WriteSettings{
		CanonicalAttrVal: true,
		CanonicalEndTags: true,
		CanonicalText:    true,
	}

	hash := ctx.Hash.New()
	_, err := doc.WriteTo(hash)
	if err != nil {
		return nil, err
	}

	return hash.Sum(nil), nil
}

func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) {
	digestAlgorithmIdentifier, ok := digestAlgorithmIdentifiers[ctx.Hash]
	if !ok {
		return nil, errors.New("unsupported hash mechanism")
	}

	signatureMethodIdentifier, ok := signatureMethodIdentifiers[ctx.Hash]
	if !ok {
		return nil, errors.New("unsupported signature method")
	}

	digest, err := ctx.digest(el)
	if err != nil {
		return nil, err
	}

	signedInfo := &etree.Element{
		Tag:   SignedInfoTag,
		Space: ctx.Prefix,
	}

	// /SignedInfo/CanonicalizationMethod
	canonicalizationMethod := ctx.createNamespacedElement(signedInfo, CanonicalizationMethodTag)
	canonicalizationMethod.CreateAttr(AlgorithmAttr, CanonicalXML11AlgorithmId)

	// /SignedInfo/SignatureMethod
	signatureMethod := ctx.createNamespacedElement(signedInfo, SignatureMethodTag)
	signatureMethod.CreateAttr(AlgorithmAttr, signatureMethodIdentifier)

	// /SignedInfo/Reference
	reference := ctx.createNamespacedElement(signedInfo, ReferenceTag)

	dataId := el.SelectAttrValue(DefaultIdAttr, "")
	if dataId == "" {
		return nil, errors.New("Missing data ID")
	}

	reference.CreateAttr(URIAttr, "#"+dataId)

	// /SignedInfo/Reference/Transforms
	transforms := ctx.createNamespacedElement(reference, TransformsTag)
	if enveloped {
		envelopedTransform := ctx.createNamespacedElement(transforms, TransformTag)
		envelopedTransform.CreateAttr(AlgorithmAttr, EnvelopedSignatureAltorithmId)
	}
	canonicalizationAlgorithm := ctx.createNamespacedElement(transforms, TransformTag)
	canonicalizationAlgorithm.CreateAttr(AlgorithmAttr, CanonicalXML11AlgorithmId)

	// /SignedInfo/Reference/DigestMethod
	digestMethod := ctx.createNamespacedElement(reference, DigestMethodTag)
	digestMethod.CreateAttr(AlgorithmAttr, digestAlgorithmIdentifier)

	// /SignedInfo/Reference/DigestValue
	digestValue := ctx.createNamespacedElement(reference, DigestValueTag)
	digestValue.SetText(base64.StdEncoding.EncodeToString(digest))

	return signedInfo, nil
}

func (ctx *SigningContext) constructSignature(el *etree.Element, enveloped bool) (*etree.Element, error) {
	signedInfo, err := ctx.constructSignedInfo(el, enveloped)
	if err != nil {
		return nil, err
	}

	sig := &etree.Element{
		Tag:   SignatureTag,
		Space: ctx.Prefix,
	}

	xmlns := "xmlns"
	if ctx.Prefix != "" {
		xmlns += ":" + ctx.Prefix
	}

	sig.CreateAttr(xmlns, Namespace)

	sig.Child = append(sig.Child, signedInfo)

	digest, err := ctx.digest(signedInfo)
	if err != nil {
		return nil, err
	}

	key, cert, err := ctx.KeyStore.GetKeyPair()
	if err != nil {
		return nil, err
	}

	rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest)
	if err != nil {
		return nil, err
	}

	signatureValue := ctx.createNamespacedElement(sig, SignatureValueTag)
	signatureValue.SetText(base64.StdEncoding.EncodeToString(rawSignature))

	keyInfo := ctx.createNamespacedElement(sig, KeyInfoTag)
	x509Data := ctx.createNamespacedElement(keyInfo, X509DataTag)
	x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag)
	x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert))

	return sig, nil
}

func (ctx *SigningContext) createNamespacedElement(el *etree.Element, tag string) *etree.Element {
	child := el.CreateElement(tag)
	child.Space = ctx.Prefix
	return child
}

func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, error) {
	sig, err := ctx.constructSignature(el, true)
	if err != nil {
		return nil, err
	}

	ret := el.Copy()
	ret.Child = append(ret.Child, sig)

	return ret, nil
}
<|endoftext|>


<commit_before>package egoscale

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

func (exo *Client) GetSecurityGroups() (map[string]string, error) {
	var sgs map[string]string
	params := url.Values{}
	resp, err := exo.Request("listSecurityGroups", params)

	if err != nil {
		return nil, err
	}

	var r ListSecurityGroupsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	sgs = make(map[string]string)
	for _, sg := range r.SecurityGroups {
		sgs[sg.Name] = sg.Id
	}
	return sgs, nil
}

func (exo *Client) GetZones() (map[string]string, error) {
	var zones map[string]string
	params := url.Values{}
	resp, err := exo.Request("listZones", params)

	if err != nil {
		return nil, err
	}

	var r ListZonesResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	zones = make(map[string]string)
	for _, zone := range r.Zones {
		zones[zone.Name] = zone.Id
	}
	return zones, nil
}

func (exo *Client) GetProfiles() (map[string]string, error) {

	var profiles map[string]string
	params := url.Values{}
	resp, err := exo.Request("listServiceOfferings", params)

	if err != nil {
		return nil, err
	}

	var r ListServiceOfferingsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	profiles = make(map[string]string)
	for _, offering := range r.ServiceOfferings {
		profiles[strings.ToLower(offering.Name)] = offering.Id
	}

	return profiles, nil
}

func (exo *Client) GetKeypairs() ([]string, error) {

	var keypairs []string
	params := url.Values{}

	resp, err := exo.Request("listSSHKeyPairs", params)

	if err != nil {
		return nil, err
	}

	var r ListSSHKeyPairsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	keypairs = make([]string, r.Count, r.Count)
	for i, keypair := range r.SSHKeyPairs {
		keypairs[i] = keypair.Name
	}
	return keypairs, nil
}

func (exo *Client) GetImages() (map[string]map[int]string, error) {
	var images map[string]map[int]string
	images = make(map[string]map[int]string)

	params := url.Values{}
	params.Set("templatefilter", "featured")

	resp, err := exo.Request("listTemplates", params)

	if err != nil {
		return nil, err
	}

	var r ListTemplatesResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	re := regexp.MustCompile(`^Linux (?P<name>.+?) (?P<version>[0-9.]+).*$`)
	for _, template := range r.Templates {
		size := int(template.Size / (1024 * 1024 * 1024))
		submatch := re.FindStringSubmatch(template.Name)
		if len(submatch) > 0 {
			name := strings.Replace(strings.ToLower(submatch[1]), " ", "-", -1)
			version := submatch[2]
			image := fmt.Sprintf("%s-%s", name, version)

			_, present := images[image]
			if !present {
				images[image] = make(map[int]string)
			}
			images[image][size] = template.Id

			images[fmt.Sprintf("%s-%s", name, version)][size] = template.Id
		}
	}
	return images, nil
}

func (exo *Client) GetTopology() (*Topology, error) {

	zones, err := exo.GetZones()
	if err != nil {
		return nil, err
	}
	images, err := exo.GetImages()
	if err != nil {
		return nil, err
	}
	groups, err := exo.GetSecurityGroups()
	if err != nil {
		return nil, err
	}
	keypairs, err := exo.GetKeypairs()
	if err != nil {
		return nil, err
	}
	profiles, err := exo.GetProfiles()
	if err != nil {
		return nil, err
	}

	topo := &Topology{
		Zones:          zones,
		Profiles:       profiles,
		Images:         images,
		Keypairs:       keypairs,
		SecurityGroups: groups,
	}

	return topo, nil
}
<commit_msg>list executable templates<commit_after>package egoscale

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

func (exo *Client) GetSecurityGroups() (map[string]string, error) {
	var sgs map[string]string
	params := url.Values{}
	resp, err := exo.Request("listSecurityGroups", params)

	if err != nil {
		return nil, err
	}

	var r ListSecurityGroupsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	sgs = make(map[string]string)
	for _, sg := range r.SecurityGroups {
		sgs[sg.Name] = sg.Id
	}
	return sgs, nil
}

func (exo *Client) GetZones() (map[string]string, error) {
	var zones map[string]string
	params := url.Values{}
	resp, err := exo.Request("listZones", params)

	if err != nil {
		return nil, err
	}

	var r ListZonesResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	zones = make(map[string]string)
	for _, zone := range r.Zones {
		zones[zone.Name] = zone.Id
	}
	return zones, nil
}

func (exo *Client) GetProfiles() (map[string]string, error) {

	var profiles map[string]string
	params := url.Values{}
	resp, err := exo.Request("listServiceOfferings", params)

	if err != nil {
		return nil, err
	}

	var r ListServiceOfferingsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	profiles = make(map[string]string)
	for _, offering := range r.ServiceOfferings {
		profiles[strings.ToLower(offering.Name)] = offering.Id
	}

	return profiles, nil
}

func (exo *Client) GetKeypairs() ([]string, error) {

	var keypairs []string
	params := url.Values{}

	resp, err := exo.Request("listSSHKeyPairs", params)

	if err != nil {
		return nil, err
	}

	var r ListSSHKeyPairsResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	keypairs = make([]string, r.Count, r.Count)
	for i, keypair := range r.SSHKeyPairs {
		keypairs[i] = keypair.Name
	}
	return keypairs, nil
}

func (exo *Client) GetImages() (map[string]map[int]string, error) {
	var images map[string]map[int]string
	images = make(map[string]map[int]string)

	params := url.Values{}
	params.Set("templatefilter", "executable")

	resp, err := exo.Request("listTemplates", params)

	if err != nil {
		return nil, err
	}

	var r ListTemplatesResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	re := regexp.MustCompile(`^Linux (?P<name>.+?) (?P<version>[0-9.]+).*$`)
	for _, template := range r.Templates {
		size := int(template.Size / (1024 * 1024 * 1024))
		submatch := re.FindStringSubmatch(template.Name)
		if len(submatch) > 0 {
			name := strings.Replace(strings.ToLower(submatch[1]), " ", "-", -1)
			version := submatch[2]
			image := fmt.Sprintf("%s-%s", name, version)

			_, present := images[image]
			if !present {
				images[image] = make(map[int]string)
			}
			images[image][size] = template.Id

			images[fmt.Sprintf("%s-%s", name, version)][size] = template.Id
		}
	}
	return images, nil
}

func (exo *Client) GetTopology() (*Topology, error) {

	zones, err := exo.GetZones()
	if err != nil {
		return nil, err
	}
	images, err := exo.GetImages()
	if err != nil {
		return nil, err
	}
	groups, err := exo.GetSecurityGroups()
	if err != nil {
		return nil, err
	}
	keypairs, err := exo.GetKeypairs()
	if err != nil {
		return nil, err
	}
	profiles, err := exo.GetProfiles()
	if err != nil {
		return nil, err
	}

	topo := &Topology{
		Zones:          zones,
		Profiles:       profiles,
		Images:         images,
		Keypairs:       keypairs,
		SecurityGroups: groups,
	}

	return topo, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"text/tabwriter"
)

var languages = []Language{
	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Haskell", mExt(".hs", ".lhs"), noComments},
	Language{"Perl", mExt(".pl", ".pm"), shComments},
	Language{"Python", mExt(".py"), noComments},
	Language{"Lisp", mExt(".lsp"), semiComments},
	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"HTML", mExt(".htm", ".html", ".xhtml"), noComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if b == lc[lp] && !(inComment > 0) {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if b == sc[sp] && !inLComment {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if b == ec[ep] && !inLComment && inComment > 0 {
			ep++
			if ep == len(ec) {
				inComment--
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if blank {
				s.BlankLines++
			}
			if inComment > 0 || inLComment {
				if blank {
					s.CodeLines++
				}
				inLComment = false
				s.CommentLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	for n, i := range info {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}
	w.Flush()
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}
	printInfo()
}
<commit_msg>Adding -V flag<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"text/tabwriter"
)

const VERSION = `0.1`

var languages = []Language{
	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Haskell", mExt(".hs", ".lhs"), noComments},
	Language{"Perl", mExt(".pl", ".pm"), shComments},
	Language{"Python", mExt(".py"), noComments},
	Language{"Lisp", mExt(".lsp"), semiComments},
	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"HTML", mExt(".htm", ".html", ".xhtml"), noComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments = Commenter{"\000", "\000", "\000", false}
	cComments  = Commenter{`//`, `/*`, `*/`, false}
	shComments = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if b == lc[lp] && !(inComment > 0) {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else { lp = 0 }
		if b == sc[sp] && !inLComment {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else { sp = 0 }
		if b == ec[ep] && !inLComment && inComment > 0 {
			ep++
			if ep == len(ec) {
				inComment--
				ep = 0
			}
		} else { ep = 0 }

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if blank {
				s.BlankLines++
			}
			if inComment > 0 || inLComment {
				if blank {
					s.CodeLines++
				}
				inLComment = false
				s.CommentLines++
			} else { s.CodeLines++ }
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFile(fname string) {
	var l Language
	ok := false
	for _, lang := range languages {
		if lang.Match(fname) {
			ok = true
			l = lang
			break
		}
	}
	if !ok {
		return // ignore this file
	}
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	for n, i := range info {
		fmt.Fprintf(
			w,
			"%s\t%d\t%d\t%d\t%d\t%d\t\n",
			n,
			i.FileCount,
			i.CodeLines,
			i.CommentLines,
			i.BlankLines,
			i.TotalLines)
	}
	w.Flush()
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	version = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}
	printInfo()
}
<|endoftext|>


<commit_before>package solr

import (
)

type Document struct {
	fields map[string]interface{}
}

type Collection struct {
	docs     []Document
	start    int
	numFound int
}

type SolrInterface struct {
	format string
	conn   *Connection
}

func NewSolrInterface(solrUrl string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c, format: "json"}, nil
}

func (si *SolrInterface) Search(q *Query) *Search {
	s := NewSearch(si.conn, q)

	return s
}

func (si *SolrInterface) Add(docs []string) {

}

func (si *SolrInterface) Delete(data map[string]interface{}) (*UpdateResponse, error) {
	// prepare delete message here
	message := data
	return si.conn.Update(message)
}

func (si *SolrInterface) Update(data map[string]interface{}) (*UpdateResponse, error) {
	// prepare message
	message := data

	return si.conn.Update(message)
}

func (si *SolrInterface) Commit() (*UpdateResponse, error) {
	return si.conn.Commit()
}

func (si *SolrInterface) Optimize() (*UpdateResponse, error) {
	return si.conn.Optimize()
}

func (si *SolrInterface) Rollback() (*UpdateResponse, error) {
	return si.conn.Rollback()
}
<commit_msg>type should be Document<commit_after>package solr

import (
)

type Document struct {
	fields map[string]interface{}
}

type Collection struct {
	docs     []Document
	start    int
	numFound int
}

type SolrInterface struct {
	format string
	conn   *Connection
}

func NewSolrInterface(solrUrl string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c, format: "json"}, nil
}

func (si *SolrInterface) Search(q *Query) *Search {
	s := NewSearch(si.conn, q)

	return s
}

func (si *SolrInterface) Add(docs []*Document) {

}

func (si *SolrInterface) Delete(data map[string]interface{}) (*UpdateResponse, error) {
	// prepare delete message here
	message := data
	return si.conn.Update(message)
}

func (si *SolrInterface) Update(data map[string]interface{}) (*UpdateResponse, error) {
	// prepare message
	message := data

	return si.conn.Update(message)
}

func (si *SolrInterface) Commit() (*UpdateResponse, error) {
	return si.conn.Commit()
}

func (si *SolrInterface) Optimize() (*UpdateResponse, error) {
	return si.conn.Optimize()
}

func (si *SolrInterface) Rollback() (*UpdateResponse, error) {
	return si.conn.Rollback()
}
<|endoftext|>


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

// Package gcimporter implements Import for gc-generated object files.
package gcimporter // import "go/internal/gcimporter"

import (
	"bufio"
	"fmt"
	"go/build"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// debugging/development support
const debug = false

var pkgExts = [...]string{".a", ".o"}

// FindPkg returns the filename and unique package id for an import
// path based on package information provided by build.Import (using
// the build.Default build.Context). A relative srcDir is interpreted
// relative to the current working directory.
// If no file was found, an empty filename is returned.
//
func FindPkg(path, srcDir string) (filename, id string) {
	if path == "" {
		return
	}

	var noext string
	switch {
	default:
		// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
		// Don't require the source files to be present.
		if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
			srcDir = abs
		}
		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
		if bp.PkgObj == "" {
			return
		}
		noext = strings.TrimSuffix(bp.PkgObj, ".a")
		id = bp.ImportPath

	case build.IsLocalImport(path):
		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
		noext = filepath.Join(srcDir, path)
		id = noext

	case filepath.IsAbs(path):
		// for completeness only - go/build.Import
		// does not support absolute imports
		// "/x" -> "/x.ext", "/x"
		noext = path
		id = path
	}

	if false { // for debugging
		if path != id {
			fmt.Printf("%s -> %s\n", path, id)
		}
	}

	// try extensions
	for _, ext := range pkgExts {
		filename = noext + ext
		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
			return
		}
	}

	filename = "" // not found
	return
}

// Import imports a gc-generated package given its import path and srcDir, adds
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
//
func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types.Package, err error) {
	filename, id := FindPkg(path, srcDir)
	if filename == "" {
		if path == "unsafe" {
			return types.Unsafe, nil
		}
		err = fmt.Errorf("can't find import: %s", id)
		return
	}

	// no need to re-import if the package was imported completely before
	if pkg = packages[id]; pkg != nil && pkg.Complete() {
		return
	}

	// open file
	f, err := os.Open(filename)
	if err != nil {
		return
	}
	defer func() {
		f.Close()
		if err != nil {
			// add file name to error
			err = fmt.Errorf("%s: %v", filename, err)
		}
	}()

	var hdr string
	buf := bufio.NewReader(f)
	if hdr, err = FindExportData(buf); err != nil {
		return
	}

	switch hdr {
	case "$$\n":
		err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
	case "$$B\n":
		var data []byte
		data, err = ioutil.ReadAll(buf)
		if err == nil {
			// TODO(gri): allow clients of go/importer to provide a FileSet.
			// Or, define a new standard go/types/gcexportdata package.
			fset := token.NewFileSet()
			_, pkg, err = BImportData(fset, packages, data, id)
			return
		}
	default:
		err = fmt.Errorf("unknown export data header: %q", hdr)
	}

	return
}

func deref(typ types.Type) types.Type {
	if p, _ := typ.(*types.Pointer); p != nil {
		return p.Elem()
	}
	return typ
}

type byPath []*types.Package

func (a byPath) Len() int           { return len(a) }
func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
<commit_msg>go/importer: report import path if package is not found<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package gcimporter implements Import for gc-generated object files.
package gcimporter // import "go/internal/gcimporter"

import (
	"bufio"
	"fmt"
	"go/build"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// debugging/development support
const debug = false

var pkgExts = [...]string{".a", ".o"}

// FindPkg returns the filename and unique package id for an import
// path based on package information provided by build.Import (using
// the build.Default build.Context). A relative srcDir is interpreted
// relative to the current working directory.
// If no file was found, an empty filename is returned.
//
func FindPkg(path, srcDir string) (filename, id string) {
	if path == "" {
		return
	}

	var noext string
	switch {
	default:
		// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
		// Don't require the source files to be present.
		if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
			srcDir = abs
		}
		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
		if bp.PkgObj == "" {
			id = path // make sure we have an id to print in error message
			return
		}
		noext = strings.TrimSuffix(bp.PkgObj, ".a")
		id = bp.ImportPath

	case build.IsLocalImport(path):
		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
		noext = filepath.Join(srcDir, path)
		id = noext

	case filepath.IsAbs(path):
		// for completeness only - go/build.Import
		// does not support absolute imports
		// "/x" -> "/x.ext", "/x"
		noext = path
		id = path
	}

	if false { // for debugging
		if path != id {
			fmt.Printf("%s -> %s\n", path, id)
		}
	}

	// try extensions
	for _, ext := range pkgExts {
		filename = noext + ext
		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
			return
		}
	}

	filename = "" // not found
	return
}

// Import imports a gc-generated package given its import path and srcDir, adds
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
//
func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types.Package, err error) {
	filename, id := FindPkg(path, srcDir)
	if filename == "" {
		if path == "unsafe" {
			return types.Unsafe, nil
		}
		err = fmt.Errorf("can't find import: %q", id)
		return
	}

	// no need to re-import if the package was imported completely before
	if pkg = packages[id]; pkg != nil && pkg.Complete() {
		return
	}

	// open file
	f, err := os.Open(filename)
	if err != nil {
		return
	}
	defer func() {
		f.Close()
		if err != nil {
			// add file name to error
			err = fmt.Errorf("%s: %v", filename, err)
		}
	}()

	var hdr string
	buf := bufio.NewReader(f)
	if hdr, err = FindExportData(buf); err != nil {
		return
	}

	switch hdr {
	case "$$\n":
		err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
	case "$$B\n":
		var data []byte
		data, err = ioutil.ReadAll(buf)
		if err == nil {
			// TODO(gri): allow clients of go/importer to provide a FileSet.
			// Or, define a new standard go/types/gcexportdata package.
			fset := token.NewFileSet()
			_, pkg, err = BImportData(fset, packages, data, id)
			return
		}
	default:
		err = fmt.Errorf("unknown export data header: %q", hdr)
	}

	return
}

func deref(typ types.Type) types.Type {
	if p, _ := typ.(*types.Pointer); p != nil {
		return p.Elem()
	}
	return typ
}

type byPath []*types.Package

func (a byPath) Len() int           { return len(a) }
func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strings"
)

type specRegistry struct {
	Types      []specType      `xml:"types>type"`
	Enums      []specEnumSet   `xml:"enums"`
	Commands   []specCommand   `xml:"commands>command"`
	Features   []specFeature   `xml:"feature"`
	Extensions []specExtension `xml:"extensions>extension"`
}

type specType struct {
	Name     string `xml:"name,attr"`
	Api      string `xml:"api,attr"`
	Requires string `xml:"requires,attr"`
	Raw      []byte `xml:",innerxml"`
}

type specEnumSet struct {
	Enums []specEnum `xml:"enum"`
}

type specEnum struct {
	Name  string `xml:"name,attr"`
	Value string `xml:"value,attr"`
	Api   string `xml:"api,attr"`
}

type specCommand struct {
	Prototype specProto   `xml:"proto"`
	Api       string      `xml:"api"`
	Params    []specParam `xml:"param"`
}

type specSignature []byte

type specProto struct {
	Raw specSignature `xml:",innerxml"`
}

type specParam struct {
	Raw specSignature `xml:",innerxml"`
}

type specFeature struct {
	Api      string        `xml:"api,attr"`
	Number   string        `xml:"number,attr"`
	Requires []specRequire `xml:"require"`
	Removes  []specRemove  `xml:"remove"`
}

type specRequire struct {
	Enums    []specEnumRef    `xml:"enum"`
	Commands []specCommandRef `xml:"command"`
}

type specRemove struct {
	Enums    []specEnumRef    `xml:"enum"`
	Commands []specCommandRef `xml:"command"`
}

type specEnumRef struct {
	Name string `xml:"name,attr"`
}

type specCommandRef struct {
	Name string `xml:"name,attr"`
}

type specExtension struct {
	Name      string        `xml:"name,attr"`
	Supported string        `xml:"supported,attr"`
	Requires  []specRequire `xml:"require"`
}

type specRef struct {
	Name string
	Api  string
}

type specTypedef struct {
	ref      specRef
	typedef  *Typedef
	required bool
}

type specFunctions map[specRef]*Function
type specEnums map[specRef]*Enum

// Use an ordered list to preserve the XML declaration ordering which encodes implicit dependencies
type specTypedefs []specTypedef

// Parsed version of the XML specification
type Specification struct {
	Functions specFunctions
	Enums     specEnums
	Typedefs  specTypedefs
	Features  []SpecificationFeature
}

type SpecificationFeature struct {
	Api     string
	Version Version

	AddedEnums      []string
	AddedCommands   []string
	RemovedEnums    []string
	RemovedCommands []string
}

func readSpecFile(file string) (*specRegistry, error) {
	var registry specRegistry

	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	err = xml.NewDecoder(f).Decode(&registry)
	if err != nil {
		return nil, err
	}

	return &registry, nil
}

func parseFunctions(commands []specCommand) (specFunctions, error) {
	functions := make(specFunctions)
	for _, cmd := range commands {
		cmdName, cmdReturnType, err := parseSignature(cmd.Prototype.Raw)
		if err != nil {
			return functions, err
		}

		parameters := make([]Parameter, 0, len(cmd.Params))
		for _, param := range cmd.Params {
			paramName, paramType, err := parseSignature(param.Raw)
			if err != nil {
				return functions, err
			}
			parameter := Parameter{
				Name: paramName,
				Type: paramType}
			parameters = append(parameters, parameter)
		}

		fnRef := specRef{cmdName, cmd.Api}
		functions[fnRef] = &Function{
			Name:       cmdName,
			GoName:     TrimGLCmdPrefix(cmdName),
			Parameters: parameters,
			Return:     cmdReturnType}
	}
	return functions, nil
}

func parseSignature(signature specSignature) (string, Type, error) {
	name := ""
	ctype := Type{}

	readingName := false
	readingType := false

	decoder := xml.NewDecoder(bytes.NewBuffer(signature))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return name, ctype, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := strings.Trim(string(t), " ")
			if readingName {
				name = raw
			} else if readingType {
				ctype.Name = raw
			} else {
				if strings.Contains(raw, "void") {
					ctype.Name = "void"
				}
				ctype.PointerLevel += strings.Count(raw, "*")
			}
			if !readingName {
				ctype.CDefinition += string(t)
			}
		case xml.StartElement:
			if t.Name.Local == "ptype" {
				readingType = true
			} else if t.Name.Local == "name" {
				readingName = true
			} else {
				return name, ctype, fmt.Errorf("Unexpected signature XML: %s", signature)
			}
		case xml.EndElement:
			if t.Name.Local == "ptype" {
				readingType = false
			} else if t.Name.Local == "name" {
				readingName = false
			}
		}
	}
	return name, ctype, nil
}

func parseEnums(enumSets []specEnumSet) (specEnums, error) {
	enums := make(specEnums)
	for _, set := range enumSets {
		for _, enum := range set.Enums {
			enumRef := specRef{enum.Name, enum.Api}
			enums[enumRef] = &Enum{
				Name:   enum.Name,
				GoName: TrimGLEnumPrefix(enum.Name),
				Value:  enum.Value}
		}
	}
	return enums, nil
}

func parseTypedefs(specTypes []specType) (specTypedefs, error) {
	typedefs := make(specTypedefs, 0, len(specTypes))
	for _, specType := range specTypes {
		typedef, err := parseTypedef(specType)
		if err != nil {
			return nil, err
		}
		specTd := specTypedef{
			specRef{typedef.Name, specType.Api},
			typedef,
			false}
		typedefs = append(typedefs, specTd)
	}
	return typedefs, nil
}

func parseTypedef(specType specType) (*Typedef, error) {
	typedef := &Typedef{
		Name:        specType.Name,
		Api:         specType.Api,
		Requires:    specType.Requires,
		CDefinition: ""}

	readingName := false
	decoder := xml.NewDecoder(bytes.NewBuffer(specType.Raw))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return typedef, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := string(t)
			typedef.CDefinition += raw
			if readingName {
				typedef.Name = raw
			}
		case xml.StartElement:
			if t.Name.Local == "name" {
				readingName = true
			} else if t.Name.Local == "apientry" {
				typedef.CDefinition += "APIENTRY"
			} else {
				return typedef, fmt.Errorf("Unexpected typedef XML: %s", specType.Raw)
			}
		case xml.EndElement:
			if t.Name.Local == "name" {
				readingName = false
			}
		default:
			return typedef, fmt.Errorf("Unexpected typedef XML: %s", specType.Raw)
		}
	}

	return typedef, nil
}

func parseFeatures(features []specFeature) ([]SpecificationFeature, error) {
	specFeatures := make([]SpecificationFeature, 0, len(features))
	for _, feature := range features {
		version, err := ParseVersion(feature.Number)
		if err != nil {
			return specFeatures, err
		}

		specFeature := SpecificationFeature{
			Api:             feature.Api,
			Version:         version,
			AddedEnums:      make([]string, 0),
			AddedCommands:   make([]string, 0),
			RemovedEnums:    make([]string, 0),
			RemovedCommands: make([]string, 0),
		}

		for _, req := range feature.Requires {
			for _, cmd := range req.Commands {
				specFeature.AddedCommands = append(specFeature.AddedCommands, cmd.Name)
			}
			for _, enum := range req.Enums {
				specFeature.AddedEnums = append(specFeature.AddedEnums, enum.Name)
			}
		}

		for _, rem := range feature.Removes {
			for _, cmd := range rem.Commands {
				specFeature.RemovedCommands = append(specFeature.RemovedCommands, cmd.Name)
			}
			for _, enum := range rem.Enums {
				specFeature.RemovedEnums = append(specFeature.RemovedEnums, enum.Name)
			}
		}

		specFeatures = append(specFeatures, specFeature)
	}
	return specFeatures, nil
}

func (functions specFunctions) get(name, api string) *Function {
	function, ok := functions[specRef{name, api}]
	if ok {
		return function
	}
	return functions[specRef{name, ""}]
}

func (enums specEnums) get(name, api string) *Enum {
	enum, ok := enums[specRef{name, api}]
	if ok {
		return enum
	}
	return enums[specRef{name, ""}]
}

func (typedefs specTypedefs) markRequired(name, api string) {
	for _, considerApi := range []bool{true, false} {
		for i, typedef := range typedefs {
			if typedef.ref.Name == name && (typedef.ref.Api == api || !considerApi) {
				typedefs[i].required = true
				if typedef.typedef.Requires != "" {
					typedefs.markRequired(typedef.typedef.Requires, api)
				}
				return
			}
		}
	}
}

// NewSpecification creates a new specification based on an XML file.
func NewSpecification(file string) (*Specification, error) {
	registry, err := readSpecFile(file)
	if err != nil {
		return nil, err
	}

	functions, err := parseFunctions(registry.Commands)
	if err != nil {
		return nil, err
	}

	enums, err := parseEnums(registry.Enums)
	if err != nil {
		return nil, err
	}

	typedefs, err := parseTypedefs(registry.Types)
	if err != nil {
		return nil, err
	}

	features, err := parseFeatures(registry.Features)
	if err != nil {
		return nil, err
	}

	spec := &Specification{
		Functions: functions,
		Enums:     enums,
		Typedefs:  typedefs,
		Features:  features,
	}
	return spec, nil
}

// HasPackage determines whether the specification can generate the specified package.
func (spec *Specification) HasPackage(pkgSpec PackageSpec) bool {
	for _, feature := range spec.Features {
		if pkgSpec.Api == feature.Api && pkgSpec.Version.Compare(feature.Version) == 0 {
			return true
		}
	}
	return false
}

// ToPackage generates a package from the specification.
func (spec *Specification) ToPackage(pkgSpec PackageSpec) *Package {
	pkg := &Package{
		Api:       pkgSpec.Api,
		Name:      pkgSpec.Api,
		Version:   pkgSpec.Version,
		Typedefs:  make([]*Typedef, 0),
		Enums:     make(Enums),
		Functions: make(Functions)}

	// Select the commands and enums relevant to the specified API version
	for _, feature := range spec.Features {
		// Skip features from a different API
		if pkg.Api != feature.Api {
			continue
		}
		// Skip features from a later version than the package
		if pkg.Version.Compare(feature.Version) < 0 {
			continue
		}

		for _, enum := range feature.AddedEnums {
			pkg.Enums[enum] = spec.Enums.get(enum, pkg.Api)
		}
		for _, cmd := range feature.AddedCommands {
			pkg.Functions[cmd] = spec.Functions.get(cmd, pkg.Api)
		}

		for _, enum := range feature.RemovedEnums {
			delete(pkg.Enums, enum)
		}
		for _, cmd := range feature.RemovedCommands {
			delete(pkg.Functions, cmd)
		}
	}

	// Add the types necessary to declare the functions
	specTypedefs := make(specTypedefs, len(spec.Typedefs))
	copy(specTypedefs, spec.Typedefs)
	for _, fn := range pkg.Functions {
		specTypedefs.markRequired(fn.Return.Name, pkg.Api)
		for _, param := range fn.Parameters {
			specTypedefs.markRequired(param.Type.Name, pkg.Api)
		}
	}
	for _, specTypedef := range specTypedefs {
		if specTypedef.required {
			pkg.Typedefs = append(pkg.Typedefs, specTypedef.typedef)
		}
	}

	return pkg
}
<commit_msg>Make the spec XML struct fields private.<commit_after>package main

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strings"
)

type specRegistry struct {
	types      []specType      `xml:"types>type"`
	enums      []specEnumSet   `xml:"enums"`
	commands   []specCommand   `xml:"commands>command"`
	features   []specFeature   `xml:"feature"`
	extensions []specExtension `xml:"extensions>extension"`
}

type specType struct {
	name     string `xml:"name,attr"`
	api      string `xml:"api,attr"`
	requires string `xml:"requires,attr"`
	raw      []byte `xml:",innerxml"`
}

type specEnumSet struct {
	enums []specEnum `xml:"enum"`
}

type specEnum struct {
	name  string `xml:"name,attr"`
	value string `xml:"value,attr"`
	api   string `xml:"api,attr"`
}

type specCommand struct {
	prototype specProto   `xml:"proto"`
	api       string      `xml:"api"`
	params    []specParam `xml:"param"`
}

type specSignature []byte

type specProto struct {
	raw specSignature `xml:",innerxml"`
}

type specParam struct {
	raw specSignature `xml:",innerxml"`
}

type specFeature struct {
	api      string        `xml:"api,attr"`
	number   string        `xml:"number,attr"`
	requires []specRequire `xml:"require"`
	removes  []specRemove  `xml:"remove"`
}

type specRequire struct {
	enums    []specEnumRef    `xml:"enum"`
	commands []specCommandRef `xml:"command"`
}

type specRemove struct {
	enums    []specEnumRef    `xml:"enum"`
	commands []specCommandRef `xml:"command"`
}

type specEnumRef struct {
	name string `xml:"name,attr"`
}

type specCommandRef struct {
	name string `xml:"name,attr"`
}

type specExtension struct {
	name      string        `xml:"name,attr"`
	supported string        `xml:"supported,attr"`
	requires  []specRequire `xml:"require"`
}

type specRef struct {
	name string
	api  string
}

type specTypedef struct {
	ref      specRef
	typedef  *Typedef
	required bool
}

type specFunctions map[specRef]*Function
type specEnums map[specRef]*Enum

// Use an ordered list to preserve the XML declaration ordering which encodes implicit dependencies
type specTypedefs []specTypedef

// Parsed version of the XML specification
type Specification struct {
	Functions specFunctions
	Enums     specEnums
	Typedefs  specTypedefs
	Features  []SpecificationFeature
}

type SpecificationFeature struct {
	Api     string
	Version Version

	AddedEnums      []string
	AddedCommands   []string
	RemovedEnums    []string
	RemovedCommands []string
}

func readSpecFile(file string) (*specRegistry, error) {
	var registry specRegistry

	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	err = xml.NewDecoder(f).Decode(&registry)
	if err != nil {
		return nil, err
	}

	return &registry, nil
}

func parseFunctions(commands []specCommand) (specFunctions, error) {
	functions := make(specFunctions)
	for _, cmd := range commands {
		cmdName, cmdReturnType, err := parseSignature(cmd.prototype.raw)
		if err != nil {
			return functions, err
		}

		parameters := make([]Parameter, 0, len(cmd.params))
		for _, param := range cmd.params {
			paramName, paramType, err := parseSignature(param.raw)
			if err != nil {
				return functions, err
			}
			parameter := Parameter{
				Name: paramName,
				Type: paramType}
			parameters = append(parameters, parameter)
		}

		fnRef := specRef{cmdName, cmd.api}
		functions[fnRef] = &Function{
			Name:       cmdName,
			GoName:     TrimGLCmdPrefix(cmdName),
			Parameters: parameters,
			Return:     cmdReturnType}
	}
	return functions, nil
}

func parseSignature(signature specSignature) (string, Type, error) {
	name := ""
	ctype := Type{}

	readingName := false
	readingType := false

	decoder := xml.NewDecoder(bytes.NewBuffer(signature))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return name, ctype, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := strings.Trim(string(t), " ")
			if readingName {
				name = raw
			} else if readingType {
				ctype.Name = raw
			} else {
				if strings.Contains(raw, "void") {
					ctype.Name = "void"
				}
				ctype.PointerLevel += strings.Count(raw, "*")
			}
			if !readingName {
				ctype.CDefinition += string(t)
			}
		case xml.StartElement:
			if t.Name.Local == "ptype" {
				readingType = true
			} else if t.Name.Local == "name" {
				readingName = true
			} else {
				return name, ctype, fmt.Errorf("Unexpected signature XML: %s", signature)
			}
		case xml.EndElement:
			if t.Name.Local == "ptype" {
				readingType = false
			} else if t.Name.Local == "name" {
				readingName = false
			}
		}
	}
	return name, ctype, nil
}

func parseEnums(enumSets []specEnumSet) (specEnums, error) {
	enums := make(specEnums)
	for _, set := range enumSets {
		for _, enum := range set.enums {
			enumRef := specRef{enum.name, enum.api}
			enums[enumRef] = &Enum{
				Name:   enum.name,
				GoName: TrimGLEnumPrefix(enum.name),
				Value:  enum.value}
		}
	}
	return enums, nil
}

func parseTypedefs(specTypes []specType) (specTypedefs, error) {
	typedefs := make(specTypedefs, 0, len(specTypes))
	for _, specType := range specTypes {
		typedef, err := parseTypedef(specType)
		if err != nil {
			return nil, err
		}
		specTd := specTypedef{
			specRef{typedef.Name, specType.api},
			typedef,
			false}
		typedefs = append(typedefs, specTd)
	}
	return typedefs, nil
}

func parseTypedef(specType specType) (*Typedef, error) {
	typedef := &Typedef{
		Name:        specType.name,
		Api:         specType.api,
		Requires:    specType.requires,
		CDefinition: ""}

	readingName := false
	decoder := xml.NewDecoder(bytes.NewBuffer(specType.raw))
	for {
		token, err := decoder.Token()
		if err == io.EOF {
			break
		}
		if err != nil {
			return typedef, err
		}
		switch t := token.(type) {
		case xml.CharData:
			raw := string(t)
			typedef.CDefinition += raw
			if readingName {
				typedef.Name = raw
			}
		case xml.StartElement:
			if t.Name.Local == "name" {
				readingName = true
			} else if t.Name.Local == "apientry" {
				typedef.CDefinition += "APIENTRY"
			} else {
				return typedef, fmt.Errorf("Unexpected typedef XML: %s", specType.raw)
			}
		case xml.EndElement:
			if t.Name.Local == "name" {
				readingName = false
			}
		default:
			return typedef, fmt.Errorf("Unexpected typedef XML: %s", specType.raw)
		}
	}

	return typedef, nil
}

func parseFeatures(features []specFeature) ([]SpecificationFeature, error) {
	specFeatures := make([]SpecificationFeature, 0, len(features))
	for _, feature := range features {
		version, err := ParseVersion(feature.number)
		if err != nil {
			return specFeatures, err
		}

		specFeature := SpecificationFeature{
			Api:             feature.api,
			Version:         version,
			AddedEnums:      make([]string, 0),
			AddedCommands:   make([]string, 0),
			RemovedEnums:    make([]string, 0),
			RemovedCommands: make([]string, 0),
		}

		for _, req := range feature.requires {
			for _, cmd := range req.commands {
				specFeature.AddedCommands = append(specFeature.AddedCommands, cmd.name)
			}
			for _, enum := range req.enums {
				specFeature.AddedEnums = append(specFeature.AddedEnums, enum.name)
			}
		}

		for _, rem := range feature.removes {
			for _, cmd := range rem.commands {
				specFeature.RemovedCommands = append(specFeature.RemovedCommands, cmd.name)
			}
			for _, enum := range rem.enums {
				specFeature.RemovedEnums = append(specFeature.RemovedEnums, enum.name)
			}
		}

		specFeatures = append(specFeatures, specFeature)
	}
	return specFeatures, nil
}

func (functions specFunctions) get(name, api string) *Function {
	function, ok := functions[specRef{name, api}]
	if ok {
		return function
	}
	return functions[specRef{name, ""}]
}

func (enums specEnums) get(name, api string) *Enum {
	enum, ok := enums[specRef{name, api}]
	if ok {
		return enum
	}
	return enums[specRef{name, ""}]
}

func (typedefs specTypedefs) markRequired(name, api string) {
	for _, considerApi := range []bool{true, false} {
		for i, typedef := range typedefs {
			if typedef.ref.name == name && (typedef.ref.api == api || !considerApi) {
				typedefs[i].required = true
				if typedef.typedef.Requires != "" {
					typedefs.markRequired(typedef.typedef.Requires, api)
				}
				return
			}
		}
	}
}

// NewSpecification creates a new specification based on an XML file.
func NewSpecification(file string) (*Specification, error) {
	registry, err := readSpecFile(file)
	if err != nil {
		return nil, err
	}

	functions, err := parseFunctions(registry.commands)
	if err != nil {
		return nil, err
	}

	enums, err := parseEnums(registry.enums)
	if err != nil {
		return nil, err
	}

	typedefs, err := parseTypedefs(registry.types)
	if err != nil {
		return nil, err
	}

	features, err := parseFeatures(registry.features)
	if err != nil {
		return nil, err
	}

	spec := &Specification{
		Functions: functions,
		Enums:     enums,
		Typedefs:  typedefs,
		Features:  features,
	}
	return spec, nil
}

// HasPackage determines whether the specification can generate the specified package.
func (spec *Specification) HasPackage(pkgSpec PackageSpec) bool {
	for _, feature := range spec.Features {
		if pkgSpec.Api == feature.Api && pkgSpec.Version.Compare(feature.Version) == 0 {
			return true
		}
	}
	return false
}

// ToPackage generates a package from the specification.
func (spec *Specification) ToPackage(pkgSpec PackageSpec) *Package {
	pkg := &Package{
		Api:       pkgSpec.Api,
		Name:      pkgSpec.Api,
		Version:   pkgSpec.Version,
		Typedefs:  make([]*Typedef, 0),
		Enums:     make(Enums),
		Functions: make(Functions)}

	// Select the commands and enums relevant to the specified API version
	for _, feature := range spec.Features {
		// Skip features from a different API
		if pkg.Api != feature.Api {
			continue
		}
		// Skip features from a later version than the package
		if pkg.Version.Compare(feature.Version) < 0 {
			continue
		}

		for _, enum := range feature.AddedEnums {
			pkg.Enums[enum] = spec.Enums.get(enum, pkg.Api)
		}
		for _, cmd := range feature.AddedCommands {
			pkg.Functions[cmd] = spec.Functions.get(cmd, pkg.Api)
		}

		for _, enum := range feature.RemovedEnums {
			delete(pkg.Enums, enum)
		}
		for _, cmd := range feature.RemovedCommands {
			delete(pkg.Functions, cmd)
		}
	}

	// Add the types necessary to declare the functions
	specTypedefs := make(specTypedefs, len(spec.Typedefs))
	copy(specTypedefs, spec.Typedefs)
	for _, fn := range pkg.Functions {
		specTypedefs.markRequired(fn.Return.Name, pkg.Api)
		for _, param := range fn.Parameters {
			specTypedefs.markRequired(param.Type.Name, pkg.Api)
		}
	}
	for _, specTypedef := range specTypedefs {
		if specTypedef.required {
			pkg.Typedefs = append(pkg.Typedefs, specTypedef.typedef)
		}
	}

	return pkg
}
<|endoftext|>


<commit_before>package block

import (
	"log"

	"chunkymonkey/item"
	"chunkymonkey/itemtype"
	. "chunkymonkey/types"
)

// spawnItemInBlock creates an item in a block. It must be run within
// instance.Chunk's goroutine.
func spawnItemInBlock(instance *BlockInstance, itemType *itemtype.ItemType, count ItemCount, data ItemData) {
	rand := instance.Chunk.GetRand()
	position := instance.BlockLoc.ToAbsXyz()
	position.X += AbsCoord(blockItemSpawnFromEdge + rand.Float64()*(1-2*blockItemSpawnFromEdge))
	position.Y += AbsCoord(blockItemSpawnFromEdge)
	position.Z += AbsCoord(blockItemSpawnFromEdge + rand.Float64()*(1-2*blockItemSpawnFromEdge))
	instance.Chunk.AddItem(
		item.NewItem(
			itemType, count, data,
			position,
			&AbsVelocity{0, 0, 0},
		),
	)
}

type blockDropItem struct {
	DroppedItem ItemTypeId
	Probability byte // Probabilities specified as a percentage
	Count       ItemCount
	CopyData    bool
}

func (bdi *blockDropItem) drop(instance *BlockInstance) {
	itemType, ok := instance.Chunk.GetItemType(bdi.DroppedItem)

	if !ok {
		log.Printf(
			"Warning: tried to create item with type ID #%d - "+
			"but no such item type is defined. block and item "+
			"definitions out of sync?", bdi.DroppedItem)

		return
	}

	var itemData ItemData
	if bdi.CopyData {
		itemData = ItemData(instance.Data)
	} else {
		itemData = 0
	}

	for i := bdi.Count; i > 0; i-- {
		spawnItemInBlock(instance, itemType, 1, itemData)
	}
}
<commit_msg>gofmt run<commit_after>package block

import (
	"log"

	"chunkymonkey/item"
	"chunkymonkey/itemtype"
	. "chunkymonkey/types"
)

// spawnItemInBlock creates an item in a block. It must be run within
// instance.Chunk's goroutine.
func spawnItemInBlock(instance *BlockInstance, itemType *itemtype.ItemType, count ItemCount, data ItemData) {
	rand := instance.Chunk.GetRand()
	position := instance.BlockLoc.ToAbsXyz()
	position.X += AbsCoord(blockItemSpawnFromEdge + rand.Float64()*(1-2*blockItemSpawnFromEdge))
	position.Y += AbsCoord(blockItemSpawnFromEdge)
	position.Z += AbsCoord(blockItemSpawnFromEdge + rand.Float64()*(1-2*blockItemSpawnFromEdge))
	instance.Chunk.AddItem(
		item.NewItem(
			itemType, count, data,
			position,
			&AbsVelocity{0, 0, 0},
		),
	)
}

type blockDropItem struct {
	DroppedItem ItemTypeId
	Probability byte // Probabilities specified as a percentage
	Count       ItemCount
	CopyData    bool
}

func (bdi *blockDropItem) drop(instance *BlockInstance) {
	itemType, ok := instance.Chunk.GetItemType(bdi.DroppedItem)

	if !ok {
		log.Printf(
			"Warning: tried to create item with type ID #%d - "+
				"but no such item type is defined. block and item "+
				"definitions out of sync?",bdi.DroppedItem)

		return
	}

	var itemData ItemData
	if bdi.CopyData {
		itemData = ItemData(instance.Data)
	} else {
		itemData = 0
	}

	for i := bdi.Count; i > 0; i-- {
		spawnItemInBlock(instance, itemType, 1, itemData)
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2015 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/

package main

import (
	"net"
	"sync"
)

var clientMapMutex sync.Mutex
var clientMap map[string]*Client = make(map[string]*Client)

func initialize_stub() {
}

func login(conn net.Conn, clientID string, loginName string, loginPassword string) byte {
	return CONNACK_Success
}

func logout(clientID string) {
}

func getClient(clientID string) *Client {
	clientMapMutex.Lock()
	defer clientMapMutex.Unlock()
	return clientMap[clientID]
}

func setClient(client *Client) {
	clientMapMutex.Lock()
	defer clientMapMutex.Unlock()
	clientMap[client.GetClientID()] = client
}

func subscribe(topics *Topics, topicName string, clientID string) byte {
	topics.Add(topicName, clientID)
	return 0 // QoS
}

func unsubscribe(topics *Topics, topicName string, clientID string) {
	topics.Remove(topicName, clientID)
	return
}
<commit_msg>remove stub.go<commit_after><|endoftext|>


<commit_before>package ostent
import (
	"libostent/types"
)

var DFTABS = dftabs{
	DFinodes: DFINODES_TABID,
	DFbytes:  DFBYTES_TABID,

	DFinodesTitle: "Disks inodes",
	DFbytesTitle:  "Disks",
}

var IFTABS = iftabs{
	IFpackets: IFPACKETS_TABID,
	IFerrors:  IFERRORS_TABID,
	IFbytes:   IFBYTES_TABID,

	IFpacketsTitle: "Interfaces packets",
	IFerrorsTitle:  "Interfaces errors",
	IFbytesTitle:   "Interfaces",
}

type dftabs struct {
	DFinodes types.SEQ
	DFbytes  types.SEQ

	DFinodesTitle string
	DFbytesTitle  string
}

func (df dftabs) Title(s types.SEQ) string {
	switch {
	case s == df.DFinodes: return df.DFinodesTitle
	case s == df.DFbytes:  return df.DFbytesTitle
	}
	panic("SHOUND NOT HAPPEN")
	return ""
}

type iftabs struct {
	IFpackets types.SEQ
	IFerrors  types.SEQ
	IFbytes   types.SEQ

	IFpacketsTitle string
	IFerrorsTitle  string
	IFbytesTitle   string
}

func (fi iftabs) Title(s types.SEQ) string {
	switch {
	case s == fi.IFpackets:  return fi.IFpacketsTitle
	case s == fi.IFerrors:   return fi.IFerrorsTitle
	case s == fi.IFbytes:    return fi.IFbytesTitle
	}
	panic("SHOUND NOT HAPPEN")
	return ""
}

const (
	____IFTABID types.SEQ = iota
	IFPACKETS_TABID
	 IFERRORS_TABID
	  IFBYTES_TABID
)

const (
	____DFTABID types.SEQ = iota
	DFINODES_TABID
	 DFBYTES_TABID
)

/* UNUSED ?
var IF_TABS = []types.SEQ{
	IFPACKETS_TABID,
	 IFERRORS_TABID,
	  IFBYTES_TABID,
}

var DF_TABS = []types.SEQ{
	DFINODES_TABID,
	 DFBYTES_TABID,
}
*/
<commit_msg>tabs.go gofmt<commit_after>package ostent

import (
	"libostent/types"
)

var DFTABS = dftabs{
	DFinodes: DFINODES_TABID,
	DFbytes:  DFBYTES_TABID,

	DFinodesTitle: "Disks inodes",
	DFbytesTitle:  "Disks",
}

var IFTABS = iftabs{
	IFpackets: IFPACKETS_TABID,
	IFerrors:  IFERRORS_TABID,
	IFbytes:   IFBYTES_TABID,

	IFpacketsTitle: "Interfaces packets",
	IFerrorsTitle:  "Interfaces errors",
	IFbytesTitle:   "Interfaces",
}

type dftabs struct {
	DFinodes types.SEQ
	DFbytes  types.SEQ

	DFinodesTitle string
	DFbytesTitle  string
}

func (df dftabs) Title(s types.SEQ) string {
	switch {
	case s == df.DFinodes:
		return df.DFinodesTitle
	case s == df.DFbytes:
		return df.DFbytesTitle
	}
	panic("SHOUND NOT HAPPEN")
	return ""
}

type iftabs struct {
	IFpackets types.SEQ
	IFerrors  types.SEQ
	IFbytes   types.SEQ

	IFpacketsTitle string
	IFerrorsTitle  string
	IFbytesTitle   string
}

func (fi iftabs) Title(s types.SEQ) string {
	switch {
	case s == fi.IFpackets:
		return fi.IFpacketsTitle
	case s == fi.IFerrors:
		return fi.IFerrorsTitle
	case s == fi.IFbytes:
		return fi.IFbytesTitle
	}
	panic("SHOUND NOT HAPPEN")
	return ""
}

const (
	____IFTABID types.SEQ = iota
	IFPACKETS_TABID
	IFERRORS_TABID
	IFBYTES_TABID
)

const (
	____DFTABID types.SEQ = iota
	DFINODES_TABID
	DFBYTES_TABID
)

/* UNUSED ?
var IF_TABS = []types.SEQ{
	IFPACKETS_TABID,
	 IFERRORS_TABID,
	  IFBYTES_TABID,
}

var DF_TABS = []types.SEQ{
	DFINODES_TABID,
	 DFBYTES_TABID,
}
*/
<|endoftext|>


<commit_before>// Analyze the data dependencies between "basic blocks" (for loops + functions)
// Any dependencies within blocks don't matter, only those that cross the
// boundaries of loops and function calls. Each basic block records:
// - New identifiers defined
// - Identifiers read
// - Identifiers written
// External reads and writes can be calculated from that list. Dependencies
// from sub-blocks are carried upwards/outwards.

package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
)

type AccessPass struct {
	BasePass
}

type AccessType uint

const (
	ReadAccess AccessType = iota
	WriteAccess
)

var accessTypeString = map[AccessType]string{
	ReadAccess:  "\x1b[34mReadAccess\x1b[0m",
	WriteAccess: "\x1b[31mWriteAccess\x1b[0m",
}

type Identifier struct {
	id        string
	isIndexed bool   // true if this is an indexed identifier
	index     string // single identifier [idx] support for now
}

// Represents a.b.c[expr].d accesses
type IdentifierGroup struct {
	t     AccessType
	group []Identifier // [a, b, c[affine expr], d]
}

func (ig *IdentifierGroup) String() string {
	var buffer bytes.Buffer
	for _, i := range ig.group {
		buffer.WriteString(i.id)
		if i.isIndexed {
			buffer.WriteString("[")
			buffer.WriteString(i.index)
			buffer.WriteString("]")
		}
		buffer.WriteString(".")
	}
	buffer.WriteString(accessTypeString[ig.t])
	return buffer.String()
}

type AccessPassData struct {
	//accesses map[string]interface{}    // name.a.b : AccessType or MemoryAccessGroup
	defines  map[string]ast.Expr // name: type expression
	accesses []IdentifierGroup   // read/write of an identifier
}

func NewAccessPassData() *AccessPassData {
	return &AccessPassData{
		defines:  make(map[string]ast.Expr),
		accesses: make([]IdentifierGroup, 0),
	}
}

type AccessPassVisitor struct {
	cur       *BasicBlock
	dataBlock *AccessPassData
	pass      *AccessPass
	c         *Compiler
}

func (v AccessPassVisitor) Done(block *BasicBlock) (modified bool, err error) {
	dataBlock := v.dataBlock

	block.Print("== Defines ==")
	for ident, expr := range dataBlock.defines {
		block.Printf("%s = %T %+v", ident, expr, expr)
	}
	block.Print("== Accesses ==")
	for _, access := range dataBlock.accesses {
		block.Printf(access.String())
	}

	return
}

func (v AccessPassVisitor) Visit(node ast.Node) (w BasicBlockVisitor) {
	// Get the closest enclosing basic block for this node
	dataBlock := v.dataBlock
	b := v.cur
	// Helper functions.
	// Define adds the identifier as being defined in this block
	Define := func(ident string, expr ast.Expr) {
		if ident == "_" {
			return
		}
		dataBlock.defines[ident] = expr
		b.Printf("Defined %s = %T %+v", ident, expr, expr)
	}

	// Access recording:
	// - RecordAccess records the final identifier group
	// - AccessIdentBuild takes an identifier group and an expression and
	//     recursively builds the group out of the expression
	// - AccessExpr
	RecordAccess := func(ident *IdentifierGroup, t AccessType) {
		ident.t = t
		if ident.group[0].id == "_" {
			return
		}
		dataBlock.accesses = append(dataBlock.accesses, *ident)
		b.Printf("Accessed: %+v", ident)
	}

	// Support:
	// a[idx].b
	// a.b[idx].c
	var AccessIdentBuild func(group *IdentifierGroup, expr ast.Expr)
	var AccessExpr func(expr ast.Expr, t AccessType)

	AccessIdentBuild = func(group *IdentifierGroup, expr ast.Expr) {
		var ident Identifier
		switch t := expr.(type) {
		case *ast.Ident:
			ident.id = t.Name
		case *ast.SelectorExpr:
			// x.y.z expressions
			// e.X = x.y
			// e.Sel = z
			ident.id = t.Sel.Name
			AccessIdentBuild(group, t.X)
		case *ast.IndexExpr:
			// a[idx][x]
			// a[idx+1]
			// e.X = a
			// e.Index = idx+1
			//AccessIdent(t.Index, ReadAccess)
			switch x := t.X.(type) {
			case *ast.Ident:
				ident.id = x.Name
			default:
				b.Print("Unresolved array expression %T %+v", x, x)
			}
			AccessExpr(t.Index, ReadAccess)
			switch i := t.Index.(type) {
			case *ast.Ident:
				ident.index = i.Name
				ident.isIndexed = true
			default:
				// can't resolve array access, record for the entire array
				b.Printf("Unresolved array access %T [%+v]", i, i)
			}
		default:
			b.Printf("Unknown ident %T %+v", t, t)
		}
		group.group = append(group.group, ident)
	}

	AccessIdent := func(expr ast.Expr, t AccessType) {
		ig := &IdentifierGroup{}
		AccessIdentBuild(ig, expr)
		RecordAccess(ig, t)
	}

	AccessExpr = func(expr ast.Expr, t AccessType) {
		// recursively fill in accesses for an expression
		switch e := expr.(type) {
		case *ast.BinaryExpr:
			b.Printf("BinaryExpr %T %+v , %T %+v", e.X, e.X, e.Y, e.Y)
			AccessExpr(e.X, ReadAccess)
			AccessExpr(e.Y, ReadAccess)
		case *ast.CallExpr:
			for _, funcArg := range e.Args {
				AccessExpr(funcArg, ReadAccess)
			}
		// These three expression types form the basis of a memory access.
		case *ast.SelectorExpr, *ast.IndexExpr, *ast.Ident:
			AccessIdent(e, t)
		case *ast.UnaryExpr:
			// <-x
			AccessExpr(e.X, ReadAccess)
		case *ast.BasicLit:
			// ignore, builtin constant
		case *ast.ArrayType, *ast.ChanType:
			// ignore, type expressions
		default:
			fmt.Printf("Unknown access expression %T %+v\n", expr, expr)
		}
	}

	if node == nil {
		// post-order actions (all sub-nodes have been visited)
		return v
	}

	b.Printf("start %T %+v", node, node)

	// Analyze all AST nodes for definitions and accesses
	switch t := node.(type) {
	case *ast.FuncDecl, *ast.FuncLit:
		// pass - go into FuncType and the body BlockStmt
	case *ast.FuncType:
		// defines arguments, named return types
		b.Printf("Func: %+v -> %+v", t.Params, t.Results)
		var defines []*ast.Field
		if t.Params != nil {
			defines = append(defines, t.Params.List...)
		}
		if t.Results != nil {
			defines = append(defines, t.Results.List...)
		}
		for _, paramGroup := range defines {
			for _, param := range paramGroup.Names {
				Define(param.Name, paramGroup.Type)
			}
		}
		return nil
	case *ast.ForStmt:
		b.Printf("For %+v; %+v; %+v", t.Init, t.Cond, t.Post)
		// TODO: t.Init defines
		//AccessExpr(t.Cond, ReadAccess)
		// TODO: t.Post accesses (writes??)
		//AccessExpr(t.Post, WriteAccess)
		//return nil
	case *ast.RangeStmt:
		// only := range
		if t.Tok == token.DEFINE {
			if key, ok := t.Key.(*ast.Ident); ok {
				// TODO: no support for maps, assumes key is always an array index
				Define(key.Name, &ast.Ident{Name: "int"})
			}
			if val, ok := t.Value.(*ast.Ident); ok {
				Define(val.Name, t.X)
			}
		}
		// reads
		AccessExpr(t.X, ReadAccess)
		return nil
	case *ast.IfStmt:
		// fallthrough to descend into t.Init, t.Cond
	case *ast.GenDecl:
		// defines
	case *ast.ValueSpec:
		// defines
		for _, name := range t.Names {
			Define(name.Name, t.Type)
		}
		// reads
		for _, expr := range t.Values {
			AccessExpr(expr, ReadAccess)
		}
		return nil
	case *ast.UnaryExpr:
		AccessExpr(t.X, ReadAccess)
		return nil
	case *ast.IncDecStmt:
		AccessExpr(t.X, ReadAccess)
		AccessExpr(t.X, WriteAccess)
		return nil
	case *ast.BinaryExpr:
		// read only??
		AccessExpr(t.X, ReadAccess)
		AccessExpr(t.Y, ReadAccess)
		return nil
	case *ast.AssignStmt:
		// a[idx], x[idx] = b+c+d, idx
		// writes: a, x reads: idx, b, c, d
		switch t.Tok {
		case token.DEFINE:
			for i, expr := range t.Lhs {
				if new, ok := expr.(*ast.Ident); ok {
					Define(new.Name, t.Rhs[i])
				}
			}
		case token.ASSIGN:
		default:
			// x += 1, etc
			for _, expr := range t.Lhs {
				AccessExpr(expr, ReadAccess)
			}
		}

		// assignment (read LHS index, read RHS, write LHS)
		for _, expr := range t.Rhs {
			AccessExpr(expr, ReadAccess)
		}
		for _, expr := range t.Lhs {
			b.Printf("write %T %+v", expr, expr)
			AccessExpr(expr, WriteAccess)
		}
		return nil // don't go down these branches
	case *ast.SendStmt:
		AccessExpr(t.Value, ReadAccess)
		AccessExpr(t.Chan, WriteAccess)
		return nil
	case *ast.CallExpr:
		for _, expr := range t.Args {
			AccessExpr(expr, ReadAccess)
		}
		switch f := t.Fun.(type) {
		case *ast.FuncLit:
			// go down a FuncLit branch (anonymous closure)
		case *ast.Ident:
			// fill in additional reads/writes once we resolve all functions
			b.Printf("\x1b[33m+\x1b[0m use in later pass: %s", f.Name)
			return nil
		default:
			b.Printf("\x1b[33mUnknown CallExpr %T\x1b[0m", t.Fun)
		}
	case *ast.BranchStmt:
		// ignore break/continue/goto/fallthrough
		return nil
	case *ast.ExprStmt, *ast.BlockStmt, *ast.ReturnStmt, *ast.DeclStmt,
		*ast.GoStmt:
		// go down the block

	default:
		b.Printf("\x1b[33mUnknown node\x1b[0m %T %+v", t, t)
		return nil // by default don't decend down un-implemented branches
	}
	return v
}

func NewAccessPass() *AccessPass {
	return &AccessPass{
		BasePass: NewBasePass(),
	}
}

func (pass *AccessPass) GetPassType() PassType {
	return AccessPassType
}

func (pass *AccessPass) GetPassMode() PassMode {
	return BasicBlockPassMode
}

func (pass *AccessPass) GetDependencies() []PassType {
	return []PassType{BasicBlockPassType, DefinedTypesPassType}
}

func (pass *AccessPass) RunBasicBlockPass(block *BasicBlock, p *Package) BasicBlockVisitor {
	dataBlock := NewAccessPassData()
	block.Set(AccessPassType, dataBlock)
	return AccessPassVisitor{cur: block, dataBlock: dataBlock, pass: pass}
}
<commit_msg>trying to recover chunk of access_pass<commit_after>// Analyze the data dependencies between "basic blocks" (for loops + functions)
// Any dependencies within blocks don't matter, only those that cross the
// boundaries of loops and function calls. Each basic block records:
// - New identifiers defined
// - Identifiers read
// - Identifiers written
// External reads and writes can be calculated from that list. Dependencies
// from sub-blocks are carried upwards/outwards.

package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
)

type AccessPass struct {
	BasePass
}

type AccessType uint

const (
	ReadAccess AccessType = iota
	WriteAccess
)

var accessTypeString = map[AccessType]string{
	ReadAccess:  "\x1b[34mReadAccess\x1b[0m",
	WriteAccess: "\x1b[31mWriteAccess\x1b[0m",
}

type Identifier struct {
	id        string
	isIndexed bool   // true if this is an indexed identifier
	index     string // single identifier [idx] support for now
}

// Represents a.b.c[expr].d accesses
type IdentifierGroup struct {
	t     AccessType
	group []Identifier // [a, b, c[affine expr], d]
}

func (ig *IdentifierGroup) String() string {
	var buffer bytes.Buffer
	for _, i := range ig.group {
		buffer.WriteString(i.id)
		if i.isIndexed {
			buffer.WriteString("[")
			buffer.WriteString(i.index)
			buffer.WriteString("]")
		}
		buffer.WriteString(".")
	}
	buffer.WriteString(accessTypeString[ig.t])
	return buffer.String()
}

type AccessPassData struct {
	//accesses map[string]interface{}    // name.a.b : AccessType or MemoryAccessGroup
	defines  map[string]ast.Expr // name: type expression
	accesses []IdentifierGroup   // read/write of an identifier
}

func NewAccessPassData() *AccessPassData {
	return &AccessPassData{
		defines:  make(map[string]ast.Expr),
		accesses: make([]IdentifierGroup, 0),
	}
}

type AccessPassVisitor struct {
	cur       *BasicBlock
	dataBlock *AccessPassData
	pass      *AccessPass
	p         *Package
}

func (v AccessPassVisitor) Done(block *BasicBlock) (modified bool, err error) {
	dataBlock := v.dataBlock

	block.Print("== Defines ==")
	for ident, expr := range dataBlock.defines {
		block.Printf("%s = %T %+v", ident, expr, expr)
	}
	block.Print("== Accesses ==")
	for _, access := range dataBlock.accesses {
		block.Printf(access.String())
	}

	return
}

func (pass *AccessPass) ParseBasicBlock(node ast.Node, p *Package) {
	// Get the closest enclosing basic block for this node
	b := pass.GetCompiler().GetPassResult(BasicBlockPassType, node).(*BasicBlock)
	dataBlock := NewAccessPassData()
	b.Set(AccessPassType, dataBlock)

	b.Printf("start %T %+v", node, node)

	// Helper functions.
	// Define adds the identifier as being defined in this block
	Define := func(ident string, expr ast.Expr) {
		if ident == "_" {
			return
		}
		dataBlock.defines[ident] = expr
		b.Printf("Defined %s = %T %+v", ident, expr, expr)
	}

	// Access recording:
	// - RecordAccess records the final identifier group
	// - AccessIdentBuild takes an identifier group and an expression and
	//     recursively builds the group out of the expression
	// - AccessExpr
	RecordAccess := func(ident *IdentifierGroup, t AccessType) {
		ident.t = t
		if ident.group[0].id == "_" {
			return
		}
		dataBlock.accesses = append(dataBlock.accesses, *ident)
		b.Printf("Accessed: %+v", ident)
	}

	// Support:
	// a[idx].b
	// a.b[idx].c
	var AccessIdentBuild func(group *IdentifierGroup, expr ast.Expr)
	var AccessExpr func(expr ast.Expr, t AccessType)

	AccessIdentBuild = func(group *IdentifierGroup, expr ast.Expr) {
		var ident Identifier
		switch t := expr.(type) {
		case *ast.Ident:
			ident.id = t.Name
		case *ast.SelectorExpr:
			// x.y.z expressions
			// e.X = x.y
			// e.Sel = z
			ident.id = t.Sel.Name
			AccessIdentBuild(group, t.X)
		case *ast.IndexExpr:
			// a[idx][x]
			// a[idx+1]
			// e.X = a
			// e.Index = idx+1
			//AccessIdent(t.Index, ReadAccess)
			switch x := t.X.(type) {
			case *ast.Ident:
				ident.id = x.Name
			default:
				b.Print("Unresolved array expression %T %+v", x, x)
			}
			AccessExpr(t.Index, ReadAccess)
			switch i := t.Index.(type) {
			case *ast.Ident:
				ident.index = i.Name
				ident.isIndexed = true
			default:
				// can't resolve array access, record for the entire array
				b.Printf("Unresolved array access %T [%+v]", i, i)
			}
		default:
			b.Printf("Unknown ident %T %+v", t, t)
		}
		group.group = append(group.group, ident)
	}

	AccessIdent := func(expr ast.Expr, t AccessType) {
		ig := &IdentifierGroup{}
		AccessIdentBuild(ig, expr)
		RecordAccess(ig, t)
	}

	// This is called recursively, starting with the block level
	// Don't recurse down into other BasicBlock statements, instead manually
	// call pass.RunBasicBlockPass()
	AccessExpr = func(node ast.Node, t AccessType) {
		if isBasicBlockNode(node) {
			pass.ParseBasicBlock(node, p)
			return // don't desend into the block
		}
		// recursively fill in accesses for an expression
		switch e := node.(type) {
		case *ast.BinaryExpr:
			b.Printf("BinaryExpr %T %+v , %T %+v", e.X, e.X, e.Y, e.Y)
			AccessExpr(e.X, ReadAccess)
			AccessExpr(e.Y, ReadAccess)
		case *ast.CallExpr:
			for _, funcArg := range e.Args {
				AccessExpr(funcArg, ReadAccess)
			}
		// These three expression types form the basis of a memory access.
		case *ast.SelectorExpr, *ast.IndexExpr, *ast.Ident:
			AccessIdent(e, t)
		case *ast.UnaryExpr:
			// <-x
			AccessExpr(e.X, ReadAccess)
		case *ast.BasicLit:
			// ignore, builtin constant
		case *ast.ArrayType, *ast.ChanType:
			// ignore, type expressions
		default:

			fmt.Printf("Unknown access expression %T %+v\n", expr, expr)

		}
	}
	return
}

func NewAccessPass() *AccessPass {
	return &AccessPass{
		BasePass: NewBasePass(),
	}
}

func (pass *AccessPass) GetPassType() PassType {
	return AccessPassType
}

func (pass *AccessPass) GetPassMode() PassMode {
	return BasicBlockPassMode
}

func (pass *AccessPass) GetDependencies() []PassType {
	return []PassType{BasicBlockPassType, DefinedTypesPassType}
}

func (pass *AccessPass) RunFunctionPass(fun *ast.FuncDecl, p *Package) (modified bool, err error) {
	pass.ParseBasicBlock(fun, p)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"

	"github.com/fatih/color"
	"github.com/hpcloud/tail"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
	"github.com/yext/edward/config"
	"github.com/yext/edward/runner"
	"github.com/yext/edward/services"
)

func tailFromFlag(c *cli.Context) error {
	fmt.Println("=== Logs ===")
	return errors.WithStack(doLog(c))
}

func doLog(c *cli.Context) error {
	if len(c.Args()) == 0 {
		return errors.New("At least one service or group must be specified")
	}
	sgs, err := config.GetServicesOrGroups(c.Args())
	if err != nil {
		return errors.WithStack(err)
	}

	var logChannel chan runner.LogLine = make(chan runner.LogLine)
	var lines []runner.LogLine
	for _, sg := range sgs {
		switch v := sg.(type) {
		case *services.ServiceConfig:
			newLines, err := followServiceLog(v, logChannel)
			if err != nil {
				return err
			}
			lines = append(lines, newLines...)
		case *services.ServiceGroupConfig:
			newLines, err := followGroupLog(v, logChannel)
			if err != nil {
				return err
			}
			lines = append(lines, newLines...)
		}
	}

	// Sort initial lines
	sort.Sort(ByTime(lines))
	for _, line := range lines {
		printMessage(line, services.CountServices(sgs) > 1)
	}

	for logMessage := range logChannel {
		printMessage(logMessage, services.CountServices(sgs) > 1)
	}

	return nil
}

type ByTime []runner.LogLine

func (a ByTime) Len() int           { return len(a) }
func (a ByTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByTime) Less(i, j int) bool { return a[i].Time.Before(a[j].Time) }

func printMessage(logMessage runner.LogLine, multiple bool) {

	if multiple {
		print("[")
		color.Set(color.FgHiYellow)
		print(logMessage.Name)
		if logMessage.Stream == "messages" {
			print(" (edward)")
		}
		color.Unset()
		print("]: ")
	}

	if logMessage.Stream == "stderr" {
		color.Set(color.FgRed)
	}
	if logMessage.Stream == "messages" {
		color.Set(color.FgYellow)
	}

	fmt.Printf("%v\n", logMessage.Message)
	color.Unset()
}

func followGroupLog(group *services.ServiceGroupConfig, logChannel chan runner.LogLine) ([]runner.LogLine, error) {
	var lines []runner.LogLine
	for _, group := range group.Groups {
		newLines, err := followGroupLog(group, logChannel)
		lines = append(lines, newLines...)
		if err != nil {
			return nil, err
		}
	}
	for _, service := range group.Services {
		newLines, err := followServiceLog(service, logChannel)
		lines = append(lines, newLines...)
		if err != nil {
			return nil, err
		}
	}
	return lines, nil
}

func followServiceLog(service *services.ServiceConfig, logChannel chan runner.LogLine) ([]runner.LogLine, error) {
	runLog := service.GetRunLog()
	logFile, err := os.Open(runLog)
	defer logFile.Close()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	var initialLines []runner.LogLine
	// create a new scanner and read the file line by line
	scanner := bufio.NewScanner(logFile)
	var lineCount int
	for scanner.Scan() {
		text := scanner.Text()
		lineCount++
		line, err := runner.ParseLogLine(text)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		initialLines = append(initialLines, line)
	}

	// check for errors
	if err = scanner.Err(); err != nil {
		return nil, errors.WithStack(err)
	}

	go doFollowServiceLog(service, lineCount, logChannel)
	return initialLines, nil
}

func doFollowServiceLog(service *services.ServiceConfig, skipLines int, logChannel chan runner.LogLine) error {
	runLog := service.GetRunLog()
	t, err := tail.TailFile(runLog, tail.Config{
		Follow: true,
		Logger: tail.DiscardingLogger,
	})
	if err != nil {
		return errors.WithStack(err)
	}
	var linesSkipped int
	for line := range t.Lines {
		if linesSkipped < skipLines {
			linesSkipped++
			continue
		}
		lineData, err := runner.ParseLogLine(line.Text)
		if err != nil {
			return errors.WithStack(err)
		}
		logChannel <- lineData
	}
	return nil
}
<commit_msg>Drop blank log lines.<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/fatih/color"
	"github.com/hpcloud/tail"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
	"github.com/yext/edward/config"
	"github.com/yext/edward/runner"
	"github.com/yext/edward/services"
)

func tailFromFlag(c *cli.Context) error {
	fmt.Println("=== Logs ===")
	return errors.WithStack(doLog(c))
}

func doLog(c *cli.Context) error {
	if len(c.Args()) == 0 {
		return errors.New("At least one service or group must be specified")
	}
	sgs, err := config.GetServicesOrGroups(c.Args())
	if err != nil {
		return errors.WithStack(err)
	}

	var logChannel chan runner.LogLine = make(chan runner.LogLine)
	var lines []runner.LogLine
	for _, sg := range sgs {
		switch v := sg.(type) {
		case *services.ServiceConfig:
			newLines, err := followServiceLog(v, logChannel)
			if err != nil {
				return err
			}
			lines = append(lines, newLines...)
		case *services.ServiceGroupConfig:
			newLines, err := followGroupLog(v, logChannel)
			if err != nil {
				return err
			}
			lines = append(lines, newLines...)
		}
	}

	// Sort initial lines
	sort.Sort(ByTime(lines))
	for _, line := range lines {
		printMessage(line, services.CountServices(sgs) > 1)
	}

	for logMessage := range logChannel {
		printMessage(logMessage, services.CountServices(sgs) > 1)
	}

	return nil
}

type ByTime []runner.LogLine

func (a ByTime) Len() int           { return len(a) }
func (a ByTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByTime) Less(i, j int) bool { return a[i].Time.Before(a[j].Time) }

func printMessage(logMessage runner.LogLine, multiple bool) {

	message := strings.TrimSpace(logMessage.Message)

	if len(message) == 0 {
		return
	}

	if multiple {
		print("[")
		color.Set(color.FgHiYellow)
		print(logMessage.Name)
		if logMessage.Stream == "messages" {
			print(" (edward)")
		}
		color.Unset()
		print("]: ")
	}

	if logMessage.Stream == "stderr" {
		color.Set(color.FgRed)
	}
	if logMessage.Stream == "messages" {
		color.Set(color.FgYellow)
	}

	fmt.Printf("%v\n", strings.TrimSpace(message))
	color.Unset()
}

func followGroupLog(group *services.ServiceGroupConfig, logChannel chan runner.LogLine) ([]runner.LogLine, error) {
	var lines []runner.LogLine
	for _, group := range group.Groups {
		newLines, err := followGroupLog(group, logChannel)
		lines = append(lines, newLines...)
		if err != nil {
			return nil, err
		}
	}
	for _, service := range group.Services {
		newLines, err := followServiceLog(service, logChannel)
		lines = append(lines, newLines...)
		if err != nil {
			return nil, err
		}
	}
	return lines, nil
}

func followServiceLog(service *services.ServiceConfig, logChannel chan runner.LogLine) ([]runner.LogLine, error) {
	runLog := service.GetRunLog()
	logFile, err := os.Open(runLog)
	defer logFile.Close()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	var initialLines []runner.LogLine
	// create a new scanner and read the file line by line
	scanner := bufio.NewScanner(logFile)
	var lineCount int
	for scanner.Scan() {
		text := scanner.Text()
		lineCount++
		line, err := runner.ParseLogLine(text)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		initialLines = append(initialLines, line)
	}

	// check for errors
	if err = scanner.Err(); err != nil {
		return nil, errors.WithStack(err)
	}

	go doFollowServiceLog(service, lineCount, logChannel)
	return initialLines, nil
}

func doFollowServiceLog(service *services.ServiceConfig, skipLines int, logChannel chan runner.LogLine) error {
	runLog := service.GetRunLog()
	t, err := tail.TailFile(runLog, tail.Config{
		Follow: true,
		Logger: tail.DiscardingLogger,
	})
	if err != nil {
		return errors.WithStack(err)
	}
	var linesSkipped int
	for line := range t.Lines {
		if linesSkipped < skipLines {
			linesSkipped++
			continue
		}
		lineData, err := runner.ParseLogLine(line.Text)
		if err != nil {
			return errors.WithStack(err)
		}
		logChannel <- lineData
	}
	return nil
}
<|endoftext|>