<commit_before>package prometheusmetrics

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/rcrowley/go-metrics"
)

// PrometheusConfig provides a container with config parameters for the
// Prometheus Exporter

type PrometheusConfig struct {
	namespace        string
	Registry         metrics.Registry // Registry to be exported
	subsystem        string
	promRegistry     prometheus.Registerer //Prometheus registry
	FlushInterval    time.Duration         //interval to update prom metrics
	gauges           map[string]prometheus.Gauge
	customMetrics    map[string]*CustomCollector
	histogramBuckets []float64
	timerBuckets     []float64
	mutex            *sync.Mutex
}

// NewPrometheusProvider returns a Provider that produces Prometheus metrics.
// Namespace and subsystem are applied to all produced metrics.
func NewPrometheusProvider(r metrics.Registry, namespace string, subsystem string, promRegistry prometheus.Registerer, FlushInterval time.Duration) *PrometheusConfig {
	return &PrometheusConfig{
		namespace:        namespace,
		subsystem:        subsystem,
		Registry:         r,
		promRegistry:     promRegistry,
		FlushInterval:    FlushInterval,
		gauges:           make(map[string]prometheus.Gauge),
		customMetrics:    make(map[string]*CustomCollector),
		histogramBuckets: []float64{0.05, 0.1, 0.25, 0.50, 0.75, 0.9, 0.95, 0.99},
		timerBuckets:     []float64{0.50, 0.95, 0.99, 0.999},
		mutex:            new(sync.Mutex),
	}
}

func (c *PrometheusConfig) WithHistogramBuckets(b []float64) *PrometheusConfig {
	c.histogramBuckets = b
	return c
}

func (c *PrometheusConfig) WithTimerBuckets(b []float64) *PrometheusConfig {
	c.timerBuckets = b
	return c
}

func (c *PrometheusConfig) flattenKey(key string) string {
	key = strings.Replace(key, " ", "_", -1)
	key = strings.Replace(key, ".", "_", -1)
	key = strings.Replace(key, "-", "_", -1)
	key = strings.Replace(key, "=", "_", -1)
	key = strings.Replace(key, "/", "_", -1)
	return key
}

func (c *PrometheusConfig) createKey(name string) string {
	return fmt.Sprintf("%s_%s_%s", c.namespace, c.subsystem, name)
}

func (c *PrometheusConfig) gaugeFromNameAndValue(name string, val float64) {
	key := c.createKey(name)
	g, ok := c.gauges[key]
	if !ok {
		g = prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: c.flattenKey(c.namespace),
			Subsystem: c.flattenKey(c.subsystem),
			Name:      c.flattenKey(name),
			Help:      name,
		})
		c.promRegistry.Register(g)
		c.gauges[key] = g
	}
	g.Set(val)
}

func (c *PrometheusConfig) histogramFromNameAndMetric(name string, goMetric interface{}, buckets []float64) {
	key := c.createKey(name)

	collector, ok := c.customMetrics[key]
	if !ok {
		collector = NewCustomCollector(c.mutex)
		c.promRegistry.MustRegister(collector)
		c.customMetrics[key] = collector
	}

	var ps []float64
	var count uint64
	var sum float64
	var typeName string

	switch metric := goMetric.(type) {
	case metrics.Histogram:
		snapshot := metric.Snapshot()
		ps = snapshot.Percentiles(buckets)
		count = uint64(snapshot.Count())
		sum = float64(snapshot.Sum())
		typeName = "histogram"
	case metrics.Timer:
		snapshot := metric.Snapshot()
		ps = snapshot.Percentiles(buckets)
		count = uint64(snapshot.Count())
		sum = float64(snapshot.Sum())
		typeName = "timer"
	default:
		panic(fmt.Sprintf("unexpected metric type %T", goMetric))
	}

	bucketVals := make(map[float64]uint64)
	for ii, bucket := range buckets {
		bucketVals[bucket] = uint64(ps[ii])
	}

	desc := prometheus.NewDesc(
		prometheus.BuildFQName(
			c.flattenKey(c.namespace),
			c.flattenKey(c.subsystem),
			fmt.Sprintf("%s_%s", c.flattenKey(name), typeName),
		),
		name,
		[]string{},
		map[string]string{},
	)

	if constHistogram, err := prometheus.NewConstHistogram(
		desc,
		count,
		sum,
		bucketVals,
	); err == nil {
		c.mutex.Lock()
		collector.metric = constHistogram
		c.mutex.Unlock()
	}
}

func (c *PrometheusConfig) UpdatePrometheusMetrics() {
	for _ = range time.Tick(c.FlushInterval) {
		c.UpdatePrometheusMetricsOnce()
	}
}

func (c *PrometheusConfig) UpdatePrometheusMetricsOnce() error {
	c.Registry.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Counter:
			c.gaugeFromNameAndValue(name, float64(metric.Count()))
		case metrics.Gauge:
			c.gaugeFromNameAndValue(name, float64(metric.Value()))
		case metrics.GaugeFloat64:
			c.gaugeFromNameAndValue(name, float64(metric.Value()))
		case metrics.Histogram:
			samples := metric.Snapshot().Sample().Values()
			if len(samples) > 0 {
				lastSample := samples[len(samples)-1]
				c.gaugeFromNameAndValue(name, float64(lastSample))
			}

			c.histogramFromNameAndMetric(name, metric, c.histogramBuckets)
		case metrics.Meter:
			lastSample := metric.Snapshot().Rate1()
			c.gaugeFromNameAndValue(name, float64(lastSample))
		case metrics.Timer:
			lastSample := metric.Snapshot().Rate1()
			c.gaugeFromNameAndValue(name, float64(lastSample))

			c.histogramFromNameAndMetric(name, metric, c.timerBuckets)
		}
	})
	return nil
}

// for collecting prometheus.constHistogram objects
type CustomCollector struct {
	prometheus.Collector

	metric prometheus.Metric
	mutex  *sync.Mutex
}

func NewCustomCollector(mutex *sync.Mutex) *CustomCollector {
	return &CustomCollector{
		mutex: mutex,
	}
}

func (c *CustomCollector) Collect(ch chan<- prometheus.Metric) {
	c.mutex.Lock()
	if c.metric != nil {
		val := c.metric
		ch <- val
	}
	c.mutex.Unlock()
}

func (p *CustomCollector) Describe(ch chan<- *prometheus.Desc) {
	// empty method to fulfill prometheus.Collector interface
}
<commit_msg>update description to use the flattened name<commit_after>package prometheusmetrics

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/rcrowley/go-metrics"
)

// PrometheusConfig provides a container with config parameters for the
// Prometheus Exporter

type PrometheusConfig struct {
	namespace        string
	Registry         metrics.Registry // Registry to be exported
	subsystem        string
	promRegistry     prometheus.Registerer //Prometheus registry
	FlushInterval    time.Duration         //interval to update prom metrics
	gauges           map[string]prometheus.Gauge
	customMetrics    map[string]*CustomCollector
	histogramBuckets []float64
	timerBuckets     []float64
	mutex            *sync.Mutex
}

// NewPrometheusProvider returns a Provider that produces Prometheus metrics.
// Namespace and subsystem are applied to all produced metrics.
func NewPrometheusProvider(r metrics.Registry, namespace string, subsystem string, promRegistry prometheus.Registerer, FlushInterval time.Duration) *PrometheusConfig {
	return &PrometheusConfig{
		namespace:        namespace,
		subsystem:        subsystem,
		Registry:         r,
		promRegistry:     promRegistry,
		FlushInterval:    FlushInterval,
		gauges:           make(map[string]prometheus.Gauge),
		customMetrics:    make(map[string]*CustomCollector),
		histogramBuckets: []float64{0.05, 0.1, 0.25, 0.50, 0.75, 0.9, 0.95, 0.99},
		timerBuckets:     []float64{0.50, 0.95, 0.99, 0.999},
		mutex:            new(sync.Mutex),
	}
}

func (c *PrometheusConfig) WithHistogramBuckets(b []float64) *PrometheusConfig {
	c.histogramBuckets = b
	return c
}

func (c *PrometheusConfig) WithTimerBuckets(b []float64) *PrometheusConfig {
	c.timerBuckets = b
	return c
}

func (c *PrometheusConfig) flattenKey(key string) string {
	key = strings.Replace(key, " ", "_", -1)
	key = strings.Replace(key, ".", "_", -1)
	key = strings.Replace(key, "-", "_", -1)
	key = strings.Replace(key, "=", "_", -1)
	key = strings.Replace(key, "/", "_", -1)
	return key
}

func (c *PrometheusConfig) createKey(name string) string {
	return fmt.Sprintf("%s_%s_%s", c.namespace, c.subsystem, name)
}

func (c *PrometheusConfig) gaugeFromNameAndValue(name string, val float64) {
	key := c.createKey(name)
	g, ok := c.gauges[key]
	if !ok {
		g = prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: c.flattenKey(c.namespace),
			Subsystem: c.flattenKey(c.subsystem),
			Name:      c.flattenKey(name),
			Help:      name,
		})
		c.promRegistry.Register(g)
		c.gauges[key] = g
	}
	g.Set(val)
}

func (c *PrometheusConfig) histogramFromNameAndMetric(name string, goMetric interface{}, buckets []float64) {
	key := c.createKey(name)

	collector, ok := c.customMetrics[key]
	if !ok {
		collector = NewCustomCollector(c.mutex)
		c.promRegistry.MustRegister(collector)
		c.customMetrics[key] = collector
	}

	var ps []float64
	var count uint64
	var sum float64
	var typeName string

	switch metric := goMetric.(type) {
	case metrics.Histogram:
		snapshot := metric.Snapshot()
		ps = snapshot.Percentiles(buckets)
		count = uint64(snapshot.Count())
		sum = float64(snapshot.Sum())
		typeName = "histogram"
	case metrics.Timer:
		snapshot := metric.Snapshot()
		ps = snapshot.Percentiles(buckets)
		count = uint64(snapshot.Count())
		sum = float64(snapshot.Sum())
		typeName = "timer"
	default:
		panic(fmt.Sprintf("unexpected metric type %T", goMetric))
	}

	bucketVals := make(map[float64]uint64)
	for ii, bucket := range buckets {
		bucketVals[bucket] = uint64(ps[ii])
	}

	desc := prometheus.NewDesc(
		prometheus.BuildFQName(
			c.flattenKey(c.namespace),
			c.flattenKey(c.subsystem),
			fmt.Sprintf("%s_%s", c.flattenKey(name), typeName),
		),
		c.flattenKey(name),
		[]string{},
		map[string]string{},
	)

	if constHistogram, err := prometheus.NewConstHistogram(
		desc,
		count,
		sum,
		bucketVals,
	); err == nil {
		c.mutex.Lock()
		collector.metric = constHistogram
		c.mutex.Unlock()
	}
}

func (c *PrometheusConfig) UpdatePrometheusMetrics() {
	for _ = range time.Tick(c.FlushInterval) {
		c.UpdatePrometheusMetricsOnce()
	}
}

func (c *PrometheusConfig) UpdatePrometheusMetricsOnce() error {
	c.Registry.Each(func(name string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Counter:
			c.gaugeFromNameAndValue(name, float64(metric.Count()))
		case metrics.Gauge:
			c.gaugeFromNameAndValue(name, float64(metric.Value()))
		case metrics.GaugeFloat64:
			c.gaugeFromNameAndValue(name, float64(metric.Value()))
		case metrics.Histogram:
			samples := metric.Snapshot().Sample().Values()
			if len(samples) > 0 {
				lastSample := samples[len(samples)-1]
				c.gaugeFromNameAndValue(name, float64(lastSample))
			}

			c.histogramFromNameAndMetric(name, metric, c.histogramBuckets)
		case metrics.Meter:
			lastSample := metric.Snapshot().Rate1()
			c.gaugeFromNameAndValue(name, float64(lastSample))
		case metrics.Timer:
			lastSample := metric.Snapshot().Rate1()
			c.gaugeFromNameAndValue(name, float64(lastSample))

			c.histogramFromNameAndMetric(name, metric, c.timerBuckets)
		}
	})
	return nil
}

// for collecting prometheus.constHistogram objects
type CustomCollector struct {
	prometheus.Collector

	metric prometheus.Metric
	mutex  *sync.Mutex
}

func NewCustomCollector(mutex *sync.Mutex) *CustomCollector {
	return &CustomCollector{
		mutex: mutex,
	}
}

func (c *CustomCollector) Collect(ch chan<- prometheus.Metric) {
	c.mutex.Lock()
	if c.metric != nil {
		val := c.metric
		ch <- val
	}
	c.mutex.Unlock()
}

func (p *CustomCollector) Describe(ch chan<- *prometheus.Desc) {
	// empty method to fulfill prometheus.Collector interface
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"log"

	"github.com/artemnikitin/devicefarm-ci-tool/errors"
)

const m = map[string]string{
	"APPIUM_JAVA_JUNIT":      "APPIUM_JAVA_JUNIT_TEST_PACKAGE",
	"APPIUM_JAVA_TESTNG":     "APPIUM_JAVA_TESTNG_TEST_PACKAGE",
	"APPIUM_PYTHON":          "APPIUM_PYTHON_TEST_PACKAGE",
	"CALABASH":               "CALABASH_TEST_PACKAGE",
	"INSTRUMENTATION":        "INSTRUMENTATION_TEST_PACKAGE",
	"UIAUTOMATOR":            "UIAUTOMATOR_TEST_PACKAGE",
	"XCTEST":                 "XCTEST_TEST_PACKAGE",
	"XCTEST_UI":              "XCTEST_UI_TEST_PACKAGE",
	"APPIUM_WEB_JAVA_JUNIT":  "APPIUM_WEB_JAVA_JUNIT_TEST_PACKAGE",
	"APPIUM_WEB_JAVA_TESTNG": "APPIUM_WEB_JAVA_TESTNG_TEST_PACKAGE",
	"APPIUM_WEB_PYTHON":      "APPIUM_WEB_PYTHON_TEST_PACKAGE",
}

// RunConfig contains serialized representation of run config from JSON file
type RunConfig struct {
	RunName string `json:"runName"`
	Test    struct {
		Filter          string            `json:"filter"`
		Parameters      map[string]string `json:"parameters"`
		TestPackageArn  string            `json:"testPackageArn"`
		TestPackagePath string            `json:"testPackagePath"`
		Type            string            `json:"type"`
	} `json:"test"`
	AdditionalData struct {
		AuxiliaryApps        []string `json:"auxiliaryApps"`
		BillingMethod        string   `json:"billingMethod"`
		ExtraDataPackageArn  string   `json:"extraDataPackageArn"`
		ExtraDataPackagePath string   `json:"extraDataPackagePath"`
		Locale               string   `json:"locale"`
		Location             struct {
			Latitude  float64 `json:"latitude"`
			Longitude float64 `json:"longitude"`
		} `json:"location"`
		NetworkProfileArn string `json:"networkProfileArn"`
		Radios            struct {
			Bluetooth string `json:"bluetooth"`
			Gps       string `json:"gps"`
			Nfc       string `json:"nfc"`
			Wifi      string `json:"wifi"`
		} `json:"radios"`
	} `json:"additionalData"`
}

// Transform unmarshall JSON config file to struct
func Transform(jsonBytes []byte) RunConfig {
	result := &RunConfig{}
	err := json.Unmarshal(jsonBytes, result)
	errors.Validate(err, "Can't read config file")
	return *result
}

// GetUploadTypeForTest return type of upload based on type of test
func GetUploadTypeForTest(testType string) string {
	v, exist := m[testType]
	if !exist {
		log.Println("Can't determine type of upload for", testType)
		return ""
	}
	return v
}
<commit_msg>Fix for CI<commit_after>package config

import (
	"encoding/json"
	"log"

	"github.com/artemnikitin/devicefarm-ci-tool/errors"
)

var m = map[string]string{
	"APPIUM_JAVA_JUNIT":      "APPIUM_JAVA_JUNIT_TEST_PACKAGE",
	"APPIUM_JAVA_TESTNG":     "APPIUM_JAVA_TESTNG_TEST_PACKAGE",
	"APPIUM_PYTHON":          "APPIUM_PYTHON_TEST_PACKAGE",
	"CALABASH":               "CALABASH_TEST_PACKAGE",
	"INSTRUMENTATION":        "INSTRUMENTATION_TEST_PACKAGE",
	"UIAUTOMATOR":            "UIAUTOMATOR_TEST_PACKAGE",
	"XCTEST":                 "XCTEST_TEST_PACKAGE",
	"XCTEST_UI":              "XCTEST_UI_TEST_PACKAGE",
	"APPIUM_WEB_JAVA_JUNIT":  "APPIUM_WEB_JAVA_JUNIT_TEST_PACKAGE",
	"APPIUM_WEB_JAVA_TESTNG": "APPIUM_WEB_JAVA_TESTNG_TEST_PACKAGE",
	"APPIUM_WEB_PYTHON":      "APPIUM_WEB_PYTHON_TEST_PACKAGE",
}

// RunConfig contains serialized representation of run config from JSON file
type RunConfig struct {
	RunName string `json:"runName"`
	Test    struct {
		Filter          string            `json:"filter"`
		Parameters      map[string]string `json:"parameters"`
		TestPackageArn  string            `json:"testPackageArn"`
		TestPackagePath string            `json:"testPackagePath"`
		Type            string            `json:"type"`
	} `json:"test"`
	AdditionalData struct {
		AuxiliaryApps        []string `json:"auxiliaryApps"`
		BillingMethod        string   `json:"billingMethod"`
		ExtraDataPackageArn  string   `json:"extraDataPackageArn"`
		ExtraDataPackagePath string   `json:"extraDataPackagePath"`
		Locale               string   `json:"locale"`
		Location             struct {
			Latitude  float64 `json:"latitude"`
			Longitude float64 `json:"longitude"`
		} `json:"location"`
		NetworkProfileArn string `json:"networkProfileArn"`
		Radios            struct {
			Bluetooth string `json:"bluetooth"`
			Gps       string `json:"gps"`
			Nfc       string `json:"nfc"`
			Wifi      string `json:"wifi"`
		} `json:"radios"`
	} `json:"additionalData"`
}

// Transform unmarshall JSON config file to struct
func Transform(jsonBytes []byte) RunConfig {
	result := &RunConfig{}
	err := json.Unmarshal(jsonBytes, result)
	errors.Validate(err, "Can't read config file")
	return *result
}

// GetUploadTypeForTest return type of upload based on type of test
func GetUploadTypeForTest(testType string) string {
	v, exist := m[testType]
	if !exist {
		log.Println("Can't determine type of upload for", testType)
		return ""
	}
	return v
}
<|endoftext|>


<commit_before>package dehumanize

import (
	log "github.com/cihub/seelog"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestYearDate(t *testing.T) {

	defer log.Flush()

	Convey("regex compiled", t, func() {
		So(initErr, ShouldBeNil)
	})
	Convey("bytes conversion", t, func() {
		So(SizeConvert("1b", 0), ShouldEqual, 1)
		So(SizeConvert("1b", 1000), ShouldEqual, 1)
		So(SizeConvert("1B", 0), ShouldEqual, 1)
	})
	Convey("kbytes conversion", t, func() {
		So(SizeConvert("1kb", 0), ShouldEqual, 1024)
		So(SizeConvert("1Kb", 0), ShouldEqual, 1024)
		So(SizeConvert("1kB", 0), ShouldEqual, 1024)
		So(SizeConvert("1KB", 0), ShouldEqual, 1024)
		So(SizeConvert("1.2kb", 0), ShouldEqual, 1228)
		So(SizeConvert("1kb", 1000), ShouldEqual, 1000)
		So(SizeConvert("1.2kb", 1000), ShouldEqual, 1200)
	})
	Convey("mbytes conversion", t, func() {
		So(SizeConvert("1mb", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1Mb", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1mB", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1MB", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1.2mb", 0), ShouldEqual, 1258291)
		So(SizeConvert("1mb", 1000), ShouldEqual, 1000000)
		So(SizeConvert("1.2mb", 1000), ShouldEqual, 1200000)
	})
	Convey("gbytes conversion", t, func() {
		So(SizeConvert("1gb", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1Gb", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1gB", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1GB", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1.2gb", 0), ShouldEqual, 1288490188)
		So(SizeConvert("1gb", 1000), ShouldEqual, 1000000000)
		So(SizeConvert("1.2gb", 1000), ShouldEqual, 1200000000)
	})
	Convey("tbytes conversion", t, func() {
		So(SizeConvert("1tb", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1Tb", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1tB", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1TB", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1.2tb", 0), ShouldEqual, 1319413953331)
		So(SizeConvert("1tb", 1000), ShouldEqual, 1000000000000)
		So(SizeConvert("1.2tb", 1000), ShouldEqual, 1200000000000)
	})
	Convey("tbytes conversion", t, func() {
		So(SizeConvert("1pb", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1Pb", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1pB", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1PB", 1000), ShouldEqual, 1000000000000000)
		So(SizeConvert("1.2pb", 1000), ShouldEqual, 1200000000000000)
	})
	Convey("garbage conversion", t, func() {
		So(SizeConvert("1nb", 0), ShouldEqual, 0)
		So(SizeConvert("1.2nb", 0), ShouldEqual, 0)
		So(SizeConvert("1.b", 0), ShouldEqual, 1)
	})
}
<commit_msg>some small test cases<commit_after>package dehumanize

import (
	log "github.com/cihub/seelog"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestYearDate(t *testing.T) {

	defer log.Flush()

	Convey("regex compiled", t, func() {
		So(initErr, ShouldBeNil)
	})
	Convey("bytes conversion", t, func() {
		So(SizeConvert("1b", 0), ShouldEqual, 1)
		So(SizeConvert("1b", 1000), ShouldEqual, 1)
		So(SizeConvert("1B", 0), ShouldEqual, 1)
	})
	Convey("kbytes conversion", t, func() {
		So(SizeConvert("1kb", 0), ShouldEqual, 1024)
		So(SizeConvert("1Kb", 0), ShouldEqual, 1024)
		So(SizeConvert("1kB", 0), ShouldEqual, 1024)
		So(SizeConvert("1KB", 0), ShouldEqual, 1024)
		So(SizeConvert("1.2kb", 0), ShouldEqual, 1228)
		So(SizeConvert("1kb", 1000), ShouldEqual, 1000)
		So(SizeConvert("1.2kb", 1000), ShouldEqual, 1200)
	})
	Convey("mbytes conversion", t, func() {
		So(SizeConvert("1mb", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1Mb", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1mB", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1MB", 0), ShouldEqual, 1024*1024)
		So(SizeConvert("1.2mb", 0), ShouldEqual, 1258291)
		So(SizeConvert("1mb", 1000), ShouldEqual, 1000000)
		So(SizeConvert("1.2mb", 1000), ShouldEqual, 1200000)
	})
	Convey("gbytes conversion", t, func() {
		So(SizeConvert("1gb", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1Gb", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1gB", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1GB", 0), ShouldEqual, 1024*1024*1024)
		So(SizeConvert("1.2gb", 0), ShouldEqual, 1288490188)
		So(SizeConvert("1gb", 1000), ShouldEqual, 1000000000)
		So(SizeConvert("1.2gb", 1000), ShouldEqual, 1200000000)
	})
	Convey("tbytes conversion", t, func() {
		So(SizeConvert("1tb", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1Tb", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1tB", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1TB", 0), ShouldEqual, 1024*1024*1024*1024)
		So(SizeConvert("1.2tb", 0), ShouldEqual, 1319413953331)
		So(SizeConvert("1tb", 1000), ShouldEqual, 1000000000000)
		So(SizeConvert("1.2tb", 1000), ShouldEqual, 1200000000000)
	})
	Convey("tbytes conversion", t, func() {
		So(SizeConvert("1pb", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1Pb", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1pB", 0), ShouldEqual, 1024*1024*1024*1024*1024)
		So(SizeConvert("1PB", 1000), ShouldEqual, 1000000000000000)
		So(SizeConvert("1.2pb", 1000), ShouldEqual, 1200000000000000)
	})
	Convey("garbage conversion", t, func() {
		So(SizeConvert("1nb", 0), ShouldEqual, 0)
		So(SizeConvert("1.2nb", 0), ShouldEqual, 0)
		So(SizeConvert("", 0), ShouldEqual, 0)
		So(SizeConvert("kb", 0), ShouldEqual, 0)
		So(SizeConvert("1.b", 0), ShouldEqual, 1)
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Tigera, Inc. All rights reserved.

// 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.

package commands

import (
	"fmt"
	"strings"

	"github.com/docopt/docopt-go"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/calicoctl/calicoctl/commands/constants"
)

func Apply(args []string) error {
	doc := constants.DatastoreIntro + `Usage:
  calicoctl apply --filename=<FILENAME> [--config=<CONFIG>] [--namespace=<NS>]

Examples:
  # Apply a policy using the data in policy.yaml.
  calicoctl apply -f ./policy.yaml

  # Apply a policy based on the JSON passed into stdin.
  cat policy.json | calicoctl apply -f -

Options:
  -h --help                 Show this screen.
  -f --filename=<FILENAME>  Filename to use to apply the resource.  If set to
                            "-" loads from stdin.
  -c --config=<CONFIG>      Path to the file containing connection
                            configuration in YAML or JSON format.
                            [default: ` + constants.DefaultConfigPath + `]
  -n --namespace=<NS>       Namespace of the resource.
                            Only applicable to NetworkPolicy, NetworkSet, and WorkloadEndpoint.
                            Uses the default namespace if not specified.

Description:
  The apply command is used to create or replace a set of resources by filename
  or stdin.  JSON and YAML formats are accepted.

  Valid resource types are:

    * bgpConfiguration
    * bgpPeer
    * felixConfiguration
    * globalNetworkPolicy
    * globalNetworkSet
    * hostEndpoint
    * ipPool
    * networkPolicy
    * networkSet
    * node
    * profile
    * workloadEndpoint

  When applying a resource:
  -  if the resource does not already exist (as determined by it's primary
     identifiers) then it is created
  -  if the resource already exists then the specification for that resource is
     replaced in it's entirety by the new resource specification.

  The output of the command indicates how many resources were successfully
  applied, and the error reason if an error occurred.

  The resources are applied in the order they are specified.  In the event of a
  failure applying a specific resource it is possible to work out which
  resource failed based on the number of resources successfully applied

  When applying a resource to perform an update, the complete resource spec
  must be provided, it is not sufficient to supply only the fields that are
  being updated.
`
	parsedArgs, err := docopt.Parse(doc, args, true, "", false, false)
	if err != nil {
		return fmt.Errorf("Invalid option: 'calicoctl %s'. Use flag '--help' to read about a specific subcommand.", strings.Join(args, " "))
	}
	if len(parsedArgs) == 0 {
		return nil
	}

	results := executeConfigCommand(parsedArgs, actionApply)
	log.Infof("results: %+v", results)

	if results.fileInvalid {
		return fmt.Errorf("Failed to execute command: %v", results.err)
	} else if results.numHandled == 0 {
		if results.numResources == 0 {
			return fmt.Errorf("No resources specified in file")
		} else if results.numResources == 1 {
			return fmt.Errorf("Failed to apply '%s' resource: %v", results.singleKind, results.resErrs)
		} else if results.singleKind != "" {
			return fmt.Errorf("Failed to apply any '%s' resources: %v", results.singleKind, results.resErrs)
		} else {
			return fmt.Errorf("Failed to apply any resources: %v", results.resErrs)
		}
	} else if len(results.resErrs) == 0 {
		if results.singleKind != "" {
			fmt.Printf("Successfully applied %d '%s' resource(s)\n", results.numHandled, results.singleKind)
		} else {
			fmt.Printf("Successfully applied %d resource(s)\n", results.numHandled)
		}
	} else {
		if results.numHandled - len(results.resErrs) > 0 {
			fmt.Printf("Partial success: ")
			if results.singleKind != "" {
				fmt.Printf("applied the first %d out of %d '%s' resources:\n",
					results.numHandled, results.numResources, results.singleKind)
			} else {
				fmt.Printf("applied the first %d out of %d resources:\n",
					results.numHandled, results.numResources)
			}
		}
		return fmt.Errorf("Hit error(s): %v", results.resErrs)
	}

	return nil
}
<commit_msg>Add kubeControllersConfig to apply docstring<commit_after>// Copyright (c) 2016-2019 Tigera, Inc. All rights reserved.

// 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.

package commands

import (
	"fmt"
	"strings"

	"github.com/docopt/docopt-go"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/calicoctl/calicoctl/commands/constants"
)

func Apply(args []string) error {
	doc := constants.DatastoreIntro + `Usage:
  calicoctl apply --filename=<FILENAME> [--config=<CONFIG>] [--namespace=<NS>]

Examples:
  # Apply a policy using the data in policy.yaml.
  calicoctl apply -f ./policy.yaml

  # Apply a policy based on the JSON passed into stdin.
  cat policy.json | calicoctl apply -f -

Options:
  -h --help                 Show this screen.
  -f --filename=<FILENAME>  Filename to use to apply the resource.  If set to
                            "-" loads from stdin.
  -c --config=<CONFIG>      Path to the file containing connection
                            configuration in YAML or JSON format.
                            [default: ` + constants.DefaultConfigPath + `]
  -n --namespace=<NS>       Namespace of the resource.
                            Only applicable to NetworkPolicy, NetworkSet, and WorkloadEndpoint.
                            Uses the default namespace if not specified.

Description:
  The apply command is used to create or replace a set of resources by filename
  or stdin.  JSON and YAML formats are accepted.

  Valid resource types are:

    * bgpConfiguration
    * bgpPeer
    * felixConfiguration
    * globalNetworkPolicy
    * globalNetworkSet
    * hostEndpoint
    * ipPool
    * kubeControllersConfiguration
    * networkPolicy
    * networkSet
    * node
    * profile
    * workloadEndpoint

  When applying a resource:
  -  if the resource does not already exist (as determined by it's primary
     identifiers) then it is created
  -  if the resource already exists then the specification for that resource is
     replaced in it's entirety by the new resource specification.

  The output of the command indicates how many resources were successfully
  applied, and the error reason if an error occurred.

  The resources are applied in the order they are specified.  In the event of a
  failure applying a specific resource it is possible to work out which
  resource failed based on the number of resources successfully applied

  When applying a resource to perform an update, the complete resource spec
  must be provided, it is not sufficient to supply only the fields that are
  being updated.
`
	parsedArgs, err := docopt.Parse(doc, args, true, "", false, false)
	if err != nil {
		return fmt.Errorf("Invalid option: 'calicoctl %s'. Use flag '--help' to read about a specific subcommand.", strings.Join(args, " "))
	}
	if len(parsedArgs) == 0 {
		return nil
	}

	results := executeConfigCommand(parsedArgs, actionApply)
	log.Infof("results: %+v", results)

	if results.fileInvalid {
		return fmt.Errorf("Failed to execute command: %v", results.err)
	} else if results.numHandled == 0 {
		if results.numResources == 0 {
			return fmt.Errorf("No resources specified in file")
		} else if results.numResources == 1 {
			return fmt.Errorf("Failed to apply '%s' resource: %v", results.singleKind, results.resErrs)
		} else if results.singleKind != "" {
			return fmt.Errorf("Failed to apply any '%s' resources: %v", results.singleKind, results.resErrs)
		} else {
			return fmt.Errorf("Failed to apply any resources: %v", results.resErrs)
		}
	} else if len(results.resErrs) == 0 {
		if results.singleKind != "" {
			fmt.Printf("Successfully applied %d '%s' resource(s)\n", results.numHandled, results.singleKind)
		} else {
			fmt.Printf("Successfully applied %d resource(s)\n", results.numHandled)
		}
	} else {
		if results.numHandled-len(results.resErrs) > 0 {
			fmt.Printf("Partial success: ")
			if results.singleKind != "" {
				fmt.Printf("applied the first %d out of %d '%s' resources:\n",
					results.numHandled, results.numResources, results.singleKind)
			} else {
				fmt.Printf("applied the first %d out of %d resources:\n",
					results.numHandled, results.numResources)
			}
		}
		return fmt.Errorf("Hit error(s): %v", results.resErrs)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
)

func main() {
	/*
	 * Parse incomign flags, dispatch to appropriate command or show help
	 * message.
	 */
	flag.Parse()
	var args []string = flag.Args()

	if len(args) == 0 {
		println("No command was given\n")
		helpCommand()
	} else {
		commands := getCommands()

		if cmd, ok := commands[args[0]]; ok {
            cmd()
        } else {
            helpCommand()
        }
	}
}

/**
 * Return a map of command-names (from user-input) to functions to
 * run.
 */
func getCommands() map[string]func() {
	return map[string]func(){
		"help": helpCommand,
	}
}

/**
 * Print help information to the user... Straight forward enough taht I'll
 * just stop typing about it now.
 *
 * TODO: define non-command help ouput in terms of flags specified for each
 *       command (not quite sure how to do this)
 */
func helpCommand() {
	println("Usage: schema [command] [options]")
	println("")
	println("Commands:")
	println("  help         Print this help message")
}
<commit_msg>main.go - Test in command declaration<commit_after>package main

import (
	"flag"
)

type command func()
type description string

/**
 * Parse incomign flags, dispatch to appropriate command or show help
 * message.
 */
func main() {
	flag.Parse()
	var args []string = flag.Args()

	if len(args) == 0 {
		println("No command was given\n")
		helpCommand()
	} else {
		commands := getCommands()

		if cmd, ok := commands[args[0]]; ok {
			cmd.command()
		} else {
			helpCommand()
		}
	}
}

/**
 * Return a map of command-names (from user-input) to functions to
 * run.
 */
func getCommands() map[string]struct {
	string
	command
} {
	return map[string]struct {
		string
		command
	}{
		"help": struct {
			string
			command
		}{
			"The help information",
			helpCommand,
		},
	}
}

/**
 * Print help information to the user... Straight forward enough taht I'll
 * just stop typing about it now.
 *
 * TODO: define non-command help ouput in terms of flags specified for each
 *       command (not quite sure how to do this)
 */
func helpCommand() {
	println("Usage: schema [command] [options]")
	println("")
	println("Commands:")
	println("  help         Print this help message")
}
<|endoftext|>


<commit_before>package generator

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"go/ast"
	"log"
	"os"
	"path"
	"regexp"
	"runtime"
	"strings"

	"github.com/yvasiyarov/swagger/markup"
	"github.com/yvasiyarov/swagger/parser"
)

const (
	AVAILABLE_FORMATS = "go|swagger|asciidoc|markdown|confluence"
)

var generatedFileTemplate = `
package main
//This file is generated automatically. Do not try to edit it manually.

var resourceListingJson = {{resourceListing}}
var apiDescriptionsJson = {{apiDescriptions}}
`

// It must return true if funcDeclaration is controller. We will try to parse only comments before controllers
func IsController(funcDeclaration *ast.FuncDecl, controllerClass string) bool {
	if len(controllerClass) == 0 {
		// Search every method
		return true
	}
	if funcDeclaration.Recv != nil && len(funcDeclaration.Recv.List) > 0 {
		if starExpression, ok := funcDeclaration.Recv.List[0].Type.(*ast.StarExpr); ok {
			receiverName := fmt.Sprint(starExpression.X)
			matched, err := regexp.MatchString(string(controllerClass), receiverName)
			if err != nil {
				log.Fatalf("The -controllerClass argument is not a valid regular expression: %v\n", err)
			}
			return matched
		}
	}
	return false
}

func generateSwaggerDocs(parser *parser.Parser, outputSpec string) error {
	fd, err := os.Create(path.Join(outputSpec, "docs.go"))
	if err != nil {
		return fmt.Errorf("Can not create document file: %v\n", err)
	}
	defer fd.Close()

	var apiDescriptions bytes.Buffer
	for apiKey, apiDescription := range parser.TopLevelApis {
		apiDescriptions.WriteString("\"" + apiKey + "\":")

		apiDescriptions.WriteString("`")
		json, err := json.MarshalIndent(apiDescription, "", "    ")
		if err != nil {
			return fmt.Errorf("Can not serialise []ApiDescription to JSON: %v\n", err)
		}
		apiDescriptions.Write(json)
		apiDescriptions.WriteString("`,")
	}

	doc := strings.Replace(generatedFileTemplate, "{{resourceListing}}", "`"+string(parser.GetResourceListingJson())+"`", -1)
	doc = strings.Replace(doc, "{{apiDescriptions}}", "map[string]string{"+apiDescriptions.String()+"}", -1)

	fd.WriteString(doc)

	return nil
}

func generateSwaggerUiFiles(parser *parser.Parser, outputSpec string) error {
	fd, err := os.Create(path.Join(outputSpec, "index.json"))
	if err != nil {
		return fmt.Errorf("Can not create the master index.json file: %v\n", err)
	}
	defer fd.Close()
	fd.WriteString(string(parser.GetResourceListingJson()))

	for apiKey, apiDescription := range parser.TopLevelApis {
		err = os.MkdirAll(path.Join(outputSpec, apiKey), 0777)
		if err != nil {
			return err
		}

		fd, err = os.Create(path.Join(outputSpec, apiKey, "index.json"))
		if err != nil {
			return fmt.Errorf("Can not create the %s/index.json file: %v\n", apiKey, err)
		}
		defer fd.Close()

		json, err := json.MarshalIndent(apiDescription, "", "    ")
		if err != nil {
			return fmt.Errorf("Can not serialise []ApiDescription to JSON: %v\n", err)
		}

		fd.Write(json)
		log.Printf("Wrote %v/index.json", apiKey)
	}

	return nil
}

func InitParser(controllerClass, ignore string) *parser.Parser {
	parser := parser.NewParser()

	parser.ControllerClass = controllerClass
	parser.IsController = IsController
	parser.Ignore = ignore

	parser.TypesImplementingMarshalInterface["NullString"] = "string"
	parser.TypesImplementingMarshalInterface["NullInt64"] = "int"
	parser.TypesImplementingMarshalInterface["NullFloat64"] = "float"
	parser.TypesImplementingMarshalInterface["NullBool"] = "bool"

	return parser
}

type Params struct {
	ApiPackage, MainApiFile, OutputFormat, OutputSpec, ControllerClass, Ignore string
	ContentsTable, Models bool
}

func Run(params Params) error {
	parser := InitParser(params.ControllerClass, params.Ignore)
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return errors.New("Please, set $GOPATH environment variable\n")
	}

	log.Println("Start parsing")

	//Support gopaths with multiple directories
	dirs := strings.Split(gopath, ":")
	if runtime.GOOS == "windows" {
        	dirs = strings.Split(gopath, ";")
	}
	found := false
	for _, d := range dirs {
		apifile := path.Join(d, "src", params.MainApiFile)
		if _, err := os.Stat(apifile); err == nil {
			parser.ParseGeneralApiInfo(apifile)
			found = true
		}
	}
	if found == false {
		if _, err := os.Stat(params.MainApiFile); err == nil {
			parser.ParseGeneralApiInfo(params.MainApiFile)
		} else {
			apifile := path.Join(gopath, "src", params.MainApiFile)
			return fmt.Errorf("Could not find apifile %s to parse\n", apifile)
		}
	}

	parser.ParseApi(params.ApiPackage)
	log.Println("Finish parsing")

	var err error
	confirmMsg := ""
	format := strings.ToLower(params.OutputFormat)
	switch format {
	case "go":
		err = generateSwaggerDocs(parser, params.OutputSpec)
		confirmMsg = "Doc file generated"
	case "asciidoc":
		err = markup.GenerateMarkup(parser, new(markup.MarkupAsciiDoc), &params.OutputSpec, ".adoc", params.ContentsTable, params.Models)
		confirmMsg = "AsciiDoc file generated"
	case "markdown":
		err = markup.GenerateMarkup(parser, new(markup.MarkupMarkDown), &params.OutputSpec, ".md", params.ContentsTable, params.Models)
		confirmMsg = "MarkDown file generated"
	case "confluence":
		err = markup.GenerateMarkup(parser, new(markup.MarkupConfluence), &params.OutputSpec, ".confluence", params.ContentsTable, params.Models)
		confirmMsg = "Confluence file generated"
	case "swagger":
		err = generateSwaggerUiFiles(parser, params.OutputSpec)
		confirmMsg = "Swagger UI files generated"
	default:
		err = fmt.Errorf("Invalid -format specified. Must be one of %v.", AVAILABLE_FORMATS)
	}

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

	return nil
}
<commit_msg>adding gopkg format<commit_after>package generator

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"go/ast"
	"log"
	"os"
	"path"
	"regexp"
	"runtime"
	"strings"

	"github.com/yvasiyarov/swagger/markup"
	"github.com/yvasiyarov/swagger/parser"
)

const (
	AVAILABLE_FORMATS = "go|gopkg|swagger|asciidoc|markdown|confluence"
)

var generatedFileTemplate = `
package main
//This file is generated automatically. Do not try to edit it manually.

var resourceListingJson = {{resourceListing}}
var apiDescriptionsJson = {{apiDescriptions}}
`

var generatedPkgTemplate = `
package {{packageName}}
//This file is generated automatically. Do not try to edit it manually.

var ResourceListingJson = {{resourceListing}}
var ApiDescriptionsJson = {{apiDescriptions}}
`

// It must return true if funcDeclaration is controller. We will try to parse only comments before controllers
func IsController(funcDeclaration *ast.FuncDecl, controllerClass string) bool {
	if len(controllerClass) == 0 {
		// Search every method
		return true
	}
	if funcDeclaration.Recv != nil && len(funcDeclaration.Recv.List) > 0 {
		if starExpression, ok := funcDeclaration.Recv.List[0].Type.(*ast.StarExpr); ok {
			receiverName := fmt.Sprint(starExpression.X)
			matched, err := regexp.MatchString(string(controllerClass), receiverName)
			if err != nil {
				log.Fatalf("The -controllerClass argument is not a valid regular expression: %v\n", err)
			}
			return matched
		}
	}
	return false
}

func generateSwaggerDocs(parser *parser.Parser, outputSpec string, pkg bool) error {
	fd, err := os.Create(path.Join(outputSpec, "docs.go"))
	if err != nil {
		return fmt.Errorf("Can not create document file: %v\n", err)
	}
	defer fd.Close()

	var apiDescriptions bytes.Buffer
	for apiKey, apiDescription := range parser.TopLevelApis {
		apiDescriptions.WriteString("\"" + apiKey + "\":")

		apiDescriptions.WriteString("`")
		json, err := json.MarshalIndent(apiDescription, "", "    ")
		if err != nil {
			return fmt.Errorf("Can not serialise []ApiDescription to JSON: %v\n", err)
		}
		apiDescriptions.Write(json)
		apiDescriptions.WriteString("`,")
	}

	var doc string
	if pkg {
		doc := strings.Replace(generatedPkgTemplate, "{{resourceListing}}", "`"+string(parser.GetResourceListingJson())+"`", -1)
		doc = strings.Replace(doc, "{{apiDescriptions}}", "map[string]string{"+apiDescriptions.String()+"}", -1)
		packageName := strings.Split(outputSpec, "/")
		doc = strings.Replace(doc, "{{packageName}}", packageName[len(packageName)-1], -1)
	} else {
		doc := strings.Replace(generatedFileTemplate, "{{resourceListing}}", "`"+string(parser.GetResourceListingJson())+"`", -1)
		doc = strings.Replace(doc, "{{apiDescriptions}}", "map[string]string{"+apiDescriptions.String()+"}", -1)
	}

	fd.WriteString(doc)

	return nil
}

func generateSwaggerUiFiles(parser *parser.Parser, outputSpec string) error {
	fd, err := os.Create(path.Join(outputSpec, "index.json"))
	if err != nil {
		return fmt.Errorf("Can not create the master index.json file: %v\n", err)
	}
	defer fd.Close()
	fd.WriteString(string(parser.GetResourceListingJson()))

	for apiKey, apiDescription := range parser.TopLevelApis {
		err = os.MkdirAll(path.Join(outputSpec, apiKey), 0777)
		if err != nil {
			return err
		}

		fd, err = os.Create(path.Join(outputSpec, apiKey, "index.json"))
		if err != nil {
			return fmt.Errorf("Can not create the %s/index.json file: %v\n", apiKey, err)
		}
		defer fd.Close()

		json, err := json.MarshalIndent(apiDescription, "", "    ")
		if err != nil {
			return fmt.Errorf("Can not serialise []ApiDescription to JSON: %v\n", err)
		}

		fd.Write(json)
		log.Printf("Wrote %v/index.json", apiKey)
	}

	return nil
}

func InitParser(controllerClass, ignore string) *parser.Parser {
	parser := parser.NewParser()

	parser.ControllerClass = controllerClass
	parser.IsController = IsController
	parser.Ignore = ignore

	parser.TypesImplementingMarshalInterface["NullString"] = "string"
	parser.TypesImplementingMarshalInterface["NullInt64"] = "int"
	parser.TypesImplementingMarshalInterface["NullFloat64"] = "float"
	parser.TypesImplementingMarshalInterface["NullBool"] = "bool"

	return parser
}

type Params struct {
	ApiPackage, MainApiFile, OutputFormat, OutputSpec, ControllerClass, Ignore string
	ContentsTable, Models                                                      bool
}

func Run(params Params) error {
	parser := InitParser(params.ControllerClass, params.Ignore)
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return errors.New("Please, set $GOPATH environment variable\n")
	}

	log.Println("Start parsing")

	//Support gopaths with multiple directories
	dirs := strings.Split(gopath, ":")
	if runtime.GOOS == "windows" {
		dirs = strings.Split(gopath, ";")
	}
	found := false
	for _, d := range dirs {
		apifile := path.Join(d, "src", params.MainApiFile)
		if _, err := os.Stat(apifile); err == nil {
			parser.ParseGeneralApiInfo(apifile)
			found = true
		}
	}
	if found == false {
		if _, err := os.Stat(params.MainApiFile); err == nil {
			parser.ParseGeneralApiInfo(params.MainApiFile)
		} else {
			apifile := path.Join(gopath, "src", params.MainApiFile)
			return fmt.Errorf("Could not find apifile %s to parse\n", apifile)
		}
	}

	parser.ParseApi(params.ApiPackage)
	log.Println("Finish parsing")

	var err error
	confirmMsg := ""
	format := strings.ToLower(params.OutputFormat)
	switch format {
	case "go":
		err = generateSwaggerDocs(parser, params.OutputSpec, false)
		confirmMsg = "Doc file generated"
	case "gopkg":
		err = generateSwaggerDocs(parser, params.OutputSpec, true)
		confirmMsg = "Doc package generated"
	case "asciidoc":
		err = markup.GenerateMarkup(parser, new(markup.MarkupAsciiDoc), &params.OutputSpec, ".adoc", params.ContentsTable, params.Models)
		confirmMsg = "AsciiDoc file generated"
	case "markdown":
		err = markup.GenerateMarkup(parser, new(markup.MarkupMarkDown), &params.OutputSpec, ".md", params.ContentsTable, params.Models)
		confirmMsg = "MarkDown file generated"
	case "confluence":
		err = markup.GenerateMarkup(parser, new(markup.MarkupConfluence), &params.OutputSpec, ".confluence", params.ContentsTable, params.Models)
		confirmMsg = "Confluence file generated"
	case "swagger":
		err = generateSwaggerUiFiles(parser, params.OutputSpec)
		confirmMsg = "Swagger UI files generated"
	default:
		err = fmt.Errorf("Invalid -format specified. Must be one of %v.", AVAILABLE_FORMATS)
	}

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

	return nil
}
<|endoftext|>


<commit_before>// Package cookies contains helper functions for setting and
// retrieving cookies, including signed and encrypted ones.
//
// Cookie values are encoded and decoded using encoding/gob, so
// you must register any non-basic type that you want to store
// in a cookie, using encoding/gob.Register.
//
// Signed cookies are signed using HMAC-SHA1. Encrypted cookies
// are encrypted with AES and then signed with HMAC-SHA1.
package cookies

import (
	"errors"
	"gnd.la/encoding/base64"
	"gnd.la/encoding/codec"
	"gnd.la/util/cryptoutil"
	"net/http"
	"time"
)

const (
	// Maximum cookie size. See section 6.3 at http://www.ietf.org/rfc/rfc2109.txt.
	MaxSize = 4096
)

var (
	// Cookie is too big. See MaxSize.
	ErrCookieTooBig = errors.New("cookie is too big (maximum size is 4096 bytes)")
	// Tried to use signed or encrypted cookies without a Signer.
	ErrNoSigner = errors.New("no signer specified")
	// Tried to use encrypted cookies without an Encrypter.
	ErrNoEncrypter = errors.New("no encrypter specified")

	// Maximum representable UNIX time with a signed 32 bit integer. This
	// means that cookies won't be really permanent, but they will expire
	// on January 19th 2038. I don't know about you, but I hope to be around
	// by that time, so hopefully I'll find a solution for this issue in the
	// next few years. See http://en.wikipedia.org/wiki/Year_2038_problem for
	// more information.
	Permanent      = time.Unix(2147483647, 0).UTC()
	deleteExpires  = time.Unix(0, 0).UTC()
	defaultCodec   = codec.Get("gob")
	cookieDefaults = &Options{Path: "/", Expires: Permanent}
)

// Options specify the default cookie Options used when setting
// a Cookie only by its name and value, like in Cookies.Set(),
// Cookies.SetSecure(), and Cookies.SetEncrypted().
//
// For more information about the cookie fields, see net/http.Cookie.
type Options struct {
	Path     string
	Domain   string
	Expires  time.Time
	MaxAge   int
	Secure   bool
	HttpOnly bool
}

// Cookies includes conveniency functions for setting
// and retrieving cookies. Use New() or gnd.la/app.Context.Cookies
// to create a Cookies instance.
type Cookies struct {
	r         *http.Request
	w         http.ResponseWriter
	c         *codec.Codec
	signer    *cryptoutil.Signer
	encrypter *cryptoutil.Encrypter
	defaults  *Options
}

type transformer func([]byte) ([]byte, error)

// New returns a new *Cookies object, which will read cookies from the
// given http.Request, and write them to the given http.ResponseWriter.
// Note that users will probably want to use gnd.la/app.Context.Cookies
// rather than this function to create a Cookies instance.
//
// The secret parameter is used for secure (signed) cookies, while
// encryptionKey is also used for encrypted cookies. If you don't use
// secure nor encrypted cookies, you might leave both parameters empty.
// If you only need signed cookies, you might leave encryptionKey
// empty.
//
// The default parameter specifies the default Options for the funcions
// which only take a name and a value. If you pass nil, Defaults will
// be used.
func New(r *http.Request, w http.ResponseWriter, c *codec.Codec, signer *cryptoutil.Signer, encrypter *cryptoutil.Encrypter, defaults *Options) *Cookies {
	if c == nil {
		c = defaultCodec
	}
	if defaults == nil {
		defaults = cookieDefaults
	}
	return &Cookies{r, w, c, signer, encrypter, defaults}
}

// Defaults returns the default coookie options, which are:
//
//  Path: "/"
//  Expires: Permanent (cookie never expires)
//
// To change the defaults, use SetDefaults.
func Defaults() *Options {
	return cookieDefaults
}

// SetDefaults changes the default cookie options.
func SetDefaults(defaults *Options) {
	if defaults == nil {
		defaults = &Options{}
	}
	cookieDefaults = defaults
}

func (c *Cookies) encode(value interface{}, t transformer) (string, error) {
	data, err := c.c.Encode(value)
	if err != nil {
		return "", err
	}
	if t != nil {
		data, err = t(data)
		if err != nil {
			return "", err
		}
	}
	return base64.Encode(data), nil
}

func (c *Cookies) decode(data string, arg interface{}, t transformer) error {
	b, err := base64.Decode(data)
	if err != nil {
		return err
	}
	if t != nil {
		b, err = t(b)
		if err != nil {
			return err
		}
	}
	return c.c.Decode(b, arg)
}

func (c *Cookies) set(name, value string, o *Options) error {
	if len(value) > MaxSize {
		return ErrCookieTooBig
	}
	if o == nil {
		// c.defaults is guaranteed to not be nil
		o = c.defaults
	}
	// TODO: Calculate MaxAge depending
	// on expires and vice-versa
	cookie := &http.Cookie{
		Name:     name,
		Value:    value,
		Path:     o.Path,
		Domain:   o.Domain,
		Expires:  o.Expires,
		MaxAge:   o.MaxAge,
		Secure:   o.Secure,
		HttpOnly: o.HttpOnly,
	}
	c.SetCookie(cookie)
	return nil
}

// setSigned sets a signed cookie from its data
func (c *Cookies) setSigned(name string, data []byte, o *Options) error {
	if c.signer == nil {
		return ErrNoSigner
	}
	signed, err := c.signer.Sign(data)
	if err != nil {
		return err
	}
	return c.set(name, signed, o)
}

// getSigned returns the signed cookie data if the signature is valid.
func (c *Cookies) getSigned(name string) ([]byte, error) {
	if c.signer == nil {
		return nil, ErrNoSigner
	}
	cookie, err := c.GetCookie(name)
	if err != nil {
		return nil, err
	}
	return c.signer.Unsign(cookie.Value)
}

// Has returns true if a cookie with the given name exists.
func (c *Cookies) Has(name string) bool {
	// TODO(hierro): This currently generates a *http.Cookie object
	// which is thrown away. Avoid that unnecessary allocation.
	cookie, _ := c.GetCookie(name)
	return cookie != nil
}

// GetCookie returns the raw *http.Coookie with
// the given name.
func (c *Cookies) GetCookie(name string) (*http.Cookie, error) {
	return c.r.Cookie(name)
}

// SetCookie sets the given *http.Cookie.
func (c *Cookies) SetCookie(cookie *http.Cookie) {
	http.SetCookie(c.w, cookie)
}

// Get uses the cookie value with the given name to
// populate the out argument. If the types don't match
// (e.g. the cookie was set to a string and you try
// to get an int), an error will be returned.
func (c *Cookies) Get(name string, out interface{}) error {
	cookie, err := c.GetCookie(name)
	if err != nil {
		return err
	}
	data, err := base64.Decode(cookie.Value)
	if err != nil {
		return err
	}
	return c.c.Decode(data, out)
}

// Set sets the cookie with the given name and encodes
// the given value using the codec provided in New. If
// the cookie size if bigger than 4096 bytes, it returns
// ErrCookieTooBig.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetOpts().
func (c *Cookies) Set(name string, value interface{}) error {
	return c.SetOpts(name, value, nil)
}

// SetOpts works like Set(), but accepts an Options parameter.
func (c *Cookies) SetOpts(name string, value interface{}, o *Options) error {
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	return c.set(name, base64.Encode(data), o)
}

// GetSecure works like Get, but for cookies set with SetSecure().
// See SetSecure() for the guarantees made about the
// cookie value.
func (c *Cookies) GetSecure(name string, out interface{}) error {
	data, err := c.getSigned(name)
	if err != nil {
		return err
	}
	return c.c.Decode(data, out)
}

// SetSecure sets a tamper-proof cookie, using the a
// *cryptoutil.Signer to sign its value. By default, it uses
// HMAC-SHA1. The user will be able to see
// the value of the cookie, but he will not be able
// to manipulate it. If you also require the value to be
// protected from being revealed to the user, use
// SetEncrypted().
//
// If you haven't set a Signer (usually set automatically for you, derived from
// the gnd.la/app.App.Secret field), this function will return an error.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetSecureOpts().
func (c *Cookies) SetSecure(name string, value interface{}) error {
	return c.SetSecureOpts(name, value, nil)
}

// SetSecureOpts works like SetSecure(), but accepts an Options parameter.
func (c *Cookies) SetSecureOpts(name string, value interface{}, o *Options) error {
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	return c.setSigned(name, data, o)
}

// GetEncrypted works like Get, but for cookies set with SetEncrypted().
// See SetEncrypted() for the guarantees made about the cookie value.
func (c *Cookies) GetEncrypted(name string, out interface{}) error {
	if c.encrypter == nil {
		return ErrNoEncrypter
	}
	data, err := c.getSigned(name)
	if err != nil {
		return err
	}
	decrypted, err := c.encrypter.Decrypt(data)
	if err != nil {
		return err
	}
	return c.c.Decode(decrypted, out)
}

// SetEncrypted sets a tamper-proof and encrypted cookie. The value is first
// encrypted using *cryptoutil.Encrypter and the signed using *cryptoutil.Signer.
// By default, these use AES and HMAC-SHA1 respectivelly. The user will not
// be able to tamper with the cookie value nor reveal its contents.
//
// If you haven't set a Signer (usually set automatically for you, derived from
// the gnd.la/app.App.Secret field) and an Encrypter (usually set automatically too,
// from gnd.la/app.App.EncryptionKey), this function will return an error.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetEncryptedOpts().
func (c *Cookies) SetEncrypted(name string, value interface{}) error {
	return c.SetEncryptedOpts(name, value, nil)
}

// SetEncryptedOpts works like SetEncrypted(), but accepts and Options parameter.
func (c *Cookies) SetEncryptedOpts(name string, value interface{}, o *Options) error {
	if c.encrypter == nil {
		return ErrNoEncrypter
	}
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	encrypted, err := c.encrypter.Encrypt(data)
	if err != nil {
		return err
	}
	return c.setSigned(name, encrypted, o)
}

// Delete deletes with cookie with the given name.
func (c *Cookies) Delete(name string) {
	cookie := &http.Cookie{
		Name:    name,
		Path:    "/",
		Expires: deleteExpires,
		MaxAge:  -1,
	}
	c.SetCookie(cookie)
}
<commit_msg>Don't panic when there's no request.<commit_after>// Package cookies contains helper functions for setting and
// retrieving cookies, including signed and encrypted ones.
//
// Cookie values are encoded and decoded using encoding/gob, so
// you must register any non-basic type that you want to store
// in a cookie, using encoding/gob.Register.
//
// Signed cookies are signed using HMAC-SHA1. Encrypted cookies
// are encrypted with AES and then signed with HMAC-SHA1.
package cookies

import (
	"errors"
	"gnd.la/encoding/base64"
	"gnd.la/encoding/codec"
	"gnd.la/util/cryptoutil"
	"net/http"
	"time"
)

const (
	// Maximum cookie size. See section 6.3 at http://www.ietf.org/rfc/rfc2109.txt.
	MaxSize = 4096
)

var (
	// Cookie is too big. See MaxSize.
	ErrCookieTooBig = errors.New("cookie is too big (maximum size is 4096 bytes)")
	// Tried to use signed or encrypted cookies without a Signer.
	ErrNoSigner = errors.New("no signer specified")
	// Tried to use encrypted cookies without an Encrypter.
	ErrNoEncrypter = errors.New("no encrypter specified")

	errNoRequest = errors.New("no request available")

	// Maximum representable UNIX time with a signed 32 bit integer. This
	// means that cookies won't be really permanent, but they will expire
	// on January 19th 2038. I don't know about you, but I hope to be around
	// by that time, so hopefully I'll find a solution for this issue in the
	// next few years. See http://en.wikipedia.org/wiki/Year_2038_problem for
	// more information.
	Permanent      = time.Unix(2147483647, 0).UTC()
	deleteExpires  = time.Unix(0, 0).UTC()
	defaultCodec   = codec.Get("gob")
	cookieDefaults = &Options{Path: "/", Expires: Permanent}
)

// Options specify the default cookie Options used when setting
// a Cookie only by its name and value, like in Cookies.Set(),
// Cookies.SetSecure(), and Cookies.SetEncrypted().
//
// For more information about the cookie fields, see net/http.Cookie.
type Options struct {
	Path     string
	Domain   string
	Expires  time.Time
	MaxAge   int
	Secure   bool
	HttpOnly bool
}

// Cookies includes conveniency functions for setting
// and retrieving cookies. Use New() or gnd.la/app.Context.Cookies
// to create a Cookies instance.
type Cookies struct {
	r         *http.Request
	w         http.ResponseWriter
	c         *codec.Codec
	signer    *cryptoutil.Signer
	encrypter *cryptoutil.Encrypter
	defaults  *Options
}

type transformer func([]byte) ([]byte, error)

// New returns a new *Cookies object, which will read cookies from the
// given http.Request, and write them to the given http.ResponseWriter.
// Note that users will probably want to use gnd.la/app.Context.Cookies
// rather than this function to create a Cookies instance.
//
// The secret parameter is used for secure (signed) cookies, while
// encryptionKey is also used for encrypted cookies. If you don't use
// secure nor encrypted cookies, you might leave both parameters empty.
// If you only need signed cookies, you might leave encryptionKey
// empty.
//
// The default parameter specifies the default Options for the funcions
// which only take a name and a value. If you pass nil, Defaults will
// be used.
func New(r *http.Request, w http.ResponseWriter, c *codec.Codec, signer *cryptoutil.Signer, encrypter *cryptoutil.Encrypter, defaults *Options) *Cookies {
	if c == nil {
		c = defaultCodec
	}
	if defaults == nil {
		defaults = cookieDefaults
	}
	return &Cookies{r, w, c, signer, encrypter, defaults}
}

// Defaults returns the default coookie options, which are:
//
//  Path: "/"
//  Expires: Permanent (cookie never expires)
//
// To change the defaults, use SetDefaults.
func Defaults() *Options {
	return cookieDefaults
}

// SetDefaults changes the default cookie options.
func SetDefaults(defaults *Options) {
	if defaults == nil {
		defaults = &Options{}
	}
	cookieDefaults = defaults
}

func (c *Cookies) encode(value interface{}, t transformer) (string, error) {
	data, err := c.c.Encode(value)
	if err != nil {
		return "", err
	}
	if t != nil {
		data, err = t(data)
		if err != nil {
			return "", err
		}
	}
	return base64.Encode(data), nil
}

func (c *Cookies) decode(data string, arg interface{}, t transformer) error {
	b, err := base64.Decode(data)
	if err != nil {
		return err
	}
	if t != nil {
		b, err = t(b)
		if err != nil {
			return err
		}
	}
	return c.c.Decode(b, arg)
}

func (c *Cookies) set(name, value string, o *Options) error {
	if len(value) > MaxSize {
		return ErrCookieTooBig
	}
	if o == nil {
		// c.defaults is guaranteed to not be nil
		o = c.defaults
	}
	// TODO: Calculate MaxAge depending
	// on expires and vice-versa
	cookie := &http.Cookie{
		Name:     name,
		Value:    value,
		Path:     o.Path,
		Domain:   o.Domain,
		Expires:  o.Expires,
		MaxAge:   o.MaxAge,
		Secure:   o.Secure,
		HttpOnly: o.HttpOnly,
	}
	c.SetCookie(cookie)
	return nil
}

// setSigned sets a signed cookie from its data
func (c *Cookies) setSigned(name string, data []byte, o *Options) error {
	if c.signer == nil {
		return ErrNoSigner
	}
	signed, err := c.signer.Sign(data)
	if err != nil {
		return err
	}
	return c.set(name, signed, o)
}

// getSigned returns the signed cookie data if the signature is valid.
func (c *Cookies) getSigned(name string) ([]byte, error) {
	if c.signer == nil {
		return nil, ErrNoSigner
	}
	cookie, err := c.GetCookie(name)
	if err != nil {
		return nil, err
	}
	return c.signer.Unsign(cookie.Value)
}

// Has returns true if a cookie with the given name exists.
func (c *Cookies) Has(name string) bool {
	// TODO(hierro): This currently generates a *http.Cookie object
	// which is thrown away. Avoid that unnecessary allocation.
	cookie, _ := c.GetCookie(name)
	return cookie != nil
}

// GetCookie returns the raw *http.Coookie with
// the given name.
func (c *Cookies) GetCookie(name string) (*http.Cookie, error) {
	if c.r == nil {
		return nil, errNoRequest
	}
	return c.r.Cookie(name)
}

// SetCookie sets the given *http.Cookie.
func (c *Cookies) SetCookie(cookie *http.Cookie) {
	if c.w != nil {
		http.SetCookie(c.w, cookie)
	}
}

// Get uses the cookie value with the given name to
// populate the out argument. If the types don't match
// (e.g. the cookie was set to a string and you try
// to get an int), an error will be returned.
func (c *Cookies) Get(name string, out interface{}) error {
	cookie, err := c.GetCookie(name)
	if err != nil {
		return err
	}
	data, err := base64.Decode(cookie.Value)
	if err != nil {
		return err
	}
	return c.c.Decode(data, out)
}

// Set sets the cookie with the given name and encodes
// the given value using the codec provided in New. If
// the cookie size if bigger than 4096 bytes, it returns
// ErrCookieTooBig.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetOpts().
func (c *Cookies) Set(name string, value interface{}) error {
	return c.SetOpts(name, value, nil)
}

// SetOpts works like Set(), but accepts an Options parameter.
func (c *Cookies) SetOpts(name string, value interface{}, o *Options) error {
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	return c.set(name, base64.Encode(data), o)
}

// GetSecure works like Get, but for cookies set with SetSecure().
// See SetSecure() for the guarantees made about the
// cookie value.
func (c *Cookies) GetSecure(name string, out interface{}) error {
	data, err := c.getSigned(name)
	if err != nil {
		return err
	}
	return c.c.Decode(data, out)
}

// SetSecure sets a tamper-proof cookie, using the a
// *cryptoutil.Signer to sign its value. By default, it uses
// HMAC-SHA1. The user will be able to see
// the value of the cookie, but he will not be able
// to manipulate it. If you also require the value to be
// protected from being revealed to the user, use
// SetEncrypted().
//
// If you haven't set a Signer (usually set automatically for you, derived from
// the gnd.la/app.App.Secret field), this function will return an error.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetSecureOpts().
func (c *Cookies) SetSecure(name string, value interface{}) error {
	return c.SetSecureOpts(name, value, nil)
}

// SetSecureOpts works like SetSecure(), but accepts an Options parameter.
func (c *Cookies) SetSecureOpts(name string, value interface{}, o *Options) error {
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	return c.setSigned(name, data, o)
}

// GetEncrypted works like Get, but for cookies set with SetEncrypted().
// See SetEncrypted() for the guarantees made about the cookie value.
func (c *Cookies) GetEncrypted(name string, out interface{}) error {
	if c.encrypter == nil {
		return ErrNoEncrypter
	}
	data, err := c.getSigned(name)
	if err != nil {
		return err
	}
	decrypted, err := c.encrypter.Decrypt(data)
	if err != nil {
		return err
	}
	return c.c.Decode(decrypted, out)
}

// SetEncrypted sets a tamper-proof and encrypted cookie. The value is first
// encrypted using *cryptoutil.Encrypter and the signed using *cryptoutil.Signer.
// By default, these use AES and HMAC-SHA1 respectivelly. The user will not
// be able to tamper with the cookie value nor reveal its contents.
//
// If you haven't set a Signer (usually set automatically for you, derived from
// the gnd.la/app.App.Secret field) and an Encrypter (usually set automatically too,
// from gnd.la/app.App.EncryptionKey), this function will return an error.
//
// The options used for the cookie are the default ones provided
// in New(), which will usually come from gnd.la/app.App.CookieOptions.
// If you need to specify different options, use SetEncryptedOpts().
func (c *Cookies) SetEncrypted(name string, value interface{}) error {
	return c.SetEncryptedOpts(name, value, nil)
}

// SetEncryptedOpts works like SetEncrypted(), but accepts and Options parameter.
func (c *Cookies) SetEncryptedOpts(name string, value interface{}, o *Options) error {
	if c.encrypter == nil {
		return ErrNoEncrypter
	}
	data, err := c.c.Encode(value)
	if err != nil {
		return err
	}
	encrypted, err := c.encrypter.Encrypt(data)
	if err != nil {
		return err
	}
	return c.setSigned(name, encrypted, o)
}

// Delete deletes with cookie with the given name.
func (c *Cookies) Delete(name string) {
	cookie := &http.Cookie{
		Name:    name,
		Path:    "/",
		Expires: deleteExpires,
		MaxAge:  -1,
	}
	c.SetCookie(cookie)
}
<|endoftext|>


<commit_before><commit_msg>add agent-name to HostMeta<commit_after><|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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.

package generator

import (
	"encoding/json"
	"regexp"
	"text/template"
)

//go:generate go-bindata -pkg=generator -ignore=.*\.sw? ./templates/...

// fwiw, don't get attached to this, still requires a better abstraction

var (
	modelTemplate *template.Template
	// modelValidatorTemplate *template.Template
	operationTemplate      *template.Template
	parameterTemplate      *template.Template
	responsesTemplate      *template.Template
	builderTemplate        *template.Template
	mainTemplate           *template.Template
	mainDocTemplate        *template.Template
	embeddedSpecTemplate   *template.Template
	configureAPITemplate   *template.Template
	clientTemplate         *template.Template
	clientParamTemplate    *template.Template
	clientResponseTemplate *template.Template
	clientFacadeTemplate   *template.Template
)

var assets = map[string][]byte{
	"validation/primitive.gotmpl":           MustAsset("templates/validation/primitive.gotmpl"),
	"validation/customformat.gotmpl":        MustAsset("templates/validation/customformat.gotmpl"),
	"docstring.gotmpl":                      MustAsset("templates/docstring.gotmpl"),
	"validation/structfield.gotmpl":         MustAsset("templates/validation/structfield.gotmpl"),
	"modelvalidator.gotmpl":                 MustAsset("templates/modelvalidator.gotmpl"),
	"structfield.gotmpl":                    MustAsset("templates/structfield.gotmpl"),
	"tupleserializer.gotmpl":                MustAsset("templates/tupleserializer.gotmpl"),
	"additionalpropertiesserializer.gotmpl": MustAsset("templates/additionalpropertiesserializer.gotmpl"),
	"schematype.gotmpl":                     MustAsset("templates/schematype.gotmpl"),
	"schemabody.gotmpl":                     MustAsset("templates/schemabody.gotmpl"),
	"schema.gotmpl":                         MustAsset("templates/schema.gotmpl"),
	"schemavalidator.gotmpl":                MustAsset("templates/schemavalidator.gotmpl"),
	"model.gotmpl":                          MustAsset("templates/model.gotmpl"),
	"header.gotmpl":                         MustAsset("templates/header.gotmpl"),
	"swagger_json_embed.gotmpl":             MustAsset("templates/swagger_json_embed.gotmpl"),

	"server/parameter.gotmpl":    MustAsset("templates/server/parameter.gotmpl"),
	"server/responses.gotmpl":    MustAsset("templates/server/responses.gotmpl"),
	"server/operation.gotmpl":    MustAsset("templates/server/operation.gotmpl"),
	"server/builder.gotmpl":      MustAsset("templates/server/builder.gotmpl"),
	"server/configureapi.gotmpl": MustAsset("templates/server/configureapi.gotmpl"),
	"server/main.gotmpl":         MustAsset("templates/server/main.gotmpl"),
	"server/doc.gotmpl":          MustAsset("templates/server/doc.gotmpl"),

	"client/parameter.gotmpl": MustAsset("templates/client/parameter.gotmpl"),
	"client/response.gotmpl":  MustAsset("templates/client/response.gotmpl"),
	"client/client.gotmpl":    MustAsset("templates/client/client.gotmpl"),
	"client/facade.gotmpl":    MustAsset("templates/client/facade.gotmpl"),
}

// var builtinTemplates = map[string]TemplateDefinition{

// 	"validatorTempl": {
// 		Dependencies: []string{
// 			"primitivevalidator",
// 			"customformatvalidator",
// 		},
// 	},

// 	"primitivevalidator": {
// 		Files: []string{"validation/primitive.gotmpl"},
// 	},
// 	"customformatvalidator": {
// 		Files: []string{"validation/customformat.gotmpl"},
// 	},

// 	"modelValidatorTemplate": {
// 		Dependencies: []string{"validatorTempl"},
// 	},

// 	"docstring": {
// 		Files: []string{"docstring.gotmpl"},
// 	},

// 	"propertyValidationDocString": {
// 		Files: []string{"validation/docstring.gotmpl"},
// 	},
// 	"schematype": {
// 		Files: []string{"schematype.gotmpl"},
// 	},
// 	"body": {
// 		Files: []string{"schemabody.gotmpl"},
// 	},
// 	"schema": {
// 		Files: []string{"schema.gotmpl"},
// 	},
// 	"schemavalidations": {
// 		Files: []string{"schemavalidator.gotmpl"},
// 	},
// 	"header": {
// 		Files: []string{"header.gotmpl"},
// 	},
// 	"fields": {
// 		Files: []string{"structfield.gotmpl"},
// 	},
// 	"tupleserializer": {
// 		Files: []string{"tupleserializer.gotmpl"},
// 	},
// 	"additionalpropertiesserializer": {
// 		Files: []string{"additionalpropertiesserializer.gotmpl"},
// 	},
// 	"model": {
// 		Dependencies: []string{
// 			"docstring",
// 			"primitivevalidator",
// 			"customformatvalidator",
// 			"propertyValidationDocString",
// 			"schematype",
// 			"body",
// 			"schema",
// 			"schemavalidations",
// 			"header",
// 			"fields",
// 			"tupleserializer",
// 			"additionalpropertiesserializer",
// 		},
// 		Files: []string{
// 			"model.gotmpl",
// 		},
// 	},

// 	"parameterTemplate": {
// 		Dependencies: []string{"model"},
// 		Files:        []string{"server/parameter.gotmpl"},
// 	},

// 	"responsesTemplate": {
// 		Dependencies: []string{"model"},
// 		Files:        []string{"server/responses.gotmpl"},
// 	},

// 	"operationTemplate": {
// 		Dependencies: []string{"model"},
// 		Files:        []string{"server/operation.gotmpl"},
// 	},

// 	"builderTemplate": {
// 		Files: []string{"server/builder.gotmpl"},
// 	},

// 	"configureAPITemplate": {
// 		Files: []string{"server/configureapi.gotmpl"},
// 	},

// 	"mainTemplate": {
// 		Files: []string{"server/main.gotmpl"},
// 	},

// 	"mainDocTemplate": {
// 		Files: []string{"server/doc.gotmpl"},
// 	},

// 	"embeddedSpecTemplate": {
// 		Files: []string{"swagger_json_embed.gotmpl"},
// 	},

// 	// Client templates
// 	"clientParamTemplate": {
// 		Dependencies: []string{"model"},
// 		Files:        []string{"client/parameter.gotmpl"},
// 	},

// 	"clientResponseTemplate": {
// 		Dependencies: []string{"model"},
// 		Files:        []string{"client/response.gotmpl"},
// 	},

// 	"clientTemplate": {
// 		Dependencies: []string{

// 			"docstring",
// 			"propertyValidationDocString",
// 			"schematype",
// 			"body",
// 		},
// 		Files: []string{
// 			"client/client.gotmpl",
// 		},
// 	},

// 	"clientFacadeTemplate": {
// 		Dependencies: []string{

// 			"docstring",
// 			"propertyValidationDocString",
// 			"schematype",
// 			"body",
// 		},
// 		Files: []string{
// 			"client/facade.gotmpl",
// 		},
// 	},
// }

var (
	notNumberExp = regexp.MustCompile("[^0-9]")
)

var templates = NewRepository(FuncMap)

func init() {

	templates.LoadDefaults()

	// for name, template := range builtinTemplates {
	// 	templates.AddTemplate(name, template)
	// }

	compileTemplates()
}

func compileTemplates() {

	modelTemplate = template.Must(templates.Get("model"))

	// common templates

	// modelValidatorTemplate = template.Must(templates.Get("modelValidatorTemplate"))

	// server templates
	parameterTemplate = template.Must(templates.Get("serverParameter"))

	responsesTemplate = template.Must(templates.Get("serverResponses"))

	operationTemplate = template.Must(templates.Get("serverOperation"))
	builderTemplate = template.Must(templates.Get("serverBuilder"))           //template.Must(template.New("builder").Funcs(FuncMap).Parse(string(assets["server/builder.gotmpl"]))))
	configureAPITemplate = template.Must(templates.Get("serverConfigureapi")) //template.Must(template.New("configureapi").Funcs(FuncMap).Parse(string(assets["server/configureapi.gotmpl"]))))
	mainTemplate = template.Must(templates.Get("serverMain"))                 //template.Must(template.New("main").Funcs(FuncMap).Parse(string(assets["server/main.gotmpl"]))))
	mainDocTemplate = template.Must(templates.Get("serverDoc"))               //template.Must(template.New("meta").Funcs(FuncMap).Parse(string(assets["server/doc.gotmpl"]))))

	embeddedSpecTemplate = template.Must(templates.Get("swaggerJsonEmbed")) //template.Must(template.New("embedded_spec").Funcs(FuncMap).Parse(string(assets["swagger_json_embed.gotmpl"]))))

	// Client templates
	clientParamTemplate = template.Must(templates.Get("clientParameter"))

	clientResponseTemplate = template.Must(templates.Get("clientResponse"))

	clientTemplate = template.Must(templates.Get("clientClient"))

	clientFacadeTemplate = template.Must(templates.Get("clientFacade"))

}

func asJSON(data interface{}) (string, error) {
	b, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(b), nil
}
<commit_msg>remove compiled from init; clean out old code<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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.

package generator

import (
	"encoding/json"
	"regexp"
	"text/template"
)

//go:generate go-bindata -pkg=generator -ignore=.*\.sw? ./templates/...

// fwiw, don't get attached to this, still requires a better abstraction

var (
	modelTemplate *template.Template
	// modelValidatorTemplate *template.Template
	operationTemplate      *template.Template
	parameterTemplate      *template.Template
	responsesTemplate      *template.Template
	builderTemplate        *template.Template
	mainTemplate           *template.Template
	mainDocTemplate        *template.Template
	embeddedSpecTemplate   *template.Template
	configureAPITemplate   *template.Template
	clientTemplate         *template.Template
	clientParamTemplate    *template.Template
	clientResponseTemplate *template.Template
	clientFacadeTemplate   *template.Template
)

var assets = map[string][]byte{
	"validation/primitive.gotmpl":           MustAsset("templates/validation/primitive.gotmpl"),
	"validation/customformat.gotmpl":        MustAsset("templates/validation/customformat.gotmpl"),
	"docstring.gotmpl":                      MustAsset("templates/docstring.gotmpl"),
	"validation/structfield.gotmpl":         MustAsset("templates/validation/structfield.gotmpl"),
	"modelvalidator.gotmpl":                 MustAsset("templates/modelvalidator.gotmpl"),
	"structfield.gotmpl":                    MustAsset("templates/structfield.gotmpl"),
	"tupleserializer.gotmpl":                MustAsset("templates/tupleserializer.gotmpl"),
	"additionalpropertiesserializer.gotmpl": MustAsset("templates/additionalpropertiesserializer.gotmpl"),
	"schematype.gotmpl":                     MustAsset("templates/schematype.gotmpl"),
	"schemabody.gotmpl":                     MustAsset("templates/schemabody.gotmpl"),
	"schema.gotmpl":                         MustAsset("templates/schema.gotmpl"),
	"schemavalidator.gotmpl":                MustAsset("templates/schemavalidator.gotmpl"),
	"model.gotmpl":                          MustAsset("templates/model.gotmpl"),
	"header.gotmpl":                         MustAsset("templates/header.gotmpl"),
	"swagger_json_embed.gotmpl":             MustAsset("templates/swagger_json_embed.gotmpl"),

	"server/parameter.gotmpl":    MustAsset("templates/server/parameter.gotmpl"),
	"server/responses.gotmpl":    MustAsset("templates/server/responses.gotmpl"),
	"server/operation.gotmpl":    MustAsset("templates/server/operation.gotmpl"),
	"server/builder.gotmpl":      MustAsset("templates/server/builder.gotmpl"),
	"server/configureapi.gotmpl": MustAsset("templates/server/configureapi.gotmpl"),
	"server/main.gotmpl":         MustAsset("templates/server/main.gotmpl"),
	"server/doc.gotmpl":          MustAsset("templates/server/doc.gotmpl"),

	"client/parameter.gotmpl": MustAsset("templates/client/parameter.gotmpl"),
	"client/response.gotmpl":  MustAsset("templates/client/response.gotmpl"),
	"client/client.gotmpl":    MustAsset("templates/client/client.gotmpl"),
	"client/facade.gotmpl":    MustAsset("templates/client/facade.gotmpl"),
}

var (
	notNumberExp = regexp.MustCompile("[^0-9]")
)

var templates = NewRepository(FuncMap)

func init() {

	templates.LoadDefaults()

}

func compileTemplates() {

	modelTemplate = template.Must(templates.Get("model"))

	// server templates
	parameterTemplate = template.Must(templates.Get("serverParameter"))

	responsesTemplate = template.Must(templates.Get("serverResponses"))

	operationTemplate = template.Must(templates.Get("serverOperation"))
	builderTemplate = template.Must(templates.Get("serverBuilder"))
	configureAPITemplate = template.Must(templates.Get("serverConfigureapi"))
	mainTemplate = template.Must(templates.Get("serverMain"))
	mainDocTemplate = template.Must(templates.Get("serverDoc"))

	embeddedSpecTemplate = template.Must(templates.Get("swaggerJsonEmbed"))

	// Client templates
	clientParamTemplate = template.Must(templates.Get("clientParameter"))

	clientResponseTemplate = template.Must(templates.Get("clientResponse"))

	clientTemplate = template.Must(templates.Get("clientClient"))

	clientFacadeTemplate = template.Must(templates.Get("clientFacade"))

}

func asJSON(data interface{}) (string, error) {
	b, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(b), nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"sort"
	"time"

	"github.com/nightlyone/lockfile"
	flag "github.com/ogier/pflag"
)

func main() {
	time_start := time.Now()

	processFlags()
	setupLogs()
	versionFlag()
	setNice()

	if config.LockfilePath != "" {
		lock, err := lockfile.New(config.LockfilePath)
		if err != nil {
			Error.Fatalf("Lockfile failed. reason: %v\n", err)
		}
		if err := lock.TryLock(); err != nil {
			Error.Fatalf("Lockfile failed. reason: %v\n", err)
		}
		defer lock.Unlock()
	}

	startTime := time.Now().Unix()
	endTime := startTime + config.MaxRunTime

	initWorkers()

	if !config.ResetXattrs {
		filterChecksumAlgos()
	}

	var allJobs []job

	// Loop over the passed in directories and get all files
	for _, path := range flag.Args() {
		Info.Printf("Processing %v...\n", path)
		if err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			j := newJob(path, info)
			allJobs = append(allJobs, j)
			return nil
		}); err != nil {
			Error.Println(err)
		}
	}

	// Sort the slice so we check the oldest first
	Info.Printf("Sorting paths...\n")
	sort.Slice(allJobs, func(i, j int) bool { return allJobs[i].checkedTime < allJobs[j].checkedTime })

	// Loop over the passed in directories and hash and/or validate
	Info.Printf("Starting jobs...\n")
	for _, j := range allJobs {
		// Did we run out of time?
		if time.Now().Unix() >= endTime && config.MaxRunTime != 0 {
			Info.Printf("Max Runtime Reached. Stopping queues...\n")
			break
		}

		if config.ResetXattrs {
			workerResetJobs <- j
		} else {
			workerStartJobs <- j
		}
	}

	shutdownWorkers()

	Info.Printf("Ran in %v", time.Since(time_start))
}
<commit_msg>Process in path order if we have the same last checked time<commit_after>package main

import (
	"os"
	"path/filepath"
	"sort"
	"time"

	"github.com/nightlyone/lockfile"
	flag "github.com/ogier/pflag"
)

func main() {
	time_start := time.Now()

	processFlags()
	setupLogs()
	versionFlag()
	setNice()

	if config.LockfilePath != "" {
		lock, err := lockfile.New(config.LockfilePath)
		if err != nil {
			Error.Fatalf("Lockfile failed. reason: %v\n", err)
		}
		if err := lock.TryLock(); err != nil {
			Error.Fatalf("Lockfile failed. reason: %v\n", err)
		}
		defer lock.Unlock()
	}

	startTime := time.Now().Unix()
	endTime := startTime + config.MaxRunTime

	initWorkers()

	if !config.ResetXattrs {
		filterChecksumAlgos()
	}

	var allJobs []job

	// Loop over the passed in directories and get all files
	for _, path := range flag.Args() {
		Info.Printf("Processing %v...\n", path)
		if err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			j := newJob(path, info)
			allJobs = append(allJobs, j)
			return nil
		}); err != nil {
			Error.Println(err)
		}
	}

	// Sort the slice so we check the oldest first
	Info.Printf("Sorting paths...\n")
	sort.Slice(allJobs,
		func(i, j int) bool {
			if allJobs[i].checkedTime == allJobs[j].checkedTime {
				return allJobs[i].path < allJobs[j].path
			}
			return allJobs[i].checkedTime < allJobs[j].checkedTime
		})

	// Loop over the passed in directories and hash and/or validate
	Info.Printf("Starting jobs...\n")
	for _, j := range allJobs {
		// Did we run out of time?
		if time.Now().Unix() >= endTime && config.MaxRunTime != 0 {
			Info.Printf("Max Runtime Reached. Stopping queues...\n")
			break
		}

		if config.ResetXattrs {
			workerResetJobs <- j
		} else {
			workerStartJobs <- j
		}
	}

	shutdownWorkers()

	Info.Printf("Ran in %v", time.Since(time_start))
}
<|endoftext|>


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

package fusis

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/log"
	tsuruNet "github.com/tsuru/tsuru/net"
	"github.com/tsuru/tsuru/router"
)

const routerType = "fusis"

type fusisRouter struct {
	apiUrl    string
	proto     string
	port      uint16
	scheduler string
	mode      string
	debug     bool
}

func init() {
	router.Register(routerType, createRouter)
}

func createRouter(routerName, configPrefix string) (router.Router, error) {
	apiUrl, err := config.GetString(configPrefix + ":api-url")
	if err != nil {
		return nil, err
	}
	r := &fusisRouter{
		apiUrl:    apiUrl,
		proto:     "tcp",
		port:      80,
		scheduler: "rr",
		mode:      "nat",
		debug:     true,
	}
	return r, nil
}

func (r *fusisRouter) doRequest(method, path string, params interface{}) (*http.Response, error) {
	buf := bytes.Buffer{}
	if params != nil {
		err := json.NewEncoder(&buf).Encode(params)
		if err != nil {
			return nil, err
		}
	}
	url := fmt.Sprintf("%s/%s", strings.TrimRight(r.apiUrl, "/"), strings.TrimLeft(path, "/"))
	var bodyData string
	if r.debug {
		bodyData = buf.String()
	}
	req, err := http.NewRequest(method, url, &buf)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	rsp, err := tsuruNet.Dial5Full60Client.Do(req)
	if r.debug {
		var code int
		if err == nil {
			code = rsp.StatusCode
		}
		log.Debugf("request %s %s %s: %d", method, url, bodyData, code)
	}
	return rsp, err
}

func (r *fusisRouter) AddBackend(name string) error {
	rsp, err := r.doRequest("POST", "/services", map[string]interface{}{
		"Name":      name,
		"Port":      r.port,
		"Protocol":  r.proto,
		"Scheduler": r.scheduler,
	})
	if err != nil {
		return err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return router.Store(name, name, routerType)
}
func (r *fusisRouter) RemoveBackend(name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	rsp, err := r.doRequest("DELETE", "/services/"+backendName, nil)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) routeName(name string, address *url.URL) string {
	return fmt.Sprintf("%s_%s", name, address.String())
}

func (r *fusisRouter) AddRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	host, port, err := net.SplitHostPort(address.Host)
	if err != nil {
		host = address.Host
		port = "80"
	}
	portInt, _ := strconv.ParseInt(port, 10, 16)
	data := map[string]interface{}{
		"Name": r.routeName(backendName, address),
		"Host": host,
		"Port": portInt,
		"Mode": r.mode,
	}
	rsp, err := r.doRequest("POST", fmt.Sprintf("/services/%s/destinations", backendName), data)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) AddRoutes(name string, addresses []*url.URL) error {
	for _, addr := range addresses {
		err := r.AddRoute(name, addr)
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *fusisRouter) RemoveRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	rsp, err := r.doRequest("DELETE", fmt.Sprintf("/services/%s/destinations/%s", backendName, r.routeName(backendName, address)), nil)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) RemoveRoutes(name string, addresses []*url.URL) error {
	for _, addr := range addresses {
		err := r.RemoveRoute(name, addr)
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *fusisRouter) SetCName(cname, name string) error {
	return nil
}
func (r *fusisRouter) UnsetCName(cname, name string) error {
	return nil
}
func (r *fusisRouter) Addr(name string) (string, error) {
	// backendName, err := router.Retrieve(name)
	// if err != nil {
	// 	return "", err
	// }
	rsp, err := r.doRequest("GET", "/services", nil)
	if err != nil {
		return "", err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return "", fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	// TODO
	return "", nil
}
func (r *fusisRouter) Swap(backend1 string, backend2 string) error {
	return router.Swap(r, backend1, backend2)
}
func (r *fusisRouter) Routes(name string) ([]*url.URL, error) {
	// backendName, err := router.Retrieve(name)
	// if err != nil {
	// 	return nil, err
	// }
	// TODO
	return nil, nil
}
<commit_msg>router/fusis: finish basic implementation of fusis integration<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fusis

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/log"
	tsuruNet "github.com/tsuru/tsuru/net"
	"github.com/tsuru/tsuru/router"
)

const routerType = "fusis"

type fusisRouter struct {
	apiUrl    string
	proto     string
	port      uint16
	scheduler string
	mode      string
	debug     bool
}

func init() {
	router.Register(routerType, createRouter)
}

func createRouter(routerName, configPrefix string) (router.Router, error) {
	apiUrl, err := config.GetString(configPrefix + ":api-url")
	if err != nil {
		return nil, err
	}
	r := &fusisRouter{
		apiUrl:    apiUrl,
		proto:     "tcp",
		port:      80,
		scheduler: "rr",
		mode:      "nat",
		debug:     true,
	}
	return r, nil
}

func (r *fusisRouter) doRequest(method, path string, params interface{}) (*http.Response, error) {
	buf := bytes.Buffer{}
	if params != nil {
		err := json.NewEncoder(&buf).Encode(params)
		if err != nil {
			return nil, err
		}
	}
	url := fmt.Sprintf("%s/%s", strings.TrimRight(r.apiUrl, "/"), strings.TrimLeft(path, "/"))
	var bodyData string
	if r.debug {
		bodyData = buf.String()
	}
	req, err := http.NewRequest(method, url, &buf)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	rsp, err := tsuruNet.Dial5Full60Client.Do(req)
	if r.debug {
		var code int
		if err == nil {
			code = rsp.StatusCode
		}
		log.Debugf("request %s %s %s: %d", method, url, bodyData, code)
	}
	return rsp, err
}

func (r *fusisRouter) AddBackend(name string) error {
	rsp, err := r.doRequest("POST", "/services", map[string]interface{}{
		"Name":      name,
		"Port":      r.port,
		"Protocol":  r.proto,
		"Scheduler": r.scheduler,
	})
	if err != nil {
		return err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return router.Store(name, name, routerType)
}
func (r *fusisRouter) RemoveBackend(name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	rsp, err := r.doRequest("DELETE", "/services/"+backendName, nil)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) routeName(name string, address *url.URL) string {
	return fmt.Sprintf("%s_%s", name, address.String())
}

func (r *fusisRouter) AddRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	host, port, err := net.SplitHostPort(address.Host)
	if err != nil {
		host = address.Host
		port = "80"
	}
	portInt, _ := strconv.ParseInt(port, 10, 16)
	data := map[string]interface{}{
		"Name": r.routeName(backendName, address),
		"Host": host,
		"Port": portInt,
		"Mode": r.mode,
	}
	rsp, err := r.doRequest("POST", fmt.Sprintf("/services/%s/destinations", backendName), data)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) AddRoutes(name string, addresses []*url.URL) error {
	for _, addr := range addresses {
		err := r.AddRoute(name, addr)
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *fusisRouter) RemoveRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	rsp, err := r.doRequest("DELETE", fmt.Sprintf("/services/%s/destinations/%s", backendName, r.routeName(backendName, address)), nil)
	if err != nil {
		return err
	}
	if rsp.StatusCode != http.StatusOK {
		data, _ := ioutil.ReadAll(rsp.Body)
		return fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	return nil
}
func (r *fusisRouter) RemoveRoutes(name string, addresses []*url.URL) error {
	for _, addr := range addresses {
		err := r.RemoveRoute(name, addr)
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *fusisRouter) SetCName(cname, name string) error {
	return nil
}
func (r *fusisRouter) UnsetCName(cname, name string) error {
	return nil
}

type Service struct {
	Name         string
	Host         string
	Port         uint16
	Destinations []Destination
}

type Destination struct {
	Name      string
	Host      string
	Port      uint16
	Weight    int32
	Mode      string
	ServiceId string `json:"service_id"`
}

func (r *fusisRouter) findService(name string) (*Service, error) {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return nil, err
	}
	rsp, err := r.doRequest("GET", "/services", nil)
	if err != nil {
		return nil, err
	}
	defer rsp.Body.Close()
	data, _ := ioutil.ReadAll(rsp.Body)
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("invalid response %d: %s", rsp.StatusCode, string(data))
	}
	var services []Service
	err = json.Unmarshal(data, &services)
	if err != nil {
		return nil, fmt.Errorf("unable unmarshal %q: %s", string(data), err)
	}
	var foundService *Service
	for i, s := range services {
		if s.Name == backendName {
			foundService = &services[i]
			break
		}
	}
	if foundService == nil {
		return nil, fmt.Errorf("service %s not found", backendName)
	}
	return foundService, nil
}

func (r *fusisRouter) Addr(name string) (string, error) {
	srv, err := r.findService(name)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s:%s", srv.Host, srv.Port), nil
}
func (r *fusisRouter) Swap(backend1 string, backend2 string) error {
	return router.Swap(r, backend1, backend2)
}
func (r *fusisRouter) Routes(name string) ([]*url.URL, error) {
	srv, err := r.findService(name)
	if err != nil {
		return nil, err
	}
	result := make([]*url.URL, len(srv.Destinations))
	for i, d := range srv.Destinations {
		var err error
		result[i], err = url.Parse(fmt.Sprintf("http://%s:%s", d.Host, d.Port))
		if err != nil {
			return nil, err
		}
	}
	return result, nil
}
<|endoftext|>