<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package views

import (
	"encoding/json"
	"strings"

	"log"

	"github.com/ernestio/api-gateway/models"

	graph "gopkg.in/r3labs/graph.v2"
)

// ServiceRender : Service representation to be rendered on the frontend
type ServiceRender struct {
	ID              string              `json:"id"`
	DatacenterID    int                 `json:"datacenter_id"`
	Project         string              `json:"project"`
	Provider        string              `json:"provider"`
	Name            string              `json:"name"`
	Version         string              `json:"version"`
	Status          string              `json:"status"`
	UserID          int                 `json:"user_id"`
	UserName        string              `json:"user_name"`
	LastKnownError  string              `json:"last_known_error"`
	Options         string              `json:"options"`
	Definition      string              `json:"definition"`
	Vpcs            []map[string]string `json:"vpcs"`
	Networks        []map[string]string `json:"networks"`
	Instances       []map[string]string `json:"instances"`
	Nats            []map[string]string `json:"nats"`
	SecurityGroups  []map[string]string `json:"security_groups"`
	Elbs            []map[string]string `json:"elbs"`
	RDSClusters     []map[string]string `json:"rds_clusters"`
	RDSInstances    []map[string]string `json:"rds_instances"`
	EBSVolumes      []map[string]string `json:"ebs_volumes"`
	LoadBalancers   []map[string]string `json:"load_balancers"`
	SQLDatabases    []map[string]string `json:"sql_databases"`
	VirtualMachines []map[string]string `json:"virtual_machines"`
	Roles           []string            `json:"roles"`
}

// Render : Map a Service to a ServiceRender
func (o *ServiceRender) Render(s models.Env) (err error) {
	o.Name = s.Name
	parts := strings.Split(o.Name, models.EnvNameSeparator)
	if len(parts) > 1 {
		o.Name = parts[1]
	}
	o.ID = s.ID
	o.DatacenterID = s.DatacenterID
	o.Version = s.Version.String()
	o.Status = s.Status
	o.UserID = s.UserID
	o.UserName = s.UserName
	if def, ok := s.Definition.(string); ok == true {
		o.Definition = def
	}

	g, err := s.Mapping()
	if err != nil {
		log.Println(err.Error())
		return err
	}

	o.Vpcs = RenderVpcs(g)
	o.Networks = RenderNetworks(g)
	o.SecurityGroups = RenderSecurityGroups(g)
	o.Nats = RenderNats(g)
	o.Instances = RenderInstances(g)
	o.Elbs = RenderELBs(g)
	o.RDSClusters = RenderRDSClusters(g)
	o.RDSInstances = RenderRDSInstances(g)
	o.EBSVolumes = RenderEBSVolumes(g)
	o.LoadBalancers = RenderLoadBalancers(g)
	o.SQLDatabases = RenderSQLDatabases(g)
	o.VirtualMachines = RenderVirtualMachines(g)
	o.Roles = s.Roles
	o.Project = s.Project
	o.Provider = s.Provider

	return err
}

// RenderVpcs : renders a services vpcs
func RenderVpcs(g *graph.Graph) []map[string]string {
	var vpcs []map[string]string

	for _, n := range g.GetComponents().ByType("vpc") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["vpc_aws_id"].(string)
		subnet, _ := (*gc)["vpc_subnet"].(string)
		vpcs = append(vpcs, map[string]string{
			"name":       name,
			"vpc_id":     id,
			"vpc_subnet": subnet,
		})
	}

	return vpcs
}

// RenderNetworks : renders a services networks
func RenderNetworks(g *graph.Graph) []map[string]string {
	var networks []map[string]string

	for _, n := range g.GetComponents().ByType("network") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["network_aws_id"].(string)
		az, _ := (*gc)["availability_zone"].(string)
		networks = append(networks, map[string]string{
			"name":              name,
			"network_aws_id":    id,
			"availability_zone": az,
		})
	}

	return networks
}

// RenderSecurityGroups : renders a services security groups
func RenderSecurityGroups(g *graph.Graph) []map[string]string {
	var sgs []map[string]string

	for _, n := range g.GetComponents().ByType("firewall") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["security_group_aws_id"].(string)
		sgs = append(sgs, map[string]string{
			"name":                  name,
			"security_group_aws_id": id,
		})
	}

	return sgs
}

// RenderNats : renders a services nat gateways
func RenderNats(g *graph.Graph) []map[string]string {
	var nats []map[string]string

	for _, n := range g.GetComponents().ByType("nat") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["nat_gateway_aws_id"].(string)
		pubIP, _ := (*gc)["nat_gateway_allocation_ip"].(string)
		nats = append(nats, map[string]string{
			"name":               name,
			"nat_gateway_aws_id": id,
			"public_ip":          pubIP,
		})
	}

	return nats
}

// RenderELBs : renders a services elbs
func RenderELBs(g *graph.Graph) []map[string]string {
	var elbs []map[string]string

	for _, n := range g.GetComponents().ByType("elb") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		dns, _ := (*gc)["dns_name"].(string)
		elbs = append(elbs, map[string]string{
			"name":     name,
			"dns_name": dns,
		})
	}

	return elbs
}

// RenderInstances : renders a services instances
func RenderInstances(g *graph.Graph) []map[string]string {
	var instances []map[string]string

	for _, n := range g.GetComponents().ByType("instance") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["instance_aws_id"].(string)
		pip, _ := (*gc)["public_ip"].(string)
		ip, _ := (*gc)["ip"].(string)
		instances = append(instances, map[string]string{
			"name":            name,
			"instance_aws_id": id,
			"public_ip":       pip,
			"ip":              ip,
		})
	}

	return instances
}

// RenderRDSClusters : renders a services rds clusters
func RenderRDSClusters(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("rds_cluster") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		endpoint, _ := (*gc)["endpoint"].(string)
		rdss = append(rdss, map[string]string{
			"name":     name,
			"endpoint": endpoint,
		})
	}

	return rdss
}

// RenderRDSInstances : renders a services rds instances
func RenderRDSInstances(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("rds_instance") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		endpoint, _ := (*gc)["endpoint"].(string)
		rdss = append(rdss, map[string]string{
			"name":     name,
			"endpoint": endpoint,
		})
	}

	return rdss
}

// RenderEBSVolumes : renders a services ebs volumes
func RenderEBSVolumes(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("ebs_volume") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["volume_aws_id"].(string)
		rdss = append(rdss, map[string]string{
			"name":          name,
			"volume_aws_id": id,
		})
	}

	return rdss
}

// RenderLoadBalancers : renders load balancers
func RenderLoadBalancers(g *graph.Graph) []map[string]string {
	var lbs []map[string]string
	ips := listIPAddresses(g)

	for _, n := range g.GetComponents().ByType("lb") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["id"].(string)
		configs, _ := (*gc)["frontend_ip_configurations"].([]interface{})
		ip := ""
		if len(configs) > 0 {
			cfg, _ := configs[0].(map[string]interface{})
			ipID, _ := cfg["public_ip_address_id"].(string)
			ip, _ = ips[ipID]
		}

		lbs = append(lbs, map[string]string{
			"name":      name,
			"id":        id,
			"public_ip": ip,
		})
	}

	return lbs
}

func listIPAddresses(g *graph.Graph) map[string]string {
	existingIPs := make(map[string]string, 0)

	for _, ip := range g.GetComponents().ByType("public_ip") {
		gc := ip.(*graph.GenericComponent)
		id, _ := (*gc)["id"].(string)
		ipAddress, _ := (*gc)["ip_address"].(string)
		existingIPs[id] = ipAddress
	}

	return existingIPs
}

// RenderVirtualMachines : renders virtual machines
func RenderVirtualMachines(g *graph.Graph) []map[string]string {
	var resources []map[string]string
	mappedIPs := make(map[string]interface{}, 0)
	existingIPs := listIPAddresses(g)

	for _, ni := range g.GetComponents().ByType("network_interface") {
		var public []string
		var private []string

		gc := ni.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		ips := make(map[string][]string)

		configs, _ := (*gc)["ip_configuration"].([]interface{})
		for _, cfg := range configs {
			c, _ := cfg.(map[string]interface{})
			pubID, _ := c["public_ip_address_id"].(string)
			pri, _ := c["private_ip_address"].(string)
			if pub, ok := existingIPs[pubID]; ok {
				public = append(public, pub)
			}
			private = append(private, pri)
		}

		ips["public"] = public
		ips["private"] = private
		mappedIPs[name] = make(map[string][]string, 0)
		mappedIPs[name] = ips
	}

	for _, n := range g.GetComponents().ByType("virtual_machine") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["id"].(string)
		networks, _ := (*gc)["network_interfaces"].([]interface{})
		publicIPs := make([]string, 0)
		privateIPs := make([]string, 0)
		for _, ni := range networks {
			netName := ni.(string)
			if val, ok := mappedIPs[netName]; ok {
				ips, _ := val.(map[string][]string)
				publicIPs = append(publicIPs, ips["public"]...)
				privateIPs = append(privateIPs, ips["private"]...)
			}
		}

		resources = append(resources, map[string]string{
			"name":       name,
			"id":         id,
			"public_ip":  strings.Join(publicIPs, ", "),
			"private_ip": strings.Join(privateIPs, ", "),
		})
	}

	return resources
}

// RenderSQLDatabases : renders sql databases
func RenderSQLDatabases(g *graph.Graph) []map[string]string {
	return renderResources(g, "sql_database", func(gc *graph.GenericComponent) map[string]string {
		name, _ := (*gc)["name"].(string)
		server, _ := (*gc)["server_name"].(string)
		id, _ := (*gc)["id"].(string)

		return map[string]string{
			"name":        name,
			"server_name": server + ".database.windows.net",
			"id":          id,
		}
	})
}

type convert func(*graph.GenericComponent) map[string]string

func renderResources(g *graph.Graph, resourceType string, f convert) (resources []map[string]string) {
	for _, n := range g.GetComponents().ByType(resourceType) {
		gc := n.(*graph.GenericComponent)
		resources = append(resources, f(gc))
	}

	return
}

// RenderCollection : Maps a collection of Service on a collection of ServiceRender
func (o *ServiceRender) RenderCollection(services []models.Env) (list []ServiceRender, err error) {
	for _, s := range services {
		var output ServiceRender
		if err := output.Render(s); err == nil {
			list = append(list, output)
		}
	}

	return list, nil
}

// ToJSON : Converts a ServiceRender to json string
func (o *ServiceRender) ToJSON() ([]byte, error) {
	return json.Marshal(o)
}

// RenderDefinition : renders service defiition steps
func RenderDefinition(service map[string]interface{}) (result []byte, err error) {
	var lines []string
	var actions = map[string]string{"create": "Create", "update": "Update", "delete": "Delete"}

	for _, change := range service["changes"].([]interface{}) {
		component := change.(map[string]interface{})
		c := component["_component"].(string)
		c = strings.Replace(c, "_", " ", -1)
		n := component["name"].(string)
		a := component["_action"].(string)
		line := actions[a] + " a " + c + " named " + n
		lines = append(lines, line)
	}

	result, err = json.Marshal(lines)
	if err != nil {
		return result, err
	}

	return result, nil
}
<commit_msg>Avoid panic on non changed dry apply<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package views

import (
	"encoding/json"
	"strings"

	"log"

	"github.com/ernestio/api-gateway/models"

	graph "gopkg.in/r3labs/graph.v2"
)

// ServiceRender : Service representation to be rendered on the frontend
type ServiceRender struct {
	ID              string              `json:"id"`
	DatacenterID    int                 `json:"datacenter_id"`
	Project         string              `json:"project"`
	Provider        string              `json:"provider"`
	Name            string              `json:"name"`
	Version         string              `json:"version"`
	Status          string              `json:"status"`
	UserID          int                 `json:"user_id"`
	UserName        string              `json:"user_name"`
	LastKnownError  string              `json:"last_known_error"`
	Options         string              `json:"options"`
	Definition      string              `json:"definition"`
	Vpcs            []map[string]string `json:"vpcs"`
	Networks        []map[string]string `json:"networks"`
	Instances       []map[string]string `json:"instances"`
	Nats            []map[string]string `json:"nats"`
	SecurityGroups  []map[string]string `json:"security_groups"`
	Elbs            []map[string]string `json:"elbs"`
	RDSClusters     []map[string]string `json:"rds_clusters"`
	RDSInstances    []map[string]string `json:"rds_instances"`
	EBSVolumes      []map[string]string `json:"ebs_volumes"`
	LoadBalancers   []map[string]string `json:"load_balancers"`
	SQLDatabases    []map[string]string `json:"sql_databases"`
	VirtualMachines []map[string]string `json:"virtual_machines"`
	Roles           []string            `json:"roles"`
}

// Render : Map a Service to a ServiceRender
func (o *ServiceRender) Render(s models.Env) (err error) {
	o.Name = s.Name
	parts := strings.Split(o.Name, models.EnvNameSeparator)
	if len(parts) > 1 {
		o.Name = parts[1]
	}
	o.ID = s.ID
	o.DatacenterID = s.DatacenterID
	o.Version = s.Version.String()
	o.Status = s.Status
	o.UserID = s.UserID
	o.UserName = s.UserName
	if def, ok := s.Definition.(string); ok == true {
		o.Definition = def
	}

	g, err := s.Mapping()
	if err != nil {
		log.Println(err.Error())
		return err
	}

	o.Vpcs = RenderVpcs(g)
	o.Networks = RenderNetworks(g)
	o.SecurityGroups = RenderSecurityGroups(g)
	o.Nats = RenderNats(g)
	o.Instances = RenderInstances(g)
	o.Elbs = RenderELBs(g)
	o.RDSClusters = RenderRDSClusters(g)
	o.RDSInstances = RenderRDSInstances(g)
	o.EBSVolumes = RenderEBSVolumes(g)
	o.LoadBalancers = RenderLoadBalancers(g)
	o.SQLDatabases = RenderSQLDatabases(g)
	o.VirtualMachines = RenderVirtualMachines(g)
	o.Roles = s.Roles
	o.Project = s.Project
	o.Provider = s.Provider

	return err
}

// RenderVpcs : renders a services vpcs
func RenderVpcs(g *graph.Graph) []map[string]string {
	var vpcs []map[string]string

	for _, n := range g.GetComponents().ByType("vpc") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["vpc_aws_id"].(string)
		subnet, _ := (*gc)["vpc_subnet"].(string)
		vpcs = append(vpcs, map[string]string{
			"name":       name,
			"vpc_id":     id,
			"vpc_subnet": subnet,
		})
	}

	return vpcs
}

// RenderNetworks : renders a services networks
func RenderNetworks(g *graph.Graph) []map[string]string {
	var networks []map[string]string

	for _, n := range g.GetComponents().ByType("network") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["network_aws_id"].(string)
		az, _ := (*gc)["availability_zone"].(string)
		networks = append(networks, map[string]string{
			"name":              name,
			"network_aws_id":    id,
			"availability_zone": az,
		})
	}

	return networks
}

// RenderSecurityGroups : renders a services security groups
func RenderSecurityGroups(g *graph.Graph) []map[string]string {
	var sgs []map[string]string

	for _, n := range g.GetComponents().ByType("firewall") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["security_group_aws_id"].(string)
		sgs = append(sgs, map[string]string{
			"name":                  name,
			"security_group_aws_id": id,
		})
	}

	return sgs
}

// RenderNats : renders a services nat gateways
func RenderNats(g *graph.Graph) []map[string]string {
	var nats []map[string]string

	for _, n := range g.GetComponents().ByType("nat") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["nat_gateway_aws_id"].(string)
		pubIP, _ := (*gc)["nat_gateway_allocation_ip"].(string)
		nats = append(nats, map[string]string{
			"name":               name,
			"nat_gateway_aws_id": id,
			"public_ip":          pubIP,
		})
	}

	return nats
}

// RenderELBs : renders a services elbs
func RenderELBs(g *graph.Graph) []map[string]string {
	var elbs []map[string]string

	for _, n := range g.GetComponents().ByType("elb") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		dns, _ := (*gc)["dns_name"].(string)
		elbs = append(elbs, map[string]string{
			"name":     name,
			"dns_name": dns,
		})
	}

	return elbs
}

// RenderInstances : renders a services instances
func RenderInstances(g *graph.Graph) []map[string]string {
	var instances []map[string]string

	for _, n := range g.GetComponents().ByType("instance") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["instance_aws_id"].(string)
		pip, _ := (*gc)["public_ip"].(string)
		ip, _ := (*gc)["ip"].(string)
		instances = append(instances, map[string]string{
			"name":            name,
			"instance_aws_id": id,
			"public_ip":       pip,
			"ip":              ip,
		})
	}

	return instances
}

// RenderRDSClusters : renders a services rds clusters
func RenderRDSClusters(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("rds_cluster") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		endpoint, _ := (*gc)["endpoint"].(string)
		rdss = append(rdss, map[string]string{
			"name":     name,
			"endpoint": endpoint,
		})
	}

	return rdss
}

// RenderRDSInstances : renders a services rds instances
func RenderRDSInstances(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("rds_instance") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		endpoint, _ := (*gc)["endpoint"].(string)
		rdss = append(rdss, map[string]string{
			"name":     name,
			"endpoint": endpoint,
		})
	}

	return rdss
}

// RenderEBSVolumes : renders a services ebs volumes
func RenderEBSVolumes(g *graph.Graph) []map[string]string {
	var rdss []map[string]string

	for _, n := range g.GetComponents().ByType("ebs_volume") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["volume_aws_id"].(string)
		rdss = append(rdss, map[string]string{
			"name":          name,
			"volume_aws_id": id,
		})
	}

	return rdss
}

// RenderLoadBalancers : renders load balancers
func RenderLoadBalancers(g *graph.Graph) []map[string]string {
	var lbs []map[string]string
	ips := listIPAddresses(g)

	for _, n := range g.GetComponents().ByType("lb") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["id"].(string)
		configs, _ := (*gc)["frontend_ip_configurations"].([]interface{})
		ip := ""
		if len(configs) > 0 {
			cfg, _ := configs[0].(map[string]interface{})
			ipID, _ := cfg["public_ip_address_id"].(string)
			ip, _ = ips[ipID]
		}

		lbs = append(lbs, map[string]string{
			"name":      name,
			"id":        id,
			"public_ip": ip,
		})
	}

	return lbs
}

func listIPAddresses(g *graph.Graph) map[string]string {
	existingIPs := make(map[string]string, 0)

	for _, ip := range g.GetComponents().ByType("public_ip") {
		gc := ip.(*graph.GenericComponent)
		id, _ := (*gc)["id"].(string)
		ipAddress, _ := (*gc)["ip_address"].(string)
		existingIPs[id] = ipAddress
	}

	return existingIPs
}

// RenderVirtualMachines : renders virtual machines
func RenderVirtualMachines(g *graph.Graph) []map[string]string {
	var resources []map[string]string
	mappedIPs := make(map[string]interface{}, 0)
	existingIPs := listIPAddresses(g)

	for _, ni := range g.GetComponents().ByType("network_interface") {
		var public []string
		var private []string

		gc := ni.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		ips := make(map[string][]string)

		configs, _ := (*gc)["ip_configuration"].([]interface{})
		for _, cfg := range configs {
			c, _ := cfg.(map[string]interface{})
			pubID, _ := c["public_ip_address_id"].(string)
			pri, _ := c["private_ip_address"].(string)
			if pub, ok := existingIPs[pubID]; ok {
				public = append(public, pub)
			}
			private = append(private, pri)
		}

		ips["public"] = public
		ips["private"] = private
		mappedIPs[name] = make(map[string][]string, 0)
		mappedIPs[name] = ips
	}

	for _, n := range g.GetComponents().ByType("virtual_machine") {
		gc := n.(*graph.GenericComponent)
		name, _ := (*gc)["name"].(string)
		id, _ := (*gc)["id"].(string)
		networks, _ := (*gc)["network_interfaces"].([]interface{})
		publicIPs := make([]string, 0)
		privateIPs := make([]string, 0)
		for _, ni := range networks {
			netName := ni.(string)
			if val, ok := mappedIPs[netName]; ok {
				ips, _ := val.(map[string][]string)
				publicIPs = append(publicIPs, ips["public"]...)
				privateIPs = append(privateIPs, ips["private"]...)
			}
		}

		resources = append(resources, map[string]string{
			"name":       name,
			"id":         id,
			"public_ip":  strings.Join(publicIPs, ", "),
			"private_ip": strings.Join(privateIPs, ", "),
		})
	}

	return resources
}

// RenderSQLDatabases : renders sql databases
func RenderSQLDatabases(g *graph.Graph) []map[string]string {
	return renderResources(g, "sql_database", func(gc *graph.GenericComponent) map[string]string {
		name, _ := (*gc)["name"].(string)
		server, _ := (*gc)["server_name"].(string)
		id, _ := (*gc)["id"].(string)

		return map[string]string{
			"name":        name,
			"server_name": server + ".database.windows.net",
			"id":          id,
		}
	})
}

type convert func(*graph.GenericComponent) map[string]string

func renderResources(g *graph.Graph, resourceType string, f convert) (resources []map[string]string) {
	for _, n := range g.GetComponents().ByType(resourceType) {
		gc := n.(*graph.GenericComponent)
		resources = append(resources, f(gc))
	}

	return
}

// RenderCollection : Maps a collection of Service on a collection of ServiceRender
func (o *ServiceRender) RenderCollection(services []models.Env) (list []ServiceRender, err error) {
	for _, s := range services {
		var output ServiceRender
		if err := output.Render(s); err == nil {
			list = append(list, output)
		}
	}

	return list, nil
}

// ToJSON : Converts a ServiceRender to json string
func (o *ServiceRender) ToJSON() ([]byte, error) {
	return json.Marshal(o)
}

// RenderDefinition : renders service defiition steps
func RenderDefinition(service map[string]interface{}) (result []byte, err error) {
	var lines []string
	var actions = map[string]string{"create": "Create", "update": "Update", "delete": "Delete"}

	if service["changes"] != nil {
		for _, change := range service["changes"].([]interface{}) {
			component := change.(map[string]interface{})
			c := component["_component"].(string)
			c = strings.Replace(c, "_", " ", -1)
			n := component["name"].(string)
			a := component["_action"].(string)
			line := actions[a] + " a " + c + " named " + n
			lines = append(lines, line)
		}
	}

	result, err = json.Marshal(lines)
	if err != nil {
		return result, err
	}

	return result, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"errors"
	"flag"
	"io/ioutil"

	"github.com/pelletier/go-toml"
	log "github.com/sirupsen/logrus"
)

type ConfigVariable struct {
	*StringVariable
	Type   ParsingType
	config configGetter
}

type configGetter interface {
	GetByVariable(string) (interface{}, error)
}

var (
	ErrFailedToLoadToml = errors.New("Failed to load toml.")
)

func (c *ConfigVariable) GetName() string {
	return c.StringVariable.Name
}

func (c *ConfigVariable) apply(interface{}) {
	log.Fatal("Config Variable does not apply values.")
}

func (c *ConfigVariable) ParseConfig(set *flag.FlagSet) error {
	// ignore error, library should handle this.
	stringPointer, _ := c.StringVariable.getFlagValue(set)
	value := stringPointer.(string)
	data, err := ioutil.ReadFile(value)
	if err != nil {
		return err
	}

	switch c.Type {
	case TomlConfig:
		tree, err := toml.Load(string(data))
		if err != nil {
			log.WithFields(log.Fields{
				"err": err,
			}).Fatal(ErrFailedToLoadToml)
			return ErrFailedToLoadToml
		}
		config := &tomlConfig{
			tree: tree,
		}
		c.config = config

		treeMap := tree.ToMap()
	default:
		log.Fatal("Unimplemented config")

	}
	return nil
}

func (c *ConfigVariable) getConfigValue(path string) (interface{}, error) {
	return c.config.GetByVariable(path)
}

type tomlConfig struct {
	tree *toml.TomlTree
}

func (t *tomlConfig) GetByVariable(path string) (interface{}, error) {
	return t.tree.Get(path), nil
}
<commit_msg>remove unused variable<commit_after>package cli

import (
	"errors"
	"flag"
	"io/ioutil"

	"github.com/pelletier/go-toml"
	log "github.com/sirupsen/logrus"
)

type ConfigVariable struct {
	*StringVariable
	Type   ParsingType
	config configGetter
}

type configGetter interface {
	GetByVariable(string) (interface{}, error)
}

var (
	ErrFailedToLoadToml = errors.New("Failed to load toml.")
)

func (c *ConfigVariable) GetName() string {
	return c.StringVariable.Name
}

func (c *ConfigVariable) apply(interface{}) {
	log.Fatal("Config Variable does not apply values.")
}

func (c *ConfigVariable) ParseConfig(set *flag.FlagSet) error {
	// ignore error, library should handle this.
	stringPointer, _ := c.StringVariable.getFlagValue(set)
	value := stringPointer.(string)
	data, err := ioutil.ReadFile(value)
	if err != nil {
		return err
	}

	switch c.Type {
	case TomlConfig:
		tree, err := toml.Load(string(data))
		if err != nil {
			log.WithFields(log.Fields{
				"err": err,
			}).Fatal(ErrFailedToLoadToml)
			return ErrFailedToLoadToml
		}
		config := &tomlConfig{
			tree: tree,
		}
		c.config = config

	default:
		log.Fatal("Unimplemented config")

	}
	return nil
}

func (c *ConfigVariable) getConfigValue(path string) (interface{}, error) {
	return c.config.GetByVariable(path)
}

type tomlConfig struct {
	tree *toml.TomlTree
}

func (t *tomlConfig) GetByVariable(path string) (interface{}, error) {
	return t.tree.Get(path), nil
}
<|endoftext|>


<commit_before>package gosql

const (
	QueryKeyAnd string = "%and" // AND 与
	QueryKeyOr         = "%or"  // OR  或
)

const (
	QueryKeyEq         string = "%eq"   // 等于
	QueryKeyNe                = "%ne"   // 不等于
	QueryKeyLt                = "%lt"   // 小于
	QueryKeyLte               = "%lte"  // 小于等于
	QueryKeyGt                = "%gt"   // 大于
	QueryKeyGte               = "%gte"  // 大于等于
	QueryKeyLike              = "%like" // 模糊搜索
	QueryKeyIn                = "%in"   // TODO: 暂时不支持
	QueryKeyBetween           = "%bt"   // 在...之间
	QueryKeyNotBetween        = "%nbt"  // 不在...之间
)

func IsQueryKey(str string) bool {
	switch str {
	case QueryKeyAnd, QueryKeyOr:
		return true
	}
	return IsQueryAnonymousKey(str)
}

func IsQueryAnonymousKey(str string) bool {
	switch str {
	case QueryKeyEq, QueryKeyNe:
		return true
	case QueryKeyLt, QueryKeyLte:
		return true
	case QueryKeyGt, QueryKeyGte:
		return true
	case QueryKeyLike:
		return true
	case QueryKeyBetween, QueryKeyNotBetween:
		return true
	}
	return false
}

type IQuery interface {
	IsAnonymous() bool
}

type QueryRoot struct {
	Values []IQuery
}

func (q *QueryRoot) IsAnonymous() bool {
	return false
}

type QueryElem struct {
	anonymous bool
	RelKey    string
	Key       string
	Values    []IQuery
}

func (q *QueryElem) IsAnonymous() bool {
	return q.anonymous
}

type QueryValue struct {
	Key   string
	Field string
	Value interface{}
}

func (q *QueryValue) IsAnonymous() bool {
	return false
}
<commit_msg>feat: new keyword 'IN'<commit_after>package gosql

const (
	QueryKeyAnd string = "%and" // AND 与
	QueryKeyOr         = "%or"  // OR  或
)

const (
	QueryKeyEq         string = "%eq"   // 等于
	QueryKeyNe                = "%ne"   // 不等于
	QueryKeyLt                = "%lt"   // 小于
	QueryKeyLte               = "%lte"  // 小于等于
	QueryKeyGt                = "%gt"   // 大于
	QueryKeyGte               = "%gte"  // 大于等于
	QueryKeyLike              = "%like" // 模糊搜索
	QueryKeyIn                = "%in"   // 在...之中
	QueryKeyBetween           = "%bt"   // 在...之间
	QueryKeyNotBetween        = "%nbt"  // 不在...之间
)

func IsQueryKey(str string) bool {
	switch str {
	case QueryKeyAnd, QueryKeyOr:
		return true
	}
	return IsQueryAnonymousKey(str)
}

func IsQueryAnonymousKey(str string) bool {
	switch str {
	case QueryKeyEq, QueryKeyNe:
		return true
	case QueryKeyLt, QueryKeyLte:
		return true
	case QueryKeyGt, QueryKeyGte:
		return true
	case QueryKeyLike:
		return true
	case QueryKeyIn:
		return true
	case QueryKeyBetween, QueryKeyNotBetween:
		return true
	}
	return false
}

type IQuery interface {
	IsAnonymous() bool
}

type QueryRoot struct {
	Values []IQuery
}

func (q *QueryRoot) IsAnonymous() bool {
	return false
}

type QueryElem struct {
	anonymous bool
	RelKey    string
	Key       string
	Values    []IQuery
}

func (q *QueryElem) IsAnonymous() bool {
	return q.anonymous
}

type QueryValue struct {
	Key   string
	Field string
	Value interface{}
}

func (q *QueryValue) IsAnonymous() bool {
	return false
}
<|endoftext|>


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

/*
Package rates 0.1.0
This package helps to manage exchange rates from any provider

Example 1: Get all exchange rates for the ECB Provider

    package main

    import (
        "fmt"

        "github.com/openprovider/rates"
        "github.com/openprovider/rates/providers"
    )

    func main() {
        registry := rates.Registry{
            // any collection of providers which implement rates.Provider interface
            providers.NewECBProvider(new(rates.Options)),
        }
        service := rates.New(registry)
        rates, errors := service.FetchLast()
        if len(errors) != 0 {
            fmt.Println(errors)
        }
        fmt.Println("European Central Bank exchange rates for today")
        for index, rate := range rates {
            fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
        }
    }

Example 2: Get exchange rates for EUR, USD, CHF, HKD

	package main

	import (
		"fmt"

		"github.com/openprovider/rates"
		"github.com/openprovider/rates/providers"
	)

	func main() {
		registry := rates.Registry{
			// any collection of providers which implement rates.Provider interface
			providers.NewECBProvider(
				&rates.Options{
					Currencies: []string{
						providers.EUR,
						providers.USD,
						providers.CHF,
						providers.HKD,
					},
				},
			),
		}
		service := rates.New(registry)
		rates, errors := service.FetchLast()
		if len(errors) != 0 {
			fmt.Println(errors)
		}
		fmt.Println("European Central Bank exchange rates for today")
		for index, rate := range rates {
			fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
		}
	}

Exchange Rates Provider
*/
package rates

import (
	"time"

	"golang.org/x/text/currency"
)

// Rate represent date and currency exchange rates
type Rate struct {
	ID       uint64        `json:"id,omitempty"`
	Date     string        `json:"date"`
	Currency string        `json:"currency"`
	Time     time.Time     `json:"-"`
	Base     currency.Unit `json:"-"`
	Unit     currency.Unit `json:"-"`
	Value    interface{}   `json:"value"`
}

// Options is some specific things for the specific provider
// It should configure the provider to manage currencies
type Options struct {
	// API key/token
	Token string
	// List of the currencies which need to get from the provider
	// If it is empty, should get all of existing currencies from the provider
	Currencies []string
	// Flexible settings list
	Settings map[string]interface{}
}

// Provider holds methods for providers which implement this interface
type Provider interface {
	FetchLast() (rates []Rate, errors []error)
	FetchHistory() (rates []Rate, errors []error)
}

// Registry contains registered providers
type Registry []Provider

// New service which contains registered providers
func New(providers ...Provider) Provider {
	var registry Registry
	for _, provider := range providers {
		registry = append(registry, provider)
	}
	return registry
}

// FetchLast returns exchange rates from all registered providers on last day
func (registry Registry) FetchLast() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchLast()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}

// FetchHistory returns exchange rates from all registered providers from history
func (registry Registry) FetchHistory() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchHistory()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}
<commit_msg>Bumped version number to 0.1.1<commit_after>// Copyright 2016 Openprovider Authors. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

/*
Package rates 0.1.1
This package helps to manage exchange rates from any provider

Example 1: Get all exchange rates for the ECB Provider

    package main

    import (
        "fmt"

        "github.com/openprovider/rates"
        "github.com/openprovider/rates/providers"
    )

    func main() {
        registry := rates.Registry{
            // any collection of providers which implement rates.Provider interface
            providers.NewECBProvider(new(rates.Options)),
        }
        service := rates.New(registry)
        rates, errors := service.FetchLast()
        if len(errors) != 0 {
            fmt.Println(errors)
        }
        fmt.Println("European Central Bank exchange rates for today")
        for index, rate := range rates {
            fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
        }
    }

Example 2: Get exchange rates for EUR, USD, CHF, HKD

	package main

	import (
		"fmt"

		"github.com/openprovider/rates"
		"github.com/openprovider/rates/providers"
	)

	func main() {
		registry := rates.Registry{
			// any collection of providers which implement rates.Provider interface
			providers.NewECBProvider(
				&rates.Options{
					Currencies: []string{
						providers.EUR,
						providers.USD,
						providers.CHF,
						providers.HKD,
					},
				},
			),
		}
		service := rates.New(registry)
		rates, errors := service.FetchLast()
		if len(errors) != 0 {
			fmt.Println(errors)
		}
		fmt.Println("European Central Bank exchange rates for today")
		for index, rate := range rates {
			fmt.Printf("%d. %s - %v\r\n", index+1, rate.Currency, rate.Value)
		}
	}

Exchange Rates Provider
*/
package rates

import (
	"time"

	"golang.org/x/text/currency"
)

// Rate represent date and currency exchange rates
type Rate struct {
	ID       uint64        `json:"id,omitempty"`
	Date     string        `json:"date"`
	Currency string        `json:"currency"`
	Time     time.Time     `json:"-"`
	Base     currency.Unit `json:"-"`
	Unit     currency.Unit `json:"-"`
	Value    interface{}   `json:"value"`
}

// Options is some specific things for the specific provider
// It should configure the provider to manage currencies
type Options struct {
	// API key/token
	Token string
	// List of the currencies which need to get from the provider
	// If it is empty, should get all of existing currencies from the provider
	Currencies []string
	// Flexible settings list
	Settings map[string]interface{}
}

// Provider holds methods for providers which implement this interface
type Provider interface {
	FetchLast() (rates []Rate, errors []error)
	FetchHistory() (rates []Rate, errors []error)
}

// Registry contains registered providers
type Registry []Provider

// New service which contains registered providers
func New(providers ...Provider) Provider {
	var registry Registry
	for _, provider := range providers {
		registry = append(registry, provider)
	}
	return registry
}

// FetchLast returns exchange rates from all registered providers on last day
func (registry Registry) FetchLast() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchLast()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}

// FetchHistory returns exchange rates from all registered providers from history
func (registry Registry) FetchHistory() (rates []Rate, errors []error) {
	for _, provider := range registry {
		r, errs := provider.FetchHistory()
		rates = append(rates, r...)
		errors = append(errors, errs...)
	}
	return
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/gobuffalo/buffalo/generators/newapp"
	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/plush"
	"github.com/markbates/inflect"
	"github.com/spf13/cobra"
)

var rootPath string
var app = &newapp.App{}

var newCmd = &cobra.Command{
	Use:   "new [name]",
	Short: "Creates a new Buffalo application",
	RunE: func(cmd *cobra.Command, args []string) error {
		if !validDbType() {
			return fmt.Errorf("Unknown db-type %s expecting one of postgres, mysql or sqlite3", app.DBType)
		}

		if len(args) == 0 {
			return errors.New("you must enter a name for your new application")
		}

		app.Name = args[0]

		if app.Name == "." {
			app.Name = filepath.Base(app.RootPath)
		} else {
			app.RootPath = filepath.Join(app.RootPath, app.Name)
		}

		err := validateInGoPath()
		if err != nil {
			return err
		}

		s, _ := os.Stat(app.RootPath)
		if s != nil {
			if app.Force {
				os.RemoveAll(app.RootPath)
			} else {
				return fmt.Errorf("%s already exists! Either delete it or use the -f flag to force", app.Name)
			}
		}

		err = genNewFiles()
		if err != nil {
			return err
		}

		fmt.Printf("Congratulations! Your application, %s, has been successfully built!\n\n", app.Name)
		fmt.Println("You can find your new application at:")
		fmt.Println(app.RootPath)
		fmt.Println("\nPlease read the README.md file in your new application for next steps on running your application.")

		return nil
	},
}

func validDbType() bool {
	return app.DBType == "postgres" || app.DBType == "mysql" || app.DBType == "sqlite3"
}

func validateInGoPath() error {
	gpMultiple := envy.GoPaths()

	var gp string
	for i := 0; i < len(gpMultiple); i++ {
		if strings.HasPrefix(app.RootPath, filepath.Join(gpMultiple[i], "src")) {
			gp = gpMultiple[i]
			break
		}
	}

	if gp == "" {
		u, err := user.Current()
		if err != nil {
			return err
		}
		t, err := plush.Render(notInGoWorkspace, plush.NewContextWith(map[string]interface{}{
			"name":     app.Name,
			"gopath":   envy.GoPath(),
			"current":  app.RootPath,
			"username": u.Username,
		}))
		if err != nil {
			return err
		}
		fmt.Println(t)
		os.Exit(-1)
	}
	return nil
}

func goPath(root string) string {
	gpMultiple := envy.GoPaths()
	path := ""

	for i := 0; i < len(gpMultiple); i++ {
		if strings.HasPrefix(root, filepath.Join(gpMultiple[i], "src")) {
			path = gpMultiple[i]
			break
		}
	}
	return path
}

func packagePath(rootPath string) string {
	gosrcpath := strings.Replace(filepath.Join(goPath(rootPath), "src"), "\\", "/", -1)
	rootPath = strings.Replace(rootPath, "\\", "/", -1)
	return strings.Replace(rootPath, gosrcpath+"/", "", 2)
}

func genNewFiles() error {
	packagePath := packagePath(app.RootPath)

	data := map[string]interface{}{
		"name":        app.Name,
		"titleName":   inflect.Titleize(app.Name),
		"packagePath": packagePath,
		"actionsPath": packagePath + "/actions",
		"modelsPath":  packagePath + "/models",
		"withPop":     !app.SkipPop,
		"withWebpack": !app.SkipWebpack,
		"dbType":      app.DBType,
		"version":     Version,
		"ciProvider":  app.CIProvider,
	}
	if app.WithYarn {
		data["withYarn"] = true
	}

	g, err := app.Generator(data)
	if err != nil {
		return err
	}
	return g.Run(app.RootPath, data)
}

func init() {
	pwd, _ := os.Getwd()

	rootPath = pwd
	app.RootPath = pwd

	RootCmd.AddCommand(newCmd)
	newCmd.Flags().BoolVarP(&app.Force, "force", "f", false, "delete and remake if the app already exists")
	newCmd.Flags().BoolVarP(&app.Verbose, "verbose", "v", false, "verbosely print out the go get/install commands")
	newCmd.Flags().BoolVar(&app.SkipPop, "skip-pop", false, "skips adding pop/soda to your app")
	newCmd.Flags().BoolVar(&app.SkipWebpack, "skip-webpack", false, "skips adding Webpack to your app")
	newCmd.Flags().BoolVar(&app.WithYarn, "with-yarn", false, "allows the use of yarn instead of npm as dependency manager")
	newCmd.Flags().StringVar(&app.DBType, "db-type", "postgres", "specify the type of database you want to use [postgres, mysql, sqlite3]")
	newCmd.Flags().StringVar(&app.CIProvider, "ci-provider", "none", "specify the type of ci file you would like buffalo to generate [none, travis, gitlab-ci]")
}

const notInGoWorkspace = `Oops! It would appear that you are not in your Go Workspace.

Your $GOPATH is set to "<%= gopath %>".

You are currently in "<%= current %>".

The standard location for putting Go projects is something along the lines of "$GOPATH/src/github.com/<%= username %>/<%= name %>" (adjust accordingly).

We recommend you go to "$GOPATH/src/github.com/<%= username %>/" and try "buffalo new <%= name %>" again.`

const noGoPath = `You do not have a $GOPATH set. In order to work with Go, you must set up your $GOPATH and your Go Workspace.

We recommend reading this tutorial on setting everything up: https://www.goinggo.net/2016/05/installing-go-and-your-workspace.html

When you're ready come back and try again. Don't worry, Buffalo will be right here waiting for you. :)`
<commit_msg>ignore case when checking if the user is in the GOPATH. fixes #340<commit_after>package cmd

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/gobuffalo/buffalo/generators/newapp"
	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/plush"
	"github.com/markbates/inflect"
	"github.com/spf13/cobra"
)

var rootPath string
var app = &newapp.App{}

var newCmd = &cobra.Command{
	Use:   "new [name]",
	Short: "Creates a new Buffalo application",
	RunE: func(cmd *cobra.Command, args []string) error {
		if !validDbType() {
			return fmt.Errorf("Unknown db-type %s expecting one of postgres, mysql or sqlite3", app.DBType)
		}

		if len(args) == 0 {
			return errors.New("you must enter a name for your new application")
		}

		app.Name = args[0]

		if app.Name == "." {
			app.Name = filepath.Base(app.RootPath)
		} else {
			app.RootPath = filepath.Join(app.RootPath, app.Name)
		}

		err := validateInGoPath()
		if err != nil {
			return err
		}

		s, _ := os.Stat(app.RootPath)
		if s != nil {
			if app.Force {
				os.RemoveAll(app.RootPath)
			} else {
				return fmt.Errorf("%s already exists! Either delete it or use the -f flag to force", app.Name)
			}
		}

		err = genNewFiles()
		if err != nil {
			return err
		}

		fmt.Printf("Congratulations! Your application, %s, has been successfully built!\n\n", app.Name)
		fmt.Println("You can find your new application at:")
		fmt.Println(app.RootPath)
		fmt.Println("\nPlease read the README.md file in your new application for next steps on running your application.")

		return nil
	},
}

func validDbType() bool {
	return app.DBType == "postgres" || app.DBType == "mysql" || app.DBType == "sqlite3"
}

func validateInGoPath() error {
	gpMultiple := envy.GoPaths()

	var gp string
	larp := strings.ToLower(app.RootPath)
	for i := 0; i < len(gpMultiple); i++ {
		lgpm := strings.ToLower(filepath.Join(gpMultiple[i], "src"))
		if strings.HasPrefix(larp, lgpm) {
			gp = gpMultiple[i]
			break
		}
	}

	if gp == "" {
		u, err := user.Current()
		if err != nil {
			return err
		}
		t, err := plush.Render(notInGoWorkspace, plush.NewContextWith(map[string]interface{}{
			"name":     app.Name,
			"gopath":   envy.GoPath(),
			"current":  app.RootPath,
			"username": u.Username,
		}))
		if err != nil {
			return err
		}
		fmt.Println(t)
		os.Exit(-1)
	}
	return nil
}

func goPath(root string) string {
	gpMultiple := envy.GoPaths()
	path := ""

	for i := 0; i < len(gpMultiple); i++ {
		if strings.HasPrefix(root, filepath.Join(gpMultiple[i], "src")) {
			path = gpMultiple[i]
			break
		}
	}
	return path
}

func packagePath(rootPath string) string {
	gosrcpath := strings.Replace(filepath.Join(goPath(rootPath), "src"), "\\", "/", -1)
	rootPath = strings.Replace(rootPath, "\\", "/", -1)
	return strings.Replace(rootPath, gosrcpath+"/", "", 2)
}

func genNewFiles() error {
	packagePath := packagePath(app.RootPath)

	data := map[string]interface{}{
		"name":        app.Name,
		"titleName":   inflect.Titleize(app.Name),
		"packagePath": packagePath,
		"actionsPath": packagePath + "/actions",
		"modelsPath":  packagePath + "/models",
		"withPop":     !app.SkipPop,
		"withWebpack": !app.SkipWebpack,
		"dbType":      app.DBType,
		"version":     Version,
		"ciProvider":  app.CIProvider,
	}
	if app.WithYarn {
		data["withYarn"] = true
	}

	g, err := app.Generator(data)
	if err != nil {
		return err
	}
	return g.Run(app.RootPath, data)
}

func init() {
	pwd, _ := os.Getwd()

	rootPath = pwd
	app.RootPath = pwd

	RootCmd.AddCommand(newCmd)
	newCmd.Flags().BoolVarP(&app.Force, "force", "f", false, "delete and remake if the app already exists")
	newCmd.Flags().BoolVarP(&app.Verbose, "verbose", "v", false, "verbosely print out the go get/install commands")
	newCmd.Flags().BoolVar(&app.SkipPop, "skip-pop", false, "skips adding pop/soda to your app")
	newCmd.Flags().BoolVar(&app.SkipWebpack, "skip-webpack", false, "skips adding Webpack to your app")
	newCmd.Flags().BoolVar(&app.WithYarn, "with-yarn", false, "allows the use of yarn instead of npm as dependency manager")
	newCmd.Flags().StringVar(&app.DBType, "db-type", "postgres", "specify the type of database you want to use [postgres, mysql, sqlite3]")
	newCmd.Flags().StringVar(&app.CIProvider, "ci-provider", "none", "specify the type of ci file you would like buffalo to generate [none, travis, gitlab-ci]")
}

const notInGoWorkspace = `Oops! It would appear that you are not in your Go Workspace.

Your $GOPATH is set to "<%= gopath %>".

You are currently in "<%= current %>".

The standard location for putting Go projects is something along the lines of "$GOPATH/src/github.com/<%= username %>/<%= name %>" (adjust accordingly).

We recommend you go to "$GOPATH/src/github.com/<%= username %>/" and try "buffalo new <%= name %>" again.`

const noGoPath = `You do not have a $GOPATH set. In order to work with Go, you must set up your $GOPATH and your Go Workspace.

We recommend reading this tutorial on setting everything up: https://www.goinggo.net/2016/05/installing-go-and-your-workspace.html

When you're ready come back and try again. Don't worry, Buffalo will be right here waiting for you. :)`
<|endoftext|>


<commit_before>package rbg2p

import (
	"fmt"
	"os"
	"reflect"
	"sort"
	"strings"
	"sync"

	"github.com/dlclark/regexp2"
)

var Debug = false

// Context in which the rule applies (left hand/right hand context specified by a regular expression)
type Context struct {
	// Input is the regexp as written in the input string
	Input string

	// Regexp is the input string converted to a regular expression for internal use (with variables expanded, and adapted anchoring)
	Regexp *regexp2.Regexp
}

// Matches checks if the input string matches the context rule
func (c Context) Matches(s string) (bool, error) {
	if c.IsDefined() {
		res, err := c.Regexp.MatchString(s)
		if err != nil {
			return false, err
		}
		return res, nil
	}
	return true, nil
}

// IsDefined returns true if the contained regexp is defined
func (c Context) IsDefined() bool {
	return (nil != c.Regexp)
}

// String returns a string representation of the Context
func (c Context) String() string {
	if c.IsDefined() {
		return c.Input
	}
	return ""
}

// equals checks for equality (including underlying regexps); used for unit tests
func (c Context) equals(c2 Context) bool {
	if c.IsDefined() && !c2.IsDefined() {
		return false
	} else if c2.IsDefined() && !c.IsDefined() {
		return false
	} else if !c2.IsDefined() && !c.IsDefined() {
		return true
	}
	return c.Input == c2.Input
}

// Filter is a regexp filter for rules that cannot be expressed using the standard rule systme
type Filter struct {
	Regexp *regexp2.Regexp
	Output string
}

// Apply is used to apply the filter to an input string
func (f Filter) Apply(s string) (string, error) {
	//return f.Regexp.ReplaceAllString(s, f.Output)
	return f.Regexp.Replace(s, f.Output, -1, -1)
}

// Rule is a g2p rule representation
type Rule struct {
	Input        string
	Output       []string
	LeftContext  Context
	RightContext Context
	LineNumber   int // for debugging
}

// String returns a string representation of the Rule
func (r Rule) String() string {
	var output string
	if len(r.Output) == 1 {
		output = r.Output[0]
	} else {
		output = fmt.Sprintf("(%s)", strings.Join(r.Output, ", "))
	}
	return fmt.Sprintf("%s -> %s / %s _ %s", r.Input, output, r.LeftContext, r.RightContext)
}

// equals: checks for equality (including underlying slices and regexps); used for unit tests
func (r Rule) equals(r2 Rule) bool {
	return r.Input == r2.Input &&
		reflect.DeepEqual(r.Output, r2.Output) &&
		r.LeftContext.equals(r2.LeftContext) &&
		r.RightContext.equals(r2.RightContext)
}

// equalsExceptOutput: checks for equality except for output (including underlying slices and regexps); used for unit tests
func (r Rule) equalsExceptOutput(r2 Rule) bool {
	return r.Input == r2.Input &&
		r.LeftContext.equals(r2.LeftContext) &&
		r.RightContext.equals(r2.RightContext)
}

// Test defines a rule test (input -> output)
type Test struct {
	Input  string
	Output []string
}

// equals checks for equality (including underlying slices); used for unit tests
func (t1 Test) equals(t2 Test) bool {
	return t1.Input == t2.Input && reflect.DeepEqual(t1.Output, t2.Output)
}

// RuleSet is a set of g2p rules, with variables and built-in tests
type RuleSet struct {
	CharacterSet      []string
	PhonemeSet        PhonemeSet
	PhonemeDelimiter  string
	SyllableDelimiter string
	DefaultPhoneme    string
	DowncaseInput     bool
	Vars              map[string]string
	Rules             []Rule
	RulesAppliedMutex *sync.RWMutex
	RulesApplied      map[string]int // for coverage checks
	Tests             []Test
	Filters           []Filter
	Syllabifier       Syllabifier
	Content           string
}

func (rs RuleSet) checkForUnusedChars(coveredChars map[string]bool, individualChars map[string]bool, validation *TestResult) {
	var errors = []string{}
	for _, char := range rs.CharacterSet {
		if _, ok := individualChars[char]; !ok {
			errors = append(errors, char)
		}
	}
	sort.Strings(errors)
	if len(errors) > 0 {
		validation.Errors = append(validation.Errors, fmt.Sprintf("no default rule for character(s): %s", strings.Join(errors, ",")))
	}
}

func (rs RuleSet) checkForUndefinedChars(coveredChars map[string]bool, individualChars map[string]bool, validation *TestResult) {
	var definedChars = make(map[string]bool)
	var errors = []string{}
	for _, char := range rs.CharacterSet {
		definedChars[char] = true
	}
	for char := range individualChars {
		for _, ch := range strings.Split(char, "") {
			if _, ok := definedChars[ch]; !ok {
				errors = append(errors, ch)
			}
		}
	}
	sort.Strings(errors)
	if len(errors) > 0 {
		validation.Errors = append(validation.Errors, fmt.Sprintf("undefined character(s) used in rule set: %s", strings.Join(errors, ",")))
	}
}

func (rs RuleSet) hasPhonemeSet() bool {
	return len(rs.PhonemeSet.Symbols) > 0
}

// Test runs the built-in tests. Returns a test result with errors and warnings, if any.
func (rs RuleSet) Test() TestResult {
	var result = TestResult{}
	var coveredChars = map[string]bool{}
	var individualChars = map[string]bool{}
	for _, rule := range rs.Rules {
		for _, char := range strings.Split(rule.Input, "") {
			coveredChars[char] = true
		}
		coveredChars[rule.Input] = true
		if !rule.LeftContext.IsDefined() && !rule.RightContext.IsDefined() {
			individualChars[rule.Input] = true
		}
	}
	rs.checkForUnusedChars(coveredChars, individualChars, &result)
	rs.checkForUndefinedChars(coveredChars, individualChars, &result)

	if rs.hasPhonemeSet() {
		validation, err := compareToPhonemeSet(rs)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("%v", err))
		}
		result.Warnings = append(result.Warnings, validation.Warnings...)
		result.Errors = append(result.Errors, validation.Errors...)
	}

	for _, test := range rs.Tests {
		input := test.Input
		expect := test.Output
		if rs.DowncaseInput {
			input = strings.ToLower(input)
		}
		res, err := rs.Apply(input)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("%v", err))
		}
		//delim := rs.PhonemeDelimiter
		if !reflect.DeepEqual(expect, res) {
			result.FailedTests = append(result.FailedTests, fmt.Sprintf("for '%s', expected /%s/, got /%s/", input, strings.Join(expect, "/ + /"), strings.Join(res, "/ + /")))
		}
	}
	return result
}

func (rs RuleSet) expandLoop(head g2p, tail []g2p, acc []trans) []trans {
	res := []trans{}
	for i := 0; i < len(acc); i++ {
		for _, add := range head.p {
			appendRange := []g2p{}
			// build prefix from previous rounds
			appendRange = append(appendRange, acc[i].phonemes...)
			// append current phonemes
			g2p := g2p{g: head.g, p: strings.Split(add, rs.PhonemeDelimiter)}
			appendRange = append(appendRange, g2p)
			res = append(res, trans{phonemes: appendRange})
		}

	}
	if len(tail) == 0 {
		return res
	}
	return rs.expandLoop(tail[0], tail[1:], res)
}

func (rs RuleSet) expand(phonemes []g2p) []trans {
	if len(phonemes) > 1 {
		return rs.expandLoop(phonemes[0], phonemes[1:], []trans{{}})
	} else if len(phonemes) == 1 {
		return rs.expandLoop(phonemes[0], []g2p{}, []trans{{}})
	}
	// empty trans
	return []trans{}
}

func (rs RuleSet) applyFilters(trans string) (string, error) {
	res := trans
	var err error
	for _, f := range rs.Filters {
		res, err = f.Apply(res)
		if err != nil {
			return res, fmt.Errorf("couldn't execute regexp : %s", err)
		}
		//HB
		//fmt.Printf("FILTER: %s\nRES: %s\n", f, res)
	}
	return res, nil
}

// Apply applies the rules to an input string, returns a slice of transcriptions. If unknown input characters are found, an error will be created, and an underscore will be appended to the transcription. Even if an error is returned, the loop will continue until the end of the input string.
func (rs RuleSet) Apply(s string) ([]string, error) {
	var i = 0
	if rs.DowncaseInput {
		s = strings.ToLower(s)
	}
	var s0 = []rune(s)
	res := []g2p{}
	var couldntMap = []string{}
	for i < len(s0) {
		ss := string(s0[i:])
		thisChar := string(s0[i : i+1])
		left := string(s0[0:i])
		var matchFound = false
		for _, rule := range rs.Rules {
			leftMatch, err := rule.LeftContext.Matches(left)
			if err != nil {
				return []string{}, fmt.Errorf("couldn't execute regexp /%s/ : %s", rule.LeftContext.Regexp, err)
			}
			if strings.HasPrefix(ss, rule.Input) && leftMatch {
				ruleInputLen := len([]rune(rule.Input))
				right := string(s0[i+ruleInputLen:])
				rightMatch, err := rule.RightContext.Matches(right)
				if err != nil {
					return []string{}, fmt.Errorf("couldn't execute regexp /%s/ : %s", rule.RightContext.Regexp, err)
				}
				if rightMatch {
					i = i + ruleInputLen
					res = append(res, g2p{g: rule.Input, p: rule.Output})
					matchFound = true
					ruleString := rule.String()
					rs.RulesAppliedMutex.Lock()
					rs.RulesApplied[ruleString]++
					rs.RulesAppliedMutex.Unlock()
					if Debug {
						fmt.Fprintf(os.Stderr, "%s\t%v\t%v\t%v\t%v\n", "RULE APPLIED", rule, s, ss, res)
					}
					break
				}
			}
		}
		if !matchFound {
			res = append(res, g2p{g: thisChar, p: []string{rs.DefaultPhoneme}})
			i = i + 1
			couldntMap = append(couldntMap, thisChar)
		}
	}
	expanded := rs.expand(res)

	transes := []string{}
	for _, t := range expanded {
		if rs.Syllabifier.IsDefined() {
			s := rs.Syllabifier.syllabifyToString(t)
			transes = append(transes, s)
		} else {
			transes = append(transes, t.string(rs.PhonemeDelimiter))
		}
	}
	var filtered []string
	for _, t := range transes {
		fted, err := rs.applyFilters(t)
		if err != nil {
			return filtered, err
		}
		filtered = append(filtered, fted)
	}
	if len(couldntMap) > 0 {
		return filtered, fmt.Errorf("found unmappable symbol(s) in input string: %v in %s", couldntMap, s)
	}
	return filtered, nil
}

// compareToPhonemeSet validates the phonemes in the g2p rule set against the specified phonemeset. Returns an array of invalid phonemes, if any; or if errors are found, this is returned instead.
func compareToPhonemeSet(ruleSet RuleSet) (TestResult, error) {
	var validation = TestResult{}
	var usedSymbols = map[string]bool{}
	for _, rule := range ruleSet.Rules {
		for _, output := range rule.Output {
			invalid, err := ruleSet.PhonemeSet.validate(output)
			if err != nil {
				return TestResult{}, fmt.Errorf("found error in rule output /%s/ : %s", output, err)
			}
			splitted, err := ruleSet.PhonemeSet.SplitTranscription(output)
			if err != nil {
				return TestResult{}, err
			}
			for _, symbol := range splitted {
				usedSymbols[symbol] = true
			}

			for _, symbol := range invalid {
				validation.Errors = append(validation.Errors, fmt.Sprintf("invalid symbol in rule output %s: %s", rule, symbol))
			}
		}
	}
	for _, test := range ruleSet.Tests {
		for _, output := range test.Output {
			invalid, err := ruleSet.PhonemeSet.validate(output)
			if err != nil {
				return TestResult{}, fmt.Errorf("found error in test output /%s/ : %s", output, err)
			}
			splitted, err := ruleSet.PhonemeSet.SplitTranscription(output)
			if err != nil {
				return TestResult{}, err
			}
			for _, symbol := range splitted {
				usedSymbols[symbol] = true
			}
			for _, symbol := range invalid {
				validation.Errors = append(validation.Errors, fmt.Sprintf("invalid symbol in test output %s: %s", test, symbol))
			}

		}
	}
	validation.Warnings = append(validation.Warnings, checkForUnusedSymbols(usedSymbols, ruleSet.PhonemeSet)...)
	return validation, nil
}
<commit_msg>ruleset checks if it's initialized before Apply can be run<commit_after>package rbg2p

import (
	"fmt"
	"os"
	"reflect"
	"sort"
	"strings"
	"sync"

	"github.com/dlclark/regexp2"
)

var Debug = false

// Context in which the rule applies (left hand/right hand context specified by a regular expression)
type Context struct {
	// Input is the regexp as written in the input string
	Input string

	// Regexp is the input string converted to a regular expression for internal use (with variables expanded, and adapted anchoring)
	Regexp *regexp2.Regexp
}

// Matches checks if the input string matches the context rule
func (c Context) Matches(s string) (bool, error) {
	if c.IsDefined() {
		res, err := c.Regexp.MatchString(s)
		if err != nil {
			return false, err
		}
		return res, nil
	}
	return true, nil
}

// IsDefined returns true if the contained regexp is defined
func (c Context) IsDefined() bool {
	return (nil != c.Regexp)
}

// String returns a string representation of the Context
func (c Context) String() string {
	if c.IsDefined() {
		return c.Input
	}
	return ""
}

// equals checks for equality (including underlying regexps); used for unit tests
func (c Context) equals(c2 Context) bool {
	if c.IsDefined() && !c2.IsDefined() {
		return false
	} else if c2.IsDefined() && !c.IsDefined() {
		return false
	} else if !c2.IsDefined() && !c.IsDefined() {
		return true
	}
	return c.Input == c2.Input
}

// Filter is a regexp filter for rules that cannot be expressed using the standard rule systme
type Filter struct {
	Regexp *regexp2.Regexp
	Output string
}

// Apply is used to apply the filter to an input string
func (f Filter) Apply(s string) (string, error) {
	//return f.Regexp.ReplaceAllString(s, f.Output)
	return f.Regexp.Replace(s, f.Output, -1, -1)
}

// Rule is a g2p rule representation
type Rule struct {
	Input        string
	Output       []string
	LeftContext  Context
	RightContext Context
	LineNumber   int // for debugging
}

// String returns a string representation of the Rule
func (r Rule) String() string {
	var output string
	if len(r.Output) == 1 {
		output = r.Output[0]
	} else {
		output = fmt.Sprintf("(%s)", strings.Join(r.Output, ", "))
	}
	return fmt.Sprintf("%s -> %s / %s _ %s", r.Input, output, r.LeftContext, r.RightContext)
}

// equals: checks for equality (including underlying slices and regexps); used for unit tests
func (r Rule) equals(r2 Rule) bool {
	return r.Input == r2.Input &&
		reflect.DeepEqual(r.Output, r2.Output) &&
		r.LeftContext.equals(r2.LeftContext) &&
		r.RightContext.equals(r2.RightContext)
}

// equalsExceptOutput: checks for equality except for output (including underlying slices and regexps); used for unit tests
func (r Rule) equalsExceptOutput(r2 Rule) bool {
	return r.Input == r2.Input &&
		r.LeftContext.equals(r2.LeftContext) &&
		r.RightContext.equals(r2.RightContext)
}

// Test defines a rule test (input -> output)
type Test struct {
	Input  string
	Output []string
}

// equals checks for equality (including underlying slices); used for unit tests
func (t1 Test) equals(t2 Test) bool {
	return t1.Input == t2.Input && reflect.DeepEqual(t1.Output, t2.Output)
}

// RuleSet is a set of g2p rules, with variables and built-in tests
type RuleSet struct {
	CharacterSet      []string
	PhonemeSet        PhonemeSet
	PhonemeDelimiter  string
	SyllableDelimiter string
	DefaultPhoneme    string
	DowncaseInput     bool
	Vars              map[string]string
	Rules             []Rule
	RulesAppliedMutex *sync.RWMutex
	RulesApplied      map[string]int // for coverage checks
	Tests             []Test
	Filters           []Filter
	Syllabifier       Syllabifier
	Content           string
}

func (rs RuleSet) isInitialized() bool {
	return len(rs.Rules) > 0
}

func (rs RuleSet) checkForUnusedChars(coveredChars map[string]bool, individualChars map[string]bool, validation *TestResult) {
	var errors = []string{}
	for _, char := range rs.CharacterSet {
		if _, ok := individualChars[char]; !ok {
			errors = append(errors, char)
		}
	}
	sort.Strings(errors)
	if len(errors) > 0 {
		validation.Errors = append(validation.Errors, fmt.Sprintf("no default rule for character(s): %s", strings.Join(errors, ",")))
	}
}

func (rs RuleSet) checkForUndefinedChars(coveredChars map[string]bool, individualChars map[string]bool, validation *TestResult) {
	var definedChars = make(map[string]bool)
	var errors = []string{}
	for _, char := range rs.CharacterSet {
		definedChars[char] = true
	}
	for char := range individualChars {
		for _, ch := range strings.Split(char, "") {
			if _, ok := definedChars[ch]; !ok {
				errors = append(errors, ch)
			}
		}
	}
	sort.Strings(errors)
	if len(errors) > 0 {
		validation.Errors = append(validation.Errors, fmt.Sprintf("undefined character(s) used in rule set: %s", strings.Join(errors, ",")))
	}
}

func (rs RuleSet) hasPhonemeSet() bool {
	return len(rs.PhonemeSet.Symbols) > 0
}

// Test runs the built-in tests. Returns a test result with errors and warnings, if any.
func (rs RuleSet) Test() TestResult {
	var result = TestResult{}
	var coveredChars = map[string]bool{}
	var individualChars = map[string]bool{}
	for _, rule := range rs.Rules {
		for _, char := range strings.Split(rule.Input, "") {
			coveredChars[char] = true
		}
		coveredChars[rule.Input] = true
		if !rule.LeftContext.IsDefined() && !rule.RightContext.IsDefined() {
			individualChars[rule.Input] = true
		}
	}
	rs.checkForUnusedChars(coveredChars, individualChars, &result)
	rs.checkForUndefinedChars(coveredChars, individualChars, &result)

	if rs.hasPhonemeSet() {
		validation, err := compareToPhonemeSet(rs)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("%v", err))
		}
		result.Warnings = append(result.Warnings, validation.Warnings...)
		result.Errors = append(result.Errors, validation.Errors...)
	}

	for _, test := range rs.Tests {
		input := test.Input
		expect := test.Output
		if rs.DowncaseInput {
			input = strings.ToLower(input)
		}
		res, err := rs.Apply(input)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("%v", err))
		}
		//delim := rs.PhonemeDelimiter
		if !reflect.DeepEqual(expect, res) {
			result.FailedTests = append(result.FailedTests, fmt.Sprintf("for '%s', expected /%s/, got /%s/", input, strings.Join(expect, "/ + /"), strings.Join(res, "/ + /")))
		}
	}
	return result
}

func (rs RuleSet) expandLoop(head g2p, tail []g2p, acc []trans) []trans {
	res := []trans{}
	for i := 0; i < len(acc); i++ {
		for _, add := range head.p {
			appendRange := []g2p{}
			// build prefix from previous rounds
			appendRange = append(appendRange, acc[i].phonemes...)
			// append current phonemes
			g2p := g2p{g: head.g, p: strings.Split(add, rs.PhonemeDelimiter)}
			appendRange = append(appendRange, g2p)
			res = append(res, trans{phonemes: appendRange})
		}

	}
	if len(tail) == 0 {
		return res
	}
	return rs.expandLoop(tail[0], tail[1:], res)
}

func (rs RuleSet) expand(phonemes []g2p) []trans {
	if len(phonemes) > 1 {
		return rs.expandLoop(phonemes[0], phonemes[1:], []trans{{}})
	} else if len(phonemes) == 1 {
		return rs.expandLoop(phonemes[0], []g2p{}, []trans{{}})
	}
	// empty trans
	return []trans{}
}

func (rs RuleSet) applyFilters(trans string) (string, error) {
	res := trans
	var err error
	for _, f := range rs.Filters {
		res, err = f.Apply(res)
		if err != nil {
			return res, fmt.Errorf("couldn't execute regexp : %s", err)
		}
		//HB
		//fmt.Printf("FILTER: %s\nRES: %s\n", f, res)
	}
	return res, nil
}

// Apply applies the rules to an input string, returns a slice of transcriptions. If unknown input characters are found, an error will be created, and an underscore will be appended to the transcription. Even if an error is returned, the loop will continue until the end of the input string.
func (rs RuleSet) Apply(s string) ([]string, error) {
	if !rs.isInitialized() {
		return []string{}, fmt.Errorf("RuleSet is not initialized")
	}

	var i = 0
	if rs.DowncaseInput {
		s = strings.ToLower(s)
	}
	var s0 = []rune(s)
	res := []g2p{}
	var couldntMap = []string{}
	for i < len(s0) {
		ss := string(s0[i:])
		thisChar := string(s0[i : i+1])
		left := string(s0[0:i])
		var matchFound = false
		for _, rule := range rs.Rules {
			leftMatch, err := rule.LeftContext.Matches(left)
			if err != nil {
				return []string{}, fmt.Errorf("couldn't execute regexp /%s/ : %s", rule.LeftContext.Regexp, err)
			}
			if strings.HasPrefix(ss, rule.Input) && leftMatch {
				ruleInputLen := len([]rune(rule.Input))
				right := string(s0[i+ruleInputLen:])
				rightMatch, err := rule.RightContext.Matches(right)
				if err != nil {
					return []string{}, fmt.Errorf("couldn't execute regexp /%s/ : %s", rule.RightContext.Regexp, err)
				}
				if rightMatch {
					i = i + ruleInputLen
					res = append(res, g2p{g: rule.Input, p: rule.Output})
					matchFound = true
					ruleString := rule.String()
					rs.RulesAppliedMutex.Lock()
					rs.RulesApplied[ruleString]++
					rs.RulesAppliedMutex.Unlock()
					if Debug {
						fmt.Fprintf(os.Stderr, "%s\t%v\t%v\t%v\t%v\n", "RULE APPLIED", rule, s, ss, res)
					}
					break
				}
			}
		}
		if !matchFound {
			res = append(res, g2p{g: thisChar, p: []string{rs.DefaultPhoneme}})
			i = i + 1
			couldntMap = append(couldntMap, thisChar)
		}
	}
	expanded := rs.expand(res)

	transes := []string{}
	for _, t := range expanded {
		if rs.Syllabifier.IsDefined() {
			s := rs.Syllabifier.syllabifyToString(t)
			transes = append(transes, s)
		} else {
			transes = append(transes, t.string(rs.PhonemeDelimiter))
		}
	}
	var filtered []string
	for _, t := range transes {
		fted, err := rs.applyFilters(t)
		if err != nil {
			return filtered, err
		}
		filtered = append(filtered, fted)
	}
	if len(couldntMap) > 0 {
		return filtered, fmt.Errorf("found unmappable symbol(s) in input string: %v in %s", couldntMap, s)
	}
	return filtered, nil
}

// compareToPhonemeSet validates the phonemes in the g2p rule set against the specified phonemeset. Returns an array of invalid phonemes, if any; or if errors are found, this is returned instead.
func compareToPhonemeSet(ruleSet RuleSet) (TestResult, error) {
	var validation = TestResult{}
	var usedSymbols = map[string]bool{}
	for _, rule := range ruleSet.Rules {
		for _, output := range rule.Output {
			invalid, err := ruleSet.PhonemeSet.validate(output)
			if err != nil {
				return TestResult{}, fmt.Errorf("found error in rule output /%s/ : %s", output, err)
			}
			splitted, err := ruleSet.PhonemeSet.SplitTranscription(output)
			if err != nil {
				return TestResult{}, err
			}
			for _, symbol := range splitted {
				usedSymbols[symbol] = true
			}

			for _, symbol := range invalid {
				validation.Errors = append(validation.Errors, fmt.Sprintf("invalid symbol in rule output %s: %s", rule, symbol))
			}
		}
	}
	for _, test := range ruleSet.Tests {
		for _, output := range test.Output {
			invalid, err := ruleSet.PhonemeSet.validate(output)
			if err != nil {
				return TestResult{}, fmt.Errorf("found error in test output /%s/ : %s", output, err)
			}
			splitted, err := ruleSet.PhonemeSet.SplitTranscription(output)
			if err != nil {
				return TestResult{}, err
			}
			for _, symbol := range splitted {
				usedSymbols[symbol] = true
			}
			for _, symbol := range invalid {
				validation.Errors = append(validation.Errors, fmt.Sprintf("invalid symbol in test output %s: %s", test, symbol))
			}

		}
	}
	validation.Warnings = append(validation.Warnings, checkForUnusedSymbols(usedSymbols, ruleSet.PhonemeSet)...)
	return validation, nil
}
<|endoftext|>


<commit_before>package redis

import (
	"crypto/tls"
	"net"
	"sync"
)

type OpenConnFunc func() (net.Conn, error)
type CloseConnFunc func(net.Conn) error
type InitConnFunc func(*Client) error

func TCPConnector(addr string) OpenConnFunc {
	return func() (net.Conn, error) {
		return net.Dial("tcp", addr)
	}
}

func TLSConnector(addr string, tlsConfig *tls.Config) OpenConnFunc {
	return func() (net.Conn, error) {
		return tls.Dial("tcp", addr, tlsConfig)
	}
}

func AuthSelectFunc(password string, db int64) InitConnFunc {
	if password == "" && db < 0 {
		return nil
	}

	return func(client *Client) error {
		if password != "" {
			auth := client.Auth(password)
			if auth.Err() != nil {
				return auth.Err()
			}
		}

		if db >= 0 {
			sel := client.Select(db)
			if sel.Err() != nil {
				return sel.Err()
			}
		}

		return nil
	}
}

//------------------------------------------------------------------------------

type BaseClient struct {
	mtx      sync.Mutex
	ConnPool ConnPool
	InitConn InitConnFunc
	reqs     []Req
}

func (c *BaseClient) WriteReq(conn *Conn, reqs ...Req) error {
	buf := make([]byte, 0, 1000)
	for _, req := range reqs {
		buf = appendReq(buf, req.Args())
	}

	_, err := conn.RW.Write(buf)
	return err
}

func (c *BaseClient) conn() (*Conn, error) {
	conn, isNew, err := c.ConnPool.Get()
	if err != nil {
		return nil, err
	}

	if isNew && c.InitConn != nil {
		client := &Client{
			BaseClient: &BaseClient{
				ConnPool: NewSingleConnPoolConn(c.ConnPool, conn, true),
			},
		}
		err = c.InitConn(client)
		if err != nil {
			if err := c.ConnPool.Remove(conn); err != nil {
				panic(err)
			}
			return nil, err
		}
	}
	return conn, nil
}

func (c *BaseClient) Process(req Req) {
	if c.reqs == nil {
		c.Run(req)
	} else {
		c.Queue(req)
	}
}

func (c *BaseClient) Run(req Req) {
	conn, err := c.conn()
	if err != nil {
		req.SetErr(err)
		return
	}

	err = c.WriteReq(conn, req)
	if err != nil {
		if err := c.ConnPool.Remove(conn); err != nil {
			panic(err)
		}
		req.SetErr(err)
		return
	}

	val, err := req.ParseReply(conn.Rd)
	if err != nil {
		if err == Nil {
			if err := c.ConnPool.Add(conn); err != nil {
				panic(err)
			}
		} else {
			if err := c.ConnPool.Remove(conn); err != nil {
				panic(err)
			}
		}
		req.SetErr(err)
		return
	}

	if err := c.ConnPool.Add(conn); err != nil {
		panic(err)
	}
	req.SetVal(val)
}

func (c *BaseClient) Queue(req Req) {
	c.mtx.Lock()
	c.reqs = append(c.reqs, req)
	c.mtx.Unlock()
}

func (c *BaseClient) Close() error {
	return c.ConnPool.Close()
}

//------------------------------------------------------------------------------

type Client struct {
	*BaseClient
	TryEvalShaMinLen int
}

func NewClient(openConn OpenConnFunc, closeConn CloseConnFunc, initConn InitConnFunc) *Client {
	return &Client{
		BaseClient: &BaseClient{
			ConnPool: NewMultiConnPool(openConn, closeConn, 10),
			InitConn: initConn,
		},
		TryEvalShaMinLen: 80,
	}
}

func NewTCPClient(addr string, password string, db int64) *Client {
	return NewClient(TCPConnector(addr), nil, AuthSelectFunc(password, db))
}

func NewTLSClient(addr string, tlsConfig *tls.Config, password string, db int64) *Client {
	return NewClient(
		TLSConnector(addr, tlsConfig),
		nil,
		AuthSelectFunc(password, db),
	)
}
<commit_msg>redis: Log errors instead panic.<commit_after>package redis

import (
	"crypto/tls"
	"log"
	"net"
	"os"
	"sync"
)

// Package logger.
var Logger = log.New(os.Stdout, "redis: ", log.Ldate|log.Ltime)

type OpenConnFunc func() (net.Conn, error)
type CloseConnFunc func(net.Conn) error
type InitConnFunc func(*Client) error

func TCPConnector(addr string) OpenConnFunc {
	return func() (net.Conn, error) {
		return net.Dial("tcp", addr)
	}
}

func TLSConnector(addr string, tlsConfig *tls.Config) OpenConnFunc {
	return func() (net.Conn, error) {
		return tls.Dial("tcp", addr, tlsConfig)
	}
}

func AuthSelectFunc(password string, db int64) InitConnFunc {
	if password == "" && db < 0 {
		return nil
	}

	return func(client *Client) error {
		if password != "" {
			auth := client.Auth(password)
			if auth.Err() != nil {
				return auth.Err()
			}
		}

		if db >= 0 {
			sel := client.Select(db)
			if sel.Err() != nil {
				return sel.Err()
			}
		}

		return nil
	}
}

//------------------------------------------------------------------------------

type BaseClient struct {
	mtx      sync.Mutex
	ConnPool ConnPool
	InitConn InitConnFunc
	reqs     []Req
}

func (c *BaseClient) WriteReq(conn *Conn, reqs ...Req) error {
	buf := make([]byte, 0, 1000)
	for _, req := range reqs {
		buf = appendReq(buf, req.Args())
	}

	_, err := conn.RW.Write(buf)
	return err
}

func (c *BaseClient) conn() (*Conn, error) {
	conn, isNew, err := c.ConnPool.Get()
	if err != nil {
		return nil, err
	}

	if isNew && c.InitConn != nil {
		client := &Client{
			BaseClient: &BaseClient{
				ConnPool: NewSingleConnPoolConn(c.ConnPool, conn, true),
			},
		}
		err = c.InitConn(client)
		if err != nil {
			if err := c.ConnPool.Remove(conn); err != nil {
				Logger.Printf("ConnPool.Remove error: %v", err)
			}
			return nil, err
		}
	}
	return conn, nil
}

func (c *BaseClient) Process(req Req) {
	if c.reqs == nil {
		c.Run(req)
	} else {
		c.Queue(req)
	}
}

func (c *BaseClient) Run(req Req) {
	conn, err := c.conn()
	if err != nil {
		req.SetErr(err)
		return
	}

	err = c.WriteReq(conn, req)
	if err != nil {
		if err := c.ConnPool.Remove(conn); err != nil {
			Logger.Printf("ConnPool.Remove error: %v", err)
		}
		req.SetErr(err)
		return
	}

	val, err := req.ParseReply(conn.Rd)
	if err != nil {
		if err == Nil {
			if err := c.ConnPool.Add(conn); err != nil {
				Logger.Printf("ConnPool.Add error: %v", err)
			}
		} else {
			if err := c.ConnPool.Remove(conn); err != nil {
				Logger.Printf("ConnPool.Remove error: %v", err)
			}
		}
		req.SetErr(err)
		return
	}

	if err := c.ConnPool.Add(conn); err != nil {
		Logger.Printf("ConnPool.Add error: %v", err)
	}
	req.SetVal(val)
}

func (c *BaseClient) Queue(req Req) {
	c.mtx.Lock()
	c.reqs = append(c.reqs, req)
	c.mtx.Unlock()
}

func (c *BaseClient) Close() error {
	return c.ConnPool.Close()
}

//------------------------------------------------------------------------------

type Client struct {
	*BaseClient
	TryEvalShaMinLen int
}

func NewClient(openConn OpenConnFunc, closeConn CloseConnFunc, initConn InitConnFunc) *Client {
	return &Client{
		BaseClient: &BaseClient{
			ConnPool: NewMultiConnPool(openConn, closeConn, 10),
			InitConn: initConn,
		},
		TryEvalShaMinLen: 80,
	}
}

func NewTCPClient(addr string, password string, db int64) *Client {
	return NewClient(TCPConnector(addr), nil, AuthSelectFunc(password, db))
}

func NewTLSClient(addr string, tlsConfig *tls.Config, password string, db int64) *Client {
	return NewClient(
		TLSConnector(addr, tlsConfig),
		nil,
		AuthSelectFunc(password, db),
	)
}
<|endoftext|>


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

// retry for ots2
package goots

import (
	"math"
	"math/rand"
	"net"
	"time"
)

// RetryPolicy 是重试策略的接口，包含2个未实现的方法和它们的参数列表。要实现一个重试策略，
// 继承这个类并实现它的2个方法。
type RetryPolicyInterface interface {
	GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64
	ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool
}

// 默认重试策略
// 最大重试次数为3，最大重试间隔为2000毫秒，对流控类错误以及读操作相关的服务端内部错误进行了重试。
//
// Methods defined here:
//
// GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64
//
// ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool
//
// ----------------------------------------------------------------------
// Data and other attributes defined here:
//
// MaxRetryDelay = 2
//
// MaxRetryTimes = 3
//
// ScaleFactor = 2
//
// ServerThrottlingExceptionDelayFactor = 0.5
//
// StabilityExceptionDelayFactor = 0.2
var OTSDefaultRetryPolicy DefaultRetryPolicy

// 不进行任何重试的重试策略
var OTSNoRetryPolicy NoRetryPolicy

// 没有延时的重试策略
// 最大重试次数为3
var OTSNoDelayRetryPolicy NoDelayRetryPolicy

func init() {
	OTSDefaultRetryPolicy.MaxRetryTimes = 3
	OTSDefaultRetryPolicy.MaxRetryDelay = 2
	OTSDefaultRetryPolicy.ScaleFactor = 2
	OTSDefaultRetryPolicy.ServerThrottlingExceptionDelayFactor = 0.5
	OTSDefaultRetryPolicy.StabilityExceptionDelayFactor = 0.2

	OTSNoDelayRetryPolicy.MaxRetryTimes = 3
}

func should_retry_no_matter_which_api(exception *OTSServiceError) bool {
	if exception != nil {
		error_code := exception.Code
		error_message := exception.Message

		if error_code == "OTSRowOperationConflict" ||
			error_code == "OTSNotEnoughCapacityUnit" ||
			error_code == "OTSTableNotReady" ||
			error_code == "OTSPartitionUnavailable" ||
			error_code == "OTSServerBusy" ||
			error_code == "OTSOperationThrottled" {
			return true
		}

		if error_code == "OTSQuotaExhausted" && error_message == "Too frequent table operations." {
			return true
		}
	}

	return false
}

func is_repeatable_api(api_name string) bool {
	if api_name == "ListTable" ||
		api_name == "DescribeTable" ||
		api_name == "GetRow" ||
		api_name == "BatchGetRow" ||
		api_name == "GetRange" ||
		api_name == "DescrieStream" ||
		api_name == "GetShardIterator" ||
		api_name == "GetStreamRecord" ||
		api_name == "ListStream" {
		return true
	}
	return false
}

func should_retry_when_api_repeatable(retry_times int, exception *OTSServiceError, api_name string) bool {
	if exception != nil {
		if exception.Err != nil {
			if _, ok := exception.Err.(net.Error); ok {
				return true
			} else if exception.Err == ErrNonResponseBody || exception.Err == ErrReadResponse {
				return true
			}
		}

		error_code := exception.Code
		//error_message := exception.Message
		http_status := exception.HttpStatus

		if error_code == "OTSTimeout" ||
			error_code == "OTSInternalServerError" ||
			error_code == "OTSServerUnavailable" {
			return true
		}

		if http_status == 500 || http_status == 502 || http_status == 503 {
			return true
		}
	}

	// TODO handle network error & timeout
	return false
}

func is_server_throttling_exception(exception *OTSServiceError) bool {
	if exception != nil {
		error_code := exception.Code
		error_message := exception.Message

		if error_code == "OTSServerBusy" ||
			error_code == "OTSNotEnoughCapacityUnit" ||
			error_code == "OTSOperationThrottled" {
			return true
		}

		if error_code == "OTSQuotaExhausted" && error_message == "Too frequent table operations." {
			return true
		}
	}

	return false
}

// 默认重试策略
// 最大重试次数为3，最大重试间隔为2000毫秒，对流控类错误以及读操作相关的服务端内部错误进行了重试。
type DefaultRetryPolicy struct {
	// 最大重试次数
	MaxRetryTimes int

	// 最大重试间隔，单位为秒
	MaxRetryDelay float64

	// 每次重试间隔的递增倍数
	ScaleFactor float64

	// 两种错误的起始重试间隔，单位为秒
	ServerThrottlingExceptionDelayFactor float64
	StabilityExceptionDelayFactor        float64
}

func (self DefaultRetryPolicy) _max_retry_time_reached(retry_times int, exception *OTSServiceError, api_name string) bool {
	return retry_times >= self.MaxRetryTimes
}

func (self DefaultRetryPolicy) _can_retry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if should_retry_no_matter_which_api(exception) {
		return true
	}

	if is_repeatable_api(api_name) && should_retry_when_api_repeatable(retry_times, exception, api_name) {
		return true
	}

	return false
}

func (self DefaultRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	var delay_factor float64
	if is_server_throttling_exception(exception) {
		delay_factor = self.ServerThrottlingExceptionDelayFactor
	} else {
		delay_factor = self.StabilityExceptionDelayFactor
	}

	delay_limit := delay_factor * math.Pow(self.ScaleFactor, float64(retry_times))

	if delay_limit >= self.MaxRetryDelay {
		delay_limit = self.MaxRetryDelay
	}

	real_delay := delay_limit*0.5 + delay_limit*0.5*rand.New(rand.NewSource(time.Now().UnixNano())).Float64()
	return real_delay
}

func (self DefaultRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if self._max_retry_time_reached(retry_times, exception, api_name) {
		return false
	}

	if self._can_retry(retry_times, exception, api_name) {
		return true
	}

	return false
}

// 不进行任何重试的重试策略
type NoRetryPolicy struct {
}

func (self NoRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	return 0
}

func (self NoRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	return false
}

// 没有延时的重试策略
type NoDelayRetryPolicy struct {
	// 最大重试次数
	MaxRetryTimes int
}

func (self NoDelayRetryPolicy) _max_retry_time_reached(retry_times int, exception *OTSServiceError, api_name string) bool {
	return retry_times >= self.MaxRetryTimes
}

func (self NoDelayRetryPolicy) _can_retry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if should_retry_no_matter_which_api(exception) {
		return true
	}

	if is_repeatable_api(api_name) && should_retry_when_api_repeatable(retry_times, exception, api_name) {
		return true
	}

	return false
}

func (sels NoDelayRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	return 0
}

func (self NoDelayRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if self._max_retry_time_reached(retry_times, exception, api_name) {
		return false
	}

	if self._can_retry(retry_times, exception, api_name) {
		return true
	}

	return false
}
<commit_msg>modify MaxRetryTimes from 3 times to 6<commit_after>// Copyright 2016 The GiterLab Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// retry for ots2
package goots

import (
	"math"
	"math/rand"
	"net"
	"time"
)

// RetryPolicy 是重试策略的接口，包含2个未实现的方法和它们的参数列表。要实现一个重试策略，
// 继承这个类并实现它的2个方法。
type RetryPolicyInterface interface {
	GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64
	ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool
}

// 默认重试策略
// 最大重试次数为3，最大重试间隔为2000毫秒，对流控类错误以及读操作相关的服务端内部错误进行了重试。
//
// Methods defined here:
//
// GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64
//
// ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool
//
// ----------------------------------------------------------------------
// Data and other attributes defined here:
//
// MaxRetryDelay = 2
//
// MaxRetryTimes = 3
//
// ScaleFactor = 2
//
// ServerThrottlingExceptionDelayFactor = 0.5
//
// StabilityExceptionDelayFactor = 0.2
var OTSDefaultRetryPolicy DefaultRetryPolicy

// 不进行任何重试的重试策略
var OTSNoRetryPolicy NoRetryPolicy

// 没有延时的重试策略
// 最大重试次数为3
var OTSNoDelayRetryPolicy NoDelayRetryPolicy

func init() {
	OTSDefaultRetryPolicy.MaxRetryTimes = 6
	OTSDefaultRetryPolicy.MaxRetryDelay = 2
	OTSDefaultRetryPolicy.ScaleFactor = 2
	OTSDefaultRetryPolicy.ServerThrottlingExceptionDelayFactor = 0.5
	OTSDefaultRetryPolicy.StabilityExceptionDelayFactor = 0.2

	OTSNoDelayRetryPolicy.MaxRetryTimes = 3
}

func should_retry_no_matter_which_api(exception *OTSServiceError) bool {
	if exception != nil {
		error_code := exception.Code
		error_message := exception.Message

		if error_code == "OTSRowOperationConflict" ||
			error_code == "OTSNotEnoughCapacityUnit" ||
			error_code == "OTSTableNotReady" ||
			error_code == "OTSPartitionUnavailable" ||
			error_code == "OTSServerBusy" ||
			error_code == "OTSOperationThrottled" {
			return true
		}

		if error_code == "OTSQuotaExhausted" && error_message == "Too frequent table operations." {
			return true
		}
	}

	return false
}

func is_repeatable_api(api_name string) bool {
	if api_name == "ListTable" ||
		api_name == "DescribeTable" ||
		api_name == "GetRow" ||
		api_name == "BatchGetRow" ||
		api_name == "GetRange" ||
		api_name == "DescrieStream" ||
		api_name == "GetShardIterator" ||
		api_name == "GetStreamRecord" ||
		api_name == "ListStream" {
		return true
	}
	return false
}

func should_retry_when_api_repeatable(retry_times int, exception *OTSServiceError, api_name string) bool {
	if exception != nil {
		if exception.Err != nil {
			if _, ok := exception.Err.(net.Error); ok {
				return true
			} else if exception.Err == ErrNonResponseBody || exception.Err == ErrReadResponse {
				return true
			}
		}

		error_code := exception.Code
		//error_message := exception.Message
		http_status := exception.HttpStatus

		if error_code == "OTSTimeout" ||
			error_code == "OTSInternalServerError" ||
			error_code == "OTSServerUnavailable" {
			return true
		}

		if http_status == 500 || http_status == 502 || http_status == 503 {
			return true
		}
	}

	// TODO handle network error & timeout
	return false
}

func is_server_throttling_exception(exception *OTSServiceError) bool {
	if exception != nil {
		error_code := exception.Code
		error_message := exception.Message

		if error_code == "OTSServerBusy" ||
			error_code == "OTSNotEnoughCapacityUnit" ||
			error_code == "OTSOperationThrottled" {
			return true
		}

		if error_code == "OTSQuotaExhausted" && error_message == "Too frequent table operations." {
			return true
		}
	}

	return false
}

// 默认重试策略
// 最大重试次数为3，最大重试间隔为2000毫秒，对流控类错误以及读操作相关的服务端内部错误进行了重试。
type DefaultRetryPolicy struct {
	// 最大重试次数
	MaxRetryTimes int

	// 最大重试间隔，单位为秒
	MaxRetryDelay float64

	// 每次重试间隔的递增倍数
	ScaleFactor float64

	// 两种错误的起始重试间隔，单位为秒
	ServerThrottlingExceptionDelayFactor float64
	StabilityExceptionDelayFactor        float64
}

func (self DefaultRetryPolicy) _max_retry_time_reached(retry_times int, exception *OTSServiceError, api_name string) bool {
	return retry_times >= self.MaxRetryTimes
}

func (self DefaultRetryPolicy) _can_retry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if should_retry_no_matter_which_api(exception) {
		return true
	}

	if is_repeatable_api(api_name) && should_retry_when_api_repeatable(retry_times, exception, api_name) {
		return true
	}

	return false
}

func (self DefaultRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	var delay_factor float64
	if is_server_throttling_exception(exception) {
		delay_factor = self.ServerThrottlingExceptionDelayFactor
	} else {
		delay_factor = self.StabilityExceptionDelayFactor
	}

	delay_limit := delay_factor * math.Pow(self.ScaleFactor, float64(retry_times))

	if delay_limit >= self.MaxRetryDelay {
		delay_limit = self.MaxRetryDelay
	}

	real_delay := delay_limit*0.5 + delay_limit*0.5*rand.New(rand.NewSource(time.Now().UnixNano())).Float64()
	return real_delay
}

func (self DefaultRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if self._max_retry_time_reached(retry_times, exception, api_name) {
		return false
	}

	if self._can_retry(retry_times, exception, api_name) {
		return true
	}

	return false
}

// 不进行任何重试的重试策略
type NoRetryPolicy struct {
}

func (self NoRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	return 0
}

func (self NoRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	return false
}

// 没有延时的重试策略
type NoDelayRetryPolicy struct {
	// 最大重试次数
	MaxRetryTimes int
}

func (self NoDelayRetryPolicy) _max_retry_time_reached(retry_times int, exception *OTSServiceError, api_name string) bool {
	return retry_times >= self.MaxRetryTimes
}

func (self NoDelayRetryPolicy) _can_retry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if should_retry_no_matter_which_api(exception) {
		return true
	}

	if is_repeatable_api(api_name) && should_retry_when_api_repeatable(retry_times, exception, api_name) {
		return true
	}

	return false
}

func (sels NoDelayRetryPolicy) GetRetryDelay(retry_times int, exception *OTSServiceError, api_name string) float64 {
	return 0
}

func (self NoDelayRetryPolicy) ShouldRetry(retry_times int, exception *OTSServiceError, api_name string) bool {
	if self._max_retry_time_reached(retry_times, exception, api_name) {
		return false
	}

	if self._can_retry(retry_times, exception, api_name) {
		return true
	}

	return false
}
<|endoftext|>