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

package admitters

import (
	"encoding/json"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"
	admissionv1 "k8s.io/api/admission/v1"
	k8sv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	v1 "kubevirt.io/api/core/v1"
	poolv1 "kubevirt.io/api/pool/v1alpha1"
	"kubevirt.io/kubevirt/pkg/testutils"
	"kubevirt.io/kubevirt/pkg/virt-api/webhooks"
)

var _ = Describe("Validating Pool Admitter", func() {
	config, _, _, _ := testutils.NewFakeClusterConfig(&k8sv1.ConfigMap{})
	poolAdmitter := &VMPoolAdmitter{ClusterConfig: config}

	always := v1.RunStrategyAlways

	table.DescribeTable("should reject documents containing unknown or missing fields for", func(data string, validationResult string, gvr metav1.GroupVersionResource, review func(ar *admissionv1.AdmissionReview) *admissionv1.AdmissionResponse) {
		input := map[string]interface{}{}
		json.Unmarshal([]byte(data), &input)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: gvr,
				Object: runtime.RawExtension{
					Raw: []byte(data),
				},
			},
		}
		resp := review(ar)
		Expect(resp.Allowed).To(BeFalse())
		Expect(resp.Result.Message).To(Equal(validationResult))
	},
		table.Entry("VirtualMachinePool creation and update",
			`{"very": "unknown", "spec": { "extremely": "unknown" }}`,
			`.very in body is a forbidden property`,
			webhooks.VirtualMachinePoolGroupVersionResource,
			poolAdmitter.Admit,
		),
	)
	table.DescribeTable("reject invalid VirtualMachineInstance spec", func(pool *poolv1.VirtualMachinePool, causes []string) {
		poolBytes, _ := json.Marshal(&pool)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: webhooks.VirtualMachinePoolGroupVersionResource,
				Object: runtime.RawExtension{
					Raw: poolBytes,
				},
			},
		}

		resp := poolAdmitter.Admit(ar)
		Expect(resp.Allowed).To(BeFalse())
		Expect(resp.Result.Details.Causes).To(HaveLen(len(causes)))
		for i, cause := range causes {
			Expect(resp.Result.Details.Causes[i].Field).To(Equal(cause))
		}
	},
		table.Entry("with missing volume and missing labels", &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "this"},
				},
				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					Spec: v1.VirtualMachineSpec{
						Template: newVirtualMachineBuilder().WithDisk(v1.Disk{
							Name: "testdisk",
						}).BuildTemplate(),
					},
				},
			},
		}, []string{
			"spec.virtualMachineTemplate.spec.template.spec.domain.devices.disks[0].name",
			"spec.virtualMachineTemplate.spec.running",
			"spec.selector",
		}),
		table.Entry("with mismatching label selectors", &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "not"},
				},
				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					ObjectMeta: metav1.ObjectMeta{
						Labels: map[string]string{"notmatch": "val"},
					},
					Spec: v1.VirtualMachineSpec{
						Template: newVirtualMachineBuilder().
							WithDisk(v1.Disk{
								Name: "testdisk",
							}).
							WithVolume(v1.Volume{
								Name: "testdisk",
								VolumeSource: v1.VolumeSource{
									ContainerDisk: testutils.NewFakeContainerDiskSource(),
								},
							}).
							BuildTemplate(),
					},
				},
			},
		}, []string{
			"spec.virtualMachineTemplate.spec.running",
			"spec.selector",
		}),
	)
	It("should accept valid vm spec", func() {
		pool := &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "me"},
				},

				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					ObjectMeta: metav1.ObjectMeta{
						Labels: map[string]string{"match": "me"},
					},
					Spec: v1.VirtualMachineSpec{
						RunStrategy: &always,
						Template: newVirtualMachineBuilder().
							WithDisk(v1.Disk{
								Name: "testdisk",
							}).
							WithVolume(v1.Volume{
								Name: "testdisk",
								VolumeSource: v1.VolumeSource{
									ContainerDisk: testutils.NewFakeContainerDiskSource(),
								},
							}).
							WithLabel("match", "me").
							BuildTemplate(),
					},
				},
			},
		}
		poolBytes, _ := json.Marshal(&pool)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: webhooks.VirtualMachinePoolGroupVersionResource,
				Object: runtime.RawExtension{
					Raw: poolBytes,
				},
			},
		}

		resp := poolAdmitter.Admit(ar)
		Expect(resp.Allowed).To(BeTrue())
	})
})
<commit_msg>Update unit tests to work properly with removal of configmap from cluster config<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2021 Red Hat, Inc.
 *
 */

package admitters

import (
	"encoding/json"

	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"
	admissionv1 "k8s.io/api/admission/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	v1 "kubevirt.io/api/core/v1"
	virtv1 "kubevirt.io/api/core/v1"
	poolv1 "kubevirt.io/api/pool/v1alpha1"
	"kubevirt.io/kubevirt/pkg/testutils"
	"kubevirt.io/kubevirt/pkg/virt-api/webhooks"
)

var _ = Describe("Validating Pool Admitter", func() {
	config, _, _ := testutils.NewFakeClusterConfigUsingKVConfig(&virtv1.KubeVirtConfiguration{})
	poolAdmitter := &VMPoolAdmitter{ClusterConfig: config}

	always := v1.RunStrategyAlways

	table.DescribeTable("should reject documents containing unknown or missing fields for", func(data string, validationResult string, gvr metav1.GroupVersionResource, review func(ar *admissionv1.AdmissionReview) *admissionv1.AdmissionResponse) {
		input := map[string]interface{}{}
		json.Unmarshal([]byte(data), &input)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: gvr,
				Object: runtime.RawExtension{
					Raw: []byte(data),
				},
			},
		}
		resp := review(ar)
		Expect(resp.Allowed).To(BeFalse())
		Expect(resp.Result.Message).To(Equal(validationResult))
	},
		table.Entry("VirtualMachinePool creation and update",
			`{"very": "unknown", "spec": { "extremely": "unknown" }}`,
			`.very in body is a forbidden property`,
			webhooks.VirtualMachinePoolGroupVersionResource,
			poolAdmitter.Admit,
		),
	)
	table.DescribeTable("reject invalid VirtualMachineInstance spec", func(pool *poolv1.VirtualMachinePool, causes []string) {
		poolBytes, _ := json.Marshal(&pool)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: webhooks.VirtualMachinePoolGroupVersionResource,
				Object: runtime.RawExtension{
					Raw: poolBytes,
				},
			},
		}

		resp := poolAdmitter.Admit(ar)
		Expect(resp.Allowed).To(BeFalse())
		Expect(resp.Result.Details.Causes).To(HaveLen(len(causes)))
		for i, cause := range causes {
			Expect(resp.Result.Details.Causes[i].Field).To(Equal(cause))
		}
	},
		table.Entry("with missing volume and missing labels", &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "this"},
				},
				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					Spec: v1.VirtualMachineSpec{
						Template: newVirtualMachineBuilder().WithDisk(v1.Disk{
							Name: "testdisk",
						}).BuildTemplate(),
					},
				},
			},
		}, []string{
			"spec.virtualMachineTemplate.spec.template.spec.domain.devices.disks[0].name",
			"spec.virtualMachineTemplate.spec.running",
			"spec.selector",
		}),
		table.Entry("with mismatching label selectors", &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "not"},
				},
				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					ObjectMeta: metav1.ObjectMeta{
						Labels: map[string]string{"notmatch": "val"},
					},
					Spec: v1.VirtualMachineSpec{
						Template: newVirtualMachineBuilder().
							WithDisk(v1.Disk{
								Name: "testdisk",
							}).
							WithVolume(v1.Volume{
								Name: "testdisk",
								VolumeSource: v1.VolumeSource{
									ContainerDisk: testutils.NewFakeContainerDiskSource(),
								},
							}).
							BuildTemplate(),
					},
				},
			},
		}, []string{
			"spec.virtualMachineTemplate.spec.running",
			"spec.selector",
		}),
	)
	It("should accept valid vm spec", func() {
		pool := &poolv1.VirtualMachinePool{
			Spec: poolv1.VirtualMachinePoolSpec{
				Selector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"match": "me"},
				},

				VirtualMachineTemplate: &poolv1.VirtualMachineTemplateSpec{
					ObjectMeta: metav1.ObjectMeta{
						Labels: map[string]string{"match": "me"},
					},
					Spec: v1.VirtualMachineSpec{
						RunStrategy: &always,
						Template: newVirtualMachineBuilder().
							WithDisk(v1.Disk{
								Name: "testdisk",
							}).
							WithVolume(v1.Volume{
								Name: "testdisk",
								VolumeSource: v1.VolumeSource{
									ContainerDisk: testutils.NewFakeContainerDiskSource(),
								},
							}).
							WithLabel("match", "me").
							BuildTemplate(),
					},
				},
			},
		}
		poolBytes, _ := json.Marshal(&pool)

		ar := &admissionv1.AdmissionReview{
			Request: &admissionv1.AdmissionRequest{
				Resource: webhooks.VirtualMachinePoolGroupVersionResource,
				Object: runtime.RawExtension{
					Raw: poolBytes,
				},
			},
		}

		resp := poolAdmitter.Admit(ar)
		Expect(resp.Allowed).To(BeTrue())
	})
})
<|endoftext|>


<commit_before>package pbdump

/*
func TestMessageWithInt(t *testing.T) {
	msg := MessageWithInt{Id: proto.Int32(42)}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasVarints(v, 42) {
		t.Fatalf("Incorrect value for field, expected '%v', got '%v'", 42, v)
	}
}

func TestMessageWithRepeatedInt(t *testing.T) {
	msg := MessageWithRepeatedInt{Ids: []int32{1, 2, 333, 456789}}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m[1]; !ok {
		t.Fatalf("Missing filed repeated field '1': '%v'", m)
	} else if !HasVarints(v, 1, 2, 333, 456789) {
		t.Fatalf("Missing values for tag '1': '%v'", v)
	}
}

func TestMessageWithString(t *testing.T) {
	name := "name"
	msg := MessageWithString{Name: &name}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasStrings(v, name) {
		t.Fatalf("Incorrect value, expected '%s', got '%s'", name, v)
	}
}

func TestMessageWithEmbeddedRepeatedMessageWithString(t *testing.T) {
	name1 := "name1"
	msg1 := MessageWithString{Name: &name1}
	name2 := "name2"
	msg2 := MessageWithString{Name: &name2}
	msg := MessageWithEmbeddedRepeatedMessageWithString{
		Messages: []*MessageWithString{
			&msg1, &msg2,
		},
	}
	buf := MustMarshal(&msg)
	m, err := Dump(buf)
	if err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	}
	v, ok := m[1]
	if !ok {
		t.Fatalf("Missing filed repeated field '1': '%v'", m)
	} else if len(v) != 2 {
		t.Fatalf("Expected to have to repeated messages, got: '%d' (%v)", len(v), v)
	}
	if v0, ok := v[0].(StringerMessage); !ok {
		t.Fatalf("Expected message, found '%#v'", v[0])
	} else if !HasStrings(v0[1], name1) {
		t.Fatal("First message expected to have string '%v', got '%v'", name1, v0)
	}
	if v1, ok := v[1].(StringerMessage); !ok {
		t.Fatalf("Expected message, found '%#v'", v[1])
	} else if !HasStrings(v1[1], name2) {
		t.Fatalf("Second message expected to have string '%v', got '%v'", name2, v1)
	}
}

func TestMessageWithDouble(t *testing.T) {
	d := float64(3.14159)
	msg := MessageWithDouble{D: &d}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasDouble(v, d) {
		t.Fatalf("Incorrect value, expected '%v', got '%v'", d, v)
	}
}
func HasVarints(actual StringerRepeated, expected ...uint64) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerVarint); !ok {
			return false
		} else if uint64(v) != expected[i] {
			return false
		}
	}
	return true
}

func HasStrings(actual StringerRepeated, expected ...string) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerString); !ok {
			return false
		} else if string(v) != expected[i] {
			return false
		}
	}
	return true
}

func HasDouble(actual StringerRepeated, expected ...float64) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerDouble); !ok {
			return false
		} else if float64(v) != expected[i] {
			return false
		}
	}
	return true
}

func MustMarshal(msg proto.Message) io.ByteReader {
	b, err := proto.Marshal(msg)
	if err != nil {
		panic(err)
	}
	return bytes.NewBuffer(b)
}
*/
<commit_msg>Fixed pbdump tests<commit_after>package pbdump

import (
	"bytes"
	"io"
	"testing"

	"github.com/golang/protobuf/proto"
)

func MustMarshal(msg proto.Message) io.ByteReader {
	b, err := proto.Marshal(msg)
	if err != nil {
		panic(err)
	}
	return bytes.NewBuffer(b)
}

func HasVarints(actual StringerRepeated, expected ...uint64) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerVarint); !ok {
			return false
		} else if uint64(v) != expected[i] {
			return false
		}
	}
	return true
}

func HasStrings(actual StringerRepeated, expected ...string) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerString); !ok {
			return false
		} else if string(v) != expected[i] {
			return false
		}
	}
	return true
}

func HasDouble(actual StringerRepeated, expected ...float64) bool {
	if len(actual) != len(expected) {
		return false
	}
	for i, _ := range actual {
		if v, ok := actual[i].(StringerDouble); !ok {
			return false
		} else if float64(v) != expected[i] {
			return false
		}
	}
	return true
}
func TestMessageWithInt(t *testing.T) {
	msg := MessageWithInt{Id: proto.Int32(42)}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m.attributes[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasVarints(v, 42) {
		t.Fatalf("Incorrect value for field, expected '%v', got '%v'", 42, v)
	}
}

func TestMessageWithRepeatedInt(t *testing.T) {
	msg := MessageWithRepeatedInt{Ids: []int32{1, 2, 333, 456789}}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m.attributes[1]; !ok {
		t.Fatalf("Missing filed repeated field '1': '%v'", m)
	} else if !HasVarints(v, 1, 2, 333, 456789) {
		t.Fatalf("Missing values for tag '1': '%v'", v)
	}
}

func TestMessageWithString(t *testing.T) {
	name := "name"
	msg := MessageWithString{Name: &name}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m.attributes[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasStrings(v, name) {
		t.Fatalf("Incorrect value, expected '%s', got '%s'", name, v)
	}
}

func TestMessageWithEmbeddedRepeatedMessageWithString(t *testing.T) {
	name1 := "name1"
	msg1 := MessageWithString{Name: &name1}
	name2 := "name2"
	msg2 := MessageWithString{Name: &name2}
	msg := MessageWithEmbeddedRepeatedMessageWithString{
		Messages: []*MessageWithString{
			&msg1, &msg2,
		},
	}
	buf := MustMarshal(&msg)
	m, err := Dump(buf)
	if err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	}
	v, ok := m.attributes[1]
	if !ok {
		t.Fatalf("Missing filed repeated field '1': '%v'", m)
	} else if len(v) != 2 {
		t.Fatalf("Expected to have to repeated messages, got: '%d' (%v)", len(v), v)
	}
	if v0, ok := v[0].(StringerMessage); !ok {
		t.Fatalf("Expected message, found '%#v'", v[0])
	} else if !HasStrings(v0.attributes[1], name1) {
		t.Fatal("First message expected to have string '%v', got '%v'", name1, v0)
	}
	if v1, ok := v[1].(StringerMessage); !ok {
		t.Fatalf("Expected message, found '%#v'", v[1])
	} else if !HasStrings(v1.attributes[1], name2) {
		t.Fatalf("Second message expected to have string '%v', got '%v'", name2, v1)
	}
}

func TestMessageWithDouble(t *testing.T) {
	d := float64(3.14159)
	msg := MessageWithDouble{D: &d}
	buf := MustMarshal(&msg)
	if m, err := Dump(buf); err != nil {
		t.Fatalf("Failed to dump: '%v'", err)
	} else if v, ok := m.attributes[1]; !ok {
		t.Fatalf("Missing required field '1': '%v'", m)
	} else if !HasDouble(v, d) {
		t.Fatalf("Incorrect value, expected '%v', got '%v'", d, v)
	}
}
<|endoftext|>


<commit_before>package catTracks

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/deet/simpleline"
	"github.com/rotblauer/trackpoints/trackPoint"
	"sort"
	"strings"
	"time"
)

const (
	testesPrefix = "testes-------"
)

var testes = false

// SetTestes run
func SetTestes(flagger bool) {
	testes = flagger
}
func getTestesPrefix() string {
	if testes {
		return testesPrefix
	}
	return ""
}

//Store a snippit of life

// itob returns an 8-byte big endian representation of v.
func itob(v int64) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}

func storePoints(trackPoints trackPoint.TrackPoints) error {
	var err error
	for _, point := range trackPoints {
		err = storePoint(point)
		if err != nil {
			return err
		}
	}
	return err
}

func storePoint(tp trackPoint.TrackPoint) error {

	var err error
	if tp.Time.IsZero() {
		tp.Time = time.Now()
	}

	go func() {
		GetDB().Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(trackKey))

			// id, _ := b.NextSequence()
			// trackPoint.ID = int(id)
			tp.ID = tp.Time.UnixNano() //dunno if can really get nanoy, or if will just *1000.
			if exists := b.Get(itob(tp.ID)); exists != nil {
				// make sure it's ours
				var existingTrackpoint trackPoint.TrackPoint
				e := json.Unmarshal(exists, &existingTrackpoint)
				if e != nil {
					fmt.Println("Checking on an existing trackpoint and got an error with one of the existing trackpoints unmarshaling.")
				}
				if existingTrackpoint.Name == tp.Name {
					fmt.Println("Got that trackpoint already. Breaking.")
					return nil
				}
			}
			// gets "" case nontestesing
			tp.Name = getTestesPrefix() + tp.Name

			trackPointJSON, err := json.Marshal(tp)
			if err != nil {
				return err
			}
			err = b.Put(itob(tp.ID), trackPointJSON)
			if err != nil {
				fmt.Println("Didn't save post trackPoint in bolt.", err)
				return err
			}
			fmt.Println("Saved trackpoint: ", tp)
			return nil
		})
	}()

	if err != nil {
		fmt.Println(err)
	}
	return err
}

// DeleteTestes wipes the entire database of all points with names prefixed with testes prefix. Saves an rm keystorke
func DeleteTestes() error {
	e := GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))
		c := b.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			var tp trackPoint.TrackPoint
			e := json.Unmarshal(v, &tp)
			if e != nil {
				fmt.Println("Error deleting testes.")
				return e
			}
			if strings.HasPrefix(tp.Name, testesPrefix) {
				b.Delete(k)
			}
		}
		return nil
	})
	return e
}

//get everthing in the db... can do filtering some other day

//TODO make queryable ala which cat when
func getAllPoints() ([]*trackPoint.TrackPoint, error) {

	var err error
	// var trackPoints trackPoint.TrackPoints
	var coords []simpleline.Point

	err = GetDB().View(func(tx *bolt.Tx) error {
		var err error
		b := tx.Bucket([]byte(trackKey))

		if b.Stats().KeyN > 0 {
			c := b.Cursor()
			for trackPointkey, trackPointval := c.First(); trackPointkey != nil; trackPointkey, trackPointval = c.Next() {
				//only if trackPoint is in given trackPoints key set (we don't want all trackPoints just feeded times)
				//but if no ids given, return em all
				var trackPoint trackPoint.TrackPoint
				json.Unmarshal(trackPointval, &trackPoint)
				// trackPoints = append(trackPoints, trackPoint)

				//rdp
				coords = append(coords, &trackPoint) //filler up

			}

		} else {
			//cuz its not an error if no trackPoints
			return nil
		}
		return err
	})

	originalCount := len(coords)

	//simpleify line
	// results, sErr := simpleline.RDP(coords, 5, simpleline.Euclidean, true)
	results, sErr := simpleline.RDP(coords, 0.001, simpleline.Euclidean, true) //0.001 bring a 3000pt run to prox 300 (cuz scale is lat and lng)
	if sErr != nil {
		fmt.Println("Errrrrrr", sErr)
	}

	rdpCount := len(results)

	//dis shit is fsck but fsckit
	//truncater
	// trackPoints = trackPoints[len(trackPoints)-3:] // lets go crazy with 3
	var tps trackPoint.TPs

	for _, insult := range results {

		// fmt.Println(insult)
		o, ok := insult.(*trackPoint.TrackPoint)
		if !ok {
			fmt.Println("shittt notok")
		}
		tps = append(tps, o)
	}
	fmt.Println("Serving points. Original count was ", originalCount, " and post-RDP is ", rdpCount)
	sort.Sort(tps)

	return tps, err
}
<commit_msg>tidycats<commit_after>package catTracks

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/deet/simpleline"
	"github.com/rotblauer/trackpoints/trackPoint"
	"sort"
	"strings"
	"time"
)

const (
	testesPrefix = "testes-------"
)

var testes = false

// SetTestes run
func SetTestes(flagger bool) {
	testes = flagger
}
func getTestesPrefix() string {
	if testes {
		return testesPrefix
	}
	return ""
}

//Store a snippit of life

// itob returns an 8-byte big endian representation of v.
func itob(v int64) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}

func storePoints(trackPoints trackPoint.TrackPoints) error {
	var err error
	for _, point := range trackPoints {
		err = storePoint(point)
		if err != nil {
			return err
		}
	}
	return err
}

func storePoint(tp trackPoint.TrackPoint) error {

	var err error
	if tp.Time.IsZero() {
		tp.Time = time.Now()
	}

	go func() {
		GetDB().Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(trackKey))

			// id, _ := b.NextSequence()
			// trackPoint.ID = int(id)
			tp.ID = tp.Time.UnixNano() //dunno if can really get nanoy, or if will just *1000.
			if exists := b.Get(itob(tp.ID)); exists != nil {
				// make sure it's ours
				var existingTrackpoint trackPoint.TrackPoint
				e := json.Unmarshal(exists, &existingTrackpoint)
				if e != nil {
					fmt.Println("Checking on an existing trackpoint and got an error with one of the existing trackpoints unmarshaling.")
				}
				if existingTrackpoint.Name == tp.Name {
					fmt.Println("Got that trackpoint already. Breaking.")
					return nil
				}
			}
			// gets "" case nontestesing
			tp.Name = getTestesPrefix() + tp.Name

			trackPointJSON, err := json.Marshal(tp)
			if err != nil {
				return err
			}
			err = b.Put(itob(tp.ID), trackPointJSON)
			if err != nil {
				fmt.Println("Didn't save post trackPoint in bolt.", err)
				return err
			}
			fmt.Println("Saved trackpoint: ", tp)
			return nil
		})
	}()

	if err != nil {
		fmt.Println(err)
	}
	return err
}

// DeleteTestes wipes the entire database of all points with names prefixed with testes prefix. Saves an rm keystorke
func DeleteTestes() error {
	e := GetDB().Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(trackKey))
		c := b.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			var tp trackPoint.TrackPoint
			e := json.Unmarshal(v, &tp)
			if e != nil {
				fmt.Println("Error deleting testes.")
				return e
			}
			if strings.HasPrefix(tp.Name, testesPrefix) {
				b.Delete(k)
			}
		}
		return nil
	})
	return e
}

//get everthing in the db... can do filtering some other day

//TODO make queryable ala which cat when
func getAllPoints() ([]*trackPoint.TrackPoint, error) {

	var err error
	var coords []simpleline.Point

	err = GetDB().View(func(tx *bolt.Tx) error {
		var err error
		b := tx.Bucket([]byte(trackKey))

		if b.Stats().KeyN > 0 {
			c := b.Cursor()
			for trackPointkey, trackPointval := c.First(); trackPointkey != nil; trackPointkey, trackPointval = c.Next() {
				var trackPoint trackPoint.TrackPoint
				json.Unmarshal(trackPointval, &trackPoint)
				coords = append(coords, &trackPoint) //filler up
			}
		} else {
			return nil //cuz its not an error if no trackPoints
		}
		return err
	})

	//simpleify line
	// results, sErr := simpleline.RDP(coords, 5, simpleline.Euclidean, true)
	originalCount := len(coords)
	results, err := simpleline.RDP(coords, 0.001, simpleline.Euclidean, true) //0.001 bring a 5700pt run to prox 300 (.001 scale is lat and lng)
	if err != nil {
		fmt.Println("Errrrrrr", err)
		results = coords // return coords, err //better dan nuttin //but not sure want to return the err...
	}
	rdpCount := len(results)

	var tps trackPoint.TPs
	for _, insult := range results {
		o, ok := insult.(*trackPoint.TrackPoint)
		if !ok {
			fmt.Println("shittt notok")
		}
		tps = append(tps, o)
	}

	fmt.Println("Serving points. Original count was ", originalCount, " and post-RDP is ", rdpCount)

	sort.Sort(tps)

	return tps, err
}
<|endoftext|>


<commit_before>package fs

import (
	"path/filepath" // filepath.SplitList for NewS
	"strings"
)

// fsPath represents a file system path with os related functionalities
// and makes it's methods available to the derived types of this package.
//  Note: fsPath itself is intentionally not exported.
//  Note: fsPath is immutable, and as such safe for concurrent use.
type fsPath struct {
	name string // file system path
}

// FsPathS represents a collection (slice) of (pointers to) fsPathes
type FsPathS []*fsPath

// String returns the FsPathS-slice as string.
func (f FsPathS) String() string {
	var s string
	s = s + "{"
	first := true
	for _, e := range f {
		if first {
			first = false
		} else {
			s = s + ", "
		}
		s = s + e.String()
	}
	s = s + "}"
	return s
}

// forcePath returns a fresh fsPath representing the the given name.
func forcePath(name string) *fsPath {
	return newPath(name)
}

// newPath returns a fresh fsPath representing some file system element (directory/file)
// with the given path, which is also filepath.FromSlash-normalised.
// regardless whether it exists, or not, or is even a pattern.
func newPath(path string) *fsPath {
	return &fsPath{filepath.FromSlash(path)}
}

// AsPath returns (a pointer to) the underlying fsPath
// or panics, if TryPath detected some invlaid content.
//  Note: AsPath exists only for symmetry with respect to the other, higher types.
func (p *fsPath) AsPath() *fsPath {
	if _, ok := p.TryPath(); !ok {
		panic("AsPath: " + p.name + " contains an invalid character such as '" + string(filepath.ListSeparator) + "' or '" + MatchAny + "' or '" + MatchOne)
	} else {
		return p
	}
}

// TryPath returns (a pointer to) the underlying fsPath
// false, iff fsPath contains
//  - any filepath.ListSeparator (= os.PathListSeparator) or
//  - any of the Match-Metacharacters (MatchAny "*" or MatchOne "?")
//  Note: Match-Metacharacters "[" and "]" are intentionally permitted;
//  they may be used not only in patterns, but also as valid name of some file or folder/directory.
func (p *fsPath) TryPath() (*fsPath, bool) {
	if strings.ContainsAny(p.name, string(filepath.ListSeparator)+MatchAny+MatchOne) {
		return p, false
	} else {
		return p, true
	}
}

// NewS returns a non-empty slice of fsPath obtained via filepath.SplitList
func NewS(names ...string) (pathS FsPathS) {
	if len(names) < 1 {
		pathS = append(pathS, newPath(""))
	} else {
		for _, nameList := range names {
			for _, pathName := range filepath.SplitList(nameList) {
				pathS = append(pathS, newPath(pathName))
			}
		}
	}
	return pathS
}

// String returns the pathtext repreented by fsPath
func (p *fsPath) String() string {
	return p.name
}

// MatchDisk is a convenience for MatchDisk(name).
func (p *fsPath) MatchDisk() (dirS FsFoldS, filS FsFileS, err error) {
	return MatchDisk(p.name)
}

// PathMatches reports whether fsPath matches any of the patterns.
func (p *fsPath) PathMatches(patterns ...*Pattern) (matched bool, err error) {
	return Match(p.name, patterns...)
}

// BaseMatches reports whether base name of fsPath matches any of the patterns.
func (p *fsPath) BaseMatches(patterns ...*Pattern) (matched bool, err error) {
	return Match(p.Base().String(), patterns...)
}

// BaseLessExt: name.Base() less name.Ext()
func (p *fsPath) BaseLessExt() *FsBase {
	return BaseLessExt(p.name)
}
<commit_msg>make `golint` more happy<commit_after>package fs

import (
	"path/filepath" // filepath.SplitList for NewS
	"strings"
)

// fsPath represents a file system path with os related functionalities
// and makes it's methods available to the derived types of this package.
//  Note: fsPath itself is intentionally not exported.
//  Note: fsPath is immutable, and as such safe for concurrent use.
type fsPath struct {
	name string // file system path
}

// FsPathS represents a collection (slice) of (pointers to) fsPathes
type FsPathS []*fsPath

// String returns the FsPathS-slice as string.
func (f FsPathS) String() string {
	var s string
	s = s + "{"
	first := true
	for _, e := range f {
		if first {
			first = false
		} else {
			s = s + ", "
		}
		s = s + e.String()
	}
	s = s + "}"
	return s
}

// forcePath returns a fresh fsPath representing the the given name.
func forcePath(name string) *fsPath {
	return newPath(name)
}

// newPath returns a fresh fsPath representing some file system element (directory/file)
// with the given path, which is also filepath.FromSlash-normalised.
// regardless whether it exists, or not, or is even a pattern.
func newPath(path string) *fsPath {
	return &fsPath{filepath.FromSlash(path)}
}

// AsPath returns (a pointer to) the underlying fsPath
// or panics, if TryPath detected some invlaid content.
//  Note: AsPath exists only for symmetry with respect to the other, higher types.
func (p *fsPath) AsPath() *fsPath {
	if _, ok := p.TryPath(); !ok {
		panic("AsPath: " + p.name + " contains an invalid character such as '" + string(filepath.ListSeparator) + "' or '" + MatchAny + "' or '" + MatchOne)
	} else {
		return p
	}
}

// TryPath returns (a pointer to) the underlying fsPath
// false, iff fsPath contains
//  - any filepath.ListSeparator (= os.PathListSeparator) or
//  - any of the Match-Metacharacters (MatchAny "*" or MatchOne "?")
//  Note: Match-Metacharacters "[" and "]" are intentionally permitted;
//  they may be used not only in patterns, but also as valid name of some file or folder/directory.
func (p *fsPath) TryPath() (*fsPath, bool) {
	switch {
	case strings.ContainsAny(p.name, string(filepath.ListSeparator)+MatchAny+MatchOne):
		return p, false
	default:
		return p, true
	}
}

// NewS returns a non-empty slice of fsPath obtained via filepath.SplitList
func NewS(names ...string) (pathS FsPathS) {
	if len(names) < 1 {
		pathS = append(pathS, newPath(""))
	} else {
		for _, nameList := range names {
			for _, pathName := range filepath.SplitList(nameList) {
				pathS = append(pathS, newPath(pathName))
			}
		}
	}
	return pathS
}

// String returns the pathtext repreented by fsPath
func (p *fsPath) String() string {
	return p.name
}

// MatchDisk is a convenience for MatchDisk(name).
func (p *fsPath) MatchDisk() (dirS FsFoldS, filS FsFileS, err error) {
	return MatchDisk(p.name)
}

// PathMatches reports whether fsPath matches any of the patterns.
func (p *fsPath) PathMatches(patterns ...*Pattern) (matched bool, err error) {
	return Match(p.name, patterns...)
}

// BaseMatches reports whether base name of fsPath matches any of the patterns.
func (p *fsPath) BaseMatches(patterns ...*Pattern) (matched bool, err error) {
	return Match(p.Base().String(), patterns...)
}

// BaseLessExt: name.Base() less name.Ext()
func (p *fsPath) BaseLessExt() *FsBase {
	return BaseLessExt(p.name)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"reflect"
	"strconv"
)

type changeType uint8

const (
	changeUnknown changeType = iota
	changeNone
	changeNonBreaking
	changeBreaking
)

func (c changeType) String() string {
	switch c {
	case changeUnknown:
		return "unknowable"
	case changeNone:
		return "no change"
	case changeNonBreaking:
		return "non-breaking change"
	}
	return "breaking change"
}

type operation uint8

const (
	opAdd operation = iota
	opRemove
	opChange
)

func (op operation) String() string {
	switch op {
	case opAdd:
		return "added"
	case opRemove:
		return "removed"
	}
	return "changed"
}

// change is the ast declaration containing the before and after
type change struct {
	id         string
	summary    string
	op         operation
	changeType changeType
	before     ast.Decl
	after      ast.Decl
}

func (c change) String() string {
	fset := token.FileSet{} // only require non-nil fset
	pcfg := printer.Config{Mode: printer.RawFormat, Indent: 1}
	buf := bytes.Buffer{}

	if c.op == opChange {
		fmt.Fprintf(&buf, "%s (%s - %s)\n", c.op, c.changeType, c.summary)
	} else {
		fmt.Fprintln(&buf, c.op)
	}

	if c.before != nil {
		pcfg.Fprint(&buf, &fset, c.before)
		fmt.Fprintln(&buf)
	}
	if c.after != nil {
		pcfg.Fprint(&buf, &fset, c.after)
		fmt.Fprintln(&buf)
	}
	return buf.String()
}

// byID implements sort.Interface for []change based on the id field
type byID []change

func (a byID) Len() int           { return len(a) }
func (a byID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byID) Less(i, j int) bool { return a[i].id < a[j].id }

// decls is a map of an identifier to actual ast, where the id is a unique
// name to match declarations for before and after
type decls map[string]ast.Decl

func diff(bdecls, adecls decls) []change {
	var changes []change
	for id, decl := range bdecls {
		if _, ok := adecls[id]; !ok {
			// in before, not in after, therefore it was removed
			changes = append(changes, change{id: id, op: opRemove, before: decl})
			continue
		}

		// in before and in after, check if there's a difference
		changeType, summary := compareDecl(bdecls[id], adecls[id])
		if changeType == changeNone || changeType == changeUnknown {
			continue
		}

		changes = append(changes, change{
			id:         id,
			op:         opChange,
			changeType: changeType,
			summary:    summary,
			before:     decl,
			after:      adecls[id]},
		)
	}

	for id, decl := range adecls {
		if _, ok := bdecls[id]; !ok {
			// in after, not in before, therefore it was added
			changes = append(changes, change{id: id, op: opAdd, after: decl})
		}
	}

	return changes
}

// equal compares two declarations and returns true if they do not have
// incompatible changes. For example, comments aren't compared, names of
// arguments aren't compared etc.
func compareDecl(before, after ast.Decl) (changeType, string) {
	// compare types, ignore comments etc, so reflect.DeepEqual isn't good enough

	if reflect.TypeOf(before) != reflect.TypeOf(after) {
		// Declaration type changed, such as GenDecl to FuncDecl (eg var/const to func)
		return changeBreaking, "changed declaration"
	}

	switch b := before.(type) {
	case *ast.GenDecl:
		a := after.(*ast.GenDecl)

		if reflect.TypeOf(b.Specs[0]) != reflect.TypeOf(a.Specs[0]) {
			// Spec changed, such as ValueSpec to TypeSpec (eg var/const to struct)
			return changeBreaking, "changed spec"
		}

		switch bspec := b.Specs[0].(type) {
		case *ast.ValueSpec:
			aspec := a.Specs[0].(*ast.ValueSpec)
			// refactoring opportunity here with equalFieldTypes

			if bspec.Type == nil || aspec.Type == nil {
				// eg: var ErrSomeError = errors.New("Some Error")
				// cannot currently determine the type
				return changeUnknown, "cannot currently determine type"
			}

			if reflect.TypeOf(bspec.Type) != reflect.TypeOf(aspec.Type) {
				// eg change from int to []int
				return changeBreaking, "changed value spec type"
			}

			// var / const
			switch btype := bspec.Type.(type) {
			case *ast.Ident:
				// int/string/etc
				atype := aspec.Type.(*ast.Ident)
				if btype.Name != atype.Name {
					// type changed
					return changeBreaking, "changed type"
				}
			case *ast.ArrayType:
				// slice/array
				atype := aspec.Type.(*ast.ArrayType)
				// compare length
				if !exprEqual(btype.Len, atype.Len) {
					// change of length, or between array and slice
					return changeBreaking, "changed of array's length"
				}
				// compare array's element's type
				if !exprEqual(btype.Elt, atype.Elt) {
					return changeBreaking, "changed of array's element's type"
				}
			default:
				panic(fmt.Errorf("Unknown val spec type: %T", btype))
			}
		case *ast.TypeSpec:
			aspec := a.Specs[0].(*ast.TypeSpec)

			// type struct/interface/aliased

			if reflect.TypeOf(bspec.Type) != reflect.TypeOf(aspec.Type) {
				// Spec change, such as from StructType to InterfaceType or different aliased types
				return changeBreaking, "changed type of value spec"
			}

			switch btype := bspec.Type.(type) {
			case *ast.InterfaceType:
				atype := aspec.Type.(*ast.InterfaceType)

				// interfaces don't care if methods are removed
				added, removed, changed := diffFields(btype.Methods.List, atype.Methods.List)
				if len(added) > 0 {
					// Fields were added
					return changeBreaking, "members added"
				} else if len(changed) > 0 {
					// Fields changed types
					return changeBreaking, "members changed types"
				} else if len(removed) > 0 {
					return changeNonBreaking, "members removed"
				}
			case *ast.StructType:
				atype := aspec.Type.(*ast.StructType)

				// structs don't care if fields were added
				added, removed, changed := diffFields(btype.Fields.List, atype.Fields.List)
				if len(removed) > 0 {
					// Fields were removed
					return changeBreaking, "members removed"
				} else if len(changed) > 0 {
					// Fields changed types
					return changeBreaking, "members changed types"
				} else if len(added) > 0 {
					return changeNonBreaking, "members added"
				}
			case *ast.Ident:
				// alias
				atype := aspec.Type.(*ast.Ident)
				if btype.Name != atype.Name {
					// Alias typing changed underlying types
					return changeBreaking, "alias changed its underlying type"
				}
			}
		}
	case *ast.FuncDecl:
		a := after.(*ast.FuncDecl)
		added, removed, changed := diffFields(b.Type.Params.List, a.Type.Params.List)
		if len(added) > 0 || len(removed) > 0 || len(changed) > 0 {
			return changeBreaking, "parameters types changed"
		}

		if b.Type.Results != nil {
			if a.Type.Results == nil {
				// removed return parameter
				return changeBreaking, "removed return parameter"
			}

			_, removed, changed := diffFields(b.Type.Results.List, a.Type.Results.List)
			// Only check if we're changing/removing return parameters
			if len(removed) > 0 || len(changed) > 0 {
				return changeBreaking, "changed or removed return parameter"
			}
		}
	default:
		panic(fmt.Errorf("Unknown type: %T", before))
	}
	return changeNone, ""
}

func diffFields(before, after []*ast.Field) (added, removed, changed []*ast.Field) {
	// Presort after for quicker matching of fieldname -> type, may not be worthwhile
	AfterMembers := make(map[string]*ast.Field)
	for i, field := range after {
		AfterMembers[fieldKey(field, i)] = field
	}

	for i, bfield := range before {
		bkey := fieldKey(bfield, i)
		if afield, ok := AfterMembers[bkey]; ok {
			if !exprEqual(bfield.Type, afield.Type) {
				// changed
				changed = append(changed, bfield)
			}
			delete(AfterMembers, bkey)
			continue
		}

		// Removed
		removed = append(removed, bfield)
	}

	// What's left in afterMembers has added
	for _, afield := range AfterMembers {
		added = append(added, afield)
	}

	return added, removed, changed
}

// Return an appropriate identifier for a field, if it has an ident (name)
// such as in the case of a struct/interface member, else, use it's provided
// position i, such as the case of a function's parameter or result list
func fieldKey(field *ast.Field, i int) string {
	if len(field.Names) > 0 {
		return field.Names[0].Name
	}
	// No name, probably a function, return position
	return strconv.FormatInt(int64(i), 10)
}

// exprEqual compares two ast.Expr to determine if they are equal
func exprEqual(before, after ast.Expr) bool {
	// For the moment just use typeToString and compare strings
	return typeToString(before) == typeToString(after)
}

// typeToString returns a type, such as ident or function and returns a string
// representation (without superfluous variable names when necessary).
//
// This is designed to make comparisons simpler by not having to handle all
// the various ast permutations, but this is the slowest method and may have
// its own set of undesirable properties (including a performance penalty).
// See the equivalent func equalFieldTypes in b3b41cc470d4258b38372b87f22d87845ecfecb6
// for an example of what it might have been (it was missing some checks though)
func typeToString(ident ast.Expr) string {
	fset := token.FileSet{} // only require non-nil fset
	pcfg := printer.Config{Mode: printer.RawFormat}
	buf := bytes.Buffer{}

	switch v := ident.(type) {
	case *ast.FuncType:
		// strip variable names in functions
		for i := range v.Params.List {
			v.Params.List[i].Names = []*ast.Ident{}
		}
		if v.Results != nil {
			for i := range v.Results.List {
				v.Results.List[i].Names = []*ast.Ident{}
			}
		}
	}
	pcfg.Fprint(&buf, &fset, ident)

	return buf.String()
}
<commit_msg>Add printast helper function<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"os"
	"reflect"
	"strconv"
)

type changeType uint8

const (
	changeUnknown changeType = iota
	changeNone
	changeNonBreaking
	changeBreaking
)

func (c changeType) String() string {
	switch c {
	case changeUnknown:
		return "unknowable"
	case changeNone:
		return "no change"
	case changeNonBreaking:
		return "non-breaking change"
	}
	return "breaking change"
}

type operation uint8

const (
	opAdd operation = iota
	opRemove
	opChange
)

func (op operation) String() string {
	switch op {
	case opAdd:
		return "added"
	case opRemove:
		return "removed"
	}
	return "changed"
}

// change is the ast declaration containing the before and after
type change struct {
	id         string
	summary    string
	op         operation
	changeType changeType
	before     ast.Decl
	after      ast.Decl
}

func (c change) String() string {
	fset := token.FileSet{} // only require non-nil fset
	pcfg := printer.Config{Mode: printer.RawFormat, Indent: 1}
	buf := bytes.Buffer{}

	if c.op == opChange {
		fmt.Fprintf(&buf, "%s (%s - %s)\n", c.op, c.changeType, c.summary)
	} else {
		fmt.Fprintln(&buf, c.op)
	}

	if c.before != nil {
		pcfg.Fprint(&buf, &fset, c.before)
		fmt.Fprintln(&buf)
	}
	if c.after != nil {
		pcfg.Fprint(&buf, &fset, c.after)
		fmt.Fprintln(&buf)
	}
	return buf.String()
}

// byID implements sort.Interface for []change based on the id field
type byID []change

func (a byID) Len() int           { return len(a) }
func (a byID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byID) Less(i, j int) bool { return a[i].id < a[j].id }

// decls is a map of an identifier to actual ast, where the id is a unique
// name to match declarations for before and after
type decls map[string]ast.Decl

func diff(bdecls, adecls decls) []change {
	var changes []change
	for id, decl := range bdecls {
		if _, ok := adecls[id]; !ok {
			// in before, not in after, therefore it was removed
			changes = append(changes, change{id: id, op: opRemove, before: decl})
			continue
		}

		// in before and in after, check if there's a difference
		changeType, summary := compareDecl(bdecls[id], adecls[id])
		if changeType == changeNone || changeType == changeUnknown {
			continue
		}

		changes = append(changes, change{
			id:         id,
			op:         opChange,
			changeType: changeType,
			summary:    summary,
			before:     decl,
			after:      adecls[id]},
		)
	}

	for id, decl := range adecls {
		if _, ok := bdecls[id]; !ok {
			// in after, not in before, therefore it was added
			changes = append(changes, change{id: id, op: opAdd, after: decl})
		}
	}

	return changes
}

// equal compares two declarations and returns true if they do not have
// incompatible changes. For example, comments aren't compared, names of
// arguments aren't compared etc.
func compareDecl(before, after ast.Decl) (changeType, string) {
	// compare types, ignore comments etc, so reflect.DeepEqual isn't good enough

	if reflect.TypeOf(before) != reflect.TypeOf(after) {
		// Declaration type changed, such as GenDecl to FuncDecl (eg var/const to func)
		return changeBreaking, "changed declaration"
	}

	switch b := before.(type) {
	case *ast.GenDecl:
		a := after.(*ast.GenDecl)

		if reflect.TypeOf(b.Specs[0]) != reflect.TypeOf(a.Specs[0]) {
			// Spec changed, such as ValueSpec to TypeSpec (eg var/const to struct)
			return changeBreaking, "changed spec"
		}

		switch bspec := b.Specs[0].(type) {
		case *ast.ValueSpec:
			aspec := a.Specs[0].(*ast.ValueSpec)
			// refactoring opportunity here with equalFieldTypes

			if bspec.Type == nil || aspec.Type == nil {
				// eg: var ErrSomeError = errors.New("Some Error")
				// cannot currently determine the type
				return changeUnknown, "cannot currently determine type"
			}

			if reflect.TypeOf(bspec.Type) != reflect.TypeOf(aspec.Type) {
				// eg change from int to []int
				return changeBreaking, "changed value spec type"
			}

			// var / const
			switch btype := bspec.Type.(type) {
			case *ast.Ident:
				// int/string/etc
				atype := aspec.Type.(*ast.Ident)
				if btype.Name != atype.Name {
					// type changed
					return changeBreaking, "changed type"
				}
			case *ast.ArrayType:
				// slice/array
				atype := aspec.Type.(*ast.ArrayType)
				// compare length
				if !exprEqual(btype.Len, atype.Len) {
					// change of length, or between array and slice
					return changeBreaking, "changed of array's length"
				}
				// compare array's element's type
				if !exprEqual(btype.Elt, atype.Elt) {
					return changeBreaking, "changed of array's element's type"
				}
			default:
				panic(fmt.Errorf("Unknown val spec type: %T", btype))
			}
		case *ast.TypeSpec:
			aspec := a.Specs[0].(*ast.TypeSpec)

			// type struct/interface/aliased

			if reflect.TypeOf(bspec.Type) != reflect.TypeOf(aspec.Type) {
				// Spec change, such as from StructType to InterfaceType or different aliased types
				return changeBreaking, "changed type of value spec"
			}

			switch btype := bspec.Type.(type) {
			case *ast.InterfaceType:
				atype := aspec.Type.(*ast.InterfaceType)

				// interfaces don't care if methods are removed
				added, removed, changed := diffFields(btype.Methods.List, atype.Methods.List)
				if len(added) > 0 {
					// Fields were added
					return changeBreaking, "members added"
				} else if len(changed) > 0 {
					// Fields changed types
					return changeBreaking, "members changed types"
				} else if len(removed) > 0 {
					return changeNonBreaking, "members removed"
				}
			case *ast.StructType:
				atype := aspec.Type.(*ast.StructType)

				// structs don't care if fields were added
				added, removed, changed := diffFields(btype.Fields.List, atype.Fields.List)
				if len(removed) > 0 {
					// Fields were removed
					return changeBreaking, "members removed"
				} else if len(changed) > 0 {
					// Fields changed types
					return changeBreaking, "members changed types"
				} else if len(added) > 0 {
					return changeNonBreaking, "members added"
				}
			case *ast.Ident:
				// alias
				atype := aspec.Type.(*ast.Ident)
				if btype.Name != atype.Name {
					// Alias typing changed underlying types
					return changeBreaking, "alias changed its underlying type"
				}
			}
		}
	case *ast.FuncDecl:
		a := after.(*ast.FuncDecl)
		added, removed, changed := diffFields(b.Type.Params.List, a.Type.Params.List)
		if len(added) > 0 || len(removed) > 0 || len(changed) > 0 {
			return changeBreaking, "parameters types changed"
		}

		if b.Type.Results != nil {
			if a.Type.Results == nil {
				// removed return parameter
				return changeBreaking, "removed return parameter"
			}

			_, removed, changed := diffFields(b.Type.Results.List, a.Type.Results.List)
			// Only check if we're changing/removing return parameters
			if len(removed) > 0 || len(changed) > 0 {
				return changeBreaking, "changed or removed return parameter"
			}
		}
	default:
		panic(fmt.Errorf("Unknown type: %T", before))
	}
	return changeNone, ""
}

func diffFields(before, after []*ast.Field) (added, removed, changed []*ast.Field) {
	// Presort after for quicker matching of fieldname -> type, may not be worthwhile
	AfterMembers := make(map[string]*ast.Field)
	for i, field := range after {
		AfterMembers[fieldKey(field, i)] = field
	}

	for i, bfield := range before {
		bkey := fieldKey(bfield, i)
		if afield, ok := AfterMembers[bkey]; ok {
			if !exprEqual(bfield.Type, afield.Type) {
				// changed
				changed = append(changed, bfield)
			}
			delete(AfterMembers, bkey)
			continue
		}

		// Removed
		removed = append(removed, bfield)
	}

	// What's left in afterMembers has added
	for _, afield := range AfterMembers {
		added = append(added, afield)
	}

	return added, removed, changed
}

// Return an appropriate identifier for a field, if it has an ident (name)
// such as in the case of a struct/interface member, else, use it's provided
// position i, such as the case of a function's parameter or result list
func fieldKey(field *ast.Field, i int) string {
	if len(field.Names) > 0 {
		return field.Names[0].Name
	}
	// No name, probably a function, return position
	return strconv.FormatInt(int64(i), 10)
}

// exprEqual compares two ast.Expr to determine if they are equal
func exprEqual(before, after ast.Expr) bool {
	// For the moment just use typeToString and compare strings
	return typeToString(before) == typeToString(after)
}

// typeToString returns a type, such as ident or function and returns a string
// representation (without superfluous variable names when necessary).
//
// This is designed to make comparisons simpler by not having to handle all
// the various ast permutations, but this is the slowest method and may have
// its own set of undesirable properties (including a performance penalty).
// See the equivalent func equalFieldTypes in b3b41cc470d4258b38372b87f22d87845ecfecb6
// for an example of what it might have been (it was missing some checks though)
func typeToString(ident ast.Expr) string {
	fset := token.FileSet{} // only require non-nil fset
	pcfg := printer.Config{Mode: printer.RawFormat}
	buf := bytes.Buffer{}

	switch v := ident.(type) {
	case *ast.FuncType:
		// strip variable names in functions
		for i := range v.Params.List {
			v.Params.List[i].Names = []*ast.Ident{}
		}
		if v.Results != nil {
			for i := range v.Results.List {
				v.Results.List[i].Names = []*ast.Ident{}
			}
		}
	}
	pcfg.Fprint(&buf, &fset, ident)

	return buf.String()
}

// printast is a debug helper to quickly print the go source of an ast
func printast(ast interface{}) {
	pcfg := printer.Config{Mode: printer.RawFormat}
	pcfg.Fprint(os.Stdout, &token.FileSet{}, ast)
}
<|endoftext|>


<commit_before>package mpb

import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/decor"
)

const (
	rLeft = iota
	rFill
	rTip
	rEmpty
	rRight
)

const (
	formatLen = 5
	etaAlpha  = 0.25
)

type fmtRunes [formatLen]rune

// Bar represents a progress Bar
type Bar struct {
	// quit channel to request b.server to quit
	quit chan struct{}
	// done channel is receiveable after b.server has been quit
	done chan struct{}
	ops  chan func(*state)

	// following are used after b.done is receiveable
	cacheState state

	once sync.Once
}

type (
	state struct {
		id               int
		width            int
		format           fmtRunes
		etaAlpha         float64
		total            int64
		current          int64
		dropRatio        int64
		trimLeftSpace    bool
		trimRightSpace   bool
		completed        bool
		aborted          bool
		dynamic          bool
		startTime        time.Time
		timeElapsed      time.Duration
		blockStartTime   time.Time
		timePerItem      time.Duration
		appendFuncs      []decor.DecoratorFunc
		prependFuncs     []decor.DecoratorFunc
		refill           *refill
		bufP, bufB, bufA *bytes.Buffer
		panic            string
	}
	refill struct {
		char rune
		till int64
	}
	writeBuf struct {
		buf                []byte
		completeAfterFlush bool
	}
)

func newBar(ID int, total int64, wg *sync.WaitGroup, cancel <-chan struct{}, options ...BarOption) *Bar {
	if total <= 0 {
		total = time.Now().Unix()
	}

	s := state{
		id:        ID,
		total:     total,
		etaAlpha:  etaAlpha,
		dropRatio: 10,
	}

	for _, opt := range options {
		opt(&s)
	}

	s.bufP = bytes.NewBuffer(make([]byte, 0, s.width/2))
	s.bufB = bytes.NewBuffer(make([]byte, 0, s.width))
	s.bufA = bytes.NewBuffer(make([]byte, 0, s.width/2))

	b := &Bar{
		quit: make(chan struct{}),
		done: make(chan struct{}),
		ops:  make(chan func(*state)),
	}

	go b.server(s, wg, cancel)
	return b
}

// RemoveAllPrependers removes all prepend functions
func (b *Bar) RemoveAllPrependers() {
	select {
	case b.ops <- func(s *state) {
		s.prependFuncs = nil
	}:
	case <-b.quit:
	}
}

// RemoveAllAppenders removes all append functions
func (b *Bar) RemoveAllAppenders() {
	select {
	case b.ops <- func(s *state) {
		s.appendFuncs = nil
	}:
	case <-b.quit:
	}
}

// ProxyReader wrapper for io operations, like io.Copy
func (b *Bar) ProxyReader(r io.Reader) *Reader {
	return &Reader{r, b}
}

// Increment shorthand for b.Incr(1)
func (b *Bar) Increment() {
	b.Incr(1)
}

// Incr increments progress bar
func (b *Bar) Incr(n int) {
	if n < 1 {
		return
	}
	select {
	case b.ops <- func(s *state) {
		next := time.Now()
		if s.current == 0 {
			s.startTime = next
			s.blockStartTime = next
		} else {
			now := time.Now()
			s.updateTimePerItemEstimate(n, now, next)
			s.timeElapsed = now.Sub(s.startTime)
		}
		s.current += int64(n)
		if s.dynamic {
			for s.current >= s.total {
				s.current -= s.current * s.dropRatio / 100
			}
		} else if s.current >= s.total {
			s.current = s.total
			s.completed = true
		}
	}:
	case <-b.quit:
	}
}

// ResumeFill fills bar with different r rune,
// from 0 to till amount of progress.
func (b *Bar) ResumeFill(r rune, till int64) {
	if till < 1 {
		return
	}
	select {
	case b.ops <- func(s *state) {
		s.refill = &refill{r, till}
	}:
	case <-b.quit:
	}
}

func (b *Bar) NumOfAppenders() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- len(s.appendFuncs) }:
		return <-result
	case <-b.done:
		return len(b.cacheState.appendFuncs)
	}
}

func (b *Bar) NumOfPrependers() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- len(s.prependFuncs) }:
		return <-result
	case <-b.done:
		return len(b.cacheState.prependFuncs)
	}
}

// ID returs id of the bar
func (b *Bar) ID() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- s.id }:
		return <-result
	case <-b.done:
		return b.cacheState.id
	}
}

func (b *Bar) Current() int64 {
	result := make(chan int64, 1)
	select {
	case b.ops <- func(s *state) { result <- s.current }:
		return <-result
	case <-b.done:
		return b.cacheState.current
	}
}

func (b *Bar) Total() int64 {
	result := make(chan int64, 1)
	select {
	case b.ops <- func(s *state) { result <- s.total }:
		return <-result
	case <-b.done:
		return b.cacheState.total
	}
}

// SetTotal sets total dynamically. The final param indicates the very last set,
// in other words you should set it to true when total is determined.
// Also you may consider providing your drop ratio via BarDropRatio BarOption func.
func (b *Bar) SetTotal(total int64, final bool) {
	select {
	case b.ops <- func(s *state) {
		s.total = total
		s.dynamic = !final
	}:
	case <-b.quit:
	}
}

// InProgress returns true, while progress is running.
// Can be used as condition in for loop
func (b *Bar) InProgress() bool {
	select {
	case <-b.quit:
		return false
	default:
		return true
	}
}

// Complete signals to the bar, that process has been completed.
// You should call this method when total is unknown and you've reached the point
// of process completion. If you don't call this method, it will be called
// implicitly, upon p.Stop() call.
func (b *Bar) Complete() {
	b.once.Do(b.shutdown)
}

func (b *Bar) shutdown() {
	close(b.quit)
}

func (b *Bar) server(s state, wg *sync.WaitGroup, cancel <-chan struct{}) {
	defer func() {
		b.cacheState = s
		close(b.done)
		wg.Done()
	}()

	for {
		select {
		case op := <-b.ops:
			op(&s)
		case <-cancel:
			s.aborted = true
			cancel = nil
			b.Complete()
		case <-b.quit:
			return
		}
	}
}

func (b *Bar) render(tw int, prependWs, appendWs *widthSync) <-chan *writeBuf {
	ch := make(chan *writeBuf, 1)

	go func() {
		select {
		case b.ops <- func(s *state) {
			defer func() {
				// recovering if external decorators panic
				if p := recover(); p != nil {
					s.panic = fmt.Sprintf("b#%02d panic: %v\n", s.id, p)
					s.prependFuncs = nil
					s.appendFuncs = nil

					ch <- &writeBuf{[]byte(s.panic), true}
				}
				close(ch)
			}()
			s.draw(tw, prependWs, appendWs)
			ch <- &writeBuf{s.toBytes(), s.isFull()}
		}:
		case <-b.done:
			s := b.cacheState
			var buf []byte
			if s.panic != "" {
				buf = []byte(s.panic)
			} else {
				s.draw(tw, prependWs, appendWs)
				buf = s.toBytes()
			}
			ch <- &writeBuf{buf, false}
			close(ch)
		}
	}()

	return ch
}

func (s *state) toBytes() []byte {
	buf := make([]byte, 0, s.bufP.Len()+s.bufB.Len()+s.bufA.Len())
	buf = concatenateBlocks(buf, s.bufP.Bytes(), s.bufB.Bytes(), s.bufA.Bytes())
	return buf
}

func (s *state) updateTimePerItemEstimate(amount int, now, next time.Time) {
	lastBlockTime := now.Sub(s.blockStartTime)
	lastItemEstimate := float64(lastBlockTime) / float64(amount)
	s.timePerItem = time.Duration((s.etaAlpha * lastItemEstimate) + (1-s.etaAlpha)*float64(s.timePerItem))
	s.blockStartTime = next
}

func (s *state) isFull() bool {
	if !s.completed {
		return false
	}
	bar := s.bufB.Bytes()
	var r rune
	var n int
	for i := 0; len(bar) > 0; i++ {
		r, n = utf8.DecodeLastRune(bar)
		bar = bar[:len(bar)-n]
		if i == 1 {
			break
		}
	}
	return r == s.format[rFill]
}

func (s *state) draw(termWidth int, prependWs, appendWs *widthSync) {
	if termWidth <= 0 {
		termWidth = 2
	}

	stat := newStatistics(s)

	// render prepend functions to the left of the bar
	s.bufP.Reset()
	for i, f := range s.prependFuncs {
		s.bufP.WriteString(f(stat, prependWs.Listen[i], prependWs.Result[i]))
	}

	if !s.trimLeftSpace {
		s.bufP.WriteByte(' ')
	}

	// render append functions to the right of the bar
	s.bufA.Reset()
	if !s.trimRightSpace {
		s.bufA.WriteByte(' ')
	}

	for i, f := range s.appendFuncs {
		s.bufA.WriteString(f(stat, appendWs.Listen[i], appendWs.Result[i]))
	}

	prependCount := utf8.RuneCount(s.bufP.Bytes())
	appendCount := utf8.RuneCount(s.bufA.Bytes())

	if termWidth > s.width {
		s.fillBar(s.width)
	} else {
		s.fillBar(termWidth - prependCount - appendCount)
	}
	barCount := utf8.RuneCount(s.bufB.Bytes())
	totalCount := prependCount + barCount + appendCount
	if totalCount > termWidth {
		s.fillBar(termWidth - prependCount - appendCount)
	}
	s.bufA.WriteByte('\n')
}

func (s *state) fillBar(width int) {
	s.bufB.Reset()
	s.bufB.WriteRune(s.format[rLeft])
	if width <= 2 {
		s.bufB.WriteRune(s.format[rRight])
		return
	}

	// bar s.width without leftEnd and rightEnd runes
	barWidth := width - 2

	completedWidth := decor.CalcPercentage(s.total, s.current, barWidth)

	if s.refill != nil {
		till := decor.CalcPercentage(s.total, s.refill.till, barWidth)
		// append refill rune
		for i := 0; i < till; i++ {
			s.bufB.WriteRune(s.refill.char)
		}
		for i := till; i < completedWidth; i++ {
			s.bufB.WriteRune(s.format[rFill])
		}
	} else {
		for i := 0; i < completedWidth; i++ {
			s.bufB.WriteRune(s.format[rFill])
		}
	}

	if completedWidth < barWidth && completedWidth > 0 {
		_, size := utf8.DecodeLastRune(s.bufB.Bytes())
		s.bufB.Truncate(s.bufB.Len() - size)
		s.bufB.WriteRune(s.format[rTip])
	}

	for i := completedWidth; i < barWidth; i++ {
		s.bufB.WriteRune(s.format[rEmpty])
	}

	s.bufB.WriteRune(s.format[rRight])
}

func newStatistics(s *state) *decor.Statistics {
	return &decor.Statistics{
		ID:                  s.id,
		Completed:           s.completed,
		Aborted:             s.aborted,
		Total:               s.total,
		Current:             s.current,
		StartTime:           s.startTime,
		TimeElapsed:         s.timeElapsed,
		TimePerItemEstimate: s.timePerItem,
	}
}

func concatenateBlocks(buf []byte, blocks ...[]byte) []byte {
	for _, block := range blocks {
		buf = append(buf, block...)
	}
	return buf
}

func (s *state) updateFormat(format string) {
	for i, n := 0, 0; len(format) > 0; i++ {
		s.format[i], n = utf8.DecodeRuneInString(format)
		format = format[n:]
	}
}
<commit_msg>No need to check bar's complete rune<commit_after>package mpb

import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/decor"
)

const (
	rLeft = iota
	rFill
	rTip
	rEmpty
	rRight
)

const (
	formatLen = 5
	etaAlpha  = 0.25
)

type fmtRunes [formatLen]rune

// Bar represents a progress Bar
type Bar struct {
	// quit channel to request b.server to quit
	quit chan struct{}
	// done channel is receiveable after b.server has been quit
	done chan struct{}
	ops  chan func(*state)

	// following are used after b.done is receiveable
	cacheState state

	once sync.Once
}

type (
	state struct {
		id               int
		width            int
		format           fmtRunes
		etaAlpha         float64
		total            int64
		current          int64
		dropRatio        int64
		trimLeftSpace    bool
		trimRightSpace   bool
		completed        bool
		aborted          bool
		dynamic          bool
		startTime        time.Time
		timeElapsed      time.Duration
		blockStartTime   time.Time
		timePerItem      time.Duration
		appendFuncs      []decor.DecoratorFunc
		prependFuncs     []decor.DecoratorFunc
		refill           *refill
		bufP, bufB, bufA *bytes.Buffer
		panic            string
	}
	refill struct {
		char rune
		till int64
	}
	writeBuf struct {
		buf                []byte
		completeAfterFlush bool
	}
)

func newBar(ID int, total int64, wg *sync.WaitGroup, cancel <-chan struct{}, options ...BarOption) *Bar {
	if total <= 0 {
		total = time.Now().Unix()
	}

	s := state{
		id:        ID,
		total:     total,
		etaAlpha:  etaAlpha,
		dropRatio: 10,
	}

	for _, opt := range options {
		opt(&s)
	}

	s.bufP = bytes.NewBuffer(make([]byte, 0, s.width/2))
	s.bufB = bytes.NewBuffer(make([]byte, 0, s.width))
	s.bufA = bytes.NewBuffer(make([]byte, 0, s.width/2))

	b := &Bar{
		quit: make(chan struct{}),
		done: make(chan struct{}),
		ops:  make(chan func(*state)),
	}

	go b.server(s, wg, cancel)
	return b
}

// RemoveAllPrependers removes all prepend functions
func (b *Bar) RemoveAllPrependers() {
	select {
	case b.ops <- func(s *state) {
		s.prependFuncs = nil
	}:
	case <-b.quit:
	}
}

// RemoveAllAppenders removes all append functions
func (b *Bar) RemoveAllAppenders() {
	select {
	case b.ops <- func(s *state) {
		s.appendFuncs = nil
	}:
	case <-b.quit:
	}
}

// ProxyReader wrapper for io operations, like io.Copy
func (b *Bar) ProxyReader(r io.Reader) *Reader {
	return &Reader{r, b}
}

// Increment shorthand for b.Incr(1)
func (b *Bar) Increment() {
	b.Incr(1)
}

// Incr increments progress bar
func (b *Bar) Incr(n int) {
	if n < 1 {
		return
	}
	select {
	case b.ops <- func(s *state) {
		next := time.Now()
		if s.current == 0 {
			s.startTime = next
			s.blockStartTime = next
		} else {
			now := time.Now()
			s.updateTimePerItemEstimate(n, now, next)
			s.timeElapsed = now.Sub(s.startTime)
		}
		s.current += int64(n)
		if s.dynamic {
			for s.current >= s.total {
				s.current -= s.current * s.dropRatio / 100
			}
		} else if s.current >= s.total {
			s.current = s.total
			s.completed = true
		}
	}:
	case <-b.quit:
	}
}

// ResumeFill fills bar with different r rune,
// from 0 to till amount of progress.
func (b *Bar) ResumeFill(r rune, till int64) {
	if till < 1 {
		return
	}
	select {
	case b.ops <- func(s *state) {
		s.refill = &refill{r, till}
	}:
	case <-b.quit:
	}
}

func (b *Bar) NumOfAppenders() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- len(s.appendFuncs) }:
		return <-result
	case <-b.done:
		return len(b.cacheState.appendFuncs)
	}
}

func (b *Bar) NumOfPrependers() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- len(s.prependFuncs) }:
		return <-result
	case <-b.done:
		return len(b.cacheState.prependFuncs)
	}
}

// ID returs id of the bar
func (b *Bar) ID() int {
	result := make(chan int, 1)
	select {
	case b.ops <- func(s *state) { result <- s.id }:
		return <-result
	case <-b.done:
		return b.cacheState.id
	}
}

func (b *Bar) Current() int64 {
	result := make(chan int64, 1)
	select {
	case b.ops <- func(s *state) { result <- s.current }:
		return <-result
	case <-b.done:
		return b.cacheState.current
	}
}

func (b *Bar) Total() int64 {
	result := make(chan int64, 1)
	select {
	case b.ops <- func(s *state) { result <- s.total }:
		return <-result
	case <-b.done:
		return b.cacheState.total
	}
}

// SetTotal sets total dynamically. The final param indicates the very last set,
// in other words you should set it to true when total is determined.
// Also you may consider providing your drop ratio via BarDropRatio BarOption func.
func (b *Bar) SetTotal(total int64, final bool) {
	select {
	case b.ops <- func(s *state) {
		s.total = total
		s.dynamic = !final
	}:
	case <-b.quit:
	}
}

// InProgress returns true, while progress is running.
// Can be used as condition in for loop
func (b *Bar) InProgress() bool {
	select {
	case <-b.quit:
		return false
	default:
		return true
	}
}

// Complete signals to the bar, that process has been completed.
// You should call this method when total is unknown and you've reached the point
// of process completion. If you don't call this method, it will be called
// implicitly, upon p.Stop() call.
func (b *Bar) Complete() {
	b.once.Do(b.shutdown)
}

func (b *Bar) shutdown() {
	close(b.quit)
}

func (b *Bar) server(s state, wg *sync.WaitGroup, cancel <-chan struct{}) {
	defer func() {
		b.cacheState = s
		close(b.done)
		wg.Done()
	}()

	for {
		select {
		case op := <-b.ops:
			op(&s)
		case <-cancel:
			s.aborted = true
			cancel = nil
			b.Complete()
		case <-b.quit:
			return
		}
	}
}

func (b *Bar) render(tw int, prependWs, appendWs *widthSync) <-chan *writeBuf {
	ch := make(chan *writeBuf, 1)

	go func() {
		select {
		case b.ops <- func(s *state) {
			defer func() {
				// recovering if external decorators panic
				if p := recover(); p != nil {
					s.panic = fmt.Sprintf("b#%02d panic: %v\n", s.id, p)
					s.prependFuncs = nil
					s.appendFuncs = nil

					ch <- &writeBuf{[]byte(s.panic), true}
				}
				close(ch)
			}()
			s.draw(tw, prependWs, appendWs)
			ch <- &writeBuf{s.toBytes(), s.completed}
		}:
		case <-b.done:
			s := b.cacheState
			var buf []byte
			if s.panic != "" {
				buf = []byte(s.panic)
			} else {
				s.draw(tw, prependWs, appendWs)
				buf = s.toBytes()
			}
			ch <- &writeBuf{buf, false}
			close(ch)
		}
	}()

	return ch
}

func (s *state) toBytes() []byte {
	buf := make([]byte, 0, s.bufP.Len()+s.bufB.Len()+s.bufA.Len())
	buf = concatenateBlocks(buf, s.bufP.Bytes(), s.bufB.Bytes(), s.bufA.Bytes())
	return buf
}

func (s *state) updateTimePerItemEstimate(amount int, now, next time.Time) {
	lastBlockTime := now.Sub(s.blockStartTime)
	lastItemEstimate := float64(lastBlockTime) / float64(amount)
	s.timePerItem = time.Duration((s.etaAlpha * lastItemEstimate) + (1-s.etaAlpha)*float64(s.timePerItem))
	s.blockStartTime = next
}

func (s *state) draw(termWidth int, prependWs, appendWs *widthSync) {
	if termWidth <= 0 {
		termWidth = 2
	}

	stat := newStatistics(s)

	// render prepend functions to the left of the bar
	s.bufP.Reset()
	for i, f := range s.prependFuncs {
		s.bufP.WriteString(f(stat, prependWs.Listen[i], prependWs.Result[i]))
	}

	if !s.trimLeftSpace {
		s.bufP.WriteByte(' ')
	}

	// render append functions to the right of the bar
	s.bufA.Reset()
	if !s.trimRightSpace {
		s.bufA.WriteByte(' ')
	}

	for i, f := range s.appendFuncs {
		s.bufA.WriteString(f(stat, appendWs.Listen[i], appendWs.Result[i]))
	}

	prependCount := utf8.RuneCount(s.bufP.Bytes())
	appendCount := utf8.RuneCount(s.bufA.Bytes())

	if termWidth > s.width {
		s.fillBar(s.width)
	} else {
		s.fillBar(termWidth - prependCount - appendCount)
	}
	barCount := utf8.RuneCount(s.bufB.Bytes())
	totalCount := prependCount + barCount + appendCount
	if totalCount > termWidth {
		s.fillBar(termWidth - prependCount - appendCount)
	}
	s.bufA.WriteByte('\n')
}

func (s *state) fillBar(width int) {
	s.bufB.Reset()
	s.bufB.WriteRune(s.format[rLeft])
	if width <= 2 {
		s.bufB.WriteRune(s.format[rRight])
		return
	}

	// bar s.width without leftEnd and rightEnd runes
	barWidth := width - 2

	completedWidth := decor.CalcPercentage(s.total, s.current, barWidth)

	if s.refill != nil {
		till := decor.CalcPercentage(s.total, s.refill.till, barWidth)
		// append refill rune
		for i := 0; i < till; i++ {
			s.bufB.WriteRune(s.refill.char)
		}
		for i := till; i < completedWidth; i++ {
			s.bufB.WriteRune(s.format[rFill])
		}
	} else {
		for i := 0; i < completedWidth; i++ {
			s.bufB.WriteRune(s.format[rFill])
		}
	}

	if completedWidth < barWidth && completedWidth > 0 {
		_, size := utf8.DecodeLastRune(s.bufB.Bytes())
		s.bufB.Truncate(s.bufB.Len() - size)
		s.bufB.WriteRune(s.format[rTip])
	}

	for i := completedWidth; i < barWidth; i++ {
		s.bufB.WriteRune(s.format[rEmpty])
	}

	s.bufB.WriteRune(s.format[rRight])
}

func newStatistics(s *state) *decor.Statistics {
	return &decor.Statistics{
		ID:                  s.id,
		Completed:           s.completed,
		Aborted:             s.aborted,
		Total:               s.total,
		Current:             s.current,
		StartTime:           s.startTime,
		TimeElapsed:         s.timeElapsed,
		TimePerItemEstimate: s.timePerItem,
	}
}

func concatenateBlocks(buf []byte, blocks ...[]byte) []byte {
	for _, block := range blocks {
		buf = append(buf, block...)
	}
	return buf
}

func (s *state) updateFormat(format string) {
	for i, n := 0, 0; len(format) > 0; i++ {
		s.format[i], n = utf8.DecodeRuneInString(format)
		format = format[n:]
	}
}
<|endoftext|>


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

// Bat is a Go implemented CLI cURL-like tool for humans
// bat [flags] [METHOD] URL [ITEM [ITEM]]
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strings"
)

const version = "0.0.1"

var (
	verbose bool
	form    bool
	auth    string
	isjson  = flag.Bool("json", true, "Send the data as a JSON object")
	method  = flag.String("method", "GET", "HTTP method")
	URL     = flag.String("url", "", "HTTP request URL")
	jsonmap map[string]interface{}
)

func init() {
	flag.BoolVar(&verbose, "verbose", false, "Print the whole HTTP exchange (request and response)")
	flag.BoolVar(&verbose, "v", false, "Print the whole HTTP exchange (request and response)")
	flag.BoolVar(&form, "form", false, "Submitting as a form")
	flag.BoolVar(&form, "f", false, "Submitting as a form")
	flag.StringVar(&auth, "auth", "", "HTTP authentication username:password, USER[:PASS]")
	flag.StringVar(&auth, "a", "", "HTTP authentication username:password, USER[:PASS]")
	jsonmap = make(map[string]interface{})
}

func main() {
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) > 0 {
		args = filter(args)
	}

	var stdin []byte
	if runtime.GOOS != "windows" {
		fi, err := os.Stdin.Stat()
		if err != nil {
			panic(err)
		}

		if fi.Size() != 0 {
			stdin, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				log.Fatal("Read from Stdin", err)
			}
		}
	}

	if *URL == "" {
		log.Fatalln("no URL given")
	}
	if strings.HasPrefix(*URL, ":") {
		urlb := []byte(*URL)
		if *URL == ":" {
			*URL = "http://localhost/"
		} else if len(*URL) > 1 && urlb[1] != '/' {
			*URL = "http://localhost" + *URL
		} else {
			*URL = "http://localhost" + string(urlb[1:])
		}
	}
	if !strings.HasPrefix(*URL, "http://") && !strings.HasPrefix(*URL, "https://") {
		*URL = "http://" + *URL
	}
	u, err := url.Parse(*URL)
	if err != nil {
		log.Fatal(err)
	}
	*URL = u.String()
	httpreq := getHTTP(*method, *URL, args)

	if len(stdin) > 0 {
		var j interface{}
		err = json.Unmarshal(stdin, &j)
		if err != nil {
			log.Fatal("json.Unmarshal", err)
		}
		httpreq.JsonBody(j)
	}

	res, err := httpreq.Response()
	if err != nil {
		log.Fatalln("can't get the url", err)
	}
	if runtime.GOOS != "windows" {
		fi, err := os.Stdout.Stat()
		if err != nil {
			panic(err)
		}
		if fi.Mode()&os.ModeDevice == os.ModeDevice {
			dump := httpreq.DumpRequest()
			fmt.Println(string(dump))
			fmt.Println("")
			fmt.Println(res.Proto, res.Status)
			for k, v := range res.Header {
				fmt.Println(k, ":", strings.Join(v, " "))
			}
			str, err := httpreq.String()
			if err != nil {
				log.Fatalln("can't get the url", err)
			}
			fmt.Println("")
			fmt.Println(str)
		} else {
			str, err := httpreq.String()
			if err != nil {
				log.Fatalln("can't get the url", err)
			}
			_, err = os.Stdout.WriteString(str)
			if err != nil {
				log.Fatal(err)
			}
		}
	} else {
		dump := httpreq.DumpRequest()
		fmt.Println(string(dump))
		fmt.Println("")
		fmt.Println(res.Proto, res.Status)
		for k, v := range res.Header {
			fmt.Println(k, ":", strings.Join(v, " "))
		}
		str, err := httpreq.String()
		if err != nil {
			log.Fatalln("can't get the url", err)
		}
		fmt.Println("")
		fmt.Println(str)
	}
}

var usageinfo string = `bat is a Go implemented CLI cURL-like tool for humans.

Usage:

	bat [flags] [METHOD] URL [ITEM [ITEM]]

flags:
  -a, -auth USER[:PASS]   Pass a username:password pair as the argument
  -f, -form=false         Submitting the data as a form
  -j, -json=true          Send the data in a JSON object
  -v, -verbose=false      Print the whole HTTP exchange (request and response)

METHOD:
   bat defaults to either GET (if there is no request data) or POST (with request data).

URL:
  The only information needed to perform a request is a URL. The default scheme is http://,
  which can be omitted from the argument; example.org works just fine.

ITEM:
  Can be any of:
    Query string   key=value
    Header         key:value
    Post data      key=value
    File upload    key@/path/file

Example:

	bat beego.me

more help information please refer to https://github.com/astaxie/bat
`

func usage() {
	fmt.Println(usageinfo)
	os.Exit(2)
}
<commit_msg>support flag auth<commit_after>// Copyright 2015 bat authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Bat is a Go implemented CLI cURL-like tool for humans
// bat [flags] [METHOD] URL [ITEM [ITEM]]
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"runtime"
	"strings"
)

const version = "0.0.1"

var (
	verbose bool
	form    bool
	auth    string
	isjson  = flag.Bool("json", true, "Send the data as a JSON object")
	method  = flag.String("method", "GET", "HTTP method")
	URL     = flag.String("url", "", "HTTP request URL")
	jsonmap map[string]interface{}
)

func init() {
	flag.BoolVar(&verbose, "verbose", false, "Print the whole HTTP exchange (request and response)")
	flag.BoolVar(&verbose, "v", false, "Print the whole HTTP exchange (request and response)")
	flag.BoolVar(&form, "form", false, "Submitting as a form")
	flag.BoolVar(&form, "f", false, "Submitting as a form")
	flag.StringVar(&auth, "auth", "", "HTTP authentication username:password, USER[:PASS]")
	flag.StringVar(&auth, "a", "", "HTTP authentication username:password, USER[:PASS]")
	jsonmap = make(map[string]interface{})
}

func main() {
	flag.Usage = usage
	flag.Parse()
	args := flag.Args()
	if len(args) > 0 {
		args = filter(args)
	}

	var stdin []byte
	if runtime.GOOS != "windows" {
		fi, err := os.Stdin.Stat()
		if err != nil {
			panic(err)
		}

		if fi.Size() != 0 {
			stdin, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				log.Fatal("Read from Stdin", err)
			}
		}
	}

	if *URL == "" {
		log.Fatalln("no URL given")
	}
	if strings.HasPrefix(*URL, ":") {
		urlb := []byte(*URL)
		if *URL == ":" {
			*URL = "http://localhost/"
		} else if len(*URL) > 1 && urlb[1] != '/' {
			*URL = "http://localhost" + *URL
		} else {
			*URL = "http://localhost" + string(urlb[1:])
		}
	}
	if !strings.HasPrefix(*URL, "http://") && !strings.HasPrefix(*URL, "https://") {
		*URL = "http://" + *URL
	}
	u, err := url.Parse(*URL)
	if err != nil {
		log.Fatal(err)
	}
	if auth != "" {
		userpass := strings.Split(auth, ":")
		if len(userpass) == 2 {
			u.User = url.UserPassword(userpass[0], userpass[1])
		} else {
			u.User = url.User(auth)
		}
	}
	*URL = u.String()
	httpreq := getHTTP(*method, *URL, args)

	if len(stdin) > 0 {
		var j interface{}
		err = json.Unmarshal(stdin, &j)
		if err != nil {
			log.Fatal("json.Unmarshal", err)
		}
		httpreq.JsonBody(j)
	}

	res, err := httpreq.Response()
	if err != nil {
		log.Fatalln("can't get the url", err)
	}
	if runtime.GOOS != "windows" {
		fi, err := os.Stdout.Stat()
		if err != nil {
			panic(err)
		}
		if fi.Mode()&os.ModeDevice == os.ModeDevice {
			dump := httpreq.DumpRequest()
			fmt.Println(string(dump))
			fmt.Println("")
			fmt.Println(res.Proto, res.Status)
			for k, v := range res.Header {
				fmt.Println(k, ":", strings.Join(v, " "))
			}
			str, err := httpreq.String()
			if err != nil {
				log.Fatalln("can't get the url", err)
			}
			fmt.Println("")
			fmt.Println(str)
		} else {
			str, err := httpreq.String()
			if err != nil {
				log.Fatalln("can't get the url", err)
			}
			_, err = os.Stdout.WriteString(str)
			if err != nil {
				log.Fatal(err)
			}
		}
	} else {
		dump := httpreq.DumpRequest()
		fmt.Println(string(dump))
		fmt.Println("")
		fmt.Println(res.Proto, res.Status)
		for k, v := range res.Header {
			fmt.Println(k, ":", strings.Join(v, " "))
		}
		str, err := httpreq.String()
		if err != nil {
			log.Fatalln("can't get the url", err)
		}
		fmt.Println("")
		fmt.Println(str)
	}
}

var usageinfo string = `bat is a Go implemented CLI cURL-like tool for humans.

Usage:

	bat [flags] [METHOD] URL [ITEM [ITEM]]

flags:
  -a, -auth USER[:PASS]   Pass a username:password pair as the argument
  -f, -form=false         Submitting the data as a form
  -j, -json=true          Send the data in a JSON object
  -v, -verbose=false      Print the whole HTTP exchange (request and response)

METHOD:
   bat defaults to either GET (if there is no request data) or POST (with request data).

URL:
  The only information needed to perform a request is a URL. The default scheme is http://,
  which can be omitted from the argument; example.org works just fine.

ITEM:
  Can be any of:
    Query string   key=value
    Header         key:value
    Post data      key=value
    File upload    key@/path/file

Example:

	bat beego.me

more help information please refer to https://github.com/astaxie/bat
`

func usage() {
	fmt.Println(usageinfo)
	os.Exit(2)
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"path/filepath"
	"time"
	"unsafe"

	"nvim-go/config"
	"nvim-go/nvim/profile"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

var (
	astInfo []byte
)

func init() {
	plugin.HandleCommand("GoAstView", &plugin.CommandOptions{Eval: "[getcwd(), expand('%:p')]"}, cmdAstView)
}

type cmdAstEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func cmdAstView(v *vim.Vim, eval *cmdAstEval) {
	go AstView(v, eval)
}

// AstView gets the Go AST informations of current buffer.
func AstView(v *vim.Vim, eval *cmdAstEval) error {
	defer profile.Start(time.Now(), "AstView")

	var (
		b vim.Buffer
		w vim.Window
	)

	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	if err := p.Wait(); err != nil {
		return err
	}

	var sources [][]byte
	p.BufferLines(b, 0, -1, false, &sources)
	if err := p.Wait(); err != nil {
		return err
	}

	var buf []byte
	for _, b := range sources {
		buf = append(buf, b...)
		buf = append(buf, byte('\n'))
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, eval.File, buf, parser.AllErrors|parser.ParseComments)
	if err != nil {
		return err
	}

	_, file := filepath.Split(eval.File)
	astInfo = append(astInfo, stringtoslicebyte(fmt.Sprintf("%s Files: %v\n", config.AstFoldIcon, file))...)
	ast.Walk(VisitorFunc(parseAST), f)

	astinfo := bytes.Split(bytes.TrimSuffix(astInfo, []byte{'\n'}), []byte{'\n'})
	if err := p.Wait(); err != nil {
		return err
	}

	p.Command("vertical botright 80 new")
	p.CurrentBuffer(&b)
	p.CurrentWindow(&w)
	if err := p.Wait(); err != nil {
		return err
	}

	p.SetWindowOption(w, "number", false)
	p.SetWindowOption(w, "list", false)
	p.SetWindowOption(w, "colorcolumn", "")

	p.SetBufferName(b, "__GoAstView__")
	p.SetBufferOption(b, "modifiable", true)
	p.SetBufferLines(b, 0, -1, true, astinfo)
	p.SetBufferOption(b, "buftype", "nofile")
	p.SetBufferOption(b, "bufhidden", "delete")
	p.SetBufferOption(b, "buflisted", false)
	p.SetBufferOption(b, "swapfile", false)
	p.SetBufferOption(b, "modifiable", false)
	p.SetBufferOption(b, "filetype", "goastview")
	p.Command("runtime! syntax/goastview.vim")

	return p.Wait()
}

// VisitorFunc for ast.Visit type.
type VisitorFunc func(n ast.Node) ast.Visitor

// Visit for ast.Visit function.
func (f VisitorFunc) Visit(n ast.Node) ast.Visitor {
	return f(n)
}

func parseAST(node ast.Node) ast.Visitor {
	switch node := node.(type) {

	default:
		return VisitorFunc(parseAST)
	case *ast.Ident:
		info := fmt.Sprintf("%s *ast.Ident\n\t Name: %v\n\t NamePos: %v\n", config.AstFoldIcon, node.Name, node.NamePos)
		if fmt.Sprint(node.Obj) != "<nil>" {
			info += fmt.Sprintf("\t Obj: %v\n", node.Obj)
		}
		astInfo = append(astInfo, stringtoslicebyte(info)...)
		return VisitorFunc(parseAST)
	case *ast.GenDecl:
		astInfo = append(astInfo,
			stringtoslicebyte(fmt.Sprintf("%s Decls: []ast.Decl\n\t TokPos: %v\n\t Tok: %v\n\t Lparen: %v\n",
				config.AstFoldIcon, node.TokPos, node.Tok, node.Lparen))...)
		return VisitorFunc(parseAST)
	case *ast.BasicLit:
		astInfo = append(astInfo,
			stringtoslicebyte(fmt.Sprintf("\t- Path: *ast.BasicLit\n\t\t\t Value: %v\n\t\t\t Kind: %v\n\t\t\t ValuePos: %v\n",
				node.Value, node.Kind, node.ValuePos))...)
		return VisitorFunc(parseAST)

	}
}

func stringtoslicebyte(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}
<commit_msg>cmds/astview: Fix create buffer and error handling<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"path/filepath"
	"time"
	"unsafe"

	"nvim-go/config"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"github.com/juju/errors"
)

const pkgAstView = "AstView"

var (
	astInfo []byte
)

func init() {
	plugin.HandleCommand("GoAstView", &plugin.CommandOptions{Eval: "[getcwd(), expand('%:p')]"}, cmdAstView)
}

type cmdAstEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func cmdAstView(v *vim.Vim, eval *cmdAstEval) {
	go astView(v, eval)
}

// AstView gets the Go AST informations of current buffer.
func astView(v *vim.Vim, eval *cmdAstEval) error {
	defer profile.Start(time.Now(), "AstView")

	var (
		b   vim.Buffer
		w   vim.Window
		blc int
	)

	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	p.CurrentWindow(&w)
	err := p.Wait()
	if err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	sources := make([][]byte, blc)
	p.BufferLines(b, 0, -1, true, &sources)
	p.BufferLineCount(b, &blc)
	if err := p.Wait(); err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	var buf []byte
	for _, b := range sources {
		buf = append(buf, b...)
		buf = append(buf, byte('\n'))
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, eval.File, buf, parser.AllErrors|parser.ParseComments)
	if err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	_, file := filepath.Split(eval.File)
	astInfo = append(astInfo, stringtoslicebyte(fmt.Sprintf("%s Files: %v\n", config.AstFoldIcon, file))...)
	ast.Walk(VisitorFunc(parseAST), f)

	astinfo := bytes.Split(bytes.TrimSuffix(astInfo, []byte{'\n'}), []byte{'\n'})
	if err := p.Wait(); err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	var (
		astBuf vim.Buffer
		astWin vim.Window
	)

	p.Command("vertical botright 80 new")
	p.CurrentBuffer(&astBuf)
	p.CurrentWindow(&astWin)
	if err := p.Wait(); err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	p.SetWindowOption(astWin, "number", false)
	p.SetWindowOption(astWin, "list", false)
	p.SetWindowOption(astWin, "colorcolumn", "")

	p.SetBufferName(astBuf, "__GoAstView__")
	p.SetBufferOption(astBuf, "modifiable", true)
	p.SetBufferLines(astBuf, 0, -1, true, astinfo)
	p.SetBufferOption(astBuf, "buftype", "nofile")
	p.SetBufferOption(astBuf, "bufhidden", "delete")
	p.SetBufferOption(astBuf, "buflisted", false)
	p.SetBufferOption(astBuf, "swapfile", false)
	p.SetBufferOption(astBuf, "modifiable", false)
	p.SetBufferOption(astBuf, "filetype", "goastview")
	p.Command("runtime! syntax/goastview.vim")
	if err := p.Wait(); err != nil {
		return nvim.ErrorWrap(v, errors.Annotate(err, pkgAstView))
	}

	p.SetCurrentWindow(w)

	return p.Wait()
}

// VisitorFunc for ast.Visit type.
type VisitorFunc func(n ast.Node) ast.Visitor

// Visit for ast.Visit function.
func (f VisitorFunc) Visit(n ast.Node) ast.Visitor {
	return f(n)
}

func parseAST(node ast.Node) ast.Visitor {
	switch node := node.(type) {

	default:
		return VisitorFunc(parseAST)
	case *ast.Ident:
		info := fmt.Sprintf("%s *ast.Ident\n\t Name: %v\n\t NamePos: %v\n", config.AstFoldIcon, node.Name, node.NamePos)
		if fmt.Sprint(node.Obj) != "<nil>" {
			info += fmt.Sprintf("\t Obj: %v\n", node.Obj)
		}
		astInfo = append(astInfo, stringtoslicebyte(info)...)
		return VisitorFunc(parseAST)
	case *ast.GenDecl:
		astInfo = append(astInfo,
			stringtoslicebyte(fmt.Sprintf("%s Decls: []ast.Decl\n\t TokPos: %v\n\t Tok: %v\n\t Lparen: %v\n",
				config.AstFoldIcon, node.TokPos, node.Tok, node.Lparen))...)
		return VisitorFunc(parseAST)
	case *ast.BasicLit:
		astInfo = append(astInfo,
			stringtoslicebyte(fmt.Sprintf("\t- Path: *ast.BasicLit\n\t\t\t Value: %v\n\t\t\t Kind: %v\n\t\t\t ValuePos: %v\n",
				node.Value, node.Kind, node.ValuePos))...)
		return VisitorFunc(parseAST)

	}
}

func stringtoslicebyte(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, M Bogus.
// This source file is part of the KUBE-AMQP-AUTOSCALE open source project
// Licensed under Apache License v2.0
// See LICENSE file for license information

package main

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/streadway/amqp"
)

var (
	queueCountSuccesses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "queue_count_successes_total",
		Help:      "Number of successful queue count retrievals.",
	})
	queueCountFailures = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "queue_count_failures_total",
		Help:      "Number of failed queue count retrievals.",
	})
	currentQueueSize = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "current_queue_size",
			Help:      "Last count retrieved for a queue.",
		},
		[]string{"queue"},
	)
	metricSaveFailures = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "metric_save_failures_total",
		Help:      "Number of times saving metrics failed.",
	})
)

type saveStat func(int) error

func monitorQueue(uri string, names []string, interval int, f saveStat, quit <-chan struct{}) {
	for {
		select {
		case <-quit:
			return
		case <-time.After(time.Duration(interval) * time.Second):
			totalMsgs := 0
			errored := false
			for _, name := range names {
				msgs, err := getQueueLength(uri, name)
				if err != nil {
					queueCountFailures.Inc()
					log.Printf("Failed to get queue length for queue %s: %v", name, err)
					errored = true
				} else {
					totalMsgs += msgs
					queueCountSuccesses.Inc()
					currentQueueSize.WithLabelValues(name).Set(float64(msgs))
				}
			}
			// Only save metrics if both counts succeeded.
			if errored == false {
				err := f(totalMsgs)
				if err != nil {
					metricSaveFailures.Inc()
					log.Printf("Error saving metrics: %v", err)
				}
			}
		}
	}
}

func getQueueLength(uri, name string) (int, error) {
	conn, err := amqp.Dial(uri)
	if err != nil {
		return 0, err
	}
	defer conn.Close()
	ch, err := conn.Channel()
	if err != nil {
		return 0, err
	}
	defer ch.Close()
	q, err := ch.QueueInspect(name)
	if err != nil {
		return 0, err
	}
	return q.Messages, nil
}
<commit_msg>Use rest api<commit_after>// Copyright (c) 2016, M Bogus.
// This source file is part of the KUBE-AMQP-AUTOSCALE open source project
// Licensed under Apache License v2.0
// See LICENSE file for license information

package main

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/streadway/amqp"
)

type APIQueueInfo struct {
	Messsages int `json:"messages"`
}

var (
	queueCountSuccesses = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "queue_count_successes_total",
		Help:      "Number of successful queue count retrievals.",
	})
	queueCountFailures = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "queue_count_failures_total",
		Help:      "Number of failed queue count retrievals.",
	})
	currentQueueSize = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "current_queue_size",
			Help:      "Last count retrieved for a queue.",
		},
		[]string{"queue"},
	)
	metricSaveFailures = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: namespace,
		Name:      "metric_save_failures_total",
		Help:      "Number of times saving metrics failed.",
	})
)

type saveStat func(int) error

func monitorQueue(uri string, names []string, interval int, f saveStat, quit <-chan struct{}) {
	for {
		select {
		case <-quit:
			return
		case <-time.After(time.Duration(interval) * time.Second):
			totalMsgs := 0
			errored := false
			for _, name := range names {
				msgs, err := getQueueLength(uri, name)
				if err != nil {
					queueCountFailures.Inc()
					log.Printf("Failed to get queue length for queue %s: %v", name, err)
					errored = true
				} else {
					totalMsgs += msgs
					queueCountSuccesses.Inc()
					currentQueueSize.WithLabelValues(name).Set(float64(msgs))
				}
			}
			// Only save metrics if both counts succeeded.
			if errored == false {
				err := f(totalMsgs)
				if err != nil {
					metricSaveFailures.Inc()
					log.Printf("Error saving metrics: %v", err)
				}
			}
		}
	}
}

func getQueueLengthFromAPI(uri, name string) (int, error) {
	apiQueueInfo := APIQueueInfo{}
	err := doApiRequest(uri, name, &apiQueueInfo)
	if err != nil {
		return 0, err
	}
	return apiQueueInfo.Messsages, nil
}

func doApiRequest(uri, name string, apiQueueInfo *APIQueueInfo) error {
	req, err := buildRequest(uri, name)
	if err != nil {
		return err
	}
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	reader := new(bytes.Buffer)
	reader.ReadFrom(resp.Body)
	return json.Unmarshal(reader.Bytes(), &apiQueueInfo)
}

func buildRequest(uri, name string) (*http.Request, error) {
	index := strings.LastIndex(uri, "/")
	vhost := uri[index:]
	uri = uri[:index]
	uri = uri + "/api/queues" + vhost + "/" + name
	return http.NewRequest("GET", uri, nil)
}

func getQueueLength(uri, name string) (int, error) {
	if strings.HasPrefix(uri, "http") {
		return getQueueLengthFromAPI(uri, name)
	}
	conn, err := amqp.Dial(uri)
	if err != nil {
		return 0, err
	}
	defer conn.Close()
	ch, err := conn.Channel()
	if err != nil {
		return 0, err
	}
	defer ch.Close()
	q, err := ch.QueueInspect(name)
	if err != nil {
		return 0, err
	}
	return q.Messages, nil
}
<|endoftext|>


<commit_before><commit_msg>WIP: adding gin tonic<commit_after><|endoftext|>