<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	DOT = "."
)

var currentGaugeVersion = &version{0, 0, 3}

type version struct {
	major int
	minor int
	patch int
}

func parseVersion(versionText string) (*version, error) {
	splits := strings.Split(versionText, DOT)
	if len(splits) != 3 {
		return nil, errors.New("Incorrect number of '.' characters in Version. Version should be of the form 1.5.7")
	}
	major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing major version number %s to integer. %s", splits[0], err.Error()))
	}
	minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing minor version number %s to integer. %s", splits[0], err.Error()))
	}
	patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing patch version number %s to integer. %s", splits[0], err.Error()))
	}

	return &version{major, minor, patch}, nil
}

func (version *version) isBetween(lower *version, greater *version) bool {
	return version.isGreaterThanEqualTo(lower) && version.isLesserThanEqualTo(greater)
}

func (version *version) isLesserThan(version1 *version) bool {
	return compareVersions(version, version1, lesserThanFunc)
}

func (version *version) isGreaterThan(version1 *version) bool {
	return compareVersions(version, version1, greaterThanFunc)
}

func (version *version) isLesserThanEqualTo(version1 *version) bool {
	return version.isLesserThan(version1) || version.isEqualTo(version1)
}

func (version *version) isGreaterThanEqualTo(version1 *version) bool {
	return version.isGreaterThan(version1) || version.isEqualTo(version1)
}

func (version *version) isEqualTo(version1 *version) bool {
	return isEqual(version.major, version1.major) && isEqual(version.minor, version1.minor) && isEqual(version.patch, version1.patch)
}

func compareVersions(first *version, second *version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.major, second.major) {
		return true
	} else if isEqual(first.major, second.major) {
		if compareFunc(first.minor, second.minor) {
			return true
		} else if isEqual(first.minor, second.minor) {
			if compareFunc(first.patch, second.patch) {
				return true
			} else {
				return false
			}
		}
	}
	return false
}

func lesserThanFunc(first, second int) bool {
	return first < second
}

func greaterThanFunc(first, second int) bool {
	return first > second
}

func isEqual(first, second int) bool {
	return first == second
}

func (version *version) String() string {
	return fmt.Sprintf("%d.%d.%d", version.major, version.minor, version.patch)
}
<commit_msg>Keeping Version 0.0.2<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	DOT = "."
)

var currentGaugeVersion = &version{0, 0, 2}

type version struct {
	major int
	minor int
	patch int
}

func parseVersion(versionText string) (*version, error) {
	splits := strings.Split(versionText, DOT)
	if len(splits) != 3 {
		return nil, errors.New("Incorrect number of '.' characters in Version. Version should be of the form 1.5.7")
	}
	major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing major version number %s to integer. %s", splits[0], err.Error()))
	}
	minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing minor version number %s to integer. %s", splits[0], err.Error()))
	}
	patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error parsing patch version number %s to integer. %s", splits[0], err.Error()))
	}

	return &version{major, minor, patch}, nil
}

func (version *version) isBetween(lower *version, greater *version) bool {
	return version.isGreaterThanEqualTo(lower) && version.isLesserThanEqualTo(greater)
}

func (version *version) isLesserThan(version1 *version) bool {
	return compareVersions(version, version1, lesserThanFunc)
}

func (version *version) isGreaterThan(version1 *version) bool {
	return compareVersions(version, version1, greaterThanFunc)
}

func (version *version) isLesserThanEqualTo(version1 *version) bool {
	return version.isLesserThan(version1) || version.isEqualTo(version1)
}

func (version *version) isGreaterThanEqualTo(version1 *version) bool {
	return version.isGreaterThan(version1) || version.isEqualTo(version1)
}

func (version *version) isEqualTo(version1 *version) bool {
	return isEqual(version.major, version1.major) && isEqual(version.minor, version1.minor) && isEqual(version.patch, version1.patch)
}

func compareVersions(first *version, second *version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.major, second.major) {
		return true
	} else if isEqual(first.major, second.major) {
		if compareFunc(first.minor, second.minor) {
			return true
		} else if isEqual(first.minor, second.minor) {
			if compareFunc(first.patch, second.patch) {
				return true
			} else {
				return false
			}
		}
	}
	return false
}

func lesserThanFunc(first, second int) bool {
	return first < second
}

func greaterThanFunc(first, second int) bool {
	return first > second
}

func isEqual(first, second int) bool {
	return first == second
}

func (version *version) String() string {
	return fmt.Sprintf("%d.%d.%d", version.major, version.minor, version.patch)
}
<|endoftext|>


<commit_before>package ipvs

import (
    "encoding/binary"
    "bytes"
    "fmt"
    "log"
    "net"
    "github.com/hkwi/nlgo"
    "syscall"
)

type Service struct {
    // id
    Af          uint16
    Protocol    uint16
    Addr        net.IP
    Port        uint16
    FwMark      uint32

    // params
    SchedName   string
    Flags       IPVSFlags
    Timeout     uint32
    Netmask     uint32
}

func unpack(buf []byte, out interface{}) error {
    return binary.Read(bytes.NewReader(buf), binary.BigEndian, out)
}

func pack (in interface{}) []byte {
    var buf bytes.Buffer

    if err := binary.Write(&buf, binary.BigEndian, in); err != nil {
        panic(err)
    }

    return buf.Bytes()
}

func htons (value uint16) uint16 {
    return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8)
}

func (self *Service) unpack(attrs nlgo.AttrList) error {
    var addr []byte
    var flags []byte

    for _, attr := range attrs {
        switch attr.Field() {
        case IPVS_SVC_ATTR_AF:          self.Af = attr.Value.(uint16)
        case IPVS_SVC_ATTR_PROTOCOL:    self.Protocol = attr.Value.(uint16)
        case IPVS_SVC_ATTR_ADDR:        addr = attr.Value.([]byte)
        case IPVS_SVC_ATTR_PORT:        self.Port = attr.Value.(uint16)
        case IPVS_SVC_ATTR_FWMARK:      self.FwMark = attr.Value.(uint32)
        case IPVS_SVC_ATTR_SCHED_NAME:  self.SchedName = attr.Value.(string)
        case IPVS_SVC_ATTR_FLAGS:       flags = attr.Value.([]byte)
        case IPVS_SVC_ATTR_TIMEOUT:     self.Timeout = attr.Value.(uint32)
        case IPVS_SVC_ATTR_NETMASK:     self.Netmask = attr.Value.(uint32)
        }
    }

    switch self.Af {
    case syscall.AF_INET:
        self.Addr = (net.IP)(addr[:4])

    case syscall.AF_INET6:
        self.Addr = (net.IP)(addr[:16])

    default:
        return fmt.Errorf("ipvs:Client.ListServices: unknown service AF=%d ADDR=%v", self.Af, addr)
    }

    if err := unpack(flags, &self.Flags); err != nil {
        return fmt.Errorf("ipvs:Service.unpack: flags: %s", err)
    }

    return nil
}

func (self *Service) attrs(full bool) nlgo.AttrList {
    var attrs nlgo.AttrList

    if self.FwMark != 0 {
        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_AF, self.Af),
            nlattr(IPVS_SVC_ATTR_FWMARK, self.FwMark),
        )
    } else if self.Protocol != 0 && self.Addr != nil && self.Port != 0 {
        var addr []byte

        switch self.Af {
        case syscall.AF_INET:   addr = ([]byte)(self.Addr.To4())
        case syscall.AF_INET6:  addr = ([]byte)(self.Addr.To16())
        default:
            panic(fmt.Errorf("ipvs:Service.attrs: unknown service Af=%d Addr=%v", self.Af, self.Addr))
        }

        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_AF, self.Af),
            nlattr(IPVS_SVC_ATTR_PROTOCOL, self.Protocol),
            nlattr(IPVS_SVC_ATTR_ADDR, addr),
            nlattr(IPVS_SVC_ATTR_PORT, htons(self.Port)),       // network-order when sending
        )
    } else {
        panic("Incomplete service id fields")
    }

    if full {
        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_SCHED_NAME,    self.SchedName),
            nlattr(IPVS_SVC_ATTR_FLAGS,         pack(&self.Flags)),
            nlattr(IPVS_SVC_ATTR_TIMEOUT,       self.Timeout),
            nlattr(IPVS_SVC_ATTR_NETMASK,       self.Netmask),
        )
    }

    return attrs
}

type cmd struct {
    serviceId   *Service
    serviceFull *Service
}

func (self cmd) attrs() nlgo.AttrList {
    attrs := nlgo.AttrList{}

    if self.serviceFull != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_SERVICE, self.serviceFull.attrs(true)))
    }

    if self.serviceId != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_SERVICE, self.serviceId.attrs(false)))
    }

    return attrs
}

func (client *Client) GetInfo() error {
    return client.request(Request{Cmd: IPVS_CMD_GET_INFO}, client.queryParser(IPVS_CMD_SET_INFO, ipvs_info_policy, func (attrs nlgo.AttrList) error {
        version := attrs.Get(IPVS_INFO_ATTR_VERSION).(uint32)
        size := attrs.Get(IPVS_INFO_ATTR_CONN_TAB_SIZE).(uint32)

        log.Printf("ipvs:Client.GetInfo: IPVS version=%d.%d.%d, size=%d\n",
            (version >> 16) & 0xFF,
            (version >> 8)  & 0xFF,
            (version >> 0)  & 0xFF,
            size,
        )

        return nil
    }))
}

func (client *Client) Flush() error {
    return client.exec(Request{Cmd: IPVS_CMD_FLUSH})
}

func (client *Client) NewService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_NEW_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceFull: &service}.attrs(),
    })
}

func (client *Client) SetService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_SET_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceFull: &service}.attrs(),
    })
}

func (client *Client) DelService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_DEL_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceId: &service}.attrs(),
    })
}

func (client *Client) ListServices() ([]Service, error) {
    services := make([]Service, 0)
    request := Request{
        Cmd:    IPVS_CMD_GET_SERVICE,
        Flags:  syscall.NLM_F_DUMP,
    }

    if err := client.request(request, client.queryParser(IPVS_CMD_NEW_SERVICE, ipvs_cmd_policy, func (cmdAttrs nlgo.AttrList) error {
        svcAttrs := cmdAttrs.Get(IPVS_CMD_ATTR_SERVICE).(nlgo.AttrList)

        //log.Printf("ipvs:Client.ListServices: svc=%+v\n", ipvs_service_policy.Dump(svc_attrs))

        service := Service{}

        if err := service.unpack(svcAttrs); err != nil {
            return err
        } else {
            services = append(services, service)
        }

        return nil
    })); err != nil {
        return services, err
    } else {
        return services, nil
    }
}

func (client *Client) ListDests(service Service) (error) {
    request := Request{
        Cmd:    IPVS_CMD_GET_DEST,
        Flags:  syscall.NLM_F_DUMP,
        Policy: ipvs_cmd_policy,
        Attrs:  cmd{serviceId: &service}.attrs(),
    }

    return client.request(request, client.queryParser(IPVS_CMD_NEW_DEST, ipvs_cmd_policy, func (cmd_attrs nlgo.AttrList) error {
        log.Printf("ipvs:Client.ListDests: cmd=%+v\n", ipvs_cmd_policy.Dump(cmd_attrs))

        return nil
    }))
}

<commit_msg>ipvs: Dest struct, pack, and add/set/del support<commit_after>package ipvs

import (
    "encoding/binary"
    "bytes"
    "fmt"
    "log"
    "net"
    "github.com/hkwi/nlgo"
    "syscall"
)

type Service struct {
    // id
    Af          uint16
    Protocol    uint16
    Addr        net.IP
    Port        uint16
    FwMark      uint32

    // params
    SchedName   string
    Flags       IPVSFlags
    Timeout     uint32
    Netmask     uint32
}

type Dest struct {
    // id
    // TODO: IPVS_DEST_ATTR_ADDR_FAMILY
    Addr        net.IP
    Port        uint16

    // params
    FwdMethod   uint32
    Weight      uint32
    UThresh     uint32
    LThresh     uint32

    // info
    ActiveConns     uint32
    InactConns      uint32
    PersistConns    uint32
}

func unpack(buf []byte, out interface{}) error {
    return binary.Read(bytes.NewReader(buf), binary.BigEndian, out)
}

func pack (in interface{}) []byte {
    var buf bytes.Buffer

    if err := binary.Write(&buf, binary.BigEndian, in); err != nil {
        panic(err)
    }

    return buf.Bytes()
}

func packAddr (af uint16, addr net.IP) []byte {
    switch af {
        case syscall.AF_INET:   return ([]byte)(addr.To4())
        case syscall.AF_INET6:  return ([]byte)(addr.To16())
        default:
            panic(fmt.Errorf("ipvs:packAddr: unknown af=%d addr=%v", af, addr))
    }
}

func htons (value uint16) uint16 {
    return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8)
}

func (self *Service) unpack(attrs nlgo.AttrList) error {
    var addr []byte
    var flags []byte

    for _, attr := range attrs {
        switch attr.Field() {
        case IPVS_SVC_ATTR_AF:          self.Af = attr.Value.(uint16)
        case IPVS_SVC_ATTR_PROTOCOL:    self.Protocol = attr.Value.(uint16)
        case IPVS_SVC_ATTR_ADDR:        addr = attr.Value.([]byte)
        case IPVS_SVC_ATTR_PORT:        self.Port = attr.Value.(uint16)
        case IPVS_SVC_ATTR_FWMARK:      self.FwMark = attr.Value.(uint32)
        case IPVS_SVC_ATTR_SCHED_NAME:  self.SchedName = attr.Value.(string)
        case IPVS_SVC_ATTR_FLAGS:       flags = attr.Value.([]byte)
        case IPVS_SVC_ATTR_TIMEOUT:     self.Timeout = attr.Value.(uint32)
        case IPVS_SVC_ATTR_NETMASK:     self.Netmask = attr.Value.(uint32)
        }
    }

    switch self.Af {
    case syscall.AF_INET:
        self.Addr = (net.IP)(addr[:4])

    case syscall.AF_INET6:
        self.Addr = (net.IP)(addr[:16])

    default:
        return fmt.Errorf("ipvs:Client.ListServices: unknown service AF=%d ADDR=%v", self.Af, addr)
    }

    if err := unpack(flags, &self.Flags); err != nil {
        return fmt.Errorf("ipvs:Service.unpack: flags: %s", err)
    }

    return nil
}

func (self *Service) attrs(full bool) nlgo.AttrList {
    var attrs nlgo.AttrList

    if self.FwMark != 0 {
        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_AF, self.Af),
            nlattr(IPVS_SVC_ATTR_FWMARK, self.FwMark),
        )
    } else if self.Protocol != 0 && self.Addr != nil && self.Port != 0 {
        addr := packAddr(self.Af, self.Addr)

        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_AF, self.Af),
            nlattr(IPVS_SVC_ATTR_PROTOCOL, self.Protocol),
            nlattr(IPVS_SVC_ATTR_ADDR, addr),
            nlattr(IPVS_SVC_ATTR_PORT, htons(self.Port)),       // network-order when sending
        )
    } else {
        panic("Incomplete service id fields")
    }

    if full {
        attrs = append(attrs,
            nlattr(IPVS_SVC_ATTR_SCHED_NAME,    self.SchedName),
            nlattr(IPVS_SVC_ATTR_FLAGS,         pack(&self.Flags)),
            nlattr(IPVS_SVC_ATTR_TIMEOUT,       self.Timeout),
            nlattr(IPVS_SVC_ATTR_NETMASK,       self.Netmask),
        )
    }

    return attrs
}

func (self *Dest) attrs(service *Service, full bool) nlgo.AttrList {
    var attrs nlgo.AttrList

    attrs = append(attrs,
        nlattr(IPVS_DEST_ATTR_ADDR, packAddr(service.Af, self.Addr)),
        nlattr(IPVS_DEST_ATTR_PORT, htons(self.Port)),
    )

    if full {
        attrs = append(attrs,
            nlattr(IPVS_DEST_ATTR_FWD_METHOD,   self.FwdMethod),
            nlattr(IPVS_DEST_ATTR_WEIGHT,       self.Weight),
            nlattr(IPVS_DEST_ATTR_U_THRESH,     self.UThresh),
            nlattr(IPVS_DEST_ATTR_L_THRESH,     self.LThresh),
        )
    }

    return attrs
}

type cmd struct {
    serviceId   *Service
    serviceFull *Service

    destId      *Dest
    destFull    *Dest
}

func (self cmd) attrs() nlgo.AttrList {
    attrs := nlgo.AttrList{}

    if self.serviceId != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_SERVICE, self.serviceId.attrs(false)))
    }
    if self.serviceFull != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_SERVICE, self.serviceFull.attrs(true)))
    }

    if self.destId != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_DEST, self.destId.attrs(self.serviceId, false)))
    }
    if self.destFull != nil {
        attrs = append(attrs, nlattr(IPVS_CMD_ATTR_DEST, self.destFull.attrs(self.serviceId, true)))
    }

    return attrs
}

func (client *Client) GetInfo() error {
    return client.request(Request{Cmd: IPVS_CMD_GET_INFO}, client.queryParser(IPVS_CMD_SET_INFO, ipvs_info_policy, func (attrs nlgo.AttrList) error {
        version := attrs.Get(IPVS_INFO_ATTR_VERSION).(uint32)
        size := attrs.Get(IPVS_INFO_ATTR_CONN_TAB_SIZE).(uint32)

        log.Printf("ipvs:Client.GetInfo: IPVS version=%d.%d.%d, size=%d\n",
            (version >> 16) & 0xFF,
            (version >> 8)  & 0xFF,
            (version >> 0)  & 0xFF,
            size,
        )

        return nil
    }))
}

func (client *Client) Flush() error {
    return client.exec(Request{Cmd: IPVS_CMD_FLUSH})
}

func (client *Client) NewService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_NEW_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceFull: &service}.attrs(),
    })
}

func (client *Client) SetService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_SET_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceFull: &service}.attrs(),
    })
}

func (client *Client) DelService(service Service) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_DEL_SERVICE,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceId: &service}.attrs(),
    })
}

func (client *Client) ListServices() ([]Service, error) {
    services := make([]Service, 0)
    request := Request{
        Cmd:    IPVS_CMD_GET_SERVICE,
        Flags:  syscall.NLM_F_DUMP,
    }

    if err := client.request(request, client.queryParser(IPVS_CMD_NEW_SERVICE, ipvs_cmd_policy, func (cmdAttrs nlgo.AttrList) error {
        svcAttrs := cmdAttrs.Get(IPVS_CMD_ATTR_SERVICE).(nlgo.AttrList)

        //log.Printf("ipvs:Client.ListServices: svc=%+v\n", ipvs_service_policy.Dump(svc_attrs))

        service := Service{}

        if err := service.unpack(svcAttrs); err != nil {
            return err
        } else {
            services = append(services, service)
        }

        return nil
    })); err != nil {
        return services, err
    } else {
        return services, nil
    }
}

func (client *Client) NewDest(service Service, dest Dest) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_NEW_DEST,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceId: &service, destFull: &dest}.attrs(),
    })
}

func (client *Client) SetDest(service Service, dest Dest) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_SET_DEST,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceId: &service, destFull: &dest}.attrs(),
    })
}

func (client *Client) DelDest(service Service, dest Dest) error {
    return client.exec(Request{
        Cmd:        IPVS_CMD_DEL_DEST,
        Policy:     ipvs_cmd_policy,
        Attrs:      cmd{serviceId: &service, destId: &dest}.attrs(),
    })
}

func (client *Client) ListDests(service Service) (error) {
    request := Request{
        Cmd:    IPVS_CMD_GET_DEST,
        Flags:  syscall.NLM_F_DUMP,
        Policy: ipvs_cmd_policy,
        Attrs:  cmd{serviceId: &service}.attrs(),
    }

    return client.request(request, client.queryParser(IPVS_CMD_NEW_DEST, ipvs_cmd_policy, func (cmd_attrs nlgo.AttrList) error {
        log.Printf("ipvs:Client.ListDests: cmd=%+v\n", ipvs_cmd_policy.Dump(cmd_attrs))

        return nil
    }))
}

<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"

	"gopkg.in/yaml.v2"
)

const (
	readmeTemplate  = "readme.tmpl"
	listTemplate    = "list.tmpl"
	aliasesTemplate = "aliases.tmpl"
	headerTemplate  = "header.tmpl"

	sigsYamlFile  = "sigs.yaml"
	sigListOutput = "sig-list.md"
	aliasesOutput = "OWNERS_ALIASES"
	indexFilename = "README.md"

	beginCustomMarkdown = "<!-- BEGIN CUSTOM CONTENT -->"
	endCustomMarkdown   = "<!-- END CUSTOM CONTENT -->"
	beginCustomYaml     = "## BEGIN CUSTOM CONTENT"
	endCustomYaml       = "## END CUSTOM CONTENT"
)

var (
	baseGeneratorDir = ""
	templateDir      = "generator"
)

// Person represents an individual person holding a role in a group.
type Person struct {
	Name    string
	Company string
	GitHub  string
}

// Meeting represents a regular meeting for a group.
type Meeting struct {
	Description   string
	Day           string
	Time          string
	TZ            string
	Frequency     string
	URL           string
	ArchiveURL    string `yaml:"archive_url"`
	RecordingsURL string `yaml:"recordings_url"`
}

// Contact represents the various contact points for a group.
type Contact struct {
	Slack       string
	MailingList string        `yaml:"mailing_list"`
	GithubTeams []GithubTeams `yaml:"teams"`
}

// GithubTeams represents a specific Github Team.
type GithubTeams struct {
	Name        string
	Description string
}

// Subproject represents a specific subproject owned by the group
type Subproject struct {
	Name        string
	Description string
	Owners      []string
	Meetings    []Meeting
}

// LeadershipGroup represents the different groups of leaders within a group
type LeadershipGroup struct {
	Chairs         []Person
	TechnicalLeads []Person `yaml:"tech_leads"`
	EmeritusLeads  []Person `yaml:"emeritus_leads"`
}

// Group represents either a Special Interest Group (SIG) or a Working Group (WG)
type Group struct {
	Name             string
	Dir              string
	MissionStatement string `yaml:"mission_statement"`
	Label            string
	Leadership       LeadershipGroup `yaml:"leadership"`
	Meetings         []Meeting
	Contact          Contact
	Subprojects      []Subproject
}

// DirName returns the directory that a group's documentation will be
// generated into. It is composed of a prefix (sig for SIGs and wg for WGs),
// and a formatted version of the group's name (in kebab case).
func (e *Group) DirName(prefix string) string {
	return fmt.Sprintf("%s-%s", prefix, strings.ToLower(strings.Replace(e.Name, " ", "-", -1)))
}

// Context is the context for the sigs.yaml file.
type Context struct {
	Sigs          []Group
	WorkingGroups []Group
}

func pathExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func createDirIfNotExists(path string) error {
	if !pathExists(path) {
		return os.MkdirAll(path, 0755)
	}
	return nil
}

func getExistingContent(path string, fileFormat string) (string, error) {
	capture := false
	var captured []string

	beginMarker := ""
	endMarker := ""
	switch fileFormat {
	case "markdown":
		beginMarker = beginCustomMarkdown
		endMarker = endCustomMarkdown
	case "yaml":
		beginMarker = beginCustomYaml
		endMarker = endCustomYaml
	case "":
		return "", nil
	}

	// NOTE: For some reason using bufio.Scanner with existing file pointer prepends
	// a bunch of null ^@ characters, so using to ioutil.ReadFile instead.
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}

	for _, line := range strings.Split(string(content), "\n") {
		if strings.Contains(line, endMarker) {
			capture = false
		}
		if capture {
			captured = append(captured, line)
		}
		if strings.Contains(line, beginMarker) {
			capture = true
		}
	}

	return strings.Join(captured, "\n"), nil
}

var funcMap = template.FuncMap{
	"tzUrlEncode": tzUrlEncode,
}

// tzUrlEncode returns an url encoded string without the + shortcut. This is
// required as the timezone conversion site we are using doesn't recognize + as
// a valid url escape character.
func tzUrlEncode(tz string) string {
	return strings.Replace(url.QueryEscape(tz), "+", "%20", -1)
}

func writeTemplate(templatePath, outputPath string, fileFormat string, data interface{}) error {
	// set up template
	t, err := template.New(filepath.Base(templatePath)).
		Funcs(funcMap).
		ParseFiles(templatePath, filepath.Join(baseGeneratorDir, templateDir, headerTemplate))
	if err != nil {
		return err
	}

	// create if not exists
	if !pathExists(outputPath) {
		_, err = os.Create(outputPath)
		if err != nil {
			return err
		}
	}

	// open file and truncate
	f, err := os.OpenFile(outputPath, os.O_RDWR, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	// get any existing content
	content, err := getExistingContent(outputPath, fileFormat)
	if err != nil {
		return err
	}

	// ensure file is empty
	f.Truncate(0)

	// generated content
	err = t.Execute(f, data)
	if err != nil {
		return err
	}

	writeCustomContentBlock(f, content, fileFormat)

	return nil
}

func writeCustomContentBlock(f *os.File, content string, fileFormat string) {
	beginMarker := ""
	endMarker := ""
	switch fileFormat {
	case "markdown":
		beginMarker = beginCustomMarkdown
		endMarker = endCustomMarkdown
	case "yaml":
		beginMarker = beginCustomYaml
		endMarker = endCustomYaml
	case "":
		return
	}

	lines := []string{beginMarker, "\n", content, "\n", endMarker, "\n"}
	for _, line := range lines {
		f.Write([]byte(line))
	}
}

func createGroupReadme(groups []Group, prefix string) error {
	// figure out if the user wants to generate one group
	var selectedGroupName *string
	if envVal, ok := os.LookupEnv("WHAT"); ok {
		selectedGroupName = &envVal
	}

	for _, group := range groups {
		group.Dir = group.DirName(prefix)
		// skip generation if the user specified only one group
		if selectedGroupName != nil && strings.HasSuffix(group.Dir, *selectedGroupName) == false {
			fmt.Printf("Skipping %s/README.md\n", group.Dir)
			continue
		}

		fmt.Printf("Generating %s/README.md\n", group.Dir)

		outputDir := filepath.Join(baseGeneratorDir, group.Dir)
		if err := createDirIfNotExists(outputDir); err != nil {
			return err
		}

		outputPath := filepath.Join(outputDir, indexFilename)
		readmePath := filepath.Join(baseGeneratorDir, templateDir, fmt.Sprintf("%s_%s", prefix, readmeTemplate))
		if err := writeTemplate(readmePath, outputPath, "markdown", group); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	yamlData, err := ioutil.ReadFile(filepath.Join(baseGeneratorDir, sigsYamlFile))
	if err != nil {
		log.Fatal(err)
	}

	var ctx Context
	err = yaml.Unmarshal(yamlData, &ctx)
	if err != nil {
		log.Fatal(err)
	}

	sort.Slice(ctx.Sigs, func(i, j int) bool {
		return strings.ToLower(ctx.Sigs[i].Name) <= strings.ToLower(ctx.Sigs[j].Name)
	})

	sort.Slice(ctx.WorkingGroups, func(i, j int) bool {
		return strings.ToLower(ctx.WorkingGroups[i].Name) <= strings.ToLower(ctx.WorkingGroups[j].Name)
	})

	err = createGroupReadme(ctx.Sigs, "sig")
	if err != nil {
		log.Fatal(err)
	}

	err = createGroupReadme(ctx.WorkingGroups, "wg")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Generating sig-list.md")
	outputPath := filepath.Join(baseGeneratorDir, sigListOutput)
	err = writeTemplate(filepath.Join(baseGeneratorDir, templateDir, listTemplate), outputPath, "markdown", ctx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Generating OWNERS_ALIASES")
	outputPath = filepath.Join(baseGeneratorDir, aliasesOutput)
	err = writeTemplate(filepath.Join(baseGeneratorDir, templateDir, aliasesTemplate), outputPath, "yaml", ctx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Finished generation!")
}
<commit_msg>fix grammar mistake<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"

	"gopkg.in/yaml.v2"
)

const (
	readmeTemplate  = "readme.tmpl"
	listTemplate    = "list.tmpl"
	aliasesTemplate = "aliases.tmpl"
	headerTemplate  = "header.tmpl"

	sigsYamlFile  = "sigs.yaml"
	sigListOutput = "sig-list.md"
	aliasesOutput = "OWNERS_ALIASES"
	indexFilename = "README.md"

	beginCustomMarkdown = "<!-- BEGIN CUSTOM CONTENT -->"
	endCustomMarkdown   = "<!-- END CUSTOM CONTENT -->"
	beginCustomYaml     = "## BEGIN CUSTOM CONTENT"
	endCustomYaml       = "## END CUSTOM CONTENT"
)

var (
	baseGeneratorDir = ""
	templateDir      = "generator"
)

// Person represents an individual person holding a role in a group.
type Person struct {
	Name    string
	Company string
	GitHub  string
}

// Meeting represents a regular meeting for a group.
type Meeting struct {
	Description   string
	Day           string
	Time          string
	TZ            string
	Frequency     string
	URL           string
	ArchiveURL    string `yaml:"archive_url"`
	RecordingsURL string `yaml:"recordings_url"`
}

// Contact represents the various contact points for a group.
type Contact struct {
	Slack       string
	MailingList string        `yaml:"mailing_list"`
	GithubTeams []GithubTeams `yaml:"teams"`
}

// GithubTeams represents a specific Github Team.
type GithubTeams struct {
	Name        string
	Description string
}

// Subproject represents a specific subproject owned by the group
type Subproject struct {
	Name        string
	Description string
	Owners      []string
	Meetings    []Meeting
}

// LeadershipGroup represents the different groups of leaders within a group
type LeadershipGroup struct {
	Chairs         []Person
	TechnicalLeads []Person `yaml:"tech_leads"`
	EmeritusLeads  []Person `yaml:"emeritus_leads"`
}

// Group represents either a Special Interest Group (SIG) or a Working Group (WG)
type Group struct {
	Name             string
	Dir              string
	MissionStatement string `yaml:"mission_statement"`
	Label            string
	Leadership       LeadershipGroup `yaml:"leadership"`
	Meetings         []Meeting
	Contact          Contact
	Subprojects      []Subproject
}

// DirName returns the directory that a group's documentation will be
// generated into. It is composed of a prefix (sig for SIGs and wg for WGs),
// and a formatted version of the group's name (in kebab case).
func (e *Group) DirName(prefix string) string {
	return fmt.Sprintf("%s-%s", prefix, strings.ToLower(strings.Replace(e.Name, " ", "-", -1)))
}

// Context is the context for the sigs.yaml file.
type Context struct {
	Sigs          []Group
	WorkingGroups []Group
}

func pathExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func createDirIfNotExists(path string) error {
	if !pathExists(path) {
		return os.MkdirAll(path, 0755)
	}
	return nil
}

func getExistingContent(path string, fileFormat string) (string, error) {
	capture := false
	var captured []string

	beginMarker := ""
	endMarker := ""
	switch fileFormat {
	case "markdown":
		beginMarker = beginCustomMarkdown
		endMarker = endCustomMarkdown
	case "yaml":
		beginMarker = beginCustomYaml
		endMarker = endCustomYaml
	case "":
		return "", nil
	}

	// NOTE: For some reason using bufio.Scanner with existing file pointer prepends
	// a bunch of null ^@ characters, so using to ioutil.ReadFile instead.
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}

	for _, line := range strings.Split(string(content), "\n") {
		if strings.Contains(line, endMarker) {
			capture = false
		}
		if capture {
			captured = append(captured, line)
		}
		if strings.Contains(line, beginMarker) {
			capture = true
		}
	}

	return strings.Join(captured, "\n"), nil
}

var funcMap = template.FuncMap{
	"tzUrlEncode": tzUrlEncode,
}

// tzUrlEncode returns a url encoded string without the + shortcut. This is
// required as the timezone conversion site we are using doesn't recognize + as
// a valid url escape character.
func tzUrlEncode(tz string) string {
	return strings.Replace(url.QueryEscape(tz), "+", "%20", -1)
}

func writeTemplate(templatePath, outputPath string, fileFormat string, data interface{}) error {
	// set up template
	t, err := template.New(filepath.Base(templatePath)).
		Funcs(funcMap).
		ParseFiles(templatePath, filepath.Join(baseGeneratorDir, templateDir, headerTemplate))
	if err != nil {
		return err
	}

	// create if not exists
	if !pathExists(outputPath) {
		_, err = os.Create(outputPath)
		if err != nil {
			return err
		}
	}

	// open file and truncate
	f, err := os.OpenFile(outputPath, os.O_RDWR, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	// get any existing content
	content, err := getExistingContent(outputPath, fileFormat)
	if err != nil {
		return err
	}

	// ensure file is empty
	f.Truncate(0)

	// generated content
	err = t.Execute(f, data)
	if err != nil {
		return err
	}

	writeCustomContentBlock(f, content, fileFormat)

	return nil
}

func writeCustomContentBlock(f *os.File, content string, fileFormat string) {
	beginMarker := ""
	endMarker := ""
	switch fileFormat {
	case "markdown":
		beginMarker = beginCustomMarkdown
		endMarker = endCustomMarkdown
	case "yaml":
		beginMarker = beginCustomYaml
		endMarker = endCustomYaml
	case "":
		return
	}

	lines := []string{beginMarker, "\n", content, "\n", endMarker, "\n"}
	for _, line := range lines {
		f.Write([]byte(line))
	}
}

func createGroupReadme(groups []Group, prefix string) error {
	// figure out if the user wants to generate one group
	var selectedGroupName *string
	if envVal, ok := os.LookupEnv("WHAT"); ok {
		selectedGroupName = &envVal
	}

	for _, group := range groups {
		group.Dir = group.DirName(prefix)
		// skip generation if the user specified only one group
		if selectedGroupName != nil && strings.HasSuffix(group.Dir, *selectedGroupName) == false {
			fmt.Printf("Skipping %s/README.md\n", group.Dir)
			continue
		}

		fmt.Printf("Generating %s/README.md\n", group.Dir)

		outputDir := filepath.Join(baseGeneratorDir, group.Dir)
		if err := createDirIfNotExists(outputDir); err != nil {
			return err
		}

		outputPath := filepath.Join(outputDir, indexFilename)
		readmePath := filepath.Join(baseGeneratorDir, templateDir, fmt.Sprintf("%s_%s", prefix, readmeTemplate))
		if err := writeTemplate(readmePath, outputPath, "markdown", group); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	yamlData, err := ioutil.ReadFile(filepath.Join(baseGeneratorDir, sigsYamlFile))
	if err != nil {
		log.Fatal(err)
	}

	var ctx Context
	err = yaml.Unmarshal(yamlData, &ctx)
	if err != nil {
		log.Fatal(err)
	}

	sort.Slice(ctx.Sigs, func(i, j int) bool {
		return strings.ToLower(ctx.Sigs[i].Name) <= strings.ToLower(ctx.Sigs[j].Name)
	})

	sort.Slice(ctx.WorkingGroups, func(i, j int) bool {
		return strings.ToLower(ctx.WorkingGroups[i].Name) <= strings.ToLower(ctx.WorkingGroups[j].Name)
	})

	err = createGroupReadme(ctx.Sigs, "sig")
	if err != nil {
		log.Fatal(err)
	}

	err = createGroupReadme(ctx.WorkingGroups, "wg")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Generating sig-list.md")
	outputPath := filepath.Join(baseGeneratorDir, sigListOutput)
	err = writeTemplate(filepath.Join(baseGeneratorDir, templateDir, listTemplate), outputPath, "markdown", ctx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Generating OWNERS_ALIASES")
	outputPath = filepath.Join(baseGeneratorDir, aliasesOutput)
	err = writeTemplate(filepath.Join(baseGeneratorDir, templateDir, aliasesTemplate), outputPath, "yaml", ctx)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Finished generation!")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"time"
)

func responseBody(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

func JenkinsJob(jenkins, jobName *string) (Job, error) {
	url := "http://" + *jenkins + "/job/" + *jobName + "/api/json?pretty=true"
	fmt.Printf("%s\n", url)
	contents, err := responseBody(url)
	if err != nil {
		return Job{}, err
	}
	// fmt.Printf("%s\n", string(contents))

	var data Job
	err = json.Unmarshal(contents, &data)
	if err != nil {
		return Job{}, err
	}
	return data, nil
}

func JenkinsBuild(jenkins, jobName *string, buildNumber *int) (Build, error) {
	build := Build{}

	url := "http://" + *jenkins +
		"/job/" + *jobName + "/" +
		strconv.Itoa(*buildNumber) + "/api/json?pretty=true"

	fmt.Printf("%s\n", url)
	contents, err := responseBody(url)
	if err != nil {
		return build, err
	}
	// fmt.Printf("%s\n", string(contents))

	err = json.Unmarshal(contents, &build)
	if err != nil {
		return build, err
	}
	return build, nil
}

type Job struct {
	Name            string `json:"name"`
	URL             string `json:"url"`
	Color           string `json:"color"`
	NextBuildNumber int    `json:"nextBuildNumber"`
	InQueue         bool   `json:"inQueue"`
}

type Build struct {
	Number            int    `json:"number"`
	Duration          int    `json:"duration"`
	EstimatedDuration int    `json:"estimatedDuration"`
	Timestamp         int    `json:"timestamp"`
	URL               string `json:"url"`
	Result            string `json:"result"`
	Building          bool   `json:"building"`
}

func main() {
	jenkins := flag.String("jenkins", "127.0.0.1:8080", "Jenkins hostname")
	jobName := flag.String("jobName", "test", "Jenkins job name")
	flag.Parse()

	job, err := JenkinsJob(jenkins, jobName)
	if err != nil {
		panic(err)
	}
	fmt.Printf("job.NextBuildNumber: %d\n", job.NextBuildNumber)
	buildNumber := job.NextBuildNumber

	url := "http://" + *jenkins + "/job/" + *jobName + "/build"
	_, err = http.Post(url, "", nil)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s\n", url)

	// while InQueue
	for {
		time.Sleep(time.Second)
		job, err := JenkinsJob(jenkins, jobName)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		fmt.Println("Time:", time.Now())
		fmt.Println("Name:", job.Name)
		fmt.Println("InQueue:", job.InQueue)

		if !job.InQueue {
			break
		}
	}

	// while Building
	for {
		time.Sleep(time.Second)
		build, err := JenkinsBuild(jenkins, jobName, &buildNumber)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		fmt.Println("Time:", time.Now())
		fmt.Println("Number:", build.Number)
		fmt.Println("Building:", build.Building)
		fmt.Println("Timestamp:", build.Timestamp)
		fmt.Println("Duration:", build.Duration)
		fmt.Println("EstimatedDuration:", build.EstimatedDuration)
		fmt.Println("Result:", build.Result)
		if !build.Building {
			break
		}
	}

	build, err := JenkinsBuild(jenkins, jobName, &buildNumber)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}
	fmt.Println("Time:", time.Now())
	fmt.Println("Number:", build.Number)
	fmt.Println("Building:", build.Building)
	fmt.Println("Timestamp:", build.Timestamp)
	fmt.Println("Duration:", build.Duration)
	fmt.Println("EstimatedDuration:", build.EstimatedDuration)
	fmt.Println("Result:", build.Result)
}
<commit_msg>calculating a Build Countdown<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"time"
)

func responseBody(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	return contents, nil
}

func JenkinsJob(jenkins, jobName *string) (Job, error) {
	url := "http://" + *jenkins + "/job/" + *jobName + "/api/json?pretty=true"
	fmt.Printf("%s\n", url)
	contents, err := responseBody(url)
	if err != nil {
		return Job{}, err
	}
	// fmt.Printf("%s\n", string(contents))

	var data Job
	err = json.Unmarshal(contents, &data)
	if err != nil {
		return Job{}, err
	}
	return data, nil
}

func JenkinsBuild(jenkins, jobName *string, buildNumber *int) (Build, error) {
	build := Build{}

	url := "http://" + *jenkins +
		"/job/" + *jobName + "/" +
		strconv.Itoa(*buildNumber) + "/api/json?pretty=true"

	fmt.Printf("%s\n", url)
	contents, err := responseBody(url)
	if err != nil {
		return build, err
	}
	// fmt.Printf("%s\n", string(contents))

	err = json.Unmarshal(contents, &build)
	if err != nil {
		return build, err
	}
	return build, nil
}

type Job struct {
	Name            string `json:"name"`
	URL             string `json:"url"`
	Color           string `json:"color"`
	NextBuildNumber int    `json:"nextBuildNumber"`
	InQueue         bool   `json:"inQueue"`
}

type Build struct {
	Number            int    `json:"number"`
	Duration          int    `json:"duration"`
	EstimatedDuration int    `json:"estimatedDuration"`
	Timestamp         int    `json:"timestamp"`
	URL               string `json:"url"`
	Result            string `json:"result"`
	Building          bool   `json:"building"`
}

func main() {
	jenkins := flag.String("jenkins", "127.0.0.1:8080", "Jenkins hostname")
	jobName := flag.String("jobName", "test", "Jenkins job name")
	flag.Parse()

	job, err := JenkinsJob(jenkins, jobName)
	if err != nil {
		panic(err)
	}
	fmt.Printf("job.NextBuildNumber: %d\n", job.NextBuildNumber)
	buildNumber := job.NextBuildNumber

	url := "http://" + *jenkins + "/job/" + *jobName + "/build"
	_, err = http.Post(url, "", nil)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s\n", url)

	// while InQueue
	for {
		time.Sleep(time.Second)
		job, err := JenkinsJob(jenkins, jobName)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		fmt.Println("Time:", time.Now())
		fmt.Println("Name:", job.Name)
		fmt.Println("InQueue:", job.InQueue)

		if !job.InQueue {
			break
		}
	}

	// while Building
	for {
		time.Sleep(time.Second)
		build, err := JenkinsBuild(jenkins, jobName, &buildNumber)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		now := time.Now()
		start := time.Unix(int64(build.Timestamp/1000), 0)
		estEnd := time.Unix(int64((build.Timestamp+build.EstimatedDuration)/1000), 0)

		buildDuration := int(time.Since(start).Seconds())
		buildCountdown := (build.EstimatedDuration / 1000) - buildDuration

		fmt.Println("Time:", now)
		fmt.Println("Number:", build.Number)
		fmt.Println("Building:", build.Building)
		fmt.Println("Timestamp:", build.Timestamp)
		fmt.Println("Start:", start)
		fmt.Println("Build Duration: (s): ", buildDuration)
		fmt.Println("Build Countdown (s): ", buildCountdown)
		fmt.Println("Estimated End:", estEnd)
		fmt.Println("Estimated Duration (s): ", build.EstimatedDuration/1000)
		if !build.Building {
			break
		}
	}

	build, err := JenkinsBuild(jenkins, jobName, &buildNumber)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}
	fmt.Println("Time:", time.Now())
	fmt.Println("Number:", build.Number)
	fmt.Println("Building:", build.Building)
	fmt.Println("Timestamp:", build.Timestamp)
	fmt.Println("Duration:", build.Duration)
	fmt.Println("EstimatedDuration:", build.EstimatedDuration)
	fmt.Println("Result:", build.Result)
}
<|endoftext|>


<commit_before>package gaurun

import (
	"strings"
	"sync/atomic"

	"github.com/RobotsAndPencils/buford/push"
)

var (
	// pusherCountAll is the shared value between workers
	PusherCountAll int64
)

func init() {
	PusherCountAll = 0
}

func StartPushWorkers(workerNum, queueNum int64) {
	QueueNotification = make(chan RequestGaurunNotification, queueNum)
	for i := int64(0); i < workerNum; i++ {
		go pushNotificationWorker()
	}
}

func isExternalServerError(err error, platform int) bool {
	switch platform {
	case PlatFormIos:
		if err == push.ErrIdleTimeout || err == push.ErrShutdown || err == push.ErrInternalServerError || err == push.ErrServiceUnavailable {
			return true
		}
	case PlatFormAndroid:
		if err.Error() == "Unavailable" || err.Error() == "InternalServerError" || strings.Contains(err.Error(), "Timeout") {
			return true
		}
	default:
		// not through
	}
	return false
}

func pushSync(pusher func(req RequestGaurunNotification) error, req RequestGaurunNotification, retryMax int) {
Retry:
	err := pusher(req)
	if err != nil && req.Retry < retryMax && isExternalServerError(err, req.Platform) {
		req.Retry++
		goto Retry
	}
}

func pushAsync(pusher func(req RequestGaurunNotification) error, req RequestGaurunNotification, retryMax int, pusherCount *int64) {
Retry:
	err := pusher(req)
	if err != nil && req.Retry < retryMax && isExternalServerError(err, req.Platform) {
		req.Retry++
		goto Retry
	}

	*pusherCount = *pusherCount - 1
	atomic.AddInt64(&PusherCountAll, -1)
}

func pushNotificationWorker() {
	var (
		retryMax    int
		pusher      func(req RequestGaurunNotification) error
		pusherCount int64
	)

	// pusherCount is the independent value between workers
	pusherCount = 0

	for {
		notification := <-QueueNotification

		switch notification.Platform {
		case PlatFormIos:
			pusher = pushNotificationIos
			retryMax = ConfGaurun.Ios.RetryMax
		case PlatFormAndroid:
			pusher = pushNotificationAndroid
			retryMax = ConfGaurun.Android.RetryMax
		default:
			LogError.Warnf("invalid platform: %d", notification.Platform)
			continue
		}

		if atomic.LoadInt64(&ConfGaurun.Core.PusherMax) <= 0 {
			pushSync(pusher, notification, retryMax)
			continue
		}

		if pusherCount < atomic.LoadInt64(&ConfGaurun.Core.PusherMax) {
			// Do not increment pusherCount and PusherCountAll in pushAsync().
			// Because pusherCount and PusherCountAll are sometimes over pusherMax
			// as the increment in goroutine runs asynchronously.
			pusherCount++
			atomic.AddInt64(&PusherCountAll, 1)

			go pushAsync(pusher, notification, retryMax, &pusherCount)
			continue
		} else {
			pushSync(pusher, notification, retryMax)
			continue
		}
	}
}
<commit_msg>worker: made pusherCount atomic.<commit_after>package gaurun

import (
	"strings"
	"sync/atomic"

	"github.com/RobotsAndPencils/buford/push"
)

var (
	// pusherCountAll is the shared value between workers
	PusherCountAll int64
)

func init() {
	PusherCountAll = 0
}

func StartPushWorkers(workerNum, queueNum int64) {
	QueueNotification = make(chan RequestGaurunNotification, queueNum)
	for i := int64(0); i < workerNum; i++ {
		go pushNotificationWorker()
	}
}

func isExternalServerError(err error, platform int) bool {
	switch platform {
	case PlatFormIos:
		if err == push.ErrIdleTimeout || err == push.ErrShutdown || err == push.ErrInternalServerError || err == push.ErrServiceUnavailable {
			return true
		}
	case PlatFormAndroid:
		if err.Error() == "Unavailable" || err.Error() == "InternalServerError" || strings.Contains(err.Error(), "Timeout") {
			return true
		}
	default:
		// not through
	}
	return false
}

func pushSync(pusher func(req RequestGaurunNotification) error, req RequestGaurunNotification, retryMax int) {
Retry:
	err := pusher(req)
	if err != nil && req.Retry < retryMax && isExternalServerError(err, req.Platform) {
		req.Retry++
		goto Retry
	}
}

func pushAsync(pusher func(req RequestGaurunNotification) error, req RequestGaurunNotification, retryMax int, pusherCount *int64) {
Retry:
	err := pusher(req)
	if err != nil && req.Retry < retryMax && isExternalServerError(err, req.Platform) {
		req.Retry++
		goto Retry
	}

	atomic.AddInt64(pusherCount, -1)
	atomic.AddInt64(&PusherCountAll, -1)
}

func pushNotificationWorker() {
	var (
		retryMax    int
		pusher      func(req RequestGaurunNotification) error
		pusherCount int64
	)

	// pusherCount is the independent value between workers
	pusherCount = 0

	for {
		notification := <-QueueNotification

		switch notification.Platform {
		case PlatFormIos:
			pusher = pushNotificationIos
			retryMax = ConfGaurun.Ios.RetryMax
		case PlatFormAndroid:
			pusher = pushNotificationAndroid
			retryMax = ConfGaurun.Android.RetryMax
		default:
			LogError.Warnf("invalid platform: %d", notification.Platform)
			continue
		}

		if atomic.LoadInt64(&ConfGaurun.Core.PusherMax) <= 0 {
			pushSync(pusher, notification, retryMax)
			continue
		}

		if atomic.LoadInt64(&pusherCount) < atomic.LoadInt64(&ConfGaurun.Core.PusherMax) {
			// Do not increment pusherCount and PusherCountAll in pushAsync().
			// Because pusherCount and PusherCountAll are sometimes over pusherMax
			// as the increment in goroutine runs asynchronously.
			atomic.AddInt64(&pusherCount, 1)
			atomic.AddInt64(&PusherCountAll, 1)

			go pushAsync(pusher, notification, retryMax, &pusherCount)
			continue
		} else {
			pushSync(pusher, notification, retryMax)
			continue
		}
	}
}
<|endoftext|>


<commit_before>package bytepool

import (
  "time"
  "strconv"
  "strings"
)

type JsonItem struct {
  *Item
  depth int
  added bool
  pool *JsonPool
}

func newJsonItem(capacity int, pool *JsonPool) *JsonItem {
  return &JsonItem {
    pool: pool,
    Item: newItem(capacity, nil),
  }
}

var JsonEncode = strings.NewReplacer(`\`, `\\`, `"`, `\"`).Replace

func (item *JsonItem) WriteString(s string) int {
  return item.WriteSafeString(JsonEncode(s))
}

func (item *JsonItem) WriteInt(value int) int {
  n := item.Item.WriteString(strconv.Itoa(value))
  return item.delimit(n)
}

func (item *JsonItem) WriteBool(value bool) int {
  n := item.Item.WriteString(strconv.FormatBool(value))
  return item.delimit(n)
}

func (item *JsonItem) WriteTime(value time.Time) int {
  return item.WriteString(value.Format(time.RFC3339))
}

func (item *JsonItem) WriteSafeString(s string) int {
  return item.writeString(s, true)
}

func (item *JsonItem) WriteKeyString(key, value string) int {
  return item.WriteKeySafeString(key, JsonEncode(value))
}

func (item *JsonItem) WriteKeySafeString(key, value string) int {
  return item.WriteKeyValue(key, value, true)
}

func (item *JsonItem) WriteKeyInt(key string, value int) int {
  return item.WriteKeyValue(key, strconv.Itoa(value), false)
}

func (item *JsonItem) WriteKeyBool(key string, value bool) int {
  return item.WriteKeyValue(key, strconv.FormatBool(value), false)
}

func (item *JsonItem) WriteKeyTime(key string, value time.Time) int {
  return item.WriteKeyString(key, value.Format(time.RFC3339))
}

func (item *JsonItem) WriteKeyArray(key string) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if item.BeginArray() { n++ }
  return n
}

func (item *JsonItem) WriteKeyObject(key string) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if item.BeginObject() { n++ }
  return n
}

func (item *JsonItem) WriteKeyValue(key, value string, surround bool) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if surround { item.WriteByte(byte('"')); n++ }
  n += item.Item.WriteString(value)
  if surround { item.WriteByte(byte('"')); n++ }
  return item.delimit(n)
}

func (item *JsonItem) writeString(s string, delimit bool) int {
  n := 0
  if item.WriteByte(byte('"')) { n++ }
  n += item.Item.WriteString(s)
  if item.WriteByte(byte('"')) { n++ }
  if delimit == false { return n }
  return item.delimit(n)
}

func (item *JsonItem) BeginArray() bool {
  item.added = false
  item.depth++
  return item.WriteByte('[')
}

func (item *JsonItem) EndArray() (int, error) {
  item.depth--
  item.TrimLastIf(',')
  return item.Write([]byte("],"))
}

func (item *JsonItem) BeginObject() bool {
  item.depth++
  return item.WriteByte('{')
}

func (item *JsonItem) EndObject() (int, error) {
  item.depth--
  item.TrimLastIf(',')
  return item.Write([]byte("},"))
}

func (item *JsonItem) delimit(length int) int {
  if item.depth == 0 { return length }
  item.WriteByte(',')
  return length + 1
}

func (item *JsonItem) Close() error {
  item.TrimLastIf(',')
  item.Item.Close()
  if item.pool != nil {
    item.depth = 0
    item.pool.list <- item
  }
  return nil
}

func (item *JsonItem) Len() int {
  item.TrimLastIf(',')
  return item.Item.Len()
}

func (item *JsonItem) Bytes() []byte {
  item.TrimLastIf(',')
  return item.Item.Bytes()
}

func (item *JsonItem) Raw() []byte {
  item.TrimLastIf(',')
  return item.Item.Raw()
}

func (item *JsonItem) String() string {
  item.TrimLastIf(',')
  return item.Item.String()
}
<commit_msg>added funcs to write a float in a json<commit_after>package bytepool

import (
  "time"
  "strconv"
  "strings"
)

type JsonItem struct {
  *Item
  depth int
  added bool
  pool *JsonPool
}

func newJsonItem(capacity int, pool *JsonPool) *JsonItem {
  return &JsonItem {
    pool: pool,
    Item: newItem(capacity, nil),
  }
}

var JsonEncode = strings.NewReplacer(`\`, `\\`, `"`, `\"`).Replace

func (item *JsonItem) WriteString(s string) int {
  return item.WriteSafeString(JsonEncode(s))
}

func (item *JsonItem) WriteInt(value int) int {
  n := item.Item.WriteString(strconv.Itoa(value))
  return item.delimit(n)
}

func (item *JsonItem) WriteFloat(value float64) int {
  n := item.Item.WriteString(strconv.FormatFloat(value, 'f', -1, 64))
  return item.delimit(n)
}

func (item *JsonItem) WriteBool(value bool) int {
  n := item.Item.WriteString(strconv.FormatBool(value))
  return item.delimit(n)
}

func (item *JsonItem) WriteTime(value time.Time) int {
  return item.WriteString(value.Format(time.RFC3339))
}

func (item *JsonItem) WriteSafeString(s string) int {
  return item.writeString(s, true)
}

func (item *JsonItem) WriteKeyString(key, value string) int {
  return item.WriteKeySafeString(key, JsonEncode(value))
}

func (item *JsonItem) WriteKeySafeString(key, value string) int {
  return item.WriteKeyValue(key, value, true)
}

func (item *JsonItem) WriteKeyInt(key string, value int) int {
  return item.WriteKeyValue(key, strconv.Itoa(value), false)
}

func (item *JsonItem) WriteKeyFloat(key string, value float64) int {
  return item.WriteKeyValue(key, strconv.FormatFloat(value, 'f', -1, 64), false)
}

func (item *JsonItem) WriteKeyBool(key string, value bool) int {
  return item.WriteKeyValue(key, strconv.FormatBool(value), false)
}

func (item *JsonItem) WriteKeyTime(key string, value time.Time) int {
  return item.WriteKeyString(key, value.Format(time.RFC3339))
}

func (item *JsonItem) WriteKeyArray(key string) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if item.BeginArray() { n++ }
  return n
}

func (item *JsonItem) WriteKeyObject(key string) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if item.BeginObject() { n++ }
  return n
}

func (item *JsonItem) WriteKeyValue(key, value string, surround bool) int {
  n := item.writeString(key, false)
  if item.WriteByte(byte(':')) { n++ }
  if surround { item.WriteByte(byte('"')); n++ }
  n += item.Item.WriteString(value)
  if surround { item.WriteByte(byte('"')); n++ }
  return item.delimit(n)
}

func (item *JsonItem) writeString(s string, delimit bool) int {
  n := 0
  if item.WriteByte(byte('"')) { n++ }
  n += item.Item.WriteString(s)
  if item.WriteByte(byte('"')) { n++ }
  if delimit == false { return n }
  return item.delimit(n)
}

func (item *JsonItem) BeginArray() bool {
  item.added = false
  item.depth++
  return item.WriteByte('[')
}

func (item *JsonItem) EndArray() (int, error) {
  item.depth--
  item.TrimLastIf(',')
  return item.Write([]byte("],"))
}

func (item *JsonItem) BeginObject() bool {
  item.depth++
  return item.WriteByte('{')
}

func (item *JsonItem) EndObject() (int, error) {
  item.depth--
  item.TrimLastIf(',')
  return item.Write([]byte("},"))
}

func (item *JsonItem) delimit(length int) int {
  if item.depth == 0 { return length }
  item.WriteByte(',')
  return length + 1
}

func (item *JsonItem) Close() error {
  item.TrimLastIf(',')
  item.Item.Close()
  if item.pool != nil {
    item.depth = 0
    item.pool.list <- item
  }
  return nil
}

func (item *JsonItem) Len() int {
  item.TrimLastIf(',')
  return item.Item.Len()
}

func (item *JsonItem) Bytes() []byte {
  item.TrimLastIf(',')
  return item.Item.Bytes()
}

func (item *JsonItem) Raw() []byte {
  item.TrimLastIf(',')
  return item.Item.Raw()
}

func (item *JsonItem) String() string {
  item.TrimLastIf(',')
  return item.Item.String()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/geek1011/kepubify/kepub"
	isatty "github.com/mattn/go-isatty"
	zglob "github.com/mattn/go-zglob"
	"github.com/ogier/pflag"
)

var version = "dev"

func helpExit() {
	fmt.Fprintf(os.Stderr, "Usage: kepubify [OPTIONS] PATH [PATH]...\n\nVersion:\n  kepubify %s\n\nOptions:\n", version)
	pflag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\nArguments:\n  PATH is the path to an epub file or directory to convert. If it is a directory, the converted dir is the name of the dir with the suffix _converted. If the path is a file, the converted file has the extension .kepub.epub.\n")
	if runtime.GOOS == "windows" {
		time.Sleep(time.Second * 2)
	}
	os.Exit(1)
}

func errExit() {
	if runtime.GOOS == "windows" {
		time.Sleep(time.Second * 2)
	}
	os.Exit(1)
}

func main() {
	help := pflag.BoolP("help", "h", false, "Show this help text")
	update := pflag.BoolP("update", "u", false, "Don't reconvert files which have already been converted")
	verbose := pflag.BoolP("verbose", "v", false, "Show extra information in output")
	output := pflag.StringP("output", "o", ".", "The directory to place the converted files")
	pflag.Parse()

	if *help || pflag.NArg() == 0 {
		helpExit()
	}

	logV := func(format string, a ...interface{}) {
		if *verbose {
			if os.Getenv("TERM") != "dumb" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && isatty.IsTerminal(os.Stdout.Fd()) {
				fmt.Print("\033[36m")
				fmt.Printf(format, a...)
				fmt.Print("\033[0m")
				return
			}
			fmt.Printf(format, a...)
		}
	}

	log := func(format string, a ...interface{}) {
		fmt.Printf(format, a...)
	}

	logE := func(format string, a ...interface{}) {
		fmt.Fprintf(os.Stderr, format, a...)
	}

	out := ""
	out, err := filepath.Abs(*output)
	if err != nil || out == "" {
		logE("Error resolving output dir '%s': %v\n", *output, err)
		errExit()
	}

	logV("version: %s\n\n", version)
	logV("output: %s\n", *output)
	logV("output-abs: %s\n", out)
	logV("help: %t\n", *help)
	logV("update: %t\n", *update)
	logV("verbose: %t\n\n", *verbose)

	paths := map[string]string{}
	for _, arg := range uniq(pflag.Args()) {
		if !exists(arg) {
			logE("Path '%s' does not exist\n", arg)
			errExit()
		}
		if isFile(arg) {
			logV("file: %s\n", arg)
			f, err := filepath.Abs(arg)
			if err != nil {
				logE("Error resolving absolute path for file '%s'\n", arg)
				errExit()
			}
			if !strings.HasSuffix(f, ".epub") {
				logE("File '%s' is not an epub\n", f)
				errExit()
			}
			if strings.HasSuffix(f, ".kepub.epub") {
				logE("File '%s' is already a kepub\n", f)
				errExit()
			}
			paths[f] = filepath.Join(out, strings.Replace(filepath.Base(f), ".epub", "", -1)+".kepub.epub")
			logV("  file-result: %s -> %s\n", f, paths[f])
		} else if isDir(arg) {
			logV("dir: %s\n", arg)
			l, err := zglob.Glob(filepath.Join(arg, "**", "*.epub"))
			if err != nil {
				logV("Error scanning dir '%s'\n", arg)
				errExit()
			}
			for _, f := range l {
				logV("  dir-file: %s\n", f)
				if !strings.HasSuffix(f, ".epub") || strings.HasSuffix(f, ".kepub.epub") {
					continue
				}

				rel, err := filepath.Rel(arg, filepath.Join(filepath.Dir(f), strings.Replace(filepath.Base(f), ".epub", "", -1)+".kepub.epub"))
				if err != nil {
					logE("Error resolving relative path for file '%s'\n", f)
					errExit()
				}

				abs, err := filepath.Abs(f)
				if err != nil {
					logE("Error resolving absolute path for file '%s'\n", f)
					errExit()
				}

				paths[abs] = filepath.Join(out, rel)
				logV("    dir-result: %s -> %s\n", abs, paths[abs])
			}
		} else {
			logE("Path '%s' is not a file or a dir\n", arg)
			errExit()
		}
	}

	logV("\n")

	log("Kepubify %s: Converting %d books\n", version, len(paths))
	log("Output folder: %s\n", out)

	n := 0
	errs := [][]string{}
	converted := 0
	skipped := 0
	errored := 0
	for i, o := range paths {
		n++
		e := exists(o)
		if e && *update {
			log("[%d/%d] Skipping '%s'\n", n, len(paths), i)
		} else {
			log("[%d/%d] Converting '%s'\n", n, len(paths), i)
		}

		de := isDir(filepath.Dir(o))

		logV("  i: %s\n", i)
		logV("  o: %s\n", o)
		logV("  e: %t\n", e)
		logV("  de: %t\n", de)

		if e && *update {
			skipped++
			continue
		}

		if !de {
			logV("  mkdirAll: %s\n", filepath.Dir(o))
			err := os.MkdirAll(o, os.ModePerm)
			if err != nil {
				e := fmt.Sprintf("error creating output dir: %v", err)
				errs = append(errs, []string{i, o, e})
				logV("  err: %v\n", e)
				logE("  Error: %v\n", e)
				errored++
				continue
			}
		}

		err := kepub.Kepubify(i, o, *verbose)
		if err != nil {
			errs = append(errs, []string{i, o, err.Error()})
			logV("  err: %v\n", err)
			logE("  Error: %v\n", err)
			errored++
		}

		converted++
	}

	logV("\nn: %d\n", n)
	logV("converted: %d\n", converted)
	logV("skipped: %d\n", skipped)
	logV("errored: %d\n", errored)
	logV("errs: %v\n", errs)

	log("\n%d total, %d converted, %d skipped, %d errored\n", len(paths), converted, skipped, errored)
	if len(errs) > 0 {
		logE("\nErrors:\n")
		for _, err := range errs {
			logE("  '%s': %s\n", err[0], err[2])
		}
	}

	if len(paths) == 1 && len(errs) > 0 {
		errExit()
	}
}
<commit_msg>Fixed directory conversion output path<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/geek1011/kepubify/kepub"
	isatty "github.com/mattn/go-isatty"
	zglob "github.com/mattn/go-zglob"
	"github.com/ogier/pflag"
)

var version = "dev"

func helpExit() {
	fmt.Fprintf(os.Stderr, "Usage: kepubify [OPTIONS] PATH [PATH]...\n\nVersion:\n  kepubify %s\n\nOptions:\n", version)
	pflag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\nArguments:\n  PATH is the path to an epub file or directory to convert. If it is a directory, the converted dir is the name of the dir with the suffix _converted. If the path is a file, the converted file has the extension .kepub.epub.\n")
	if runtime.GOOS == "windows" {
		time.Sleep(time.Second * 2)
	}
	os.Exit(1)
}

func errExit() {
	if runtime.GOOS == "windows" {
		time.Sleep(time.Second * 2)
	}
	os.Exit(1)
}

func main() {
	help := pflag.BoolP("help", "h", false, "Show this help text")
	update := pflag.BoolP("update", "u", false, "Don't reconvert files which have already been converted")
	verbose := pflag.BoolP("verbose", "v", false, "Show extra information in output")
	output := pflag.StringP("output", "o", ".", "The directory to place the converted files")
	pflag.Parse()

	if *help || pflag.NArg() == 0 {
		helpExit()
	}

	logV := func(format string, a ...interface{}) {
		if *verbose {
			if os.Getenv("TERM") != "dumb" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && isatty.IsTerminal(os.Stdout.Fd()) {
				fmt.Print("\033[36m")
				fmt.Printf(format, a...)
				fmt.Print("\033[0m")
				return
			}
			fmt.Printf(format, a...)
		}
	}

	log := func(format string, a ...interface{}) {
		fmt.Printf(format, a...)
	}

	logE := func(format string, a ...interface{}) {
		fmt.Fprintf(os.Stderr, format, a...)
	}

	out := ""
	out, err := filepath.Abs(*output)
	if err != nil || out == "" {
		logE("Error resolving output dir '%s': %v\n", *output, err)
		errExit()
	}

	logV("version: %s\n\n", version)
	logV("output: %s\n", *output)
	logV("output-abs: %s\n", out)
	logV("help: %t\n", *help)
	logV("update: %t\n", *update)
	logV("verbose: %t\n\n", *verbose)

	paths := map[string]string{}
	for _, arg := range uniq(pflag.Args()) {
		if !exists(arg) {
			logE("Path '%s' does not exist\n", arg)
			errExit()
		}
		if isFile(arg) {
			logV("file: %s\n", arg)
			f, err := filepath.Abs(arg)
			if err != nil {
				logE("Error resolving absolute path for file '%s'\n", arg)
				errExit()
			}
			if !strings.HasSuffix(f, ".epub") {
				logE("File '%s' is not an epub\n", f)
				errExit()
			}
			if strings.HasSuffix(f, ".kepub.epub") {
				logE("File '%s' is already a kepub\n", f)
				errExit()
			}
			paths[f] = filepath.Join(out, strings.Replace(filepath.Base(f), ".epub", "", -1)+".kepub.epub")
			logV("  file-result: %s -> %s\n", f, paths[f])
		} else if isDir(arg) {
			logV("dir: %s\n", arg)
			l, err := zglob.Glob(filepath.Join(arg, "**", "*.epub"))
			if err != nil {
				logV("Error scanning dir '%s'\n", arg)
				errExit()
			}
			for _, f := range l {
				logV("  dir-file: %s\n", f)
				if !strings.HasSuffix(f, ".epub") || strings.HasSuffix(f, ".kepub.epub") {
					continue
				}

				rel, err := filepath.Rel(arg, filepath.Join(filepath.Dir(f), strings.Replace(filepath.Base(f), ".epub", "", -1)+".kepub.epub"))
				if err != nil {
					logE("Error resolving relative path for file '%s'\n", f)
					errExit()
				}

				abs, err := filepath.Abs(f)
				if err != nil {
					logE("Error resolving absolute path for file '%s'\n", f)
					errExit()
				}

				paths[abs] = filepath.Join(out, filepath.Base(arg) + "_converted", rel)
				logV("    dir-result: %s -> %s\n", abs, paths[abs])
			}
		} else {
			logE("Path '%s' is not a file or a dir\n", arg)
			errExit()
		}
	}

	logV("\n")

	log("Kepubify %s: Converting %d books\n", version, len(paths))
	log("Output folder: %s\n", out)

	n := 0
	errs := [][]string{}
	converted := 0
	skipped := 0
	errored := 0
	for i, o := range paths {
		n++
		e := exists(o)
		if e && *update {
			log("[%d/%d] Skipping '%s'\n", n, len(paths), i)
		} else {
			log("[%d/%d] Converting '%s'\n", n, len(paths), i)
		}

		de := isDir(filepath.Dir(o))

		logV("  i: %s\n", i)
		logV("  o: %s\n", o)
		logV("  e: %t\n", e)
		logV("  de: %t\n", de)

		if e && *update {
			skipped++
			continue
		}

		if !de {
			logV("  mkdirAll: %s\n", filepath.Dir(o))
			err := os.MkdirAll(o, os.ModePerm)
			if err != nil {
				e := fmt.Sprintf("error creating output dir: %v", err)
				errs = append(errs, []string{i, o, e})
				logV("  err: %v\n", e)
				logE("  Error: %v\n", e)
				errored++
				continue
			}
		}

		err := kepub.Kepubify(i, o, *verbose)
		if err != nil {
			errs = append(errs, []string{i, o, err.Error()})
			logV("  err: %v\n", err)
			logE("  Error: %v\n", err)
			errored++
		}

		converted++
	}

	logV("\nn: %d\n", n)
	logV("converted: %d\n", converted)
	logV("skipped: %d\n", skipped)
	logV("errored: %d\n", errored)
	logV("errs: %v\n", errs)

	log("\n%d total, %d converted, %d skipped, %d errored\n", len(paths), converted, skipped, errored)
	if len(errs) > 0 {
		logE("\nErrors:\n")
		for _, err := range errs {
			logE("  '%s': %s\n", err[0], err[2])
		}
	}

	if len(paths) == 1 && len(errs) > 0 {
		errExit()
	}
}
<|endoftext|>


<commit_before>package gentle

import (
	"errors"
	"github.com/afex/hystrix-go/hystrix"
	log15 "gopkg.in/inconshreveable/log15.v2"
	"time"
)

var (
	// Package level logger. It uses log15(gopkg.in/inconshreveable/log15.v2)
	// to provide finer control over logging.
	Log = log15.New()

	// Errors that CircuitBreakerStream.Get() and
	// CircuitBreakerHandler.Handle() might return. They are replacement of
	// hystrix errors.
	ErrCbOpen           = errors.New(hystrix.ErrCircuitOpen.Error())
	ErrCbMaxConcurrency = errors.New(hystrix.ErrMaxConcurrency.Error())
	ErrCbTimeout        = errors.New(hystrix.ErrTimeout.Error())

	ErrMaxConcurrency = errors.New("Reached Max Concurrency")
	ErrInvalidType    = errors.New("Invalid Type")
)

func init() {
	Log.SetHandler(log15.DiscardHandler())
}

type Message interface {
	// A Message is obliged to implement Id() for better tracing.
	Id() string
}

// errors that implements IgnorableError would be examined and ignored if
// necessary by RetryXXX and CircuitBreakerXXX.
type IgnorableError interface {
	Ignored() bool
}

func ToIgnore(err error) bool {
	if ig, ok := err.(IgnorableError); !ok {
		return false
	} else {
		return ig.Ignored()
	}
}

// Stream emits Message. Messages of a stream goes one way. Though two streams
// can simulate two-way communication but it would require out-of-band logic.
type Stream interface {
	// Get() returns either a Message or an error. Returned Message is nil
	// if only if error is not nil.
	Get() (Message, error)
}

// Handler transforms a Message.
type Handler interface {
	// Handle() transforms an Message. Returned Message is nil if only if
	// error is not nil.
	Handle(msg Message) (Message, error)
}

type Names struct {
	Namespace string
	Mixin     string
	Name      string
}

type Identity interface {
	GetNames() *Names
}

// A Logger writes key/value pairs to a Handler
type Logger interface {
	// Log a message at the given level with context key/value pairs
	Debug(msg string, ctx ...interface{})
	Info(msg string, ctx ...interface{})
	Warn(msg string, ctx ...interface{})
	Error(msg string, ctx ...interface{})
	Crit(msg string, ctx ...interface{})
}

// A do-nothing Logger
type noOpLogger struct{}

func (l *noOpLogger) Debug(msg string, ctx ...interface{}) {}
func (l *noOpLogger) Info(msg string, ctx ...interface{})  {}
func (l *noOpLogger) Warn(msg string, ctx ...interface{})  {}
func (l *noOpLogger) Error(msg string, ctx ...interface{}) {}
func (l *noOpLogger) Crit(msg string, ctx ...interface{})  {}

var noopLogger = &noOpLogger{}

// RateLimit is an interface for a "token bucket" algorithm.
type RateLimit interface {
	// Wait for $count tokens are granted(return true) or timeout(return
	// false). If $timeout == 0, it would block as long as it needs.
	Wait(count int, timeout time.Duration) bool
}

type BackOff interface {
	// Next() should immediately return
	Next() time.Duration
}

const BackOffStop time.Duration = -1

// Converts $millis of int to time.Duration.
func IntToMillis(millis int) time.Duration {
	return time.Duration(millis) * time.Millisecond
}

// GetHystrixDefaultConfig() returns a new hystrix.CommandConfig filled with defaults(https://godoc.org/github.com/afex/hystrix-go/hystrix#pkg-variables):
func GetHystrixDefaultConfig() *hystrix.CommandConfig {
	return &hystrix.CommandConfig{
		// DefaultTimeout = 1000, is how long to wait for command to complete, in milliseconds
		Timeout: hystrix.DefaultTimeout,
		// DefaultMaxConcurrent = 10 is how many commands of the same type can run at the same time
		MaxConcurrentRequests: hystrix.DefaultMaxConcurrent,
		// DefaultVolumeThreshold = 20 is the minimum number of requests needed before a circuit can be tripped due to health
		RequestVolumeThreshold: hystrix.DefaultVolumeThreshold,
		// DefaultSleepWindow = 5000 is how long, in milliseconds, to wait after a circuit opens before testing for recovery
		SleepWindow: hystrix.DefaultSleepWindow,
		// DefaultErrorPercentThreshold = 50 causes circuits to open once the rolling measure of errors exceeds this percent of requests
		ErrorPercentThreshold: hystrix.DefaultErrorPercentThreshold,
	}
}

type CircuitBreakerConf struct {
	// Timeout is how long to wait for command to complete
	Timeout time.Duration
	// MaxConcurrent is how many commands of the same type can run
	// at the same time
	MaxConcurrent int
	// VolumeThreshold is the minimum number of requests needed
	// before a circuit can be tripped due to health
	VolumeThreshold int
	// ErrorPercentThreshold causes circuits to open once the
	// rolling measure of errors exceeds this percent of requests
	ErrorPercentThreshold int
	// SleepWindow is how long to wait after a circuit opens before testing
	// for recovery is allowed
	SleepWindow time.Duration
}

func NewDefaultCircuitBreakerConf() *CircuitBreakerConf {
	return &CircuitBreakerConf{
		Timeout:               10 * time.Second,
		MaxConcurrent:         1024,
		VolumeThreshold:       20,
		ErrorPercentThreshold: 50,
		SleepWindow:           5 * time.Second,
	}
}

func (c *CircuitBreakerConf) RegisterFor(circuit string) {
	hystrix.ConfigureCommand(circuit, hystrix.CommandConfig{
		Timeout:                int(c.Timeout / time.Millisecond),
		MaxConcurrentRequests:  c.MaxConcurrent,
		RequestVolumeThreshold: c.VolumeThreshold,
		SleepWindow:            int(c.SleepWindow / time.Millisecond),
		ErrorPercentThreshold:  c.ErrorPercentThreshold,
	})
}

type tuple struct {
	fst interface{}
	snd interface{}
}
<commit_msg>add IgnorableErr<commit_after>package gentle

import (
	"errors"
	"github.com/afex/hystrix-go/hystrix"
	log15 "gopkg.in/inconshreveable/log15.v2"
	"time"
)

var (
	// Package level logger. It uses log15(gopkg.in/inconshreveable/log15.v2)
	// to provide finer control over logging.
	Log = log15.New()

	// Errors that CircuitBreakerStream.Get() and
	// CircuitBreakerHandler.Handle() might return. They are replacement of
	// hystrix errors.
	ErrCbOpen           = errors.New(hystrix.ErrCircuitOpen.Error())
	ErrCbMaxConcurrency = errors.New(hystrix.ErrMaxConcurrency.Error())
	ErrCbTimeout        = errors.New(hystrix.ErrTimeout.Error())

	ErrMaxConcurrency = errors.New("Reached Max Concurrency")
	ErrInvalidType    = errors.New("Invalid Type")
)

func init() {
	Log.SetHandler(log15.DiscardHandler())
}

type Message interface {
	// A Message is obliged to implement Id() for better tracing.
	Id() string
}

// errors that implements IgnorableError would be examined and ignored if
// necessary by RetryXXX and CircuitBreakerXXX.
type IgnorableError interface {
	error
	Ignored() bool
}

func ToIgnore(err error) bool {
	if ig, ok := err.(IgnorableError); !ok {
		return false
	} else {
		return ig.Ignored()
	}
}

// Stream emits Message. Messages of a stream goes one way. Though two streams
// can simulate two-way communication but it would require out-of-band logic.
type Stream interface {
	// Get() returns either a Message or an error. Returned Message is nil
	// if only if error is not nil.
	Get() (Message, error)
}

// Handler transforms a Message.
type Handler interface {
	// Handle() transforms an Message. Returned Message is nil if only if
	// error is not nil.
	Handle(msg Message) (Message, error)
}

type Names struct {
	Namespace string
	Mixin     string
	Name      string
}

type Identity interface {
	GetNames() *Names
}

// A Logger writes key/value pairs to a Handler
type Logger interface {
	// Log a message at the given level with context key/value pairs
	Debug(msg string, ctx ...interface{})
	Info(msg string, ctx ...interface{})
	Warn(msg string, ctx ...interface{})
	Error(msg string, ctx ...interface{})
	Crit(msg string, ctx ...interface{})
}

// A do-nothing Logger
type noOpLogger struct{}

func (l *noOpLogger) Debug(msg string, ctx ...interface{}) {}
func (l *noOpLogger) Info(msg string, ctx ...interface{})  {}
func (l *noOpLogger) Warn(msg string, ctx ...interface{})  {}
func (l *noOpLogger) Error(msg string, ctx ...interface{}) {}
func (l *noOpLogger) Crit(msg string, ctx ...interface{})  {}

var noopLogger = &noOpLogger{}

// RateLimit is an interface for a "token bucket" algorithm.
type RateLimit interface {
	// Wait for $count tokens are granted(return true) or timeout(return
	// false). If $timeout == 0, it would block as long as it needs.
	Wait(count int, timeout time.Duration) bool
}

type BackOff interface {
	// Next() should immediately return
	Next() time.Duration
}

const BackOffStop time.Duration = -1

// Converts $millis of int to time.Duration.
func IntToMillis(millis int) time.Duration {
	return time.Duration(millis) * time.Millisecond
}

// GetHystrixDefaultConfig() returns a new hystrix.CommandConfig filled with defaults(https://godoc.org/github.com/afex/hystrix-go/hystrix#pkg-variables):
func GetHystrixDefaultConfig() *hystrix.CommandConfig {
	return &hystrix.CommandConfig{
		// DefaultTimeout = 1000, is how long to wait for command to complete, in milliseconds
		Timeout: hystrix.DefaultTimeout,
		// DefaultMaxConcurrent = 10 is how many commands of the same type can run at the same time
		MaxConcurrentRequests: hystrix.DefaultMaxConcurrent,
		// DefaultVolumeThreshold = 20 is the minimum number of requests needed before a circuit can be tripped due to health
		RequestVolumeThreshold: hystrix.DefaultVolumeThreshold,
		// DefaultSleepWindow = 5000 is how long, in milliseconds, to wait after a circuit opens before testing for recovery
		SleepWindow: hystrix.DefaultSleepWindow,
		// DefaultErrorPercentThreshold = 50 causes circuits to open once the rolling measure of errors exceeds this percent of requests
		ErrorPercentThreshold: hystrix.DefaultErrorPercentThreshold,
	}
}

type CircuitBreakerConf struct {
	// Timeout is how long to wait for command to complete
	Timeout time.Duration
	// MaxConcurrent is how many commands of the same type can run
	// at the same time
	MaxConcurrent int
	// VolumeThreshold is the minimum number of requests needed
	// before a circuit can be tripped due to health
	VolumeThreshold int
	// ErrorPercentThreshold causes circuits to open once the
	// rolling measure of errors exceeds this percent of requests
	ErrorPercentThreshold int
	// SleepWindow is how long to wait after a circuit opens before testing
	// for recovery is allowed
	SleepWindow time.Duration
}

func NewDefaultCircuitBreakerConf() *CircuitBreakerConf {
	return &CircuitBreakerConf{
		Timeout:               10 * time.Second,
		MaxConcurrent:         1024,
		VolumeThreshold:       20,
		ErrorPercentThreshold: 50,
		SleepWindow:           5 * time.Second,
	}
}

func (c *CircuitBreakerConf) RegisterFor(circuit string) {
	hystrix.ConfigureCommand(circuit, hystrix.CommandConfig{
		Timeout:                int(c.Timeout / time.Millisecond),
		MaxConcurrentRequests:  c.MaxConcurrent,
		RequestVolumeThreshold: c.VolumeThreshold,
		SleepWindow:            int(c.SleepWindow / time.Millisecond),
		ErrorPercentThreshold:  c.ErrorPercentThreshold,
	})
}

type tuple struct {
	fst interface{}
	snd interface{}
}
<|endoftext|>


<commit_before>package mapbox

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
)

var _ = log.Print

type GeocodingAPI struct {
	c *Client
}

// QueryByAddress performs a forward geo-encoding. It takes an
// address and returns all kinds of information about it, e.g.
// the latitude and longitude. There might be more than one
// such result. See QueryByAddressResponse for details.
func (api *GeocodingAPI) QueryByAddress(address *QueryByAddressRequest) (*QueryByAddressResponse, error) {
	u, err := api.buildURL(address)
	if err != nil {
		return nil, err
	}

	res := new(QueryByAddressResponse)
	if err := api.c.getJSON(u, res); err != nil {
		return nil, err
	}
	return res, nil
}

// buildURL returns the complete URL for the forward geocoding request,
// including the access token specified in the Client.
func (api *GeocodingAPI) buildURL(req *QueryByAddressRequest) (string, error) {
	u, err := url.Parse(fmt.Sprintf("%s/geocode/%s/%s.json",
		api.c.BaseURL(),
		url.QueryEscape(req.Index),
		url.QueryEscape(req.Query)))
	if err != nil {
		return "", err
	}

	// Add access_token as query string parameter
	q := u.Query()
	q.Set("access_token", api.c.accessToken)
	u.RawQuery = q.Encode()
	return u.String(), nil
}

type QueryByAddressRequest struct {
	// Index is the geocoding index as specified on
	// https://www.mapbox.com/developers/api/geocoding/.
	// If you construct a QueryByAddressRequest via
	// NewQueryByAddressRequest, the the Index is set to
	// "mapbox.places-v1" by default.
	Index string

	// Query is the address you want to decode.
	Query string
}

// NewQueryByAddressRequest creates a new QueryByAddressRequest.
// It initializes the geocoding index with "mapbox.places-v1".
func NewQueryByAddressRequest() *QueryByAddressRequest {
	return &QueryByAddressRequest{
		Index: "mapbox.places-v1",
	}
}

// QueryByAddressResponse is the result of a call to QueryByAddress.
type QueryByAddressResponse struct {
	Attribution string                           `json:"attribution,omitempty"`
	Features    []*QueryByAddressResponseFeature `json:"features,omitempty"`
	Query       []string                         `json:"query,omitempty"`
	Type        string                           `json:"type,omitempty"`
}

type QueryByAddressResponseFeature struct {
	Type        string                 `json:"type,omitempty"`
	Text        string                 `json:"text,omitempty"`
	Relevance   float64                `json:"relevance,omitempty"`
	PlaceName   string                 `json:"place_name,omitempty"`
	Properties  map[string]interface{} `json:properties,omitempty"`
	ID          string                 `json:"id,omitempty"`
	Geometry    *json.RawMessage       `json:"geometry,omitempty"`
	Context     *json.RawMessage       `json:"context,omitempty"`
	Center      []float64              `json:"center,omitempty"`
	BoundingBox []float64              `json:"bbox,omitempty"`
}

/*
func (api *GeocodingAPI) QueryByLonLat(lonLat *QueryByLonLatRequest) (*QueryByLonLatResponse, error) {
	return nil, nil
}

type QueryByLonLatRequest struct {
}

type QueryByLonLatResponse struct {
	Results []*QueryByLonLatResult
}

type QueryByLonLatResult struct {
}
*/
<commit_msg>fix JSON struct tag error<commit_after>package mapbox

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
)

var _ = log.Print

type GeocodingAPI struct {
	c *Client
}

// QueryByAddress performs a forward geo-encoding. It takes an
// address and returns all kinds of information about it, e.g.
// the latitude and longitude. There might be more than one
// such result. See QueryByAddressResponse for details.
func (api *GeocodingAPI) QueryByAddress(address *QueryByAddressRequest) (*QueryByAddressResponse, error) {
	u, err := api.buildURL(address)
	if err != nil {
		return nil, err
	}

	res := new(QueryByAddressResponse)
	if err := api.c.getJSON(u, res); err != nil {
		return nil, err
	}
	return res, nil
}

// buildURL returns the complete URL for the forward geocoding request,
// including the access token specified in the Client.
func (api *GeocodingAPI) buildURL(req *QueryByAddressRequest) (string, error) {
	u, err := url.Parse(fmt.Sprintf("%s/geocode/%s/%s.json",
		api.c.BaseURL(),
		url.QueryEscape(req.Index),
		url.QueryEscape(req.Query)))
	if err != nil {
		return "", err
	}

	// Add access_token as query string parameter
	q := u.Query()
	q.Set("access_token", api.c.accessToken)
	u.RawQuery = q.Encode()
	return u.String(), nil
}

type QueryByAddressRequest struct {
	// Index is the geocoding index as specified on
	// https://www.mapbox.com/developers/api/geocoding/.
	// If you construct a QueryByAddressRequest via
	// NewQueryByAddressRequest, the the Index is set to
	// "mapbox.places-v1" by default.
	Index string

	// Query is the address you want to decode.
	Query string
}

// NewQueryByAddressRequest creates a new QueryByAddressRequest.
// It initializes the geocoding index with "mapbox.places-v1".
func NewQueryByAddressRequest() *QueryByAddressRequest {
	return &QueryByAddressRequest{
		Index: "mapbox.places-v1",
	}
}

// QueryByAddressResponse is the result of a call to QueryByAddress.
type QueryByAddressResponse struct {
	Attribution string                           `json:"attribution,omitempty"`
	Features    []*QueryByAddressResponseFeature `json:"features,omitempty"`
	Query       []string                         `json:"query,omitempty"`
	Type        string                           `json:"type,omitempty"`
}

type QueryByAddressResponseFeature struct {
	Type        string                 `json:"type,omitempty"`
	Text        string                 `json:"text,omitempty"`
	Relevance   float64                `json:"relevance,omitempty"`
	PlaceName   string                 `json:"place_name,omitempty"`
	Properties  map[string]interface{} `json:"properties,omitempty"`
	ID          string                 `json:"id,omitempty"`
	Geometry    *json.RawMessage       `json:"geometry,omitempty"`
	Context     *json.RawMessage       `json:"context,omitempty"`
	Center      []float64              `json:"center,omitempty"`
	BoundingBox []float64              `json:"bbox,omitempty"`
}

/*
func (api *GeocodingAPI) QueryByLonLat(lonLat *QueryByLonLatRequest) (*QueryByLonLatResponse, error) {
	return nil, nil
}

type QueryByLonLatRequest struct {
}

type QueryByLonLatResponse struct {
	Results []*QueryByLonLatResult
}

type QueryByLonLatResult struct {
}
*/
<|endoftext|>


<commit_before>// Temperature controller for Raspberry Pi
package main

import (
	"code.google.com/p/go.crypto/ssh/terminal"
	"flag"
	"kgerator/refrig"
	"kgerator/tempcontrol"
	"kgerator/tempcontrol/chilltest"
	"kgerator/thermo"
	"kgerator/thermo/ds18b20"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	ds18b20Path         = "/sys/bus/w1/devices/28-blah/w1_slave"
	REFRIG_PIN          = 17
	RECOVERY_SEC        = 600
	SAMPLE_SEC          = 30
	THERMOMETER_RETRIES = 3
)

var (
	tempSet    thermo.F = 72.0
	tempMargin thermo.F = 2.0
	tempIncr   thermo.F = 0.25

	hwsim = flag.Bool("hwsim", false, "Simulate hardware.")
)

func main() {
	flag.Parse()

	eLog, err := openEventLog()
	if err != nil {
		panic(err)
	}

	var thermometer thermo.Meter
	var fridge tempcontrol.StartStopper

	if *hwsim {
		ct := chilltest.New(78, 0.05, 0.01)
		thermometer = ct
		fridge = ct
	} else {
		// TODO: these devices could offer a pub/sub model that the main could
		// use to mix with logging or to take action on events like waiting on
		// fridge Recover->Stop
		realFridge, err := refrig.New("Fridge", REFRIG_PIN, RECOVERY_SEC*time.Second)
		if err != nil {
			eLog.Fatalf("Fatal error fridge init: %s", err)
		}
		defer realFridge.Close()
		fridge = realFridge

		thermometer, err = ds18b20.Open(ds18b20Path)
		if err != nil {
			// TODO: does eLog writer need to be closed on exit?
			eLog.Fatalf("Fatal error fridge temp sensor init: %s", err)
		}
	}
	controller := tempcontrol.New(thermometer, fridge, eLog)
	controller.Set(tempSet, tempSet-tempMargin)

	inCh := make(chan byte)
	go readStdin(eLog, inCh)
	go sampler(eLog, thermometer, fridge)

	// Wait for signal, shutdown
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt, os.Kill)

	for {
		select {
		case input := <-inCh:
			switch input {
			case 'a':
				tempMargin += tempIncr
			case 'z':
				tempMargin -= tempIncr
			case '+', '=':
				tempSet += tempIncr
			case '-', '_':
				tempSet -= tempIncr
			case 'q', 'Q':
				return
			}

			controller.Set(tempSet, tempSet-tempMargin)

		case sig := <-sigCh:
			eLog.Println("Got signal", sig, ". Shutting down.")
			return
		}
	}
}

func sampler(eLog *log.Logger, t thermo.Meter, f tempcontrol.StartStopper) {
	tick := time.NewTicker(5 * time.Second)
	for {
		<-tick.C
		// TODO: reflect on type, if chilltest then just print one
		eLog.Println(t, " ", f)
	}
}

func readStdin(eLog *log.Logger, inCh chan byte) {
	doRawInput := false

	if doRawInput {
		_, err := terminal.MakeRaw(syscall.Stdin)
		if err != nil {
			eLog.Fatalf("Couldn't make raw terminal.")
		}
	}

	for {
		ch := make([]byte, 1)
		var n int
		var err error

		if doRawInput {
			n, err = syscall.Read(syscall.Stdin, ch)
		} else {
			n, err = os.Stdin.Read(ch)
		}

		if n > 0 {
			inCh <- ch[0]
		}
		if err != nil {
			eLog.Println("Error on stdin: ", err)
		}
	}
}

func openEventLog() (*log.Logger, error) {
	// TODO: is this going to a file?
	return log.New(os.Stdout, "", log.LstdFlags), nil
}
<commit_msg>Wire for my hardware<commit_after>// Temperature controller for Raspberry Pi
package main

import (
	"code.google.com/p/go.crypto/ssh/terminal"
	"flag"
	"kgerator/refrig"
	"kgerator/tempcontrol"
	"kgerator/tempcontrol/chilltest"
	"kgerator/thermo"
	"kgerator/thermo/ds18b20"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	ds18b20Path         = "/sys/bus/w1/devices/28-000004a82f20/w1_slave"
	REFRIG_PIN          = 18
	RECOVERY_SEC        = 600
	SAMPLE_SEC          = 30
	THERMOMETER_RETRIES = 3
)

var (
	tempSet    thermo.F = 72.0
	tempMargin thermo.F = 2.0
	tempIncr   thermo.F = 0.25

	hwsim = flag.Bool("hwsim", false, "Simulate hardware.")
)

func main() {
	flag.Parse()

	eLog, err := openEventLog()
	if err != nil {
		panic(err)
	}

	var thermometer thermo.Meter
	var fridge tempcontrol.StartStopper

	if *hwsim {
		ct := chilltest.New(78, 0.05, 0.01)
		thermometer = ct
		fridge = ct
	} else {
		// TODO: these devices could offer a pub/sub model that the main could
		// use to mix with logging or to take action on events like waiting on
		// fridge Recover->Stop
		realFridge, err := refrig.New("Fridge", REFRIG_PIN, RECOVERY_SEC*time.Second)
		if err != nil {
			eLog.Fatalf("Fatal error fridge init: %s", err)
		}
		defer realFridge.Close()
		fridge = realFridge

		thermometer, err = ds18b20.Open(ds18b20Path)
		if err != nil {
			// TODO: does eLog writer need to be closed on exit?
			eLog.Fatalf("Fatal error fridge temp sensor init: %s", err)
		}
	}
	controller := tempcontrol.New(thermometer, fridge, eLog)
	controller.Set(tempSet, tempSet-tempMargin)

	inCh := make(chan byte)
	go readStdin(eLog, inCh)
	go sampler(eLog, thermometer, fridge)

	// Wait for signal, shutdown
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt, os.Kill)

	for {
		select {
		case input := <-inCh:
			switch input {
			case 'a':
				tempMargin += tempIncr
			case 'z':
				tempMargin -= tempIncr
			case '+', '=':
				tempSet += tempIncr
			case '-', '_':
				tempSet -= tempIncr
			case 'q', 'Q':
				return
			}

			controller.Set(tempSet, tempSet-tempMargin)

		case sig := <-sigCh:
			eLog.Println("Got signal", sig, ". Shutting down.")
			return
		}
	}
}

func sampler(eLog *log.Logger, t thermo.Meter, f tempcontrol.StartStopper) {
	tick := time.NewTicker(5 * time.Second)
	for {
		<-tick.C
		// TODO: reflect on type, if chilltest then just print one
		eLog.Println(t, " ", f)
	}
}

func readStdin(eLog *log.Logger, inCh chan byte) {
	doRawInput := false

	if doRawInput {
		_, err := terminal.MakeRaw(syscall.Stdin)
		if err != nil {
			eLog.Fatalf("Couldn't make raw terminal.")
		}
	}

	for {
		ch := make([]byte, 1)
		var n int
		var err error

		if doRawInput {
			n, err = syscall.Read(syscall.Stdin, ch)
		} else {
			n, err = os.Stdin.Read(ch)
		}

		if n > 0 {
			inCh <- ch[0]
		}
		if err != nil {
			eLog.Println("Error on stdin: ", err)
		}
	}
}

func openEventLog() (*log.Logger, error) {
	// TODO: is this going to a file?
	return log.New(os.Stdout, "", log.LstdFlags), nil
}
<|endoftext|>


<commit_before>package gitlab

import (
	"encoding/json"
)

type Author struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

type Commit struct {
	Author    Author `json:"author"`
	ID        string `json:"id"`
	Message   string `json:"message"`
	Timestamp string `json:"timestamp"`
	URL       string `json:"url"`
}

type Repository struct {
	Description string `json:"description"`
	Homepage    string `json:"homepage"`
	Name        string `json:"name"`
	URL         string `json:"url"`
}

type Push struct {
	After             string     `json:"after"`
	Before            string     `json:"before"`
	Commits           []Commit   `json:"commits"`
	ProjectID         float64    `json:"project_id"`
	Ref               string     `json:"ref"`
	Repository        Repository `json:"repository"`
	TotalCommitsCount float64    `json:"total_commits_count"`
	UserID            float64    `json:"user_id"`
	UserName          string     `json:"user_name"`
}

func NewPush(data []byte) (Push, error) {
	var push Push
	if err := json.Unmarshal(data, &push); err != nil {
		return push, err
	}

	return push, nil
}
<commit_msg>Remove GitLab<commit_after><|endoftext|>