<commit_before>// Force12.io is a package that monitors demand for resource in a system and then scales and repurposes
// containers, based on agreed "quality of service" contracts, to best handle that demand within the constraints of your existing VM
// or physical infrastructure (for v1).
//
// Force12 is defined to optimize the use of existing physical and VM resources instantly. VMs cannot be scaled in real time (it takes
// several minutes) and new physical machines take even longer. However, containers can be started or stopped at sub second speeds,
// allowing your infrastructure to adapt itself in real time to meet system demands.
//
// Force12 is aimed at effectively using the resources you have right now - your existing VMs or physical servers - by using them as
// optimally as possible.
//
// The Force12 approach is analogous to the way that a router dynamically optimises the use of a physical network. A router is limited
// by the capacity of the lines physically connected to it. Adding additional capacity is a physical process and takes time. Routers
// therefore make decisions in real time about which packets will be prioritized on a particular line based on the packet's priority
// (defined by a "quality of service" contract).
//
// For example, at times of high bandwidth usage a router might prioritize VOIP traffic over web browsing in real time.
//
// Containers allow Force12 to make similar "instant" judgements on service prioritisation within your existing infrastructure. Routers
// make very simplistic judgments because they have limited time and cpu and they act at a per packet level. Force12 has the capability
// of making far more sophisticated judgements, although even fairly simple ones will still provide a significant new service.
//
// This prototype is a bare bones implementation of Force12.io that recognises only 1 demand type:
// randomised demand for a priority 1 service. Resources are allocated to meet this demand for priority 1, and spare resource can
// be used for a priority 2 service.
//
// These demand type examples have been chosen purely for simplicity of demonstration. In the future more demand types
// will be offered
//
// V1 - Force12.io reacts to increased demand by starting/stopping containers on the slaves already in play.
//
// This version of Force12 starts and stops containers on a Mesos cluser using Marathon as the scheduler
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"os"
	"time"

	"bitbucket.org/force12io/force12-scheduler/marathon"
	"bitbucket.org/force12io/force12-scheduler/scheduler"
)

type sendStatePayload struct {
	CreatedAt          int64 `json:"createdAt"`
	Priority1Requested int   `json:"priority1Requested"`
	Priority1Running   int   `json:"priority1Running"`
	Priority2Running   int   `json:"priority2Running"`
}

const const_sleep = 100     //milliseconds
const const_stopsleep = 250 //milliseconds pause between stopping and restarting containers
const const_p1demandstart int = 5
const const_p2demandstart int = 4
const const_maxcontainers int = 9

type Demand struct {
	sched scheduler.Scheduler

	p1demand    int // number of Priority 1 tasks demanded
	p2demand    int
	p1requested int // indicates how many P1 tasks we've tried to kick off.
	p2requested int
}

// set returns values that were there (p1, p2)
// if provided value is -1 don't update, demand will always be between 0 and const_maxcontainers
func (d *Demand) set(p1, p2 int) (int, int) {
	//d.mu.Lock()
	p1old := d.p1demand
	p2old := d.p2demand
	if p2 != -1 {
		d.p2demand = p2
	}
	if p1 != -1 {
		d.p1demand = p1
	}
	//d.mu.Unlock()
	return p1old, p2old
}

// get returns client, server AEC - Combine this with the set to reduce code
func (d *Demand) get() (int, int) {
	return d.p1demand, d.p2demand
}

// handle processes a change in demand
// Note that handle will make any judgment on what to do with a demand
// change, including potentially nothing.
func (d *Demand) handle() error {
	var err error
	// AEC NOTE THIS FUNCTION NEEDS TO BE HEAVILY REWRITTEN TO HANDLE ECS
	// WHEN WE PORT THAT OVER TO THE SAME STRUCTURE.
	// THe reason is that all the code we wrote to handle stopping before
	// starting etc.. is handled directly by Marathon so that code
	// from the old scheduler needs to go behind the scheduler interface
	err = d.sched.StopStartNTasks(os.Getenv("CLIENT_TASK"), os.Getenv("CLIENT_FAMILY"), d.p1demand, d.p1requested)
	if err != nil {
		log.Printf("Failed to start Priority1 tasks. %v", err)
	}
	d.sched.StopStartNTasks(os.Getenv("SERVER_TASK"), os.Getenv("SERVER_FAMILY"), d.p2demand, d.p2requested)
	if err != nil {
		log.Printf("Failed to start Priority2 tasks. %v", err)
	}

	return err
}

// update checks for changes in demand, returning true if demand changed
// Note that this function makes no judgement on whether a demand change is
// significant. handle() will determine that.
func (d *Demand) update() bool {
	//log.Println("demand update check.")
	var demandchange bool = false

	container_count, err := d.sched.GetContainerCount("priority1-demand")
	if err != nil {
		log.Printf("Failed to get container count. %v", err)
		return false
	}
	//log.Printf("container count %v\n", container_count)

	//Update our saved p1 demand
	oldP1, _ := d.set(container_count, const_maxcontainers-container_count)

	//Has the demand changed?
	demandchange = (container_count != oldP1)

	if demandchange {
		log.Println("demandchange from, to ", oldP1, container_count)
	}

	return demandchange
}

// sendStateToAPI checks the current state of cluster (or single node) and sends that
// state to the f12 API
func sendStateToAPI(currentdemand *Demand) error {
	count1, count2, err := currentdemand.sched.CountAllTasks()
	if err != nil {
		return fmt.Errorf("Failed to get state err %v", err)
	}

	// Submit a PUT request to the API
	// Note the magic hardcoded string is the user ID, we need to pass this in in some way. ENV VAR?
	url := getBaseF12APIUrl() + "/metrics/" + "5k5gk"
	log.Printf("API PUT: %s", url)

	payload := sendStatePayload{
		CreatedAt:          time.Now().Unix(),
		Priority1Requested: currentdemand.p1demand,
		Priority1Running:   count1,
		Priority2Running:   count2,
	}

	w := &bytes.Buffer{}
	encoder := json.NewEncoder(w)
	err = encoder.Encode(&payload)
	if err != nil {
		return fmt.Errorf("Failed to encode API json. %v", err)
	}

	req, err := http.NewRequest("PUT", url, w)

	if err != nil {
		return fmt.Errorf("Failed to build API PUT request err %v", err)
	}
	//req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	if err != nil {
		// handle error
		return fmt.Errorf("API state err %v", err)
	}

	if resp.StatusCode > 204 {
		return fmt.Errorf("error response from API. %s", resp.Status)
	}
	return err
}

func getBaseF12APIUrl() string {
	baseUrl := os.Getenv("API_ADDRESS")
	if baseUrl == "" {
		baseUrl = "https://force12-windtunnel.herokuapp.com"
	}
	return baseUrl
}

// For the simple prototype, Force12.io sits in a loop checking for demand changes every X milliseconds
// In phase 2 we'll add a reactive mode where appropriate.
//
// Note - we don't route messages from demandcheckers to demandhandlers using channels because we want new values
// to override old values. Queued history is of no importance here.
//
// Also for simplicity this first release is concurrency free (single threaded)
func main() {
	currentdemand := Demand{
		sched: marathon.NewScheduler(),
	}
	currentdemand.set(const_p1demandstart, const_p2demandstart)
	var demandchangeflag bool
	//uncomment code below to output logs to file, but there's nothing clever in here to limit file size
	//f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
	//if err != nil {
	//   panic(err)
	//}
	//defer f.Close()

	//log.SetOutput(f)
	log.Println("This is a test log entry")

	// Initialise container types
	err := currentdemand.sched.InitScheduler(os.Getenv("CLIENT_TASK"))
	if err != nil {
		log.Printf("Failed to start P1 task. %v", err)
		return
	}
	err = currentdemand.sched.InitScheduler(os.Getenv("SERVER_TASK"))
	if err != nil {
		log.Printf("Failed to start P2 task. %v", err)
		return
	}

	//Now we can talk to the DB to check our client demand
	demandchangeflag = currentdemand.update()
	demandchangeflag = true

	var sleepcount float64 = 0
	var sleep time.Duration
	sleep = const_sleep * time.Millisecond

	for {
		//Update currentdemand with latest client and server demand, if changed, set flag
		demandchangeflag = currentdemand.update()
		if demandchangeflag {
			//make any changes dictated by this new demand level
			currentdemand.p1requested, currentdemand.p2requested, err = currentdemand.sched.CountAllTasks()
			if err != nil {
				log.Printf("Failed to count tasks. %v", err)
			}
			err = currentdemand.handle()
			if err != nil {
				log.Printf("Failed to handle demand change. %v", err)
			}
		}

		// Sleep for a while
		time.Sleep(sleep)
		sleepcount++

		//Periodically send state to the API if required
		if os.Getenv("SENDSTATETO_API") == "true" {
			_, frac := math.Modf(math.Mod(sleepcount, 5))
			if frac == 0 {
				err = sendStateToAPI(&currentdemand)
				if err != nil {
					log.Printf("Failed to send state. %v", err)
				}
			}
		}
	}
}
<commit_msg>Simplify, and reset sleeps so we really can loop forever<commit_after>// Force12.io is a package that monitors demand for resource in a system and then scales and repurposes
// containers, based on agreed "quality of service" contracts, to best handle that demand within the constraints of your existing VM
// or physical infrastructure (for v1).
//
// Force12 is defined to optimize the use of existing physical and VM resources instantly. VMs cannot be scaled in real time (it takes
// several minutes) and new physical machines take even longer. However, containers can be started or stopped at sub second speeds,
// allowing your infrastructure to adapt itself in real time to meet system demands.
//
// Force12 is aimed at effectively using the resources you have right now - your existing VMs or physical servers - by using them as
// optimally as possible.
//
// The Force12 approach is analogous to the way that a router dynamically optimises the use of a physical network. A router is limited
// by the capacity of the lines physically connected to it. Adding additional capacity is a physical process and takes time. Routers
// therefore make decisions in real time about which packets will be prioritized on a particular line based on the packet's priority
// (defined by a "quality of service" contract).
//
// For example, at times of high bandwidth usage a router might prioritize VOIP traffic over web browsing in real time.
//
// Containers allow Force12 to make similar "instant" judgements on service prioritisation within your existing infrastructure. Routers
// make very simplistic judgments because they have limited time and cpu and they act at a per packet level. Force12 has the capability
// of making far more sophisticated judgements, although even fairly simple ones will still provide a significant new service.
//
// This prototype is a bare bones implementation of Force12.io that recognises only 1 demand type:
// randomised demand for a priority 1 service. Resources are allocated to meet this demand for priority 1, and spare resource can
// be used for a priority 2 service.
//
// These demand type examples have been chosen purely for simplicity of demonstration. In the future more demand types
// will be offered
//
// V1 - Force12.io reacts to increased demand by starting/stopping containers on the slaves already in play.
//
// This version of Force12 starts and stops containers on a Mesos cluser using Marathon as the scheduler
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"os"
	"time"

	"bitbucket.org/force12io/force12-scheduler/marathon"
	"bitbucket.org/force12io/force12-scheduler/scheduler"
)

type sendStatePayload struct {
	CreatedAt          int64 `json:"createdAt"`
	Priority1Requested int   `json:"priority1Requested"`
	Priority1Running   int   `json:"priority1Running"`
	Priority2Running   int   `json:"priority2Running"`
}

const const_sleep = 100     //milliseconds
const const_sendstate_sleeps = 5 // number of sleeps before we send state on the API
const const_stopsleep = 250 //milliseconds pause between stopping and restarting containers
const const_p1demandstart int = 5
const const_p2demandstart int = 4
const const_maxcontainers int = 9

type Demand struct {
	sched scheduler.Scheduler

	p1demand    int // number of Priority 1 tasks demanded
	p2demand    int
	p1requested int // indicates how many P1 tasks we've tried to kick off.
	p2requested int
}

// set returns values that were there (p1, p2)
// if provided value is -1 don't update, demand will always be between 0 and const_maxcontainers
func (d *Demand) set(p1, p2 int) (int, int) {
	//d.mu.Lock()
	p1old := d.p1demand
	p2old := d.p2demand
	if p2 != -1 {
		d.p2demand = p2
	}
	if p1 != -1 {
		d.p1demand = p1
	}
	//d.mu.Unlock()
	return p1old, p2old
}

// get returns client, server AEC - Combine this with the set to reduce code
func (d *Demand) get() (int, int) {
	return d.p1demand, d.p2demand
}

// handle processes a change in demand
// Note that handle will make any judgment on what to do with a demand
// change, including potentially nothing.
func (d *Demand) handle() error {
	var err error
	// AEC NOTE THIS FUNCTION NEEDS TO BE HEAVILY REWRITTEN TO HANDLE ECS
	// WHEN WE PORT THAT OVER TO THE SAME STRUCTURE.
	// THe reason is that all the code we wrote to handle stopping before
	// starting etc.. is handled directly by Marathon so that code
	// from the old scheduler needs to go behind the scheduler interface
	err = d.sched.StopStartNTasks(os.Getenv("CLIENT_TASK"), os.Getenv("CLIENT_FAMILY"), d.p1demand, d.p1requested)
	if err != nil {
		log.Printf("Failed to start Priority1 tasks. %v", err)
	}
	d.sched.StopStartNTasks(os.Getenv("SERVER_TASK"), os.Getenv("SERVER_FAMILY"), d.p2demand, d.p2requested)
	if err != nil {
		log.Printf("Failed to start Priority2 tasks. %v", err)
	}

	return err
}

// update checks for changes in demand, returning true if demand changed
// Note that this function makes no judgement on whether a demand change is
// significant. handle() will determine that.
func (d *Demand) update() bool {
	//log.Println("demand update check.")
	var demandchange bool = false

	container_count, err := d.sched.GetContainerCount("priority1-demand")
	if err != nil {
		log.Printf("Failed to get container count. %v", err)
		return false
	}
	//log.Printf("container count %v\n", container_count)

	//Update our saved p1 demand
	oldP1, _ := d.set(container_count, const_maxcontainers-container_count)

	//Has the demand changed?
	demandchange = (container_count != oldP1)

	if demandchange {
		log.Println("demandchange from, to ", oldP1, container_count)
	}

	return demandchange
}

// sendStateToAPI checks the current state of cluster (or single node) and sends that
// state to the f12 API
func sendStateToAPI(currentdemand *Demand) error {
	count1, count2, err := currentdemand.sched.CountAllTasks()
	if err != nil {
		return fmt.Errorf("Failed to get state err %v", err)
	}

	// Submit a PUT request to the API
	// Note the magic hardcoded string is the user ID, we need to pass this in in some way. ENV VAR?
	url := getBaseF12APIUrl() + "/metrics/" + "5k5gk"
	log.Printf("API PUT: %s", url)

	payload := sendStatePayload{
		CreatedAt:          time.Now().Unix(),
		Priority1Requested: currentdemand.p1demand,
		Priority1Running:   count1,
		Priority2Running:   count2,
	}

	w := &bytes.Buffer{}
	encoder := json.NewEncoder(w)
	err = encoder.Encode(&payload)
	if err != nil {
		return fmt.Errorf("Failed to encode API json. %v", err)
	}

	req, err := http.NewRequest("PUT", url, w)

	if err != nil {
		return fmt.Errorf("Failed to build API PUT request err %v", err)
	}
	//req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	if err != nil {
		// handle error
		return fmt.Errorf("API state err %v", err)
	}

	if resp.StatusCode > 204 {
		return fmt.Errorf("error response from API. %s", resp.Status)
	}
	return err
}

func getBaseF12APIUrl() string {
	baseUrl := os.Getenv("API_ADDRESS")
	if baseUrl == "" {
		baseUrl = "https://force12-windtunnel.herokuapp.com"
	}
	return baseUrl
}

// For the simple prototype, Force12.io sits in a loop checking for demand changes every X milliseconds
// In phase 2 we'll add a reactive mode where appropriate.
//
// Note - we don't route messages from demandcheckers to demandhandlers using channels because we want new values
// to override old values. Queued history is of no importance here.
//
// Also for simplicity this first release is concurrency free (single threaded)
func main() {
	currentdemand := Demand{
		sched: marathon.NewScheduler(),
	}
	currentdemand.set(const_p1demandstart, const_p2demandstart)
	var demandchangeflag bool
	//uncomment code below to output logs to file, but there's nothing clever in here to limit file size
	//f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
	//if err != nil {
	//   panic(err)
	//}
	//defer f.Close()

	//log.SetOutput(f)
	log.Println("This is a test log entry")

	// Initialise container types
	err := currentdemand.sched.InitScheduler(os.Getenv("CLIENT_TASK"))
	if err != nil {
		log.Printf("Failed to start P1 task. %v", err)
		return
	}
	err = currentdemand.sched.InitScheduler(os.Getenv("SERVER_TASK"))
	if err != nil {
		log.Printf("Failed to start P2 task. %v", err)
		return
	}

	var demandchangeflag bool
	demandchangeflag = currentdemand.update()
	demandchangeflag = true

	var sleepcount int = 0
	var sleep time.Duration
	sleep = const_sleep * time.Millisecond

	for {
		//Update currentdemand with latest client and server demand, if changed, set flag
		demandchangeflag = currentdemand.update()
		if demandchangeflag {
			//make any changes dictated by this new demand level
			currentdemand.p1requested, currentdemand.p2requested, err = currentdemand.sched.CountAllTasks()
			if err != nil {
				log.Printf("Failed to count tasks. %v", err)
			}
			err = currentdemand.handle()
			if err != nil {
				log.Printf("Failed to handle demand change. %v", err)
			}
		}

		time.Sleep(sleep)
		sleepcount++
		if sleepcount == const_sendstate_sleeps {
			sleepcount = 0

			//Periodically send state to the API if required
			if os.Getenv("SENDSTATETO_API") == "true" {
				err = sendStateToAPI(&currentdemand)
				if err != nil {
					log.Printf("Failed to send state. %v", err)
				}
			}
		}

	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/flynn/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
	disc "github.com/flynn/flannel/Godeps/_workspace/src/github.com/flynn/flynn/discoverd/client"
	"github.com/flynn/flannel/Godeps/_workspace/src/github.com/flynn/flynn/pkg/status"
	log "github.com/flynn/flannel/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/flynn/flannel/backend"
	"github.com/flynn/flannel/backend/alloc"
	"github.com/flynn/flannel/backend/hostgw"
	"github.com/flynn/flannel/backend/udp"
	"github.com/flynn/flannel/backend/vxlan"
	"github.com/flynn/flannel/discoverd"
	"github.com/flynn/flannel/pkg/ip"
	"github.com/flynn/flannel/pkg/task"
	"github.com/flynn/flannel/subnet"
)

type CmdLineOpts struct {
	etcdEndpoints string
	etcdPrefix    string
	etcdKeyfile   string
	etcdCertfile  string
	etcdCAFile    string
	help          bool
	version       bool
	ipMasq        bool
	subnetFile    string
	iface         string
	notifyURL     string
	discoverdURL  string
	httpPort      string
}

var opts CmdLineOpts

func init() {
	flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001", "a comma-delimited list of etcd endpoints")
	flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
	flag.StringVar(&opts.etcdKeyfile, "etcd-keyfile", "", "SSL key file used to secure etcd communication")
	flag.StringVar(&opts.etcdCertfile, "etcd-certfile", "", "SSL certification file used to secure etcd communication")
	flag.StringVar(&opts.etcdCAFile, "etcd-cafile", "", "SSL Certificate Authority file used to secure etcd communication")
	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
	flag.StringVar(&opts.notifyURL, "notify-url", "", "URL to send webhook after starting")
	flag.StringVar(&opts.discoverdURL, "discoverd-url", "", "URL of discoverd registry")
	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
	flag.StringVar(&opts.httpPort, "http-port", "5001", "port to listen for HTTP requests on allocated IP")
	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
	flag.BoolVar(&opts.help, "help", false, "print this message")
	flag.BoolVar(&opts.version, "version", false, "print version and exit")
}

// TODO: This is yet another copy (others found in etcd, fleet) -- Pull it out!
// flagsFromEnv parses all registered flags in the given flagset,
// and if they are not already set it attempts to set their values from
// environment variables. Environment variables take the name of the flag but
// are UPPERCASE, have the given prefix, and any dashes are replaced by
// underscores - for example: some-flag => PREFIX_SOME_FLAG
func flagsFromEnv(prefix string, fs *flag.FlagSet) {
	alreadySet := make(map[string]bool)
	fs.Visit(func(f *flag.Flag) {
		alreadySet[f.Name] = true
	})
	fs.VisitAll(func(f *flag.Flag) {
		if !alreadySet[f.Name] {
			key := strings.ToUpper(prefix + "_" + strings.Replace(f.Name, "-", "_", -1))
			val := os.Getenv(key)
			if val != "" {
				fs.Set(f.Name, val)
			}
		}
	})
}

func writeSubnetFile(sn *backend.SubnetDef) error {
	// Write out the first usable IP by incrementing
	// sn.IP by one
	sn.Net.IP += 1

	dir, name := filepath.Split(opts.subnetFile)
	os.MkdirAll(dir, 0755)

	tempFile := filepath.Join(dir, "."+name)
	f, err := os.Create(tempFile)
	if err != nil {
		return err
	}

	fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", sn.Net)
	fmt.Fprintf(f, "FLANNEL_MTU=%d\n", sn.MTU)
	_, err = fmt.Fprintf(f, "FLANNEL_IPMASQ=%v\n", opts.ipMasq)
	f.Close()
	if err != nil {
		return err
	}

	// rename(2) the temporary file to the desired location so that it becomes
	// atomically visible with the contents
	return os.Rename(tempFile, opts.subnetFile)
}

func notifyWebhook(sn *backend.SubnetDef) error {
	if opts.notifyURL == "" {
		return nil
	}
	data := struct {
		Subnet string `json:"subnet"`
		MTU    int    `json:"mtu"`
	}{sn.Net.String(), sn.MTU}
	payload, _ := json.Marshal(data)
	res, err := http.Post(opts.notifyURL, "application/json", bytes.NewReader(payload))
	if err != nil {
		return err
	}
	res.Body.Close()
	return nil
}

func lookupIface() (*net.Interface, net.IP, error) {
	var iface *net.Interface
	var ipaddr net.IP
	var err error

	if len(opts.iface) > 0 {
		if ipaddr = net.ParseIP(opts.iface); ipaddr != nil {
			iface, err = ip.GetInterfaceByIP(ipaddr)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		} else {
			iface, err = net.InterfaceByName(opts.iface)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		}
	} else {
		log.Info("Determining IP address of default interface")
		if iface, err = ip.GetDefaultGatewayIface(); err != nil {
			return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
		}
	}

	if ipaddr == nil {
		ipaddr, err = ip.GetIfaceIP4Addr(iface)
		if err != nil {
			return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
		}
	}

	return iface, ipaddr, nil
}

func makeSubnetManager() *subnet.SubnetManager {
	var registryFn func() (subnet.Registry, error)
	if opts.discoverdURL != "" {
		client := disc.NewClientWithURL(opts.discoverdURL)
		registryFn = func() (subnet.Registry, error) {
			return discoverd.NewRegistry(client, "flannel")
		}
	} else {
		cfg := &subnet.EtcdConfig{
			Endpoints: strings.Split(opts.etcdEndpoints, ","),
			Keyfile:   opts.etcdKeyfile,
			Certfile:  opts.etcdCertfile,
			CAFile:    opts.etcdCAFile,
			Prefix:    opts.etcdPrefix,
		}
		registryFn = func() (subnet.Registry, error) {
			return subnet.NewEtcdSubnetRegistry(cfg)
		}
	}

	for {
		reg, err := registryFn()
		if err != nil {
			log.Error("Failed to create subnet registry: ", err)
			time.Sleep(time.Second)
			continue
		}

		sm, err := subnet.NewSubnetManager(reg)
		if err == nil {
			return sm
		}

		log.Error("Failed to create SubnetManager: ", err)
		time.Sleep(time.Second)
	}
}

func newBackend() (backend.Backend, *subnet.SubnetManager, error) {
	sm := makeSubnetManager()
	config := sm.GetConfig()

	var bt struct {
		Type string
	}

	if len(config.Backend) == 0 {
		bt.Type = "udp"
	} else {
		if err := json.Unmarshal(config.Backend, &bt); err != nil {
			return nil, nil, fmt.Errorf("Error decoding Backend property of config: %v", err)
		}
	}

	switch strings.ToLower(bt.Type) {
	case "udp":
		return udp.New(sm, config.Backend), sm, nil
	case "alloc":
		return alloc.New(sm), sm, nil
	case "host-gw":
		return hostgw.New(sm), sm, nil
	case "vxlan":
		return vxlan.New(sm, config.Backend), sm, nil
	default:
		return nil, nil, fmt.Errorf("'%v': unknown backend type", bt.Type)
	}
}

func httpServer(sn *subnet.SubnetManager, port string) error {
	l, err := net.Listen("tcp", net.JoinHostPort(sn.Lease().Network.IP.String(), port))
	if err != nil {
		return err
	}
	http.HandleFunc("/ping", func(http.ResponseWriter, *http.Request) {})
	status.AddHandler(status.SimpleHandler(func() error {
		return pingLeases(sn.Leases())
	}))
	go http.Serve(l, nil)
	return nil
}

// ping neighbor leases five at a time, timeout 1 second, returning as soon as
// one returns success.
func pingLeases(leases []subnet.SubnetLease) error {
	const workers = 5
	const timeout = 1 * time.Second

	if len(leases) == 0 {
		return nil
	}

	work := make(chan subnet.SubnetLease)
	results := make(chan bool, workers)
	client := http.Client{Timeout: timeout}

	var wg sync.WaitGroup
	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go func() {
			for l := range work {
				res, err := client.Get(fmt.Sprintf("http://%s:%s/ping", l.Network.IP, l.Attrs.HTTPPort))
				if err == nil {
					res.Body.Close()
				}
				results <- err == nil && res.StatusCode == 200
			}
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	for _, l := range leases {
		select {
		case work <- l:
		case success := <-results:
			if success {
				close(work)
				return nil
			}
		}
	}
	close(work)

	for success := range results {
		if success {
			return nil
		}
	}

	return errors.New("failed to successfully ping a neighbor")
}

func run(be backend.Backend, sm *subnet.SubnetManager, exit chan int) {
	var err error
	defer func() {
		if err == nil || err == task.ErrCanceled {
			exit <- 0
		} else {
			log.Error(err)
			exit <- 1
		}
	}()

	iface, ipaddr, err := lookupIface()
	if err != nil {
		return
	}

	if iface.MTU == 0 {
		err = fmt.Errorf("Failed to determine MTU for %s interface", ipaddr)
		return
	}

	log.Infof("Using %s as external interface", ipaddr)

	sn, err := be.Init(iface, ipaddr, opts.httpPort, opts.ipMasq)
	if err != nil {
		return
	}

	writeSubnetFile(sn)
	notifyWebhook(sn)
	daemon.SdNotify("READY=1")

	if err = httpServer(sm, opts.httpPort); err != nil {
		err = fmt.Errorf("error starting HTTP server: %s", err)
		return
	}

	log.Infof("%s mode initialized", be.Name())
	be.Run()
}

func main() {
	// glog will log to tmp files by default. override so all entries
	// can flow into journald (if running under systemd)
	flag.Set("logtostderr", "true")

	// now parse command line args
	flag.Parse()

	if opts.help {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	if opts.version {
		fmt.Fprintln(os.Stderr, Version)
		os.Exit(0)
	}

	flagsFromEnv("FLANNELD", flag.CommandLine)

	be, sm, err := newBackend()
	if err != nil {
		log.Info(err)
		os.Exit(1)
	}

	// Register for SIGINT and SIGTERM and wait for one of them to arrive
	log.Info("Installing signal handlers")
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)

	exit := make(chan int)
	go run(be, sm, exit)

	for {
		select {
		case <-sigs:
			// unregister to get default OS nuke behaviour in case we don't exit cleanly
			signal.Stop(sigs)

			log.Info("Exiting...")
			be.Stop()

		case code := <-exit:
			log.Infof("%s mode exited", be.Name())
			os.Exit(code)
		}
	}
}
<commit_msg>Avoid mutating the subnet IP<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/flynn/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
	disc "github.com/flynn/flannel/Godeps/_workspace/src/github.com/flynn/flynn/discoverd/client"
	"github.com/flynn/flannel/Godeps/_workspace/src/github.com/flynn/flynn/pkg/status"
	log "github.com/flynn/flannel/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/flynn/flannel/backend"
	"github.com/flynn/flannel/backend/alloc"
	"github.com/flynn/flannel/backend/hostgw"
	"github.com/flynn/flannel/backend/udp"
	"github.com/flynn/flannel/backend/vxlan"
	"github.com/flynn/flannel/discoverd"
	"github.com/flynn/flannel/pkg/ip"
	"github.com/flynn/flannel/pkg/task"
	"github.com/flynn/flannel/subnet"
)

type CmdLineOpts struct {
	etcdEndpoints string
	etcdPrefix    string
	etcdKeyfile   string
	etcdCertfile  string
	etcdCAFile    string
	help          bool
	version       bool
	ipMasq        bool
	subnetFile    string
	iface         string
	notifyURL     string
	discoverdURL  string
	httpPort      string
}

var opts CmdLineOpts

func init() {
	flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001", "a comma-delimited list of etcd endpoints")
	flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
	flag.StringVar(&opts.etcdKeyfile, "etcd-keyfile", "", "SSL key file used to secure etcd communication")
	flag.StringVar(&opts.etcdCertfile, "etcd-certfile", "", "SSL certification file used to secure etcd communication")
	flag.StringVar(&opts.etcdCAFile, "etcd-cafile", "", "SSL Certificate Authority file used to secure etcd communication")
	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
	flag.StringVar(&opts.notifyURL, "notify-url", "", "URL to send webhook after starting")
	flag.StringVar(&opts.discoverdURL, "discoverd-url", "", "URL of discoverd registry")
	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
	flag.StringVar(&opts.httpPort, "http-port", "5001", "port to listen for HTTP requests on allocated IP")
	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
	flag.BoolVar(&opts.help, "help", false, "print this message")
	flag.BoolVar(&opts.version, "version", false, "print version and exit")
}

// TODO: This is yet another copy (others found in etcd, fleet) -- Pull it out!
// flagsFromEnv parses all registered flags in the given flagset,
// and if they are not already set it attempts to set their values from
// environment variables. Environment variables take the name of the flag but
// are UPPERCASE, have the given prefix, and any dashes are replaced by
// underscores - for example: some-flag => PREFIX_SOME_FLAG
func flagsFromEnv(prefix string, fs *flag.FlagSet) {
	alreadySet := make(map[string]bool)
	fs.Visit(func(f *flag.Flag) {
		alreadySet[f.Name] = true
	})
	fs.VisitAll(func(f *flag.Flag) {
		if !alreadySet[f.Name] {
			key := strings.ToUpper(prefix + "_" + strings.Replace(f.Name, "-", "_", -1))
			val := os.Getenv(key)
			if val != "" {
				fs.Set(f.Name, val)
			}
		}
	})
}

func writeSubnetFile(sn *backend.SubnetDef) error {
	// Write out the first usable IP by incrementing
	// sn.IP by one
	net := sn.Net
	net.IP += 1

	dir, name := filepath.Split(opts.subnetFile)
	os.MkdirAll(dir, 0755)

	tempFile := filepath.Join(dir, "."+name)
	f, err := os.Create(tempFile)
	if err != nil {
		return err
	}

	fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", net)
	fmt.Fprintf(f, "FLANNEL_MTU=%d\n", sn.MTU)
	_, err = fmt.Fprintf(f, "FLANNEL_IPMASQ=%v\n", opts.ipMasq)
	f.Close()
	if err != nil {
		return err
	}

	// rename(2) the temporary file to the desired location so that it becomes
	// atomically visible with the contents
	return os.Rename(tempFile, opts.subnetFile)
}

func notifyWebhook(sn *backend.SubnetDef) error {
	if opts.notifyURL == "" {
		return nil
	}
	net := sn.Net
	net.IP += 1
	data := struct {
		Subnet string `json:"subnet"`
		MTU    int    `json:"mtu"`
	}{net.String(), sn.MTU}
	payload, _ := json.Marshal(data)
	res, err := http.Post(opts.notifyURL, "application/json", bytes.NewReader(payload))
	if err != nil {
		return err
	}
	res.Body.Close()
	return nil
}

func lookupIface() (*net.Interface, net.IP, error) {
	var iface *net.Interface
	var ipaddr net.IP
	var err error

	if len(opts.iface) > 0 {
		if ipaddr = net.ParseIP(opts.iface); ipaddr != nil {
			iface, err = ip.GetInterfaceByIP(ipaddr)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		} else {
			iface, err = net.InterfaceByName(opts.iface)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		}
	} else {
		log.Info("Determining IP address of default interface")
		if iface, err = ip.GetDefaultGatewayIface(); err != nil {
			return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
		}
	}

	if ipaddr == nil {
		ipaddr, err = ip.GetIfaceIP4Addr(iface)
		if err != nil {
			return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
		}
	}

	return iface, ipaddr, nil
}

func makeSubnetManager() *subnet.SubnetManager {
	var registryFn func() (subnet.Registry, error)
	if opts.discoverdURL != "" {
		client := disc.NewClientWithURL(opts.discoverdURL)
		registryFn = func() (subnet.Registry, error) {
			return discoverd.NewRegistry(client, "flannel")
		}
	} else {
		cfg := &subnet.EtcdConfig{
			Endpoints: strings.Split(opts.etcdEndpoints, ","),
			Keyfile:   opts.etcdKeyfile,
			Certfile:  opts.etcdCertfile,
			CAFile:    opts.etcdCAFile,
			Prefix:    opts.etcdPrefix,
		}
		registryFn = func() (subnet.Registry, error) {
			return subnet.NewEtcdSubnetRegistry(cfg)
		}
	}

	for {
		reg, err := registryFn()
		if err != nil {
			log.Error("Failed to create subnet registry: ", err)
			time.Sleep(time.Second)
			continue
		}

		sm, err := subnet.NewSubnetManager(reg)
		if err == nil {
			return sm
		}

		log.Error("Failed to create SubnetManager: ", err)
		time.Sleep(time.Second)
	}
}

func newBackend() (backend.Backend, *subnet.SubnetManager, error) {
	sm := makeSubnetManager()
	config := sm.GetConfig()

	var bt struct {
		Type string
	}

	if len(config.Backend) == 0 {
		bt.Type = "udp"
	} else {
		if err := json.Unmarshal(config.Backend, &bt); err != nil {
			return nil, nil, fmt.Errorf("Error decoding Backend property of config: %v", err)
		}
	}

	switch strings.ToLower(bt.Type) {
	case "udp":
		return udp.New(sm, config.Backend), sm, nil
	case "alloc":
		return alloc.New(sm), sm, nil
	case "host-gw":
		return hostgw.New(sm), sm, nil
	case "vxlan":
		return vxlan.New(sm, config.Backend), sm, nil
	default:
		return nil, nil, fmt.Errorf("'%v': unknown backend type", bt.Type)
	}
}

func httpServer(sn *subnet.SubnetManager, port string) error {
	l, err := net.Listen("tcp", net.JoinHostPort(sn.Lease().Network.IP.String(), port))
	if err != nil {
		return err
	}
	http.HandleFunc("/ping", func(http.ResponseWriter, *http.Request) {})
	status.AddHandler(status.SimpleHandler(func() error {
		return pingLeases(sn.Leases())
	}))
	go http.Serve(l, nil)
	return nil
}

// ping neighbor leases five at a time, timeout 1 second, returning as soon as
// one returns success.
func pingLeases(leases []subnet.SubnetLease) error {
	const workers = 5
	const timeout = 1 * time.Second

	if len(leases) == 0 {
		return nil
	}

	work := make(chan subnet.SubnetLease)
	results := make(chan bool, workers)
	client := http.Client{Timeout: timeout}

	var wg sync.WaitGroup
	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go func() {
			for l := range work {
				res, err := client.Get(fmt.Sprintf("http://%s:%s/ping", l.Network.IP, l.Attrs.HTTPPort))
				if err == nil {
					res.Body.Close()
				}
				results <- err == nil && res.StatusCode == 200
			}
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	for _, l := range leases {
		select {
		case work <- l:
		case success := <-results:
			if success {
				close(work)
				return nil
			}
		}
	}
	close(work)

	for success := range results {
		if success {
			return nil
		}
	}

	return errors.New("failed to successfully ping a neighbor")
}

func run(be backend.Backend, sm *subnet.SubnetManager, exit chan int) {
	var err error
	defer func() {
		if err == nil || err == task.ErrCanceled {
			exit <- 0
		} else {
			log.Error(err)
			exit <- 1
		}
	}()

	iface, ipaddr, err := lookupIface()
	if err != nil {
		return
	}

	if iface.MTU == 0 {
		err = fmt.Errorf("Failed to determine MTU for %s interface", ipaddr)
		return
	}

	log.Infof("Using %s as external interface", ipaddr)

	sn, err := be.Init(iface, ipaddr, opts.httpPort, opts.ipMasq)
	if err != nil {
		return
	}

	writeSubnetFile(sn)
	notifyWebhook(sn)
	daemon.SdNotify("READY=1")

	if err = httpServer(sm, opts.httpPort); err != nil {
		err = fmt.Errorf("error starting HTTP server: %s", err)
		return
	}

	log.Infof("%s mode initialized", be.Name())
	be.Run()
}

func main() {
	// glog will log to tmp files by default. override so all entries
	// can flow into journald (if running under systemd)
	flag.Set("logtostderr", "true")

	// now parse command line args
	flag.Parse()

	if opts.help {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	if opts.version {
		fmt.Fprintln(os.Stderr, Version)
		os.Exit(0)
	}

	flagsFromEnv("FLANNELD", flag.CommandLine)

	be, sm, err := newBackend()
	if err != nil {
		log.Info(err)
		os.Exit(1)
	}

	// Register for SIGINT and SIGTERM and wait for one of them to arrive
	log.Info("Installing signal handlers")
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)

	exit := make(chan int)
	go run(be, sm, exit)

	for {
		select {
		case <-sigs:
			// unregister to get default OS nuke behaviour in case we don't exit cleanly
			signal.Stop(sigs)

			log.Info("Exiting...")
			be.Stop()

		case code := <-exit:
			log.Infof("%s mode exited", be.Name())
			os.Exit(code)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"

	"github.com/bitrise-io/go-utils/colorstring"
)

const (
	formattingModeAttachment = "attachment"
	formattingModeText       = "text"
)

// ConfigsModel ...
type ConfigsModel struct {
	// Slack Inputs
	WebhookURL          string
	Channel             string
	FromUsername        string
	FromUsernameOnError string
	Message             string
	MessageOnError      string
	FormattingMode      string
	Color               string
	ColorOnError        string
	Emoji               string
	EmojiOnError        string
	IconURL             string
	IconURLOnError      string
	// Other Inputs
	IsDebugMode bool
	// Other configs
	IsBuildFailed bool
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		WebhookURL:          os.Getenv("webhook_url"),
		Channel:             os.Getenv("channel"),
		FromUsername:        os.Getenv("from_username"),
		FromUsernameOnError: os.Getenv("from_username_on_error"),
		Message:             os.Getenv("message"),
		MessageOnError:      os.Getenv("message_on_error"),
		FormattingMode:      os.Getenv("formatting_mode"),
		Emoji:               os.Getenv("emoji"),
		EmojiOnError:        os.Getenv("emoji_on_error"),
		Color:               os.Getenv("color"),
		ColorOnError:        os.Getenv("color_on_error"),
		IconURL:             os.Getenv("icon_url"),
		IconURLOnError:      os.Getenv("icon_url_on_error"),
		//
		IsDebugMode: (os.Getenv("is_debug_mode") == "yes"),
		//
		IsBuildFailed: (os.Getenv("STEPLIB_BUILD_STATUS") != "0"),
	}
}

func (configs ConfigsModel) print() {
	fmt.Println("")
	fmt.Println(colorstring.Blue("Slack configs:"))
	fmt.Println(" - WebhookURL:", configs.WebhookURL)
	fmt.Println(" - Channel:", configs.Channel)
	fmt.Println(" - FromUsername:", configs.FromUsername)
	fmt.Println(" - FromUsernameOnError:", configs.FromUsernameOnError)
	fmt.Println(" - Message:", configs.Message)
	fmt.Println(" - MessageOnError:", configs.MessageOnError)
	fmt.Println(" - FormattingMode:", configs.FormattingMode)
	fmt.Println(" - Color:", configs.Color)
	fmt.Println(" - ColorOnError:", configs.ColorOnError)
	fmt.Println(" - Emoji:", configs.Emoji)
	fmt.Println(" - EmojiOnError:", configs.EmojiOnError)
	fmt.Println(" - IconURL:", configs.IconURL)
	fmt.Println(" - IconURLOnError:", configs.IconURLOnError)
	fmt.Println("")
	fmt.Println(colorstring.Blue("Other configs:"))
	fmt.Println(" - IsDebugMode:", configs.IsDebugMode)
	fmt.Println(" - IsBuildFailed:", configs.IsBuildFailed)
	fmt.Println("")
}

func (configs ConfigsModel) validate() error {
	// required
	if configs.WebhookURL == "" {
		return errors.New("No Webhook URL parameter specified!")
	}
	if configs.Message == "" {
		return errors.New("No Message parameter specified!")
	}
	if configs.Color == "" {
		return errors.New("No Color parameter specified!")
	}
	if configs.FormattingMode == "" {
		return errors.New("No FormattingMode parameter specified!")
	} else if configs.FormattingMode != formattingModeText && configs.FormattingMode != formattingModeAttachment {
		return fmt.Errorf("Invalid FormattingMode: %s", configs.FormattingMode)
	}
	return nil
}

// AttachmentItemModel ...
type AttachmentItemModel struct {
	Fallback string `json:"fallback"`
	Text     string `json:"text"`
	Color    string `json:"color,omitempty"`
}

// RequestParams ...
type RequestParams struct {
	// - required
	Text string `json:"text"`
	// OR use attachment instead of text, for better formatting
	Attachments []AttachmentItemModel `json:"attachments,omitempty"`
	// - optional
	Channel   *string `json:"channel"`
	Username  *string `json:"username"`
	EmojiIcon *string `json:"icon_emoji"`
	IconURL   *string `json:"icon_url"`
}

// CreatePayloadParam ...
func CreatePayloadParam(configs ConfigsModel) (string, error) {
	// - required
	msgColor := configs.Color
	if configs.IsBuildFailed {
		if configs.ColorOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no color_on_error defined, using default."))
		} else {
			msgColor = configs.ColorOnError
		}
	}
	msgText := configs.Message
	if configs.IsBuildFailed {
		if configs.MessageOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no message_on_error defined, using default."))
		} else {
			msgText = configs.MessageOnError
		}
	}

	reqParams := RequestParams{}
	if configs.FormattingMode == formattingModeAttachment {
		reqParams.Attachments = []AttachmentItemModel{
			{Fallback: msgText, Text: msgText, Color: msgColor},
		}
	} else if configs.FormattingMode == formattingModeText {
		reqParams.Text = msgText
	} else {
		fmt.Println(colorstring.Red("Invalid formatting mode:"), configs.FormattingMode)
		os.Exit(1)
	}

	// - optional
	reqChannel := configs.Channel
	if reqChannel != "" {
		reqParams.Channel = &reqChannel
	}
	reqUsername := configs.FromUsername
	if reqUsername != "" {
		reqParams.Username = &reqUsername
	}
	if configs.IsBuildFailed {
		if configs.FromUsernameOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no from_username_on_error defined, using default."))
		} else {
			reqParams.Username = &configs.FromUsernameOnError
		}
	}

	reqEmojiIcon := configs.Emoji
	if reqEmojiIcon != "" {
		reqParams.EmojiIcon = &reqEmojiIcon
	}
	if configs.IsBuildFailed {
		if configs.EmojiOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no emoji_on_error defined, using default."))
		} else {
			reqParams.EmojiIcon = &configs.EmojiOnError
		}
	}

	reqIconURL := configs.IconURL
	if reqIconURL != "" {
		reqParams.IconURL = &reqIconURL
	}
	if configs.IsBuildFailed {
		if configs.IconURLOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no icon_url_on_error defined, using default."))
		} else {
			reqParams.IconURL = &configs.IconURLOnError
		}
	}
	// if Icon URL defined ignore the emoji input
	if reqParams.IconURL != nil {
		reqParams.EmojiIcon = nil
	}

	if configs.IsDebugMode {
		fmt.Printf("Parameters: %#v\n", reqParams)
	}

	// JSON serialize the request params
	reqParamsJSONBytes, err := json.Marshal(reqParams)
	if err != nil {
		return "", nil
	}
	reqParamsJSONString := string(reqParamsJSONBytes)

	return reqParamsJSONString, nil
}

func main() {
	configs := createConfigsModelFromEnvs()
	configs.print()
	if err := configs.validate(); err != nil {
		fmt.Println()
		fmt.Println(colorstring.Red("Issue with input:"), err)
		fmt.Println()
		os.Exit(1)
	}

	//
	// request URL
	requestURL := configs.WebhookURL

	//
	// request parameters
	reqParamsJSONString, err := CreatePayloadParam(configs)
	if err != nil {
		fmt.Println(colorstring.Red("Failed to create JSON payload:"), err)
		os.Exit(1)
	}
	if configs.IsDebugMode {
		fmt.Println()
		fmt.Println("JSON payload: ", reqParamsJSONString)
	}

	//
	// send request
	resp, err := http.PostForm(requestURL,
		url.Values{"payload": []string{reqParamsJSONString}})
	if err != nil {
		fmt.Println(colorstring.Red("Failed to send the request:"), err)
		os.Exit(1)
	}

	//
	// process the response
	body, err := ioutil.ReadAll(resp.Body)
	bodyStr := string(body)
	resp.Body.Close()

	if resp.StatusCode != 200 {
		fmt.Println()
		fmt.Println(colorstring.Red("Request failed"))
		fmt.Println("Response from Slack: ", bodyStr)
		fmt.Println()
		os.Exit(1)
	}

	if configs.IsDebugMode {
		fmt.Println()
		fmt.Println("Response from Slack: ", bodyStr)
	}
	fmt.Println()
	fmt.Println(colorstring.Green("Slack message successfully sent! 🚀"))
	fmt.Println()
	os.Exit(0)
}
<commit_msg>minor check syntax change<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"

	"github.com/bitrise-io/go-utils/colorstring"
)

const (
	formattingModeAttachment = "attachment"
	formattingModeText       = "text"
)

// ConfigsModel ...
type ConfigsModel struct {
	// Slack Inputs
	WebhookURL          string
	Channel             string
	FromUsername        string
	FromUsernameOnError string
	Message             string
	MessageOnError      string
	FormattingMode      string
	Color               string
	ColorOnError        string
	Emoji               string
	EmojiOnError        string
	IconURL             string
	IconURLOnError      string
	// Other Inputs
	IsDebugMode bool
	// Other configs
	IsBuildFailed bool
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		WebhookURL:          os.Getenv("webhook_url"),
		Channel:             os.Getenv("channel"),
		FromUsername:        os.Getenv("from_username"),
		FromUsernameOnError: os.Getenv("from_username_on_error"),
		Message:             os.Getenv("message"),
		MessageOnError:      os.Getenv("message_on_error"),
		FormattingMode:      os.Getenv("formatting_mode"),
		Emoji:               os.Getenv("emoji"),
		EmojiOnError:        os.Getenv("emoji_on_error"),
		Color:               os.Getenv("color"),
		ColorOnError:        os.Getenv("color_on_error"),
		IconURL:             os.Getenv("icon_url"),
		IconURLOnError:      os.Getenv("icon_url_on_error"),
		//
		IsDebugMode: (os.Getenv("is_debug_mode") == "yes"),
		//
		IsBuildFailed: (os.Getenv("STEPLIB_BUILD_STATUS") != "0"),
	}
}

func (configs ConfigsModel) print() {
	fmt.Println("")
	fmt.Println(colorstring.Blue("Slack configs:"))
	fmt.Println(" - WebhookURL:", configs.WebhookURL)
	fmt.Println(" - Channel:", configs.Channel)
	fmt.Println(" - FromUsername:", configs.FromUsername)
	fmt.Println(" - FromUsernameOnError:", configs.FromUsernameOnError)
	fmt.Println(" - Message:", configs.Message)
	fmt.Println(" - MessageOnError:", configs.MessageOnError)
	fmt.Println(" - FormattingMode:", configs.FormattingMode)
	fmt.Println(" - Color:", configs.Color)
	fmt.Println(" - ColorOnError:", configs.ColorOnError)
	fmt.Println(" - Emoji:", configs.Emoji)
	fmt.Println(" - EmojiOnError:", configs.EmojiOnError)
	fmt.Println(" - IconURL:", configs.IconURL)
	fmt.Println(" - IconURLOnError:", configs.IconURLOnError)
	fmt.Println("")
	fmt.Println(colorstring.Blue("Other configs:"))
	fmt.Println(" - IsDebugMode:", configs.IsDebugMode)
	fmt.Println(" - IsBuildFailed:", configs.IsBuildFailed)
	fmt.Println("")
}

func (configs ConfigsModel) validate() error {
	// required
	if configs.WebhookURL == "" {
		return errors.New("No Webhook URL parameter specified!")
	}
	if configs.Message == "" {
		return errors.New("No Message parameter specified!")
	}
	if configs.Color == "" {
		return errors.New("No Color parameter specified!")
	}

	switch configs.FormattingMode {
	case formattingModeText, formattingModeAttachment:
		// allowed/accepted
	case "":
		return errors.New("No FormattingMode parameter specified!")
	default:
		return fmt.Errorf("Invalid FormattingMode: %s", configs.FormattingMode)
	}
	return nil
}

// AttachmentItemModel ...
type AttachmentItemModel struct {
	Fallback string `json:"fallback"`
	Text     string `json:"text"`
	Color    string `json:"color,omitempty"`
}

// RequestParams ...
type RequestParams struct {
	// - required
	Text string `json:"text"`
	// OR use attachment instead of text, for better formatting
	Attachments []AttachmentItemModel `json:"attachments,omitempty"`
	// - optional
	Channel   *string `json:"channel"`
	Username  *string `json:"username"`
	EmojiIcon *string `json:"icon_emoji"`
	IconURL   *string `json:"icon_url"`
}

// CreatePayloadParam ...
func CreatePayloadParam(configs ConfigsModel) (string, error) {
	// - required
	msgColor := configs.Color
	if configs.IsBuildFailed {
		if configs.ColorOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no color_on_error defined, using default."))
		} else {
			msgColor = configs.ColorOnError
		}
	}
	msgText := configs.Message
	if configs.IsBuildFailed {
		if configs.MessageOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no message_on_error defined, using default."))
		} else {
			msgText = configs.MessageOnError
		}
	}

	reqParams := RequestParams{}
	if configs.FormattingMode == formattingModeAttachment {
		reqParams.Attachments = []AttachmentItemModel{
			{Fallback: msgText, Text: msgText, Color: msgColor},
		}
	} else if configs.FormattingMode == formattingModeText {
		reqParams.Text = msgText
	} else {
		fmt.Println(colorstring.Red("Invalid formatting mode:"), configs.FormattingMode)
		os.Exit(1)
	}

	// - optional
	reqChannel := configs.Channel
	if reqChannel != "" {
		reqParams.Channel = &reqChannel
	}
	reqUsername := configs.FromUsername
	if reqUsername != "" {
		reqParams.Username = &reqUsername
	}
	if configs.IsBuildFailed {
		if configs.FromUsernameOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no from_username_on_error defined, using default."))
		} else {
			reqParams.Username = &configs.FromUsernameOnError
		}
	}

	reqEmojiIcon := configs.Emoji
	if reqEmojiIcon != "" {
		reqParams.EmojiIcon = &reqEmojiIcon
	}
	if configs.IsBuildFailed {
		if configs.EmojiOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no emoji_on_error defined, using default."))
		} else {
			reqParams.EmojiIcon = &configs.EmojiOnError
		}
	}

	reqIconURL := configs.IconURL
	if reqIconURL != "" {
		reqParams.IconURL = &reqIconURL
	}
	if configs.IsBuildFailed {
		if configs.IconURLOnError == "" {
			fmt.Println(colorstring.Yellow(" (i) Build failed but no icon_url_on_error defined, using default."))
		} else {
			reqParams.IconURL = &configs.IconURLOnError
		}
	}
	// if Icon URL defined ignore the emoji input
	if reqParams.IconURL != nil {
		reqParams.EmojiIcon = nil
	}

	if configs.IsDebugMode {
		fmt.Printf("Parameters: %#v\n", reqParams)
	}

	// JSON serialize the request params
	reqParamsJSONBytes, err := json.Marshal(reqParams)
	if err != nil {
		return "", nil
	}
	reqParamsJSONString := string(reqParamsJSONBytes)

	return reqParamsJSONString, nil
}

func main() {
	configs := createConfigsModelFromEnvs()
	configs.print()
	if err := configs.validate(); err != nil {
		fmt.Println()
		fmt.Println(colorstring.Red("Issue with input:"), err)
		fmt.Println()
		os.Exit(1)
	}

	//
	// request URL
	requestURL := configs.WebhookURL

	//
	// request parameters
	reqParamsJSONString, err := CreatePayloadParam(configs)
	if err != nil {
		fmt.Println(colorstring.Red("Failed to create JSON payload:"), err)
		os.Exit(1)
	}
	if configs.IsDebugMode {
		fmt.Println()
		fmt.Println("JSON payload: ", reqParamsJSONString)
	}

	//
	// send request
	resp, err := http.PostForm(requestURL,
		url.Values{"payload": []string{reqParamsJSONString}})
	if err != nil {
		fmt.Println(colorstring.Red("Failed to send the request:"), err)
		os.Exit(1)
	}

	//
	// process the response
	body, err := ioutil.ReadAll(resp.Body)
	bodyStr := string(body)
	resp.Body.Close()

	if resp.StatusCode != 200 {
		fmt.Println()
		fmt.Println(colorstring.Red("Request failed"))
		fmt.Println("Response from Slack: ", bodyStr)
		fmt.Println()
		os.Exit(1)
	}

	if configs.IsDebugMode {
		fmt.Println()
		fmt.Println("Response from Slack: ", bodyStr)
	}
	fmt.Println()
	fmt.Println(colorstring.Green("Slack message successfully sent! 🚀"))
	fmt.Println()
	os.Exit(0)
}
<|endoftext|>


<commit_before>// Package adapt provides an algorithm for adaptive hierarchical interpolation
// with local refinements.
package adapt

import (
	"runtime"
)

// Grid is a sparse grid in [0, 1]^n.
type Grid interface {
	Compute(indices []uint64) []float64
	Refine(indices []uint64) []uint64
	Parent(index []uint64, i uint)
	Sibling(index []uint64, i uint)
}

// Basis is a functional basis in [0, 1]^n.
type Basis interface {
	Compute(index []uint64, point []float64) float64
	Integrate(index []uint64) float64
}

// Interpolator is an instance of the algorithm.
type Interpolator struct {
	grid   Grid
	basis  Basis
	config Config
}

// Progress contains information about the interpolation process.
type Progress struct {
	Iteration uint      // Iteration number
	Level     uint      // Interpolation level
	Accepted  uint      // Number of accepted nodes
	Rejected  uint      // Number of rejected nodes
	Current   uint      // Number of nodes of the iteration
	Integral  []float64 // Integral over the whole domain
}

// New creates a new interpolator.
func New(grid Grid, basis Basis, config *Config) *Interpolator {
	interpolator := &Interpolator{
		grid:   grid,
		basis:  basis,
		config: *config,
	}

	config = &interpolator.config
	if config.Workers == 0 {
		config.Workers = uint(runtime.GOMAXPROCS(0))
	}
	if config.Rate == 0 {
		config.Rate = 1
	}

	return interpolator
}

// Compute constructs an interpolant for a function.
func (self *Interpolator) Compute(target Target) *Surrogate {
	config := &self.config

	ni, no := target.Dimensions()
	nw := config.Workers

	surrogate := newSurrogate(ni, no)
	tracker := newQueue(ni, config)
	history := newHash(ni)

	na, nr, nc := uint(0), uint(0), uint(1)

	indices := make([]uint64, nc*ni)
	nodes := self.grid.Compute(indices)

	integral, compensation := make([]float64, no), make([]float64, no)

	for k := uint(0); nc > 0; k++ {
		progress := Progress{
			Iteration: k,
			Level:     tracker.lnow,
			Accepted:  na,
			Rejected:  nr,
			Current:   nc,
			Integral:  integral,
		}

		target.Monitor(&progress)

		surpluses := subtract(
			invoke(target.Compute, nodes, ni, no, nw),
			approximate(self.basis, surrogate.Indices,
				surrogate.Surpluses, nodes, ni, no, nw),
		)

		location := Location{}
		scores := measure(self.basis, indices, ni)
		for i := uint(0); i < nc; i++ {
			location = Location{
				Node:    nodes[i*ni : (i+1)*ni],
				Surplus: surpluses[i*no : (i+1)*no],
				Volume:  scores[i],
			}
			scores[i] = target.Score(&location, &progress)
		}

		indices, surpluses, scores = compact(indices, surpluses, scores, ni, no, nc)

		nn := uint(len(scores))
		na, nr = na+nn, nr+nc-nn

		tracker.push(indices, scores)
		surrogate.push(indices, surpluses)
		surrogate.step(tracker.lnow, nn, nc-nn)

		cumulate(self.basis, indices, surpluses, ni, no, nn, integral, compensation)

		indices = history.unseen(self.grid.Refine(tracker.pull()))
		if config.Balance {
			indices = append(indices, balance(self.grid, history, indices)...)
		}

		nodes = self.grid.Compute(indices)

		nc = uint(len(indices)) / ni
	}

	return surrogate
}

// Evaluate computes the values of an interpolant at a set of points.
func (self *Interpolator) Evaluate(surrogate *Surrogate, points []float64) []float64 {
	return approximate(self.basis, surrogate.Indices, surrogate.Surpluses, points,
		surrogate.Inputs, surrogate.Outputs, self.config.Workers)
}

// Integrate computes the integral of an interpolant over [0, 1]^n.
func (self *Interpolator) Integrate(surrogate *Surrogate) []float64 {
	ni, no, nn := surrogate.Inputs, surrogate.Outputs, surrogate.Nodes

	integral, compensation := make([]float64, no), make([]float64, no)
	cumulate(self.basis, surrogate.Indices, surrogate.Surpluses,
		ni, no, nn, integral, compensation)

	return integral
}
<commit_msg>Exclude Level from Progress<commit_after>// Package adapt provides an algorithm for adaptive hierarchical interpolation
// with local refinements.
package adapt

import (
	"runtime"
)

// Grid is a sparse grid in [0, 1]^n.
type Grid interface {
	Compute(indices []uint64) []float64
	Refine(indices []uint64) []uint64
	Parent(index []uint64, i uint)
	Sibling(index []uint64, i uint)
}

// Basis is a functional basis in [0, 1]^n.
type Basis interface {
	Compute(index []uint64, point []float64) float64
	Integrate(index []uint64) float64
}

// Interpolator is an instance of the algorithm.
type Interpolator struct {
	grid   Grid
	basis  Basis
	config Config
}

// Progress contains information about the interpolation process.
type Progress struct {
	Iteration uint      // Iteration number
	Accepted  uint      // Number of accepted nodes
	Rejected  uint      // Number of rejected nodes
	Current   uint      // Number of nodes of the iteration
	Integral  []float64 // Integral over the whole domain
}

// New creates a new interpolator.
func New(grid Grid, basis Basis, config *Config) *Interpolator {
	interpolator := &Interpolator{
		grid:   grid,
		basis:  basis,
		config: *config,
	}

	config = &interpolator.config
	if config.Workers == 0 {
		config.Workers = uint(runtime.GOMAXPROCS(0))
	}
	if config.Rate == 0 {
		config.Rate = 1
	}

	return interpolator
}

// Compute constructs an interpolant for a function.
func (self *Interpolator) Compute(target Target) *Surrogate {
	config := &self.config

	ni, no := target.Dimensions()
	nw := config.Workers

	surrogate := newSurrogate(ni, no)
	tracker := newQueue(ni, config)
	history := newHash(ni)

	na, nr, nc := uint(0), uint(0), uint(1)

	indices := make([]uint64, nc*ni)
	nodes := self.grid.Compute(indices)

	integral, compensation := make([]float64, no), make([]float64, no)

	for k := uint(0); nc > 0; k++ {
		progress := Progress{
			Iteration: k,
			Accepted:  na,
			Rejected:  nr,
			Current:   nc,
			Integral:  integral,
		}

		target.Monitor(&progress)

		surpluses := subtract(
			invoke(target.Compute, nodes, ni, no, nw),
			approximate(self.basis, surrogate.Indices,
				surrogate.Surpluses, nodes, ni, no, nw),
		)

		location := Location{}
		scores := measure(self.basis, indices, ni)
		for i := uint(0); i < nc; i++ {
			location = Location{
				Node:    nodes[i*ni : (i+1)*ni],
				Surplus: surpluses[i*no : (i+1)*no],
				Volume:  scores[i],
			}
			scores[i] = target.Score(&location, &progress)
		}

		indices, surpluses, scores = compact(indices, surpluses, scores, ni, no, nc)

		nn := uint(len(scores))
		na, nr = na+nn, nr+nc-nn

		tracker.push(indices, scores)
		surrogate.push(indices, surpluses)
		surrogate.step(tracker.lnow, nn, nc-nn)

		cumulate(self.basis, indices, surpluses, ni, no, nn, integral, compensation)

		indices = history.unseen(self.grid.Refine(tracker.pull()))
		if config.Balance {
			indices = append(indices, balance(self.grid, history, indices)...)
		}

		nodes = self.grid.Compute(indices)

		nc = uint(len(indices)) / ni
	}

	return surrogate
}

// Evaluate computes the values of an interpolant at a set of points.
func (self *Interpolator) Evaluate(surrogate *Surrogate, points []float64) []float64 {
	return approximate(self.basis, surrogate.Indices, surrogate.Surpluses, points,
		surrogate.Inputs, surrogate.Outputs, self.config.Workers)
}

// Integrate computes the integral of an interpolant over [0, 1]^n.
func (self *Interpolator) Integrate(surrogate *Surrogate) []float64 {
	ni, no, nn := surrogate.Inputs, surrogate.Outputs, surrogate.Nodes

	integral, compensation := make([]float64, no), make([]float64, no)
	cumulate(self.basis, surrogate.Indices, surrogate.Surpluses,
		ni, no, nn, integral, compensation)

	return integral
}
<|endoftext|>


<commit_before>package chouse

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	defaultURL  = "https://api.companieshouse.gov.uk"
	contentType = "application/json"
)

type Company struct {
	Etag                  string         `json:"etag"`
	Accounts              AnnualAccounts `json:"accounts"`
	AnnualReturn          AnnualReturn   `json:"annual_return"`
	Branch                Branch         `json:"branch_company_details"`
	CanFile               bool           `json:"can_file"`
	CompanyName           string         `json:"company_name"`
	CompanyNumber         string         `json:"company_number"`
	CompanyStatus         string         `json:"company_status"`
	CompanyStatusDetail   string         `json:"company_status_detail"`
	ConfirmationStatement AnnualReturn   `json:"confirmation_statement"`
	DateOfCessation       string         `json:"date_of_cessation"`
	DateOfCreation        string         `json:"date_of_creation"`
	ForeignCompany        ForeignCompany `json:"foreign_company_details"`
	Liquidated            bool           `json:"has_been_liquidated"`
	Charges               bool           `json:"has_charges"`
	InsolvencyHistory     bool           `json:"has_insolvency_history"`
	Cic                   bool           `json:"is_community_interest_company"`
	Jurisdiction          string         `json:"jurisdiction"`
	LastMembersList       string         `json:"last_full_members_list_date"`
	Links                 Links          `json:"links"`
	PartialData           string         `json:"partial_data_available"`
	PreviousNames         []PreviousName `json:"previous_company_names"`
	RegisteredOffice      Address        `json:"registered_office_address"`
	RoDispute             bool           `json:"registered_office_is_in_dispute"`
	SicCodes              []string       `json:"sic_codes"`
	CompanyType           string         `json:"type"`
	RoUndeliverable       bool           `json:"undeliverable_registered_office_address"`
}

type AnnualAccounts struct {
	RefDate      RefDate `json:"accounting_reference_date"`
	LastAccounts struct {
		MadeUpTo string `json:"made_up_to"`
		Type     string `json:"type"`
	} `json:"last_accounts"`
	NextDue      string `json:"next_due"`
	NextMadeUpTo string `json:"next_made_up_to"`
	Overdue      bool   `json:"overdue"`
}

type RefDate struct {
	Day   string `json:"day"`
	Month string `json:"month"`
}

type AnnualReturn struct {
	LastMadeUpTo string `json:"last_made_up_to"`
	NextDue      string `json:"next_due"`
	NextMadeUpTo string `json:"next_made_up_to"`
	Overdue      bool   `json:"overdue"`
}

type Branch struct {
	Activity            string `json:"business_activity"`
	ParentCompanyCame   string `json:"parent_company_name"`
	ParentCompanyNumber string `json:"parent_company_number"`
}

type ForeignCompany struct {
	AccountingRequirement struct {
		AccountType string `json:"foreign_account_type"`
		Terms       string `json:"terms_of_account_publication"`
	} `json:"accounting_requirement"`
	Accounts struct {
		From   RefDate `json:"account_period_from"`
		To     RefDate `json:"account_period_to"`
		Within struct {
			Months int `json:"months"`
		} `json:"must_file_within"`
	} `json:"accounts`
	BusinessActivity    string `json:"business_activity"`
	CompanyType         string `json:"company_type"`
	GovernedBy          string `json:"governed_by"`
	FinanceInstitution  bool   `json:"is_a_credit_finance_institution"`
	OriginatingRegistry struct {
		Country string `json:"country"`
		Name    string `json:"name"`
	} `json:"originating_registry"`
	RegistrationNumber string `json:"registration_number"`
}

type Links struct {
	Charges       string `json:"charges"`
	FilingHistory string `json:"filing_history"`
	Insolvency    string `json:"insolvency"`
	Officers      string `json:"officers"`
	Psc           string `json:"persons_with_significant_control"`
	PscStatements string `json:"persons_with_significant_control_statements`
	Registers     string `json:"registers"`
	Self          string `json:"self"`
}

type PreviousName struct {
	CeasedOn      string `json:"ceased_on"`
	EffectiveFrom string `json:"effective_from"`
	Name          string `json:"name"`
}

type Address struct {
	Address1 string `json:"address_line_1"`
	Address2 string `json:"address_line_2"`
	CareOf   string `json:"care_of"`
	Country  string `json:"country"`
	Locality string `json:"locality"`
	PoBox    string `json:"po_box"`
	Postcode string `json:"postal_code"`
	Premises string `json:"premises"`
	Region   string `json:"region"`
}

type FilingHistoryList struct {
	Etag         string              `json:"etag"`
	Status       string              `json:"filing_history_status"`
	Items        []FilingHistoryItem `json:"items"`
	ItemsPerPage int                 `json:"items_per_page"`
	Kind         string              `json:"kind"`
	Start        int                 `json:"start_index"`
	TotalCount   int                 `json:"total_count"`
}

type FilingHistoryItem struct {
	Annotations []struct {
		Annotation        string `json:"annotation"`
		Category          string `json:"category"`
		Date              string `json:"date"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Description string `json:"description"`
		} `json:"description_values"`
		Type string `json:"type"`
	} `json:"annotations"`
	Associated []struct {
		ActionDate        int    `json:"action_date"`
		Category          string `json:"category"`
		Date              string `json:"date"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Capital []struct {
				Currency string `json:"currency"`
				Figure   string `json:"figure"`
			} `json:"capital"`
			Date string `json:"date"`
		} `json:"description_values"`
		OriginalDescription string `json:"original_description"`
		Type                string `json:"type"`
	} `json:"associated_filings"`
	DescriptionValues struct {
		MadeUpDate      string `json:"made_up_date"`
		OfficerName     string `json:"officer_name"`
		AppointmentDate string `json:"appointment_date"`
		NewAddress      string `json:"new_address"`
		ChangeDate      string `json:"change_date"`
		OldAddress      string `json:"old_address"`
		Date            string `json:"date"`
		Capital         []struct {
			Figure   string `json:"figure"`
			Currency string `json:"currency"`
		} `json:"capital"`
	} `json:"description_values"`
	Barcode     string `json:"barcode"`
	Category    string `json:"category"`
	Date        string `json:"date"`
	ActionDate  string `json:"action_date"`
	Description string `json:"description"`
	Links       Links  `json:"links"`
	Pages       int    `json:"pages"`
	PaperFiled  bool   `json:"paper_filed"`
	Resolutions []struct {
		Category          string `json:"category"`
		DeltaAt           string `json:"delta_at"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Description string `json:"description"`
			ResType     string `json:"res_type"`
		} `json:"description_values"`
		DocumentID  string `json:"document_id"`
		ReceiveDate string `json:"receive_date"`
		// It's either Array or String...
		// Subcategory struct `json:"subcategory"`
		Type string `json:"type"`
	} `json:"resolutions"`
	Subcategory   string `json:"subcategory"`
	TransactionID string `json:"transaction_id"`
	Type          string `json:"type"`
}

type CoHouseAPI struct {
	apiKey        string
	companyNumber string
}

func Explore(n string) *CoHouseAPI {
	ak := os.Getenv("CHOUSE_APIKEY")
	if ak == "" {
		fmt.Println("ERR: Env variable 'CHOUSE_APIKEY' is empty.")
		os.Exit(0)
	}
	return &CoHouseAPI{apiKey: ak, companyNumber: n}
}

func (ch *CoHouseAPI) callApi(path string) ([]byte, error) {
	url := defaultURL + path

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(ch.apiKey, "")
	req.Header.Set("Accept", contentType)

	client := &http.Client{}
	resp, errc := client.Do(req)
	if errc != nil {
		return nil, errc
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, errors.New(resp.Status)
	}

	return ioutil.ReadAll(resp.Body)
}

func (ch *CoHouseAPI) Company() (*Company, error) {
	c := &Company{}

	body, err := ch.callApi("/company/" + ch.companyNumber)
	if err != nil {
		return c, err
	}

	err = json.Unmarshal(body, &c)
	if err != nil {
		return c, err
	}

	return c, nil
}

func (ch *CoHouseAPI) Filings() (*FilingHistoryList, error) {
	fhl := &FilingHistoryList{}

	body, err := ch.callApi("/company/" + ch.companyNumber + "/filing-history")
	if err != nil {
		return fhl, err
	}

	err = json.Unmarshal(body, &fhl)
	if err != nil {
		return fhl, err
	}

	return fhl, nil
}
<commit_msg>Add missing file to Filing struct<commit_after>package chouse

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const (
	defaultURL  = "https://api.companieshouse.gov.uk"
	contentType = "application/json"
)

type Company struct {
	Etag                  string         `json:"etag"`
	Accounts              AnnualAccounts `json:"accounts"`
	AnnualReturn          AnnualReturn   `json:"annual_return"`
	Branch                Branch         `json:"branch_company_details"`
	CanFile               bool           `json:"can_file"`
	CompanyName           string         `json:"company_name"`
	CompanyNumber         string         `json:"company_number"`
	CompanyStatus         string         `json:"company_status"`
	CompanyStatusDetail   string         `json:"company_status_detail"`
	ConfirmationStatement AnnualReturn   `json:"confirmation_statement"`
	DateOfCessation       string         `json:"date_of_cessation"`
	DateOfCreation        string         `json:"date_of_creation"`
	ForeignCompany        ForeignCompany `json:"foreign_company_details"`
	Liquidated            bool           `json:"has_been_liquidated"`
	Charges               bool           `json:"has_charges"`
	InsolvencyHistory     bool           `json:"has_insolvency_history"`
	Cic                   bool           `json:"is_community_interest_company"`
	Jurisdiction          string         `json:"jurisdiction"`
	LastMembersList       string         `json:"last_full_members_list_date"`
	Links                 Links          `json:"links"`
	PartialData           string         `json:"partial_data_available"`
	PreviousNames         []PreviousName `json:"previous_company_names"`
	RegisteredOffice      Address        `json:"registered_office_address"`
	RoDispute             bool           `json:"registered_office_is_in_dispute"`
	SicCodes              []string       `json:"sic_codes"`
	CompanyType           string         `json:"type"`
	RoUndeliverable       bool           `json:"undeliverable_registered_office_address"`
}

type AnnualAccounts struct {
	RefDate      RefDate `json:"accounting_reference_date"`
	LastAccounts struct {
		MadeUpTo string `json:"made_up_to"`
		Type     string `json:"type"`
	} `json:"last_accounts"`
	NextDue      string `json:"next_due"`
	NextMadeUpTo string `json:"next_made_up_to"`
	Overdue      bool   `json:"overdue"`
}

type RefDate struct {
	Day   string `json:"day"`
	Month string `json:"month"`
}

type AnnualReturn struct {
	LastMadeUpTo string `json:"last_made_up_to"`
	NextDue      string `json:"next_due"`
	NextMadeUpTo string `json:"next_made_up_to"`
	Overdue      bool   `json:"overdue"`
}

type Branch struct {
	Activity            string `json:"business_activity"`
	ParentCompanyCame   string `json:"parent_company_name"`
	ParentCompanyNumber string `json:"parent_company_number"`
}

type ForeignCompany struct {
	AccountingRequirement struct {
		AccountType string `json:"foreign_account_type"`
		Terms       string `json:"terms_of_account_publication"`
	} `json:"accounting_requirement"`
	Accounts struct {
		From   RefDate `json:"account_period_from"`
		To     RefDate `json:"account_period_to"`
		Within struct {
			Months int `json:"months"`
		} `json:"must_file_within"`
	} `json:"accounts`
	BusinessActivity    string `json:"business_activity"`
	CompanyType         string `json:"company_type"`
	GovernedBy          string `json:"governed_by"`
	FinanceInstitution  bool   `json:"is_a_credit_finance_institution"`
	OriginatingRegistry struct {
		Country string `json:"country"`
		Name    string `json:"name"`
	} `json:"originating_registry"`
	RegistrationNumber string `json:"registration_number"`
}

type Links struct {
	Charges       string `json:"charges"`
	FilingHistory string `json:"filing_history"`
	Insolvency    string `json:"insolvency"`
	Officers      string `json:"officers"`
	Psc           string `json:"persons_with_significant_control"`
	PscStatements string `json:"persons_with_significant_control_statements`
	Registers     string `json:"registers"`
	Self          string `json:"self"`
}

type PreviousName struct {
	CeasedOn      string `json:"ceased_on"`
	EffectiveFrom string `json:"effective_from"`
	Name          string `json:"name"`
}

type Address struct {
	Address1 string `json:"address_line_1"`
	Address2 string `json:"address_line_2"`
	CareOf   string `json:"care_of"`
	Country  string `json:"country"`
	Locality string `json:"locality"`
	PoBox    string `json:"po_box"`
	Postcode string `json:"postal_code"`
	Premises string `json:"premises"`
	Region   string `json:"region"`
}

type FilingHistoryList struct {
	Etag         string              `json:"etag"`
	Status       string              `json:"filing_history_status"`
	Items        []FilingHistoryItem `json:"items"`
	ItemsPerPage int                 `json:"items_per_page"`
	Kind         string              `json:"kind"`
	Start        int                 `json:"start_index"`
	TotalCount   int                 `json:"total_count"`
}

type FilingHistoryItem struct {
	Annotations []struct {
		Annotation        string `json:"annotation"`
		Category          string `json:"category"`
		Date              string `json:"date"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Description string `json:"description"`
		} `json:"description_values"`
		Type string `json:"type"`
	} `json:"annotations"`
	Associated []struct {
		ActionDate        int    `json:"action_date"`
		Category          string `json:"category"`
		Date              string `json:"date"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Capital []struct {
				Currency string `json:"currency"`
				Figure   string `json:"figure"`
			} `json:"capital"`
			Date string `json:"date"`
		} `json:"description_values"`
		OriginalDescription string `json:"original_description"`
		Type                string `json:"type"`
	} `json:"associated_filings"`
	DescriptionValues struct {
		MadeUpDate      string `json:"made_up_date"`
		NewDate         string `json:"new_date"`
		Description     string `json:"description"`
		OfficerName     string `json:"officer_name"`
		AppointmentDate string `json:"appointment_date"`
		NewAddress      string `json:"new_address"`
		ChangeDate      string `json:"change_date"`
		OldAddress      string `json:"old_address"`
		Date            string `json:"date"`
		Capital         []struct {
			Figure   string `json:"figure"`
			Currency string `json:"currency"`
		} `json:"capital"`
	} `json:"description_values"`
	Barcode     string `json:"barcode"`
	Category    string `json:"category"`
	Date        string `json:"date"`
	ActionDate  string `json:"action_date"`
	Description string `json:"description"`
	Links       Links  `json:"links"`
	Pages       int    `json:"pages"`
	PaperFiled  bool   `json:"paper_filed"`
	Resolutions []struct {
		Category          string `json:"category"`
		DeltaAt           string `json:"delta_at"`
		Description       string `json:"description"`
		DescriptionValues struct {
			Description string `json:"description"`
			ResType     string `json:"res_type"`
		} `json:"description_values"`
		DocumentID  string `json:"document_id"`
		ReceiveDate string `json:"receive_date"`
		// It's either Array or String...
		// Subcategory struct `json:"subcategory"`
		Type string `json:"type"`
	} `json:"resolutions"`
	Subcategory   string `json:"subcategory"`
	TransactionID string `json:"transaction_id"`
	Type          string `json:"type"`
}

type CoHouseAPI struct {
	apiKey        string
	companyNumber string
}

func Explore(n string) *CoHouseAPI {
	ak := os.Getenv("CHOUSE_APIKEY")
	if ak == "" {
		fmt.Println("ERR: Env variable 'CHOUSE_APIKEY' is empty.")
		os.Exit(0)
	}
	return &CoHouseAPI{apiKey: ak, companyNumber: n}
}

func (ch *CoHouseAPI) callApi(path string) ([]byte, error) {
	url := defaultURL + path

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(ch.apiKey, "")
	req.Header.Set("Accept", contentType)

	client := &http.Client{}
	resp, errc := client.Do(req)
	if errc != nil {
		return nil, errc
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, errors.New(resp.Status)
	}

	return ioutil.ReadAll(resp.Body)
}

func (ch *CoHouseAPI) Company() (*Company, error) {
	c := &Company{}

	body, err := ch.callApi("/company/" + ch.companyNumber)
	if err != nil {
		return c, err
	}

	err = json.Unmarshal(body, &c)
	if err != nil {
		return c, err
	}

	return c, nil
}

func (ch *CoHouseAPI) Filings() (*FilingHistoryList, error) {
	fhl := &FilingHistoryList{}

	body, err := ch.callApi("/company/" + ch.companyNumber + "/filing-history")
	if err != nil {
		return fhl, err
	}

	err = json.Unmarshal(body, &fhl)
	if err != nil {
		return fhl, err
	}

	return fhl, nil
}
<|endoftext|>


<commit_before><commit_msg>go fmt<commit_after><|endoftext|>


<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/mithrandie/csvq/lib/action"
	"github.com/mithrandie/csvq/lib/cmd"
	"github.com/mithrandie/csvq/lib/query"

	"github.com/urfave/cli"
)

var version = "v0.8.6"

func main() {
	cli.AppHelpTemplate = appHHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate

	app := cli.NewApp()

	app.Name = "csvq"
	app.Usage = "SQL like query language for csv"
	app.ArgsUsage = "[\"query\"|\"statements\"|argument]"
	app.Version = version

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "delimiter, d",
			Usage: "field delimiter. Default is \",\" for csv files, \"\\t\" for tsv files.",
		},
		cli.StringFlag{
			Name:  "encoding, e",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "line-break, l",
			Value: "LF",
			Usage: "line break. one of: CRLF|LF|CR",
		},
		cli.StringFlag{
			Name:  "timezone, z",
			Value: "Local",
			Usage: "default timezone. \"Local\", \"UTC\" or a timezone name(e.g. \"America/Los_Angeles\")",
		},
		cli.StringFlag{
			Name:  "repository, r",
			Usage: "directory path where files are located",
		},
		cli.StringFlag{
			Name:  "source, s",
			Usage: "load query from `FILE`",
		},
		cli.StringFlag{
			Name:  "datetime-format, t",
			Usage: "set datetime format to parse strings",
		},
		cli.StringFlag{
			Name:  "wait-timeout, w",
			Value: "10",
			Usage: "limit of the waiting time in seconds to wait for locked files to be released",
		},
		cli.BoolFlag{
			Name:  "no-header, n",
			Usage: "import the first line as a record",
		},
		cli.BoolFlag{
			Name:  "without-null, a",
			Usage: "parse empty fields as empty strings",
		},
		cli.StringFlag{
			Name:  "write-encoding, E",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "out, o",
			Usage: "write output to `FILE`",
		},
		cli.StringFlag{
			Name:  "format, f",
			Usage: "output format. one of: CSV|TSV|JSON|TEXT",
		},
		cli.StringFlag{
			Name:  "write-delimiter, D",
			Usage: "field delimiter for CSV",
		},
		cli.BoolFlag{
			Name:  "without-header, N",
			Usage: "when the file format is specified as CSV or TSV, write without the header line",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "suppress operation log output",
		},
		cli.IntFlag{
			Name:  "cpu, p",
			Usage: "hint for the number of cpu cores to be used. 1 - number of cpu cores",
		},
		cli.BoolFlag{
			Name:  "stats, x",
			Usage: "show execution time and memory statistics",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "fields",
			Usage:     "Show fields in a file",
			ArgsUsage: "CSV_FILE_PATH",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "fields")
					return cli.NewExitError("table is not specified", 1)
				}

				table := c.Args().First()

				err := action.ShowFields(table)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "calc",
			Usage:     "Calculate a value from stdin",
			ArgsUsage: "\"expression\"",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "calc")
					return cli.NewExitError("expression is empty", 1)
				}

				expr := c.Args().First()
				err := action.Calc(expr)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		err := setFlags(c)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		return nil
	}

	app.Action = func(c *cli.Context) error {
		queryString, err := readQuery(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return cli.NewExitError(err.Error(), 1)
		}

		if len(queryString) < 1 {
			err = action.LaunchInteractiveShell()
		} else {
			err = action.Run(queryString, cmd.GetFlags().Source)
		}

		if err != nil {
			code := 1
			if apperr, ok := err.(query.AppError); ok {
				code = apperr.GetCode()
			} else if ex, ok := err.(*query.Exit); ok {
				code = ex.GetCode()
			}
			return cli.NewExitError(err.Error(), code)
		}

		return nil
	}

	app.Run(os.Args)
}

func readQuery(c *cli.Context) (string, error) {
	var queryString string

	flags := cmd.GetFlags()
	if 0 < len(flags.Source) {
		fp, err := os.Open(flags.Source)
		if err != nil {
			return queryString, err
		}
		defer fp.Close()

		buf, err := ioutil.ReadAll(fp)
		if err != nil {
			return queryString, err
		}
		queryString = string(buf)

	} else {
		if 1 < c.NArg() {
			return queryString, errors.New("multiple queries or statements were passed")
		}
		queryString = c.Args().First()
	}

	return queryString, nil
}

func setFlags(c *cli.Context) error {
	if err := cmd.SetDelimiter(c.GlobalString("delimiter")); err != nil {
		return err
	}
	if err := cmd.SetEncoding(c.GlobalString("encoding")); err != nil {
		return err
	}
	if err := cmd.SetLineBreak(c.String("line-break")); err != nil {
		return err
	}
	if err := cmd.SetLocation(c.String("timezone")); err != nil {
		return err
	}
	if err := cmd.SetRepository(c.GlobalString("repository")); err != nil {
		return err
	}
	if err := cmd.SetSource(c.GlobalString("source")); err != nil {
		return err
	}
	cmd.SetDatetimeFormat(c.GlobalString("datetime-format"))
	if err := cmd.SetWaitTimeout(c.GlobalString("wait-timeout")); err != nil {
		return err
	}
	cmd.SetNoHeader(c.GlobalBool("no-header"))
	cmd.SetWithoutNull(c.GlobalBool("without-null"))

	if err := cmd.SetWriteEncoding(c.GlobalString("write-encoding")); err != nil {
		return err
	}
	if err := cmd.SetOut(c.GlobalString("out")); err != nil {
		return err
	}
	if err := cmd.SetFormat(c.GlobalString("format")); err != nil {
		return err
	}
	if err := cmd.SetWriteDelimiter(c.GlobalString("write-delimiter")); err != nil {
		return err
	}
	cmd.SetWithoutHeader(c.GlobalBool("without-header"))

	cmd.SetQuiet(c.GlobalBool("quiet"))
	cmd.SetCPU(c.GlobalInt("cpu"))
	cmd.SetStats(c.GlobalBool("stats"))

	return nil
}
<commit_msg>Update version for Release v0.8.7<commit_after>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/mithrandie/csvq/lib/action"
	"github.com/mithrandie/csvq/lib/cmd"
	"github.com/mithrandie/csvq/lib/query"

	"github.com/urfave/cli"
)

var version = "v0.8.7"

func main() {
	cli.AppHelpTemplate = appHHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate

	app := cli.NewApp()

	app.Name = "csvq"
	app.Usage = "SQL like query language for csv"
	app.ArgsUsage = "[\"query\"|\"statements\"|argument]"
	app.Version = version

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "delimiter, d",
			Usage: "field delimiter. Default is \",\" for csv files, \"\\t\" for tsv files.",
		},
		cli.StringFlag{
			Name:  "encoding, e",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "line-break, l",
			Value: "LF",
			Usage: "line break. one of: CRLF|LF|CR",
		},
		cli.StringFlag{
			Name:  "timezone, z",
			Value: "Local",
			Usage: "default timezone. \"Local\", \"UTC\" or a timezone name(e.g. \"America/Los_Angeles\")",
		},
		cli.StringFlag{
			Name:  "repository, r",
			Usage: "directory path where files are located",
		},
		cli.StringFlag{
			Name:  "source, s",
			Usage: "load query from `FILE`",
		},
		cli.StringFlag{
			Name:  "datetime-format, t",
			Usage: "set datetime format to parse strings",
		},
		cli.StringFlag{
			Name:  "wait-timeout, w",
			Value: "10",
			Usage: "limit of the waiting time in seconds to wait for locked files to be released",
		},
		cli.BoolFlag{
			Name:  "no-header, n",
			Usage: "import the first line as a record",
		},
		cli.BoolFlag{
			Name:  "without-null, a",
			Usage: "parse empty fields as empty strings",
		},
		cli.StringFlag{
			Name:  "write-encoding, E",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "out, o",
			Usage: "write output to `FILE`",
		},
		cli.StringFlag{
			Name:  "format, f",
			Usage: "output format. one of: CSV|TSV|JSON|TEXT",
		},
		cli.StringFlag{
			Name:  "write-delimiter, D",
			Usage: "field delimiter for CSV",
		},
		cli.BoolFlag{
			Name:  "without-header, N",
			Usage: "when the file format is specified as CSV or TSV, write without the header line",
		},
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "suppress operation log output",
		},
		cli.IntFlag{
			Name:  "cpu, p",
			Usage: "hint for the number of cpu cores to be used. 1 - number of cpu cores",
		},
		cli.BoolFlag{
			Name:  "stats, x",
			Usage: "show execution time and memory statistics",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "fields",
			Usage:     "Show fields in a file",
			ArgsUsage: "CSV_FILE_PATH",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "fields")
					return cli.NewExitError("table is not specified", 1)
				}

				table := c.Args().First()

				err := action.ShowFields(table)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "calc",
			Usage:     "Calculate a value from stdin",
			ArgsUsage: "\"expression\"",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "calc")
					return cli.NewExitError("expression is empty", 1)
				}

				expr := c.Args().First()
				err := action.Calc(expr)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		err := setFlags(c)
		if err != nil {
			return cli.NewExitError(err.Error(), 1)
		}
		return nil
	}

	app.Action = func(c *cli.Context) error {
		queryString, err := readQuery(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return cli.NewExitError(err.Error(), 1)
		}

		if len(queryString) < 1 {
			err = action.LaunchInteractiveShell()
		} else {
			err = action.Run(queryString, cmd.GetFlags().Source)
		}

		if err != nil {
			code := 1
			if apperr, ok := err.(query.AppError); ok {
				code = apperr.GetCode()
			} else if ex, ok := err.(*query.Exit); ok {
				code = ex.GetCode()
			}
			return cli.NewExitError(err.Error(), code)
		}

		return nil
	}

	app.Run(os.Args)
}

func readQuery(c *cli.Context) (string, error) {
	var queryString string

	flags := cmd.GetFlags()
	if 0 < len(flags.Source) {
		fp, err := os.Open(flags.Source)
		if err != nil {
			return queryString, err
		}
		defer fp.Close()

		buf, err := ioutil.ReadAll(fp)
		if err != nil {
			return queryString, err
		}
		queryString = string(buf)

	} else {
		if 1 < c.NArg() {
			return queryString, errors.New("multiple queries or statements were passed")
		}
		queryString = c.Args().First()
	}

	return queryString, nil
}

func setFlags(c *cli.Context) error {
	if err := cmd.SetDelimiter(c.GlobalString("delimiter")); err != nil {
		return err
	}
	if err := cmd.SetEncoding(c.GlobalString("encoding")); err != nil {
		return err
	}
	if err := cmd.SetLineBreak(c.String("line-break")); err != nil {
		return err
	}
	if err := cmd.SetLocation(c.String("timezone")); err != nil {
		return err
	}
	if err := cmd.SetRepository(c.GlobalString("repository")); err != nil {
		return err
	}
	if err := cmd.SetSource(c.GlobalString("source")); err != nil {
		return err
	}
	cmd.SetDatetimeFormat(c.GlobalString("datetime-format"))
	if err := cmd.SetWaitTimeout(c.GlobalString("wait-timeout")); err != nil {
		return err
	}
	cmd.SetNoHeader(c.GlobalBool("no-header"))
	cmd.SetWithoutNull(c.GlobalBool("without-null"))

	if err := cmd.SetWriteEncoding(c.GlobalString("write-encoding")); err != nil {
		return err
	}
	if err := cmd.SetOut(c.GlobalString("out")); err != nil {
		return err
	}
	if err := cmd.SetFormat(c.GlobalString("format")); err != nil {
		return err
	}
	if err := cmd.SetWriteDelimiter(c.GlobalString("write-delimiter")); err != nil {
		return err
	}
	cmd.SetWithoutHeader(c.GlobalBool("without-header"))

	cmd.SetQuiet(c.GlobalBool("quiet"))
	cmd.SetCPU(c.GlobalInt("cpu"))
	cmd.SetStats(c.GlobalBool("stats"))

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"

	"github.com/igungor/ilberbot/command"
	"github.com/igungor/tlbot"
)

// flags
var (
	token   = flag.String("token", "", "telegram bot token")
	webhook = flag.String("webhook", "", "webhook url")
	host    = flag.String("host", "", "host to listen to")
	port    = flag.String("port", "1985", "port to listen to")
)

func usage() {
	fmt.Fprintf(os.Stderr, "ilberbot is a multi-purpose Telegram bot\n\n")
	fmt.Fprintf(os.Stderr, "usage:\n")
	fmt.Fprintf(os.Stderr, "  ilberbot -token <insert-your-telegrambot-token> -webhook <insert-your-webhook-url>\n\n")
	fmt.Fprintf(os.Stderr, "flags:\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("ilberbot: ")
	flag.Usage = usage
	flag.Parse()

	if *token == "" {
		log.Printf("missing token parameter\n\n")
		flag.Usage()
	}
	if *webhook == "" {
		log.Printf("missing webhook parameter\n\n")
		flag.Usage()
	}

	b := tlbot.New(*token)
	err := b.SetWebhook(*webhook)
	if err != nil {
		log.Fatal(err)
	}

	messages := b.Listen(net.JoinHostPort(*host, *port))
	for msg := range messages {
		// is message a command?
		cmdname := msg.Command()
		if cmdname == "" {
			continue
		}

		// does it even exist?
		cmd := command.Lookup(cmdname)
		if cmd == nil {
			continue
		}

		// cool, run it!
		cmd.Run(&b, &msg)
	}
}
<commit_msg>redundant comment changes<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"

	"github.com/igungor/ilberbot/command"
	"github.com/igungor/tlbot"
)

// flags
var (
	token   = flag.String("token", "", "telegram bot token")
	webhook = flag.String("webhook", "", "webhook url")
	host    = flag.String("host", "", "host to listen to")
	port    = flag.String("port", "1985", "port to listen to")
)

func usage() {
	fmt.Fprintf(os.Stderr, "ilberbot is a multi-purpose Telegram bot\n\n")
	fmt.Fprintf(os.Stderr, "usage:\n")
	fmt.Fprintf(os.Stderr, "  ilberbot -token <insert-your-telegrambot-token> -webhook <insert-your-webhook-url>\n\n")
	fmt.Fprintf(os.Stderr, "flags:\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	log.SetFlags(0)
	log.SetPrefix("ilberbot: ")
	flag.Usage = usage
	flag.Parse()

	if *token == "" {
		log.Printf("missing token parameter\n\n")
		flag.Usage()
	}
	if *webhook == "" {
		log.Printf("missing webhook parameter\n\n")
		flag.Usage()
	}

	b := tlbot.New(*token)
	err := b.SetWebhook(*webhook)
	if err != nil {
		log.Fatal(err)
	}

	messages := b.Listen(net.JoinHostPort(*host, *port))
	for msg := range messages {
		// is message a command?
		cmdname := msg.Command()
		if cmdname == "" {
			continue
		}

		// does the command even registered?
		cmd := command.Lookup(cmdname)
		if cmd == nil {
			continue
		}

		// it is. cool, run it!
		cmd.Run(&b, &msg)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/google/subcommands"
	"github.com/kotakanbe/go-cve-dictionary/commands"
)

// Name ... Name
const Name string = "go-cve-dictionary"

// Version ... Version
var version = "0.4.0"

// Revision of Git
var revision string

func main() {
	subcommands.Register(subcommands.HelpCommand(), "")
	subcommands.Register(subcommands.FlagsCommand(), "")
	subcommands.Register(subcommands.CommandsCommand(), "")
	subcommands.Register(&commands.ServerCmd{}, "server")
	subcommands.Register(&commands.FetchJvnCmd{}, "fetchjvn")
	subcommands.Register(&commands.FetchNvdCmd{}, "fetchnvd")
	subcommands.Register(&commands.ListCmd{}, "list")

	if envArgs := os.Getenv("GO_CVE_DICTIONARY_ARGS"); 0 < len(envArgs) {
		if err := flag.CommandLine.Parse(strings.Fields(envArgs)); err != nil {
			fmt.Printf("Failed to parse ENV_VARs: %s", err)
			os.Exit(int(subcommands.ExitUsageError))
		}
	} else {
		flag.Parse()
	}

	var v = flag.Bool("v", false, "Show version")
	if *v {
		fmt.Printf("go-cve-dictionary %s %s\n", version, revision)
		os.Exit(int(subcommands.ExitSuccess))
	}

	ctx := context.Background()
	os.Exit(int(subcommands.Execute(ctx)))
}
<commit_msg>bump up version<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/google/subcommands"
	"github.com/kotakanbe/go-cve-dictionary/commands"
)

// Name ... Name
const Name string = "go-cve-dictionary"

// Version ... Version
var version = "0.5.0"

// Revision of Git
var revision string

func main() {
	subcommands.Register(subcommands.HelpCommand(), "")
	subcommands.Register(subcommands.FlagsCommand(), "")
	subcommands.Register(subcommands.CommandsCommand(), "")
	subcommands.Register(&commands.ServerCmd{}, "server")
	subcommands.Register(&commands.FetchJvnCmd{}, "fetchjvn")
	subcommands.Register(&commands.FetchNvdCmd{}, "fetchnvd")
	subcommands.Register(&commands.ListCmd{}, "list")

	if envArgs := os.Getenv("GO_CVE_DICTIONARY_ARGS"); 0 < len(envArgs) {
		if err := flag.CommandLine.Parse(strings.Fields(envArgs)); err != nil {
			fmt.Printf("Failed to parse ENV_VARs: %s", err)
			os.Exit(int(subcommands.ExitUsageError))
		}
	} else {
		flag.Parse()
	}

	var v = flag.Bool("v", false, "Show version")
	if *v {
		fmt.Printf("go-cve-dictionary %s %s\n", version, revision)
		os.Exit(int(subcommands.ExitSuccess))
	}

	ctx := context.Background()
	os.Exit(int(subcommands.Execute(ctx)))
}
<|endoftext|>