<commit_before>package slug

import (
	"code.google.com/p/go.text/unicode/norm"
	"regexp"
	"strings"
	"unicode"
)

// don't even quote these
var _SKIP = []*unicode.RangeTable{
	unicode.Mark,
	unicode.Sk,
	unicode.Lm,
}

var _SAFE = []*unicode.RangeTable{
	unicode.Letter,
	unicode.Number,
}

func safe(r rune) rune {
	switch {
	case unicode.IsOneOf(_SKIP, r):
		return -1
	case unicode.IsOneOf(_SAFE, r):
		return unicode.ToLower(r)
	}
	return '-'
}

var _DOUBLEDASH_RE = regexp.MustCompile("--+")

func noRepeat(s string) string {
	return _DOUBLEDASH_RE.ReplaceAllString(s, "-")
}

// Slugify a string. The result will only contain lowercase letters,
// digits and dashes. It will not begin or end with a dash, and it
// will not contain runs of multiple dashes.
//
// It is NOT forced into being ASCII, but may contain any Unicode
// characters, with the above restrictions.
func Slug(s string) string {
	s = norm.NFKD.String(s)
	s = strings.Map(safe, s)
	s = strings.Trim(s, "-")
	s = noRepeat(s)
	return s
}
<commit_msg>Use new golang.org/x/ import paths<commit_after>package slug

import (
	"golang.org/x/text/unicode/norm"
	"regexp"
	"strings"
	"unicode"
)

// don't even quote these
var _SKIP = []*unicode.RangeTable{
	unicode.Mark,
	unicode.Sk,
	unicode.Lm,
}

var _SAFE = []*unicode.RangeTable{
	unicode.Letter,
	unicode.Number,
}

func safe(r rune) rune {
	switch {
	case unicode.IsOneOf(_SKIP, r):
		return -1
	case unicode.IsOneOf(_SAFE, r):
		return unicode.ToLower(r)
	}
	return '-'
}

var _DOUBLEDASH_RE = regexp.MustCompile("--+")

func noRepeat(s string) string {
	return _DOUBLEDASH_RE.ReplaceAllString(s, "-")
}

// Slugify a string. The result will only contain lowercase letters,
// digits and dashes. It will not begin or end with a dash, and it
// will not contain runs of multiple dashes.
//
// It is NOT forced into being ASCII, but may contain any Unicode
// characters, with the above restrictions.
func Slug(s string) string {
	s = norm.NFKD.String(s)
	s = strings.Map(safe, s)
	s = strings.Trim(s, "-")
	s = noRepeat(s)
	return s
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Alcatel-Lucent Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name of bambou nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bambou

import (
	"fmt"
)

type VsdErrorList struct {
	VsdErrors    []VsdError `json:"errors"`
	VsdErrorCode int        `json:"internalErrorCode"`
}

type VsdError struct {
	Property     string  `json:"property"`
	Descriptions []Error `json:"descriptions"` // XXX -- note
}

// Errors at this level can be of two types: 1) Connection logic / setup errors (e.g. invalid credentials) 2) VSD error response.
// We use Bambou Error for both of those, even if they are conceptually different -- hence the note above

type Error struct {
	Title       string `json:"title"`
	Description string `json:"description"`
}

func NewBambouError(title, description string) *Error {
	return &Error{
		Title:       title,
		Description: description,
	}
}

// Sometimes I want to scream and shout... -- Old broken code
func NewError(code int, description string) *Error {
	return &Error{
		Title:       fmt.Sprintf("Error code: %d", code),
		Description: description,
	}
}

// Error returns the string representation of a Bambou Error (making it an "error")
func (be *Error) Error() string {
	// return fmt.Sprintf("%+v", *be)
	return fmt.Sprintf("{\"title\": \"%s\", \"description\": \"%s\"}", be.Title, be.Description) // Valid JSON formatted
}
<commit_msg>Fixed some comments<commit_after>// Copyright (c) 2015, Alcatel-Lucent Inc.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name of bambou nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package bambou

import (
	"fmt"
)

type VsdErrorList struct {
	VsdErrors    []VsdError `json:"errors"`
	VsdErrorCode int        `json:"internalErrorCode"`
}

type VsdError struct {
	Property     string  `json:"property"`
	Descriptions []Error `json:"descriptions"` // XXX -- note
}

// Errors at this level can be of two types: 1) Connection logic / setup errors (e.g. invalid credentials) 2) VSD error response.
// We use Bambou Error for both, even if they are conceptually different -- hence the note above

type Error struct {
	Title       string `json:"title"`
	Description string `json:"description"`
}

func NewBambouError(title, description string) *Error {
	return &Error{
		Title:       title,
		Description: description,
	}
}

func NewError(code int, description string) *Error {
	return &Error{
		Title:       fmt.Sprintf("Error code: %d", code),
		Description: description,
	}
}

// Error returns the string representation of a Bambou Error (making it an "error")
// Valid JSON formatted
func (be *Error) Error() string {
	// return fmt.Sprintf("%+v", *be)
	return fmt.Sprintf("{\"title\": \"%s\", \"description\": \"%s\"}", be.Title, be.Description)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

var cmdSoql = &Command{
	Run:   runSoql,
	Usage: "soql <soql statement> [output format]",
	Short: "Execute a SOQL statement",
	Long: `
Execute a SOQL statement

Examples:

  force soql select Id, Name, Account.Name From Contact

  force soql select Id, Name, Account.Name From Contact --format:csv

`,
}

func runSoql(cmd *Command, args []string) {
	force, _ := ActiveForce()
	if len(args) < 1 {
		ErrorAndExit("must specify a SOQL statement")
	}
	format := "console"
	formatArg := args[len(args)-1]

	if strings.Contains(formatArg, "--format:") {
		args = args[:len(args) - 1]
		format = strings.SplitN(formatArg, ":", 2)[1]
	}

	soql := strings.Join(args, " ")
	records, err := force.Query(fmt.Sprintf("%s", soql))
	if err != nil {
		ErrorAndExit(err.Error())
	} else {
		if format == "console" {
			DisplayForceRecords(records)
		} else  {
			DisplayForceRecordsf(records, format)
		}
	}
}
<commit_msg>fixed help for soql<commit_after>package main

import (
	"fmt"
	"strings"
)

var cmdSoql = &Command{
	Run:   runSoql,
	Usage: "soql <soql statement> [output format]",
	Short: "Execute a SOQL statement",
	Long: `
Execute a SOQL statement

Examples:

  force soql select Id, Name, Account.Name From Contact

  force soql select Id, Name, Account.Name From Contact --format:csv

`,
}

func runSoql(cmd *Command, args []string) {
	force, _ := ActiveForce()
	if len(args) < 1 {
		cmd.printUsage()
	} else {
		format := "console"
		formatArg := args[len(args)-1]

		if strings.Contains(formatArg, "--format:") {
			args = args[:len(args) - 1]
			format = strings.SplitN(formatArg, ":", 2)[1]
		}

		soql := strings.Join(args, " ")
		records, err := force.Query(fmt.Sprintf("%s", soql))
		if err != nil {
			ErrorAndExit(err.Error())
		} else {
			if format == "console" {
				DisplayForceRecords(records)
			} else  {
				DisplayForceRecordsf(records, format)
			}
		}
	}
}
<|endoftext|>


<commit_before>package sorg

import (
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
)

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "2"
)

const (
	// ContentDir is the location of the site's content (articles, fragments,
	// assets, etc.).
	ContentDir = "./content"

	// LayoutsDir is the source directory for view layouts.
	LayoutsDir = "./layouts"

	// MainLayout is the site's main layout.
	MainLayout = LayoutsDir + "/main"

	// PagesDir is the source directory for one-off page content.
	PagesDir = "./pages"

	// TargetDir is the target location where the site will be built to.
	TargetDir = "./public"

	// TargetVersionedAssetsDir is the target directory where static assets are
	// placed which should be versioned by release number. Versioned assets are
	// those that might need to change on release like CSS or JS files.
	TargetVersionedAssetsDir = TargetDir + "/assets/" + Release

	// ViewsDir is the source directory for views.
	ViewsDir = "./views"
)

// A list of all directories that are in the built static site.
var targetDirs = []string{
	TargetDir,
	TargetDir + "/articles",
	TargetDir + "/assets",
	TargetDir + "/assets/photos",
	TargetDir + "/fragments",
	TargetDir + "/photos",
	TargetDir + "/reading",
	TargetDir + "/runs",
	TargetDir + "/twitter",
	TargetVersionedAssetsDir,
}

// CreateTargetDirs creates TargetDir and all other necessary directories for
// the build if they don't already exist.
func CreateTargetDirs() error {
	start := time.Now()
	defer func() {
		log.Debugf("Created target directories in %v.", time.Now().Sub(start))
	}()

	for _, targetDir := range targetDirs {
		err := os.MkdirAll(targetDir, 0755)
		if err != nil {
			return err
		}
	}

	return nil
}

// InitLog initializes logging for singularity programs.
func InitLog(verbose bool) {
	log.SetFormatter(&plainFormatter{})

	if verbose {
		log.SetLevel(log.DebugLevel)
	}
}

// plainFormatter is a logrus formatter that displays text in a much more
// simple fashion that's more suitable as CLI output.
type plainFormatter struct {
}

// Format takes a logrus.Entry and returns bytes that are suitable for log
// output.
func (f *plainFormatter) Format(entry *log.Entry) ([]byte, error) {
	bytes := []byte(entry.Message + "\n")

	if entry.Level == log.DebugLevel {
		bytes = append([]byte("DEBUG: "), bytes...)
	}

	return bytes, nil
}
<commit_msg>Bump assets version<commit_after>package sorg

import (
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
)

const (
	// Release is the asset version of the site. Bump when any assets are
	// updated to blow away any browser caches.
	Release = "3"
)

const (
	// ContentDir is the location of the site's content (articles, fragments,
	// assets, etc.).
	ContentDir = "./content"

	// LayoutsDir is the source directory for view layouts.
	LayoutsDir = "./layouts"

	// MainLayout is the site's main layout.
	MainLayout = LayoutsDir + "/main"

	// PagesDir is the source directory for one-off page content.
	PagesDir = "./pages"

	// TargetDir is the target location where the site will be built to.
	TargetDir = "./public"

	// TargetVersionedAssetsDir is the target directory where static assets are
	// placed which should be versioned by release number. Versioned assets are
	// those that might need to change on release like CSS or JS files.
	TargetVersionedAssetsDir = TargetDir + "/assets/" + Release

	// ViewsDir is the source directory for views.
	ViewsDir = "./views"
)

// A list of all directories that are in the built static site.
var targetDirs = []string{
	TargetDir,
	TargetDir + "/articles",
	TargetDir + "/assets",
	TargetDir + "/assets/photos",
	TargetDir + "/fragments",
	TargetDir + "/photos",
	TargetDir + "/reading",
	TargetDir + "/runs",
	TargetDir + "/twitter",
	TargetVersionedAssetsDir,
}

// CreateTargetDirs creates TargetDir and all other necessary directories for
// the build if they don't already exist.
func CreateTargetDirs() error {
	start := time.Now()
	defer func() {
		log.Debugf("Created target directories in %v.", time.Now().Sub(start))
	}()

	for _, targetDir := range targetDirs {
		err := os.MkdirAll(targetDir, 0755)
		if err != nil {
			return err
		}
	}

	return nil
}

// InitLog initializes logging for singularity programs.
func InitLog(verbose bool) {
	log.SetFormatter(&plainFormatter{})

	if verbose {
		log.SetLevel(log.DebugLevel)
	}
}

// plainFormatter is a logrus formatter that displays text in a much more
// simple fashion that's more suitable as CLI output.
type plainFormatter struct {
}

// Format takes a logrus.Entry and returns bytes that are suitable for log
// output.
func (f *plainFormatter) Format(entry *log.Entry) ([]byte, error) {
	bytes := []byte(entry.Message + "\n")

	if entry.Level == log.DebugLevel {
		bytes = append([]byte("DEBUG: "), bytes...)
	}

	return bytes, nil
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/devices"
	"github.com/opencontainers/specs"
)

var specCommand = cli.Command{
	Name:  "spec",
	Usage: "create a new specification file",
	Action: func(context *cli.Context) {
		spec := specs.LinuxSpec{
			Spec: specs.Spec{
				Version: specs.Version,
				Platform: specs.Platform{
					OS:   runtime.GOOS,
					Arch: runtime.GOARCH,
				},
				Root: specs.Root{
					Path:     "rootfs",
					Readonly: true,
				},
				Process: specs.Process{
					Terminal: true,
					User:     specs.User{},
					Args: []string{
						"sh",
					},
					Env: []string{
						"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
						"TERM=xterm",
					},
				},
				Hostname: "shell",
				Mounts: []specs.Mount{
					{
						Type:        "proc",
						Source:      "proc",
						Destination: "/proc",
						Options:     "",
					},
					{
						Type:        "tmpfs",
						Source:      "tmpfs",
						Destination: "/dev",
						Options:     "nosuid,strictatime,mode=755,size=65536k",
					},
					{
						Type:        "devpts",
						Source:      "devpts",
						Destination: "/dev/pts",
						Options:     "nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5",
					},
					{
						Type:        "tmpfs",
						Source:      "shm",
						Destination: "/dev/shm",
						Options:     "nosuid,noexec,nodev,mode=1777,size=65536k",
					},
					{
						Type:        "mqueue",
						Source:      "mqueue",
						Destination: "/dev/mqueue",
						Options:     "nosuid,noexec,nodev",
					},
					{
						Type:        "sysfs",
						Source:      "sysfs",
						Destination: "/sys",
						Options:     "nosuid,noexec,nodev",
					},
					{
						Type:        "cgroup",
						Source:      "cgroup",
						Destination: "/sys/fs/cgroup",
						Options:     "nosuid,noexec,nodev,relatime,ro",
					},
				},
			},
			Linux: specs.Linux{
				Namespaces: []specs.Namespace{
					{
						Type: "process",
					},
					{
						Type: "network",
					},
					{
						Type: "ipc",
					},
					{
						Type: "uts",
					},
					{
						Type: "mount",
					},
				},
				Capabilities: []string{
					"AUDIT_WRITE",
					"KILL",
					"NET_BIND_SERVICE",
				},
				Devices: []string{
					"null",
					"random",
					"full",
					"tty",
					"zero",
					"urandom",
				},
				Resources: specs.Resources{
					Memory: specs.Memory{
						Swappiness: -1,
					},
				},
			},
		}
		data, err := json.MarshalIndent(&spec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		fmt.Printf("%s", data)
	},
}

var namespaceMapping = map[string]configs.NamespaceType{
	"process": configs.NEWPID,
	"network": configs.NEWNET,
	"mount":   configs.NEWNS,
	"user":    configs.NEWUSER,
	"ipc":     configs.NEWIPC,
	"uts":     configs.NEWUTS,
}

// loadSpec loads the specification from the provided path.
// If the path is empty then the default path will be "config.json"
func loadSpec(path string) (*specs.LinuxSpec, error) {
	if path == "" {
		path = "config.json"
	}
	f, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("JSON specification file for %s not found", path)
		}
		return nil, err
	}
	defer f.Close()
	var s *specs.LinuxSpec
	if err := json.NewDecoder(f).Decode(&s); err != nil {
		return nil, err
	}
	return s, checkSpecVersion(s)
}

// checkSpecVersion makes sure that the spec version matches runc's while we are in the initial
// development period.  It is better to hard fail than have missing fields or options in the spec.
func checkSpecVersion(s *specs.LinuxSpec) error {
	if s.Version != specs.Version {
		return fmt.Errorf("spec version is not compatible with implemented version %q: spec %q", specs.Version, s.Version)
	}
	return nil
}

func createLibcontainerConfig(spec *specs.LinuxSpec) (*configs.Config, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	rootfsPath := spec.Root.Path
	if !filepath.IsAbs(rootfsPath) {
		rootfsPath = filepath.Join(cwd, rootfsPath)
	}
	config := &configs.Config{
		Rootfs:       rootfsPath,
		Capabilities: spec.Linux.Capabilities,
		Readonlyfs:   spec.Root.Readonly,
		Hostname:     spec.Hostname,
		Privatefs:    true,
	}
	for _, ns := range spec.Linux.Namespaces {
		t, exists := namespaceMapping[ns.Type]
		if !exists {
			return nil, fmt.Errorf("namespace %q does not exist", ns)
		}
		config.Namespaces.Add(t, ns.Path)
	}
	for _, m := range spec.Mounts {
		config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m))
	}
	if err := createDevices(spec, config); err != nil {
		return nil, err
	}
	if err := setupUserNamespace(spec, config); err != nil {
		return nil, err
	}
	c, err := createCgroupConfig(spec, config.Devices)
	if err != nil {
		return nil, err
	}
	config.Cgroups = c
	if config.Readonlyfs {
		setReadonly(config)
		config.MaskPaths = []string{
			"/proc/kcore",
		}
		config.ReadonlyPaths = []string{
			"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
		}
	}
	config.Sysctl = spec.Linux.Sysctl
	return config, nil
}

func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount {
	flags, data := parseMountOptions(m.Options)
	source := m.Source
	if m.Type == "bind" {
		if !filepath.IsAbs(source) {
			source = filepath.Join(cwd, m.Source)
		}
	}
	return &configs.Mount{
		Device:      m.Type,
		Source:      source,
		Destination: m.Destination,
		Data:        data,
		Flags:       flags,
	}
}

func createCgroupConfig(spec *specs.LinuxSpec, devices []*configs.Device) (*configs.Cgroup, error) {
	myCgroupPath, err := cgroups.GetThisCgroupDir("devices")
	if err != nil {
		return nil, err
	}
	c := &configs.Cgroup{
		Name:           getDefaultID(),
		Parent:         myCgroupPath,
		AllowedDevices: append(devices, allowedDevices...),
	}
	r := spec.Linux.Resources
	c.Memory = r.Memory.Limit
	c.MemoryReservation = r.Memory.Reservation
	c.MemorySwap = r.Memory.Swap
	c.KernelMemory = r.Memory.Kernel
	c.MemorySwappiness = r.Memory.Swappiness
	c.CpuShares = r.CPU.Shares
	c.CpuQuota = r.CPU.Quota
	c.CpuPeriod = r.CPU.Period
	c.CpuRtRuntime = r.CPU.RealtimeRuntime
	c.CpuRtPeriod = r.CPU.RealtimePeriod
	c.CpusetCpus = r.CPU.Cpus
	c.CpusetMems = r.CPU.Mems
	c.BlkioThrottleReadBpsDevice = r.BlockIO.ThrottleReadBpsDevice
	c.BlkioThrottleWriteBpsDevice = r.BlockIO.ThrottleWriteBpsDevice
	c.BlkioThrottleReadIOpsDevice = r.BlockIO.ThrottleReadIOpsDevice
	c.BlkioThrottleWriteIOpsDevice = r.BlockIO.ThrottleWriteIOpsDevice
	c.BlkioWeight = r.BlockIO.Weight
	c.BlkioWeightDevice = r.BlockIO.WeightDevice
	for _, l := range r.HugepageLimits {
		c.HugetlbLimit = append(c.HugetlbLimit, &configs.HugepageLimit{
			Pagesize: l.Pagesize,
			Limit:    l.Limit,
		})
	}
	c.OomKillDisable = r.DisableOOMKiller
	c.NetClsClassid = r.Network.ClassID
	for _, m := range r.Network.Priorities {
		c.NetPrioIfpriomap = append(c.NetPrioIfpriomap, &configs.IfPrioMap{
			Interface: m.Name,
			Priority:  m.Priority,
		})
	}
	return c, nil
}

func createDevices(spec *specs.LinuxSpec, config *configs.Config) error {
	for _, name := range spec.Linux.Devices {
		d, err := devices.DeviceFromPath(filepath.Join("/dev", name), "rwm")
		if err != nil {
			return err
		}
		config.Devices = append(config.Devices, d)
	}
	return nil
}

func setReadonly(config *configs.Config) {
	for _, m := range config.Mounts {
		if m.Device == "sysfs" {
			m.Flags |= syscall.MS_RDONLY
		}
	}
}

func setupUserNamespace(spec *specs.LinuxSpec, config *configs.Config) error {
	if len(spec.Linux.UidMappings) == 0 {
		return nil
	}
	config.Namespaces.Add(configs.NEWUSER, "")
	create := func(m specs.IDMapping) configs.IDMap {
		return configs.IDMap{
			HostID:      int(m.HostID),
			ContainerID: int(m.ContainerID),
			Size:        int(m.Size),
		}
	}
	for _, m := range spec.Linux.UidMappings {
		config.UidMappings = append(config.UidMappings, create(m))
	}
	for _, m := range spec.Linux.GidMappings {
		config.GidMappings = append(config.GidMappings, create(m))
	}
	rootUid, err := config.HostUID()
	if err != nil {
		return err
	}
	rootGid, err := config.HostGID()
	if err != nil {
		return err
	}
	for _, node := range config.Devices {
		node.Uid = uint32(rootUid)
		node.Gid = uint32(rootGid)
	}
	return nil
}

// parseMountOptions parses the string and returns the flags and any mount data that
// it contains.
func parseMountOptions(options string) (int, string) {
	var (
		flag int
		data []string
	)
	flags := map[string]struct {
		clear bool
		flag  int
	}{
		"async":         {true, syscall.MS_SYNCHRONOUS},
		"atime":         {true, syscall.MS_NOATIME},
		"bind":          {false, syscall.MS_BIND},
		"defaults":      {false, 0},
		"dev":           {true, syscall.MS_NODEV},
		"diratime":      {true, syscall.MS_NODIRATIME},
		"dirsync":       {false, syscall.MS_DIRSYNC},
		"exec":          {true, syscall.MS_NOEXEC},
		"mand":          {false, syscall.MS_MANDLOCK},
		"noatime":       {false, syscall.MS_NOATIME},
		"nodev":         {false, syscall.MS_NODEV},
		"nodiratime":    {false, syscall.MS_NODIRATIME},
		"noexec":        {false, syscall.MS_NOEXEC},
		"nomand":        {true, syscall.MS_MANDLOCK},
		"norelatime":    {true, syscall.MS_RELATIME},
		"nostrictatime": {true, syscall.MS_STRICTATIME},
		"nosuid":        {false, syscall.MS_NOSUID},
		"private":       {false, syscall.MS_PRIVATE},
		"rbind":         {false, syscall.MS_BIND | syscall.MS_REC},
		"relatime":      {false, syscall.MS_RELATIME},
		"remount":       {false, syscall.MS_REMOUNT},
		"ro":            {false, syscall.MS_RDONLY},
		"rprivate":      {false, syscall.MS_PRIVATE | syscall.MS_REC},
		"rshared":       {false, syscall.MS_SHARED | syscall.MS_REC},
		"rslave":        {false, syscall.MS_SLAVE | syscall.MS_REC},
		"runbindable":   {false, syscall.MS_UNBINDABLE | syscall.MS_REC},
		"rw":            {true, syscall.MS_RDONLY},
		"shared":        {false, syscall.MS_SHARED},
		"slave":         {false, syscall.MS_SLAVE},
		"strictatime":   {false, syscall.MS_STRICTATIME},
		"suid":          {true, syscall.MS_NOSUID},
		"sync":          {false, syscall.MS_SYNCHRONOUS},
		"unbindable":    {false, syscall.MS_UNBINDABLE},
	}
	for _, o := range strings.Split(options, ",") {
		// If the option does not exist in the flags table or the flag
		// is not supported on the platform,
		// then it is a data value for a specific fs type
		if f, exists := flags[o]; exists && f.flag != 0 {
			if f.clear {
				flag &= ^f.flag
			} else {
				flag |= f.flag
			}
		} else {
			data = append(data, o)
		}
	}
	return flag, strings.Join(data, ",")
}
<commit_msg>bring the loopback interface up<commit_after>// +build linux

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/devices"
	"github.com/opencontainers/specs"
)

var specCommand = cli.Command{
	Name:  "spec",
	Usage: "create a new specification file",
	Action: func(context *cli.Context) {
		spec := specs.LinuxSpec{
			Spec: specs.Spec{
				Version: specs.Version,
				Platform: specs.Platform{
					OS:   runtime.GOOS,
					Arch: runtime.GOARCH,
				},
				Root: specs.Root{
					Path:     "rootfs",
					Readonly: true,
				},
				Process: specs.Process{
					Terminal: true,
					User:     specs.User{},
					Args: []string{
						"sh",
					},
					Env: []string{
						"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
						"TERM=xterm",
					},
				},
				Hostname: "shell",
				Mounts: []specs.Mount{
					{
						Type:        "proc",
						Source:      "proc",
						Destination: "/proc",
						Options:     "",
					},
					{
						Type:        "tmpfs",
						Source:      "tmpfs",
						Destination: "/dev",
						Options:     "nosuid,strictatime,mode=755,size=65536k",
					},
					{
						Type:        "devpts",
						Source:      "devpts",
						Destination: "/dev/pts",
						Options:     "nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5",
					},
					{
						Type:        "tmpfs",
						Source:      "shm",
						Destination: "/dev/shm",
						Options:     "nosuid,noexec,nodev,mode=1777,size=65536k",
					},
					{
						Type:        "mqueue",
						Source:      "mqueue",
						Destination: "/dev/mqueue",
						Options:     "nosuid,noexec,nodev",
					},
					{
						Type:        "sysfs",
						Source:      "sysfs",
						Destination: "/sys",
						Options:     "nosuid,noexec,nodev",
					},
					{
						Type:        "cgroup",
						Source:      "cgroup",
						Destination: "/sys/fs/cgroup",
						Options:     "nosuid,noexec,nodev,relatime,ro",
					},
				},
			},
			Linux: specs.Linux{
				Namespaces: []specs.Namespace{
					{
						Type: "process",
					},
					{
						Type: "network",
					},
					{
						Type: "ipc",
					},
					{
						Type: "uts",
					},
					{
						Type: "mount",
					},
				},
				Capabilities: []string{
					"AUDIT_WRITE",
					"KILL",
					"NET_BIND_SERVICE",
				},
				Devices: []string{
					"null",
					"random",
					"full",
					"tty",
					"zero",
					"urandom",
				},
				Resources: specs.Resources{
					Memory: specs.Memory{
						Swappiness: -1,
					},
				},
			},
		}
		data, err := json.MarshalIndent(&spec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		fmt.Printf("%s", data)
	},
}

var namespaceMapping = map[string]configs.NamespaceType{
	"process": configs.NEWPID,
	"network": configs.NEWNET,
	"mount":   configs.NEWNS,
	"user":    configs.NEWUSER,
	"ipc":     configs.NEWIPC,
	"uts":     configs.NEWUTS,
}

// loadSpec loads the specification from the provided path.
// If the path is empty then the default path will be "config.json"
func loadSpec(path string) (*specs.LinuxSpec, error) {
	if path == "" {
		path = "config.json"
	}
	f, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("JSON specification file for %s not found", path)
		}
		return nil, err
	}
	defer f.Close()
	var s *specs.LinuxSpec
	if err := json.NewDecoder(f).Decode(&s); err != nil {
		return nil, err
	}
	return s, checkSpecVersion(s)
}

// checkSpecVersion makes sure that the spec version matches runc's while we are in the initial
// development period.  It is better to hard fail than have missing fields or options in the spec.
func checkSpecVersion(s *specs.LinuxSpec) error {
	if s.Version != specs.Version {
		return fmt.Errorf("spec version is not compatible with implemented version %q: spec %q", specs.Version, s.Version)
	}
	return nil
}

func createLibcontainerConfig(spec *specs.LinuxSpec) (*configs.Config, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	rootfsPath := spec.Root.Path
	if !filepath.IsAbs(rootfsPath) {
		rootfsPath = filepath.Join(cwd, rootfsPath)
	}
	config := &configs.Config{
		Rootfs:       rootfsPath,
		Capabilities: spec.Linux.Capabilities,
		Readonlyfs:   spec.Root.Readonly,
		Hostname:     spec.Hostname,
		Privatefs:    true,
		Networks: []*configs.Network{
			{
				Type: "loopback",
			},
		},
	}
	for _, ns := range spec.Linux.Namespaces {
		t, exists := namespaceMapping[ns.Type]
		if !exists {
			return nil, fmt.Errorf("namespace %q does not exist", ns)
		}
		config.Namespaces.Add(t, ns.Path)
	}
	for _, m := range spec.Mounts {
		config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m))
	}
	if err := createDevices(spec, config); err != nil {
		return nil, err
	}
	if err := setupUserNamespace(spec, config); err != nil {
		return nil, err
	}
	c, err := createCgroupConfig(spec, config.Devices)
	if err != nil {
		return nil, err
	}
	config.Cgroups = c
	if config.Readonlyfs {
		setReadonly(config)
		config.MaskPaths = []string{
			"/proc/kcore",
		}
		config.ReadonlyPaths = []string{
			"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
		}
	}
	config.Sysctl = spec.Linux.Sysctl
	return config, nil
}

func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount {
	flags, data := parseMountOptions(m.Options)
	source := m.Source
	if m.Type == "bind" {
		if !filepath.IsAbs(source) {
			source = filepath.Join(cwd, m.Source)
		}
	}
	return &configs.Mount{
		Device:      m.Type,
		Source:      source,
		Destination: m.Destination,
		Data:        data,
		Flags:       flags,
	}
}

func createCgroupConfig(spec *specs.LinuxSpec, devices []*configs.Device) (*configs.Cgroup, error) {
	myCgroupPath, err := cgroups.GetThisCgroupDir("devices")
	if err != nil {
		return nil, err
	}
	c := &configs.Cgroup{
		Name:           getDefaultID(),
		Parent:         myCgroupPath,
		AllowedDevices: append(devices, allowedDevices...),
	}
	r := spec.Linux.Resources
	c.Memory = r.Memory.Limit
	c.MemoryReservation = r.Memory.Reservation
	c.MemorySwap = r.Memory.Swap
	c.KernelMemory = r.Memory.Kernel
	c.MemorySwappiness = r.Memory.Swappiness
	c.CpuShares = r.CPU.Shares
	c.CpuQuota = r.CPU.Quota
	c.CpuPeriod = r.CPU.Period
	c.CpuRtRuntime = r.CPU.RealtimeRuntime
	c.CpuRtPeriod = r.CPU.RealtimePeriod
	c.CpusetCpus = r.CPU.Cpus
	c.CpusetMems = r.CPU.Mems
	c.BlkioThrottleReadBpsDevice = r.BlockIO.ThrottleReadBpsDevice
	c.BlkioThrottleWriteBpsDevice = r.BlockIO.ThrottleWriteBpsDevice
	c.BlkioThrottleReadIOpsDevice = r.BlockIO.ThrottleReadIOpsDevice
	c.BlkioThrottleWriteIOpsDevice = r.BlockIO.ThrottleWriteIOpsDevice
	c.BlkioWeight = r.BlockIO.Weight
	c.BlkioWeightDevice = r.BlockIO.WeightDevice
	for _, l := range r.HugepageLimits {
		c.HugetlbLimit = append(c.HugetlbLimit, &configs.HugepageLimit{
			Pagesize: l.Pagesize,
			Limit:    l.Limit,
		})
	}
	c.OomKillDisable = r.DisableOOMKiller
	c.NetClsClassid = r.Network.ClassID
	for _, m := range r.Network.Priorities {
		c.NetPrioIfpriomap = append(c.NetPrioIfpriomap, &configs.IfPrioMap{
			Interface: m.Name,
			Priority:  m.Priority,
		})
	}
	return c, nil
}

func createDevices(spec *specs.LinuxSpec, config *configs.Config) error {
	for _, name := range spec.Linux.Devices {
		d, err := devices.DeviceFromPath(filepath.Join("/dev", name), "rwm")
		if err != nil {
			return err
		}
		config.Devices = append(config.Devices, d)
	}
	return nil
}

func setReadonly(config *configs.Config) {
	for _, m := range config.Mounts {
		if m.Device == "sysfs" {
			m.Flags |= syscall.MS_RDONLY
		}
	}
}

func setupUserNamespace(spec *specs.LinuxSpec, config *configs.Config) error {
	if len(spec.Linux.UidMappings) == 0 {
		return nil
	}
	config.Namespaces.Add(configs.NEWUSER, "")
	create := func(m specs.IDMapping) configs.IDMap {
		return configs.IDMap{
			HostID:      int(m.HostID),
			ContainerID: int(m.ContainerID),
			Size:        int(m.Size),
		}
	}
	for _, m := range spec.Linux.UidMappings {
		config.UidMappings = append(config.UidMappings, create(m))
	}
	for _, m := range spec.Linux.GidMappings {
		config.GidMappings = append(config.GidMappings, create(m))
	}
	rootUid, err := config.HostUID()
	if err != nil {
		return err
	}
	rootGid, err := config.HostGID()
	if err != nil {
		return err
	}
	for _, node := range config.Devices {
		node.Uid = uint32(rootUid)
		node.Gid = uint32(rootGid)
	}
	return nil
}

// parseMountOptions parses the string and returns the flags and any mount data that
// it contains.
func parseMountOptions(options string) (int, string) {
	var (
		flag int
		data []string
	)
	flags := map[string]struct {
		clear bool
		flag  int
	}{
		"async":         {true, syscall.MS_SYNCHRONOUS},
		"atime":         {true, syscall.MS_NOATIME},
		"bind":          {false, syscall.MS_BIND},
		"defaults":      {false, 0},
		"dev":           {true, syscall.MS_NODEV},
		"diratime":      {true, syscall.MS_NODIRATIME},
		"dirsync":       {false, syscall.MS_DIRSYNC},
		"exec":          {true, syscall.MS_NOEXEC},
		"mand":          {false, syscall.MS_MANDLOCK},
		"noatime":       {false, syscall.MS_NOATIME},
		"nodev":         {false, syscall.MS_NODEV},
		"nodiratime":    {false, syscall.MS_NODIRATIME},
		"noexec":        {false, syscall.MS_NOEXEC},
		"nomand":        {true, syscall.MS_MANDLOCK},
		"norelatime":    {true, syscall.MS_RELATIME},
		"nostrictatime": {true, syscall.MS_STRICTATIME},
		"nosuid":        {false, syscall.MS_NOSUID},
		"private":       {false, syscall.MS_PRIVATE},
		"rbind":         {false, syscall.MS_BIND | syscall.MS_REC},
		"relatime":      {false, syscall.MS_RELATIME},
		"remount":       {false, syscall.MS_REMOUNT},
		"ro":            {false, syscall.MS_RDONLY},
		"rprivate":      {false, syscall.MS_PRIVATE | syscall.MS_REC},
		"rshared":       {false, syscall.MS_SHARED | syscall.MS_REC},
		"rslave":        {false, syscall.MS_SLAVE | syscall.MS_REC},
		"runbindable":   {false, syscall.MS_UNBINDABLE | syscall.MS_REC},
		"rw":            {true, syscall.MS_RDONLY},
		"shared":        {false, syscall.MS_SHARED},
		"slave":         {false, syscall.MS_SLAVE},
		"strictatime":   {false, syscall.MS_STRICTATIME},
		"suid":          {true, syscall.MS_NOSUID},
		"sync":          {false, syscall.MS_SYNCHRONOUS},
		"unbindable":    {false, syscall.MS_UNBINDABLE},
	}
	for _, o := range strings.Split(options, ",") {
		// If the option does not exist in the flags table or the flag
		// is not supported on the platform,
		// then it is a data value for a specific fs type
		if f, exists := flags[o]; exists && f.flag != 0 {
			if f.clear {
				flag &= ^f.flag
			} else {
				flag |= f.flag
			}
		} else {
			data = append(data, o)
		}
	}
	return flag, strings.Join(data, ",")
}
<|endoftext|>


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

package spec

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path/filepath"

	"github.com/go-swagger/go-swagger/swag"
)

//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/...
//go:generate perl -pi -e s,Json,JSON,g bindata.go

const (
	// SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs
	SwaggerSchemaURL = "http://swagger.io/v2/schema.json#"
	// JSONSchemaURL the url for the json schema schema
	JSONSchemaURL = "http://json-schema.org/draft-04/schema#"
)

var (
	jsonSchema    = MustLoadJSONSchemaDraft04()
	swaggerSchema = MustLoadSwagger20Schema()
)

// DocLoader represents a doc loader type
type DocLoader func(string) (json.RawMessage, error)

// JSONSpec loads a spec from a json document
func JSONSpec(path string) (*Document, error) {
	data, err := swag.JSONDoc(path)
	if err != nil {
		return nil, err
	}
	// convert to json
	return New(json.RawMessage(data), "")
}

// YAMLSpec loads a swagger spec document
func YAMLSpec(path string) (*Document, error) {
	data, err := swag.YAMLDoc(path)
	if err != nil {
		return nil, err
	}

	return New(data, "")
}

// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error
func MustLoadJSONSchemaDraft04() *Schema {
	d, e := JSONSchemaDraft04()
	if e != nil {
		panic(e)
	}
	return d
}

// JSONSchemaDraft04 loads the json schema document for json shema draft04
func JSONSchemaDraft04() (*Schema, error) {
	b, err := Asset("jsonschema-draft-04.json")
	if err != nil {
		return nil, err
	}

	schema := new(Schema)
	if err := json.Unmarshal(b, schema); err != nil {
		return nil, err
	}
	return schema, nil
}

// MustLoadSwagger20Schema panics when Swagger20Schema returns an error
func MustLoadSwagger20Schema() *Schema {
	d, e := Swagger20Schema()
	if e != nil {
		panic(e)
	}
	return d
}

// Swagger20Schema loads the swagger 2.0 schema from the embedded assets
func Swagger20Schema() (*Schema, error) {

	b, err := Asset("v2/schema.json")
	if err != nil {
		return nil, err
	}

	schema := new(Schema)
	if err := json.Unmarshal(b, schema); err != nil {
		return nil, err
	}
	return schema, nil
}

// Document represents a swagger spec document
type Document struct {
	// specAnalyzer
	spec   *Swagger
	schema *Schema
	raw    json.RawMessage
	orig   *Document
}

// Load loads a new spec document
func Load(path string) (*Document, error) {
	specURL, err := url.Parse(path)
	if err != nil {
		return nil, err
	}

	ext := filepath.Ext(specURL.Path)
	if ext == ".yaml" || ext == ".yml" {
		return YAMLSpec(path)
	}

	return JSONSpec(path)
}

// New creates a new shema document
func New(data json.RawMessage, version string) (*Document, error) {
	if version == "" {
		version = "2.0"
	}
	if version != "2.0" {
		return nil, fmt.Errorf("spec version %q is not supported", version)
	}

	spec := new(Swagger)
	if err := json.Unmarshal(data, spec); err != nil {
		return nil, err
	}

	d := &Document{
		// specAnalyzer: specAnalyzer{
		// 	spec:        spec,
		// 	consumes:    make(map[string]struct{}),
		// 	produces:    make(map[string]struct{}),
		// 	authSchemes: make(map[string]struct{}),
		// 	operations:  make(map[string]map[string]*Operation),
		// 	allSchemas:  make(map[string]SchemaRef),
		// 	allOfs:      make(map[string]SchemaRef),
		// },
		schema: MustLoadSwagger20Schema(),
		spec:   spec,
		raw:    data,
	}
	// d.initialize()
	d.orig = &(*d)
	d.orig.spec = &(*spec)
	return d, nil
}

// Expanded expands the ref fields in the spec document and returns a new spec document
func (d *Document) Expanded() (*Document, error) {
	spec := new(Swagger)
	if err := json.Unmarshal(d.raw, spec); err != nil {
		return nil, err
	}
	if err := expandSpec(spec); err != nil {
		return nil, err
	}

	dd := &Document{
		// specAnalyzer: specAnalyzer{
		// 	spec:        spec,
		// 	consumes:    make(map[string]struct{}),
		// 	produces:    make(map[string]struct{}),
		// 	authSchemes: make(map[string]struct{}),
		// 	operations:  make(map[string]map[string]*Operation),
		// 	allSchemas:  make(map[string]SchemaRef),
		// 	allOfs:      make(map[string]SchemaRef),
		// },
		spec:   spec,
		schema: MustLoadSwagger20Schema(),
		raw:    d.raw,
	}
	// dd.initialize()
	dd.orig = d.orig
	dd.orig.spec = &(*d.orig.spec)

	return dd, nil
}

// BasePath the base path for this spec
func (d *Document) BasePath() string {
	return d.spec.BasePath
}

// Version returns the version of this spec
func (d *Document) Version() string {
	return d.spec.Swagger
}

// Schema returns the swagger 2.0 schema
func (d *Document) Schema() *Schema {
	return d.schema
}

// Spec returns the swagger spec object model
func (d *Document) Spec() *Swagger {
	return d.spec
}

// Host returns the host for the API
func (d *Document) Host() string {
	return d.spec.Host
}

// Raw returns the raw swagger spec as json bytes
func (d *Document) Raw() json.RawMessage {
	return d.raw
}

// Reload reanalyzes the spec
func (d *Document) Reload() *Document {
	// orig := d.orig
	// d.specAnalyzer = specAnalyzer{
	// 	spec:        d.spec,
	// 	consumes:    make(map[string]struct{}),
	// 	produces:    make(map[string]struct{}),
	// 	authSchemes: make(map[string]struct{}),
	// 	operations:  make(map[string]map[string]*Operation),
	// 	allSchemas:  make(map[string]SchemaRef),
	// 	allOfs:      make(map[string]SchemaRef),
	// }
	// d.initialize()
	// d.orig = orig
	return d
}

// ResetDefinitions gives a shallow copy with the models reset
func (d *Document) ResetDefinitions() *Document {
	defs := make(map[string]Schema)
	for k, v := range d.orig.spec.Definitions {
		defs[k] = v
	}

	dd := &(*d)
	dd.spec = &(*d.orig.spec)
	dd.schema = MustLoadSwagger20Schema()
	dd.spec.Definitions = defs
	// dd.initialize()
	dd.orig = d.orig
	return dd.Reload()
}

// Pristine creates a new pristine document instance based on the input data
func (d *Document) Pristine() *Document {
	dd, _ := New(d.Raw(), d.Version())
	return dd
}
<commit_msg>pre-allocate known lengths, remove some commented code<commit_after>// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package spec

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path/filepath"

	"github.com/go-swagger/go-swagger/swag"
)

//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/...
//go:generate perl -pi -e s,Json,JSON,g bindata.go

const (
	// SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs
	SwaggerSchemaURL = "http://swagger.io/v2/schema.json#"
	// JSONSchemaURL the url for the json schema schema
	JSONSchemaURL = "http://json-schema.org/draft-04/schema#"
)

var (
	jsonSchema    = MustLoadJSONSchemaDraft04()
	swaggerSchema = MustLoadSwagger20Schema()
)

// DocLoader represents a doc loader type
type DocLoader func(string) (json.RawMessage, error)

// JSONSpec loads a spec from a json document
func JSONSpec(path string) (*Document, error) {
	data, err := swag.JSONDoc(path)
	if err != nil {
		return nil, err
	}
	// convert to json
	return New(json.RawMessage(data), "")
}

// YAMLSpec loads a swagger spec document
func YAMLSpec(path string) (*Document, error) {
	data, err := swag.YAMLDoc(path)
	if err != nil {
		return nil, err
	}

	return New(data, "")
}

// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error
func MustLoadJSONSchemaDraft04() *Schema {
	d, e := JSONSchemaDraft04()
	if e != nil {
		panic(e)
	}
	return d
}

// JSONSchemaDraft04 loads the json schema document for json shema draft04
func JSONSchemaDraft04() (*Schema, error) {
	b, err := Asset("jsonschema-draft-04.json")
	if err != nil {
		return nil, err
	}

	schema := new(Schema)
	if err := json.Unmarshal(b, schema); err != nil {
		return nil, err
	}
	return schema, nil
}

// MustLoadSwagger20Schema panics when Swagger20Schema returns an error
func MustLoadSwagger20Schema() *Schema {
	d, e := Swagger20Schema()
	if e != nil {
		panic(e)
	}
	return d
}

// Swagger20Schema loads the swagger 2.0 schema from the embedded assets
func Swagger20Schema() (*Schema, error) {

	b, err := Asset("v2/schema.json")
	if err != nil {
		return nil, err
	}

	schema := new(Schema)
	if err := json.Unmarshal(b, schema); err != nil {
		return nil, err
	}
	return schema, nil
}

// Document represents a swagger spec document
type Document struct {
	// specAnalyzer
	spec   *Swagger
	schema *Schema
	raw    json.RawMessage
	orig   *Document
}

// Load loads a new spec document
func Load(path string) (*Document, error) {
	specURL, err := url.Parse(path)
	if err != nil {
		return nil, err
	}

	ext := filepath.Ext(specURL.Path)
	if ext == ".yaml" || ext == ".yml" {
		return YAMLSpec(path)
	}

	return JSONSpec(path)
}

// New creates a new shema document
func New(data json.RawMessage, version string) (*Document, error) {
	if version == "" {
		version = "2.0"
	}
	if version != "2.0" {
		return nil, fmt.Errorf("spec version %q is not supported", version)
	}

	spec := new(Swagger)
	if err := json.Unmarshal(data, spec); err != nil {
		return nil, err
	}

	d := &Document{
		schema: MustLoadSwagger20Schema(),
		spec:   spec,
		raw:    data,
	}
	// d.initialize()
	d.orig = &(*d)
	d.orig.spec = &(*spec)
	return d, nil
}

// Expanded expands the ref fields in the spec document and returns a new spec document
func (d *Document) Expanded() (*Document, error) {
	spec := new(Swagger)
	if err := json.Unmarshal(d.raw, spec); err != nil {
		return nil, err
	}
	if err := expandSpec(spec); err != nil {
		return nil, err
	}

	dd := &Document{
		spec:   spec,
		schema: MustLoadSwagger20Schema(),
		raw:    d.raw,
	}
	// dd.initialize()
	dd.orig = d.orig
	dd.orig.spec = &(*d.orig.spec)

	return dd, nil
}

// BasePath the base path for this spec
func (d *Document) BasePath() string {
	return d.spec.BasePath
}

// Version returns the version of this spec
func (d *Document) Version() string {
	return d.spec.Swagger
}

// Schema returns the swagger 2.0 schema
func (d *Document) Schema() *Schema {
	return d.schema
}

// Spec returns the swagger spec object model
func (d *Document) Spec() *Swagger {
	return d.spec
}

// Host returns the host for the API
func (d *Document) Host() string {
	return d.spec.Host
}

// Raw returns the raw swagger spec as json bytes
func (d *Document) Raw() json.RawMessage {
	return d.raw
}

// Reload reanalyzes the spec
func (d *Document) Reload() *Document {
	// TODO: make use of analyzer again here
	return d.Pristine()
}

// ResetDefinitions gives a shallow copy with the models reset
func (d *Document) ResetDefinitions() *Document {
	defs := make(map[string]Schema, len(d.orig.spec.Definitions))
	for k, v := range d.orig.spec.Definitions {
		defs[k] = v
	}

	dd := &(*d)
	dd.spec = &(*d.orig.spec)
	dd.schema = MustLoadSwagger20Schema()
	dd.spec.Definitions = defs
	// dd.initialize()
	dd.orig = d.orig
	return dd.Reload()
}

// Pristine creates a new pristine document instance based on the input data
func (d *Document) Pristine() *Document {
	dd, _ := New(d.Raw(), d.Version())
	return dd
}
<|endoftext|>


<commit_before>package libspf2

/*
#cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lspf2
#cgo CFLAGS: -g -O2 -Wno-error -I/usr/include -I/usr/local/include

#include <stdlib.h>
#include <netdb.h>
#include <spf2/spf.h>
*/
import "C"

import (
	"errors"
	"net"
	"unsafe"
)

const (
	SPFResultINVALID   = Result(C.SPF_RESULT_INVALID)   // (invalid)
	SPFResultPASS      = Result(C.SPF_RESULT_PASS)      // pass
	SPFResultFAIL      = Result(C.SPF_RESULT_FAIL)      // fail
	SPFResultSOFTFAIL  = Result(C.SPF_RESULT_SOFTFAIL)  // softfail
	SPFResultNEUTRAL   = Result(C.SPF_RESULT_NEUTRAL)   // neutral
	SPFResultPERMERROR = Result(C.SPF_RESULT_PERMERROR) // permerror
	SPFResultTEMPERROR = Result(C.SPF_RESULT_TEMPERROR) // temperror
	SPFResultNONE      = Result(C.SPF_RESULT_NONE)      // none
)

type Client interface {
	Query(host string, ip net.IP) (Result, error)
	Close()
}

type clientImpl struct {
	s *C.SPF_server_t
}

// NewClient creates a new SPF client.
func NewClient() Client {
	client := new(clientImpl)
	client.s = C.SPF_server_new(C.SPF_DNS_CACHE, 0)
	return client
}

func (s *clientImpl) Query(host string, ip net.IP) (Result, error) {
	if s.s == nil {
		return SPFResultINVALID, errors.New("client already closed")
	}
	req := newRequest(s)
	defer req.free()
	if err := req.setEnvFrom(host); err != nil {
		return SPFResultINVALID, err
	}
	if err := req.setIpAddr(ip); err != nil {
		return SPFResultINVALID, err
	}
	resp, err := req.query()
	if err != nil {
		return SPFResultNONE, err
	}
	defer resp.free()
	return resp.result(), nil
}

func (s *clientImpl) Close() {
	if s.s != nil {
		C.SPF_server_free(s.s)
		s.s = nil
	}
}

type request struct {
	s *clientImpl
	r *C.SPF_request_t
}

func newRequest(s *clientImpl) *request {
	r := new(request)
	r.s = s
	r.r = C.SPF_request_new(s.s)
	return r
}

// SetIPAddr sets the IP address of the client (sending) MTA
func (r *request) setIpAddr(ip net.IP) error {
	var stat C.SPF_errcode_t
	cstring := C.CString(ip.String())
	defer C.free(unsafe.Pointer(cstring))
	if ip.To4() != nil {
		stat = C.SPF_request_set_ipv4_str(r.r, cstring)
	} else {
		stat = C.SPF_request_set_ipv6_str(r.r, cstring)
	}
	if stat != C.SPF_E_SUCCESS {
		return &spfError{stat}
	}
	return nil
}

// SetEnvFrom sets the envelope from email address from the SMTP MAIL FROM: command
func (r *request) setEnvFrom(from string) error {
	var stat C.int
	cstring := C.CString(from)
	defer C.free(unsafe.Pointer(cstring))
	stat = C.SPF_request_set_env_from(r.r, cstring)
	if stat != C.int(C.SPF_E_SUCCESS) {
		return &spfError{C.SPF_errcode_t(stat)}
	}
	return nil
}

// Query starts the SPF query
func (r *request) query() (*response, error) {
	var stat C.SPF_errcode_t
	var resp *C.SPF_response_t
	stat = C.SPF_request_query_mailfrom(r.r, &resp)
	if stat != C.SPF_E_SUCCESS {
		return nil, &spfError{stat}
	}
	return &response{resp}, nil
}

// Free the request handle
func (r *request) free() {
	if r.r != nil {
		C.SPF_request_free(r.r)
		r.r = nil
	}
}

type response struct {
	r *C.SPF_response_t
}

// Result returns the SPF validation result
func (r *response) result() Result {
	return Result(C.SPF_response_result(r.r))
}

// Free frees the response handle
func (r *response) free() {
	if r.r != nil {
		C.SPF_response_free(r.r)
		r.r = nil
	}
}

type Result int

func (r Result) String() string {
	return C.GoString(C.SPF_strresult(C.SPF_result_t(r)))
}

type spfError struct {
	code C.SPF_errcode_t
}

func (e *spfError) Error() string {
	return C.GoString(C.SPF_strerror(e.code))
}
<commit_msg>FreeBSD compat<commit_after>package libspf2

/*
#cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lspf2
#cgo CFLAGS: -g -O2 -Wno-error -I/usr/include -I/usr/local/include

#include <time.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <spf2/spf.h>
*/
import "C"

import (
	"errors"
	"net"
	"unsafe"
)

const (
	SPFResultINVALID   = Result(C.SPF_RESULT_INVALID)   // (invalid)
	SPFResultPASS      = Result(C.SPF_RESULT_PASS)      // pass
	SPFResultFAIL      = Result(C.SPF_RESULT_FAIL)      // fail
	SPFResultSOFTFAIL  = Result(C.SPF_RESULT_SOFTFAIL)  // softfail
	SPFResultNEUTRAL   = Result(C.SPF_RESULT_NEUTRAL)   // neutral
	SPFResultPERMERROR = Result(C.SPF_RESULT_PERMERROR) // permerror
	SPFResultTEMPERROR = Result(C.SPF_RESULT_TEMPERROR) // temperror
	SPFResultNONE      = Result(C.SPF_RESULT_NONE)      // none
)

type Client interface {
	Query(host string, ip net.IP) (Result, error)
	Close()
}

type clientImpl struct {
	s *C.SPF_server_t
}

// NewClient creates a new SPF client.
func NewClient() Client {
	client := new(clientImpl)
	client.s = C.SPF_server_new(C.SPF_DNS_CACHE, 0)
	return client
}

func (s *clientImpl) Query(host string, ip net.IP) (Result, error) {
	if s.s == nil {
		return SPFResultINVALID, errors.New("client already closed")
	}
	req := newRequest(s)
	defer req.free()
	if err := req.setEnvFrom(host); err != nil {
		return SPFResultINVALID, err
	}
	if err := req.setIpAddr(ip); err != nil {
		return SPFResultINVALID, err
	}
	resp, err := req.query()
	if err != nil {
		return SPFResultNONE, err
	}
	defer resp.free()
	return resp.result(), nil
}

func (s *clientImpl) Close() {
	if s.s != nil {
		C.SPF_server_free(s.s)
		s.s = nil
	}
}

type request struct {
	s *clientImpl
	r *C.SPF_request_t
}

func newRequest(s *clientImpl) *request {
	r := new(request)
	r.s = s
	r.r = C.SPF_request_new(s.s)
	return r
}

// SetIPAddr sets the IP address of the client (sending) MTA
func (r *request) setIpAddr(ip net.IP) error {
	var stat C.SPF_errcode_t
	cstring := C.CString(ip.String())
	defer C.free(unsafe.Pointer(cstring))
	if ip.To4() != nil {
		stat = C.SPF_request_set_ipv4_str(r.r, cstring)
	} else {
		stat = C.SPF_request_set_ipv6_str(r.r, cstring)
	}
	if stat != C.SPF_E_SUCCESS {
		return &spfError{stat}
	}
	return nil
}

// SetEnvFrom sets the envelope from email address from the SMTP MAIL FROM: command
func (r *request) setEnvFrom(from string) error {
	var stat C.int
	cstring := C.CString(from)
	defer C.free(unsafe.Pointer(cstring))
	stat = C.SPF_request_set_env_from(r.r, cstring)
	if stat != C.int(C.SPF_E_SUCCESS) {
		return &spfError{C.SPF_errcode_t(stat)}
	}
	return nil
}

// Query starts the SPF query
func (r *request) query() (*response, error) {
	var stat C.SPF_errcode_t
	var resp *C.SPF_response_t
	stat = C.SPF_request_query_mailfrom(r.r, &resp)
	if stat != C.SPF_E_SUCCESS {
		return nil, &spfError{stat}
	}
	return &response{resp}, nil
}

// Free the request handle
func (r *request) free() {
	if r.r != nil {
		C.SPF_request_free(r.r)
		r.r = nil
	}
}

type response struct {
	r *C.SPF_response_t
}

// Result returns the SPF validation result
func (r *response) result() Result {
	return Result(C.SPF_response_result(r.r))
}

// Free frees the response handle
func (r *response) free() {
	if r.r != nil {
		C.SPF_response_free(r.r)
		r.r = nil
	}
}

type Result int

func (r Result) String() string {
	return C.GoString(C.SPF_strresult(C.SPF_result_t(r)))
}

type spfError struct {
	code C.SPF_errcode_t
}

func (e *spfError) Error() string {
	return C.GoString(C.SPF_strerror(e.code))
}
<|endoftext|>


<commit_before>package eda

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"time"

	"github.com/chop-dbhi/eda/internal/pb"
	"github.com/golang/protobuf/proto"
	"github.com/nats-io/go-nats"
	stan "github.com/nats-io/go-nats-streaming"
	stanpb "github.com/nats-io/go-nats-streaming/pb"
	"github.com/nats-io/nuid"
)

// resetDurable resets a durable subscription by name.
func resetDurable(conn stan.Conn, stream, queueName, durableName string) error {
	// Connect with the durable name to unsubscribe.
	sub, err := conn.QueueSubscribe(stream, queueName, func(*stan.Msg) {}, stan.DurableName(durableName))

	if err != nil {
		return err
	}

	return sub.Unsubscribe()
}

// stanConn is an implementation of Conn.
type stanConn struct {
	ctx    context.Context
	cancel context.CancelFunc

	logger *log.Logger
	errch  chan error

	subs []stan.Subscription

	client  string
	cluster string

	nats *nats.Conn
	stan stan.Conn
}

func (c *stanConn) handleInterrupt() {
	sig := make(chan os.Signal)
	signal.Notify(sig, os.Kill, os.Interrupt)

	// Either an OS signal will be caught or
	// a programmatic cancel will be triggered.
	select {
	case s := <-sig:
		c.logger.Printf("signal received: %s", s)
		c.cancel()

	case <-c.ctx.Done():
		c.logger.Print("connection done")
	}

	c.errch <- nil
}

// monitor monitors the client connection.
func (c *stanConn) monitor() {
	ticker := time.Tick(5 * time.Second)

	connected := true

	for {
		select {
		case <-ticker:
			status := c.nats.Status()

			if status == nats.CONNECTED {
				if !connected {
					c.logger.Print("reconnected!")
					connected = true
				}
				break
			}

			connected = false

			switch status {
			case nats.DISCONNECTED:
				c.logger.Print("disconnected")
			case nats.CLOSED:
				c.logger.Print("closed")
			case nats.RECONNECTING:
				c.logger.Print("reconnecting")
			case nats.CONNECTING:
				c.logger.Print("connecting")
			}

		case <-c.ctx.Done():
			return
		}
	}
}

// Close closes all subscriptions and the underlying connections.
func (c *stanConn) Close() error {
	// Shut down background routines.
	c.cancel()

	for _, s := range c.subs {
		if err := s.Close(); err != nil {
			c.logger.Printf("subscription close error: %s", err)
		}
	}

	if err := c.stan.Close(); err != nil {
		c.logger.Printf("connection close error: %s", err)
	}

	// No returned error.
	c.nats.Close()

	return nil
}

func (c *stanConn) Publish(stream string, typ string, data Encodable, opts ...PublishOption) (string, error) {
	var (
		err      error
		datab    []byte
		encoding string
	)

	if data != nil {
		// Decodable.
		if dec, ok := data.(*decodable); ok {
			encoding = data.Type()
			datab, err = data.Encode()
		} else {
			encoding = data.Type()
			datab, err = data.Encode()
		}
	}

	if err != nil {
		return "", err
	}

	var o PublishOptions
	o.Apply(opts...)

	id := nuid.Next()

	b, err := proto.Marshal(&pb.Event{
		Id:       id,
		Type:     typ,
		Cause:    o.Cause,
		Client:   c.client,
		Data:     datab,
		Encoding: encoding,
	})

	if err != nil {
		return "", err
	}

	// Publish event.
	err = c.stan.Publish(stream, b)
	if err != nil {
		return id, err
	}

	c.logger.Printf("publish(type=%v stream=%v)", typ, stream)

	return id, nil
}

func (c *stanConn) Subscribe(stream string, handle Handler, opts ...SubscriptionOption) (Subscription, error) {
	// Copy defaults.
	subOpts := *DefaultSubscriptionOptions
	subOpts.Apply(opts...)

	// TODO: Any long-term issue with this?
	consumerName := subOpts.ConsumerName
	if consumerName == "" {
		consumerName = c.client
	}
	durableName := consumerName

	if subOpts.Reset {
		if err := resetDurable(c.stan, stream, consumerName, durableName); err != nil {
			return nil, err
		}
	}

	// Handler for the raw message.
	msgHandler := func(msg *stan.Msg) {
		var e pb.Event

		// Message sent on stream that is not a protobuf format.
		err := proto.Unmarshal(msg.Data, &e)
		if err != nil {
			c.errch <- err
			c.cancel()
			return
		}

		dec := decodable{
			b: e.Data,
			t: e.Encoding,
		}

		evt := &Event{
			ID:     e.Id,
			Time:   msg.Timestamp,
			Type:   e.Type,
			Cause:  e.Cause,
			Client: e.Client,
			Data:   &dec,
			msg:    msg,
		}

		// Use ack timeout as max context timeout to signal handler components.
		ctx, _ := context.WithTimeout(c.ctx, subOpts.AckTimeout)

		// Recover from panic to properly close connection.
		defer func() {
			if err := recover(); err != nil {
				c.cancel()
				c.Close()
				panic(err)
			}
		}()

		// Handler error implies a timeout or implementation issue.
		if err := handle(ctx, evt, c); err != nil {
			c.errch <- err
			c.cancel()
			return
		}

		// Couldn't acknowledge the event has been handled.
		// Bad subscription or bad connection.
		if err := msg.Ack(); err != nil {
			c.errch <- err
			c.cancel()
		}
	}

	// Map start position.
	var startPos stanpb.StartPosition

	switch subOpts.StartPosition {
	case StartPositionFirst:
		startPos = stanpb.StartPosition_First
	case StartPositionNew:
		startPos = stanpb.StartPosition_NewOnly
	default:
		return nil, fmt.Errorf("invalid start position: %d", subOpts.StartPosition)
	}

	subOptions := []stan.SubscriptionOption{
		// Set the initial start position.
		stan.StartAt(startPos),

		// Length of time to wait before the server resends the message.
		stan.AckWait(subOpts.AckTimeout),

		// Use manual acks to manage errors.
		stan.SetManualAckMode(),
	}

	if subOpts.Serial {
		subOptions = append(subOptions, stan.MaxInflight(1))
	}

	if subOpts.Durable {
		subOptions = append(subOptions, stan.DurableName(durableName))
	}

	sub, err := c.stan.QueueSubscribe(
		stream,
		consumerName,
		msgHandler,
		subOptions...,
	)
	if err != nil {
		return nil, err
	}

	c.logger.Printf("subscribe(id=%v stream=%v durable=%v serial=%v", consumerName, stream, subOpts.Durable, subOpts.Serial)

	c.subs = append(c.subs, sub)

	return sub, nil
}

func (c *stanConn) Wait() error {
	// Block until signaled done. Either due to an OS signal or error.
	<-c.ctx.Done()

	// Return nil or the error.
	return <-c.errch
}

// Connect establishes a connection to the event stream backend.
func Connect(ctx context.Context, addr, cluster, client string) (Conn, error) {
	ctx, cancel := context.WithCancel(ctx)

	nc, err := nats.Connect(
		addr,
		// Try reconnecting indefinitely.
		nats.MaxReconnects(-1),
	)
	if err != nil {
		return nil, err
	}

	// Initialize streaming connection.
	snc, err := stan.Connect(cluster, client, stan.NatsConn(nc))
	if err != nil {
		return nil, err
	}

	var logger *log.Logger
	if DefaultLogger == nil {
		logger = log.New(ioutil.Discard, "", 0)
	} else {
		logger = &(*DefaultLogger)
	}

	conn := stanConn{
		ctx:     ctx,
		cancel:  cancel,
		client:  client,
		cluster: cluster,
		logger:  logger,
		stan:    snc,
		nats:    nc,
		errch:   make(chan error, 2),
	}

	// Start monitoring.
	go conn.monitor()

	// Handle OS signals.
	go conn.handleInterrupt()

	logger.Printf("connect(id=%v addr=%v cluster=%v)", client, addr, cluster)

	return &conn, nil
}

/*
type MultiSubscription struct {
	conn Conn
	subs   []Subscription
}

func (m *MultiSubscription) Close() error {
	for _, s := range subs {
		s.Close()
	}
}

func NewMultiSubscription(conn Conn, streams []string, handler stan.MsgHandler, opts ...SubscriptionOption) (*MultiSubscription, error) {
	subs := make([]Subscription, len(streams))

	// Create subscription per stream and fan-in events.
	for i, stream := range streams {
		sub, err := conn.Subscribe(stream, handler, opts...)
		if err != nil {
			return nil, err
		}

		subs[i] = sub
	}

	return &MultiSubscription{
		conn: Conn,
		subs:   subs,
	}, nil
}
*/
<commit_msg>Set the “nil” encoding type<commit_after>package eda

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"time"

	"github.com/chop-dbhi/eda/internal/pb"
	"github.com/golang/protobuf/proto"
	"github.com/nats-io/go-nats"
	stan "github.com/nats-io/go-nats-streaming"
	stanpb "github.com/nats-io/go-nats-streaming/pb"
	"github.com/nats-io/nuid"
)

// resetDurable resets a durable subscription by name.
func resetDurable(conn stan.Conn, stream, queueName, durableName string) error {
	// Connect with the durable name to unsubscribe.
	sub, err := conn.QueueSubscribe(stream, queueName, func(*stan.Msg) {}, stan.DurableName(durableName))

	if err != nil {
		return err
	}

	return sub.Unsubscribe()
}

// stanConn is an implementation of Conn.
type stanConn struct {
	ctx    context.Context
	cancel context.CancelFunc

	logger *log.Logger
	errch  chan error

	subs []stan.Subscription

	client  string
	cluster string

	nats *nats.Conn
	stan stan.Conn
}

func (c *stanConn) handleInterrupt() {
	sig := make(chan os.Signal)
	signal.Notify(sig, os.Kill, os.Interrupt)

	// Either an OS signal will be caught or
	// a programmatic cancel will be triggered.
	select {
	case s := <-sig:
		c.logger.Printf("signal received: %s", s)
		c.cancel()

	case <-c.ctx.Done():
		c.logger.Print("connection done")
	}

	c.errch <- nil
}

// monitor monitors the client connection.
func (c *stanConn) monitor() {
	ticker := time.Tick(5 * time.Second)

	connected := true

	for {
		select {
		case <-ticker:
			status := c.nats.Status()

			if status == nats.CONNECTED {
				if !connected {
					c.logger.Print("reconnected!")
					connected = true
				}
				break
			}

			connected = false

			switch status {
			case nats.DISCONNECTED:
				c.logger.Print("disconnected")
			case nats.CLOSED:
				c.logger.Print("closed")
			case nats.RECONNECTING:
				c.logger.Print("reconnecting")
			case nats.CONNECTING:
				c.logger.Print("connecting")
			}

		case <-c.ctx.Done():
			return
		}
	}
}

// Close closes all subscriptions and the underlying connections.
func (c *stanConn) Close() error {
	// Shut down background routines.
	c.cancel()

	for _, s := range c.subs {
		if err := s.Close(); err != nil {
			c.logger.Printf("subscription close error: %s", err)
		}
	}

	if err := c.stan.Close(); err != nil {
		c.logger.Printf("connection close error: %s", err)
	}

	// No returned error.
	c.nats.Close()

	return nil
}

func (c *stanConn) Publish(stream string, typ string, data Encodable, opts ...PublishOption) (string, error) {
	var (
		err      error
		datab    []byte
		encoding string
	)

	if data != nil {
		// Check for decoable and use that directly.
		if dec, ok := data.(*decodable); ok {
			encoding = data.Type()
			datab, err = data.Encode()
		} else {
			encoding = data.Type()
			datab, err = data.Encode()
		}
	} else {
		encoding = "nil"
	}

	if err != nil {
		return "", err
	}

	var o PublishOptions
	o.Apply(opts...)

	id := nuid.Next()

	b, err := proto.Marshal(&pb.Event{
		Id:       id,
		Type:     typ,
		Cause:    o.Cause,
		Client:   c.client,
		Data:     datab,
		Encoding: encoding,
	})

	if err != nil {
		return "", err
	}

	// Publish event.
	err = c.stan.Publish(stream, b)
	if err != nil {
		return id, err
	}

	c.logger.Printf("publish(type=%v stream=%v)", typ, stream)

	return id, nil
}

func (c *stanConn) Subscribe(stream string, handle Handler, opts ...SubscriptionOption) (Subscription, error) {
	// Copy defaults.
	subOpts := *DefaultSubscriptionOptions
	subOpts.Apply(opts...)

	// TODO: Any long-term issue with this?
	consumerName := subOpts.ConsumerName
	if consumerName == "" {
		consumerName = c.client
	}
	durableName := consumerName

	if subOpts.Reset {
		if err := resetDurable(c.stan, stream, consumerName, durableName); err != nil {
			return nil, err
		}
	}

	// Handler for the raw message.
	msgHandler := func(msg *stan.Msg) {
		var e pb.Event

		// Message sent on stream that is not a protobuf format.
		err := proto.Unmarshal(msg.Data, &e)
		if err != nil {
			c.errch <- err
			c.cancel()
			return
		}

		dec := decodable{
			b: e.Data,
			t: e.Encoding,
		}

		evt := &Event{
			ID:     e.Id,
			Time:   msg.Timestamp,
			Type:   e.Type,
			Cause:  e.Cause,
			Client: e.Client,
			Data:   &dec,
			msg:    msg,
		}

		// Use ack timeout as max context timeout to signal handler components.
		ctx, _ := context.WithTimeout(c.ctx, subOpts.AckTimeout)

		// Recover from panic to properly close connection.
		defer func() {
			if err := recover(); err != nil {
				c.cancel()
				c.Close()
				panic(err)
			}
		}()

		// Handler error implies a timeout or implementation issue.
		if err := handle(ctx, evt, c); err != nil {
			c.errch <- err
			c.cancel()
			return
		}

		// Couldn't acknowledge the event has been handled.
		// Bad subscription or bad connection.
		if err := msg.Ack(); err != nil {
			c.errch <- err
			c.cancel()
		}
	}

	// Map start position.
	var startPos stanpb.StartPosition

	switch subOpts.StartPosition {
	case StartPositionFirst:
		startPos = stanpb.StartPosition_First
	case StartPositionNew:
		startPos = stanpb.StartPosition_NewOnly
	default:
		return nil, fmt.Errorf("invalid start position: %d", subOpts.StartPosition)
	}

	subOptions := []stan.SubscriptionOption{
		// Set the initial start position.
		stan.StartAt(startPos),

		// Length of time to wait before the server resends the message.
		stan.AckWait(subOpts.AckTimeout),

		// Use manual acks to manage errors.
		stan.SetManualAckMode(),
	}

	if subOpts.Serial {
		subOptions = append(subOptions, stan.MaxInflight(1))
	}

	if subOpts.Durable {
		subOptions = append(subOptions, stan.DurableName(durableName))
	}

	sub, err := c.stan.QueueSubscribe(
		stream,
		consumerName,
		msgHandler,
		subOptions...,
	)
	if err != nil {
		return nil, err
	}

	c.logger.Printf("subscribe(id=%v stream=%v durable=%v serial=%v", consumerName, stream, subOpts.Durable, subOpts.Serial)

	c.subs = append(c.subs, sub)

	return sub, nil
}

func (c *stanConn) Wait() error {
	// Block until signaled done. Either due to an OS signal or error.
	<-c.ctx.Done()

	// Return nil or the error.
	return <-c.errch
}

// Connect establishes a connection to the event stream backend.
func Connect(ctx context.Context, addr, cluster, client string) (Conn, error) {
	ctx, cancel := context.WithCancel(ctx)

	nc, err := nats.Connect(
		addr,
		// Try reconnecting indefinitely.
		nats.MaxReconnects(-1),
	)
	if err != nil {
		return nil, err
	}

	// Initialize streaming connection.
	snc, err := stan.Connect(cluster, client, stan.NatsConn(nc))
	if err != nil {
		return nil, err
	}

	var logger *log.Logger
	if DefaultLogger == nil {
		logger = log.New(ioutil.Discard, "", 0)
	} else {
		logger = &(*DefaultLogger)
	}

	conn := stanConn{
		ctx:     ctx,
		cancel:  cancel,
		client:  client,
		cluster: cluster,
		logger:  logger,
		stan:    snc,
		nats:    nc,
		errch:   make(chan error, 2),
	}

	// Start monitoring.
	go conn.monitor()

	// Handle OS signals.
	go conn.handleInterrupt()

	logger.Printf("connect(id=%v addr=%v cluster=%v)", client, addr, cluster)

	return &conn, nil
}

/*
type MultiSubscription struct {
	conn Conn
	subs   []Subscription
}

func (m *MultiSubscription) Close() error {
	for _, s := range subs {
		s.Close()
	}
}

func NewMultiSubscription(conn Conn, streams []string, handler stan.MsgHandler, opts ...SubscriptionOption) (*MultiSubscription, error) {
	subs := make([]Subscription, len(streams))

	// Create subscription per stream and fan-in events.
	for i, stream := range streams {
		sub, err := conn.Subscribe(stream, handler, opts...)
		if err != nil {
			return nil, err
		}

		subs[i] = sub
	}

	return &MultiSubscription{
		conn: Conn,
		subs:   subs,
	}, nil
}
*/
<|endoftext|>


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

package queue

import (
	"crypto/rand"
	"errors"
	"fmt"
	"github.com/globocom/tsuru/log"
	"sync"
	"sync/atomic"
	"time"
)

const (
	stopped int32 = iota
	running
	stopping
)

// Handler is a thread safe generic handler for queue messages.
//
// When started, whenever a new message arrives, handler invokes F, giving the
// message as parameter. F is invoked in its own goroutine, so the handler can
// handle other messages as they arrive.
type Handler struct {
	F     func(*Message)
	state int32
	id    string
}

// Start starts the handler. It's safe to call this function multiple times.
func (h *Handler) Start() {
	r.add(h)
	if atomic.CompareAndSwapInt32(&h.state, stopped, running) {
		go h.loop()
	}
}

// DryRun changes the state of the handler, but does not start it.
//
// It's intended for using in tests. It returns an error if the handler is not
// stopped.
func (h *Handler) DryRun() error {
	if !atomic.CompareAndSwapInt32(&h.state, stopped, running) {
		return errors.New("Handler is not stopped.")
	}
	r.add(h)
	go h.fakeLoop()
	return nil
}

// Stop sends a signal to stop the handler, it won't stop the handler
// immediately. After calling Stop, one should call Wait for blocking until the
// handler is stopped.
//
// This method will return an error if the handler is not running.
func (h *Handler) Stop() error {
	if !atomic.CompareAndSwapInt32(&h.state, running, stopping) {
		return errors.New("Not running.")
	}
	r.remove(h)
	return nil
}

// Wait blocks until the handler is stopped.
func (h *Handler) Wait() {
	for atomic.LoadInt32(&h.state) != stopped {
		time.Sleep(1e3)
	}
}

func (h *Handler) fakeLoop() {
	for atomic.LoadInt32(&h.state) == running {
		time.Sleep(1e3)
	}
	atomic.StoreInt32(&h.state, stopped)
}

// loop will get messages from the queue and dispatch them to Handler.F.
func (h *Handler) loop() {
	for {
		if atomic.LoadInt32(&h.state) != running {
			atomic.StoreInt32(&h.state, stopped)
			return
		} else if message, err := Get(1e9); err == nil {
			go h.F(message)
		} else {
			log.Printf("Failed to get message from the queue: %s. Trying again...", err)
			continue
		}
	}
}

// registry stores references to all running handlers.
type registry struct {
	mut      sync.Mutex
	handlers map[string]*Handler
}

func newRegistry() *registry {
	return &registry{
		handlers: make(map[string]*Handler),
	}
}

func (r *registry) add(h *Handler) {
	if h.id == "" {
		var buf [16]byte
		rand.Read(buf[:])
		h.id = fmt.Sprintf("%x", buf)
	}
	r.mut.Lock()
	r.handlers[h.id] = h
	r.mut.Unlock()
}

func (r *registry) remove(h *Handler) {
	if h.id != "" {
		r.mut.Lock()
		delete(r.handlers, h.id)
		r.mut.Unlock()
	}
}

var r *registry = newRegistry()

// Preempt calls Stop and Wait for each running handler.
func Preempt() {
	var wg sync.WaitGroup
	r.mut.Lock()
	preemptable := make(map[string]*Handler, len(r.handlers))
	for k, v := range r.handlers {
		preemptable[k] = v
	}
	r.mut.Unlock()
	wg.Add(len(preemptable))
	for _, h := range preemptable {
		go func(h *Handler) {
			defer wg.Done()
			if err := h.Stop(); err == nil {
				h.Wait()
			}
		}(h)
	}
	wg.Wait()
}
<commit_msg>queue: some refactoring on Handler.loop<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package queue

import (
	"crypto/rand"
	"errors"
	"fmt"
	"github.com/globocom/tsuru/log"
	"sync"
	"sync/atomic"
	"time"
)

const (
	stopped int32 = iota
	running
	stopping
)

// Handler is a thread safe generic handler for queue messages.
//
// When started, whenever a new message arrives, handler invokes F, giving the
// message as parameter. F is invoked in its own goroutine, so the handler can
// handle other messages as they arrive.
type Handler struct {
	F     func(*Message)
	state int32
	id    string
}

// Start starts the handler. It's safe to call this function multiple times.
func (h *Handler) Start() {
	r.add(h)
	if atomic.CompareAndSwapInt32(&h.state, stopped, running) {
		go h.loop(func() {
			if message, err := Get(1e9); err == nil {
				go h.F(message)
			} else {
				log.Printf("Failed to get message from the queue: %s. Trying again...", err)
			}
		})
	}
}

// DryRun changes the state of the handler, but does not start it.
//
// It's intended for using in tests. It returns an error if the handler is not
// stopped.
func (h *Handler) DryRun() error {
	if !atomic.CompareAndSwapInt32(&h.state, stopped, running) {
		return errors.New("Handler is not stopped.")
	}
	r.add(h)
	go h.loop(func() { time.Sleep(1e3) })
	return nil
}

// Stop sends a signal to stop the handler, it won't stop the handler
// immediately. After calling Stop, one should call Wait for blocking until the
// handler is stopped.
//
// This method will return an error if the handler is not running.
func (h *Handler) Stop() error {
	if !atomic.CompareAndSwapInt32(&h.state, running, stopping) {
		return errors.New("Not running.")
	}
	r.remove(h)
	return nil
}

// Wait blocks until the handler is stopped.
func (h *Handler) Wait() {
	for atomic.LoadInt32(&h.state) != stopped {
		time.Sleep(1e3)
	}
}

// loop will execute inner while the handler is in "running" state.
func (h *Handler) loop(inner func()) {
	for atomic.LoadInt32(&h.state) == running {
		inner()
	}
	atomic.StoreInt32(&h.state, stopped)
}

// registry stores references to all running handlers.
type registry struct {
	mut      sync.Mutex
	handlers map[string]*Handler
}

func newRegistry() *registry {
	return &registry{
		handlers: make(map[string]*Handler),
	}
}

func (r *registry) add(h *Handler) {
	if h.id == "" {
		var buf [16]byte
		rand.Read(buf[:])
		h.id = fmt.Sprintf("%x", buf)
	}
	r.mut.Lock()
	r.handlers[h.id] = h
	r.mut.Unlock()
}

func (r *registry) remove(h *Handler) {
	if h.id != "" {
		r.mut.Lock()
		delete(r.handlers, h.id)
		r.mut.Unlock()
	}
}

var r *registry = newRegistry()

// Preempt calls Stop and Wait for each running handler.
func Preempt() {
	var wg sync.WaitGroup
	r.mut.Lock()
	preemptable := make(map[string]*Handler, len(r.handlers))
	for k, v := range r.handlers {
		preemptable[k] = v
	}
	r.mut.Unlock()
	wg.Add(len(preemptable))
	for _, h := range preemptable {
		go func(h *Handler) {
			defer wg.Done()
			if err := h.Stop(); err == nil {
				h.Wait()
			}
		}(h)
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"text/template"
)

type dim struct {
	Z  string
	M  string
	ZM string
}

var dims = []dim{
	{Z: "", M: "", ZM: ""},
	{Z: "Z", M: "", ZM: "Z"},
	{Z: "", M: "M", ZM: "M"},
	{Z: "Z", M: "M", ZM: "ZM"},
}

const point = `package geom
{{range .Dims}}
type Point{{.ZM}} struct {
	X float64
	Y float64{{with .Z}}
	Z float64{{end}}{{with .M}}
	M float64{{end}}
}

func (point{{.ZM}} Point{{.ZM}}) Bounds() *Bounds {
	return NewBoundsPoint{{.ZM}}(point{{.ZM}})
}
{{end}}`

const pointWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func point{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	point{{.ZM}} := geom.Point{{.ZM}}{}
	if err := binary.Read(r, byteOrder, &point{{.ZM}}); err != nil {
		return nil, err
	}
	return point{{.ZM}}, nil
}

func readPoint{{.ZM}}s(r io.Reader, byteOrder binary.ByteOrder) ([]geom.Point{{.ZM}}, error) {
	var numPoints uint32
	if err := binary.Read(r, byteOrder, &numPoints); err != nil {
		return nil, err
	}
	point{{.ZM}}s := make([]geom.Point{{.ZM}}, numPoints)
	if err := binary.Read(r, byteOrder, &point{{.ZM}}s); err != nil {
		return nil, err
	}
	return point{{.ZM}}s, nil
}

func writePoint{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}} geom.Point{{.ZM}}) error {
	return binary.Write(w, byteOrder, &point{{.ZM}})
}

func writePoint{{.ZM}}s(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}}s []geom.Point{{.ZM}}) error {
	if err := binary.Write(w, byteOrder, uint32(len(point{{.ZM}}s))); err != nil {
		return err
	}
	return binary.Write(w, byteOrder, &point{{.ZM}}s)
}

func writePoint{{.ZM}}ss(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}}ss [][]geom.Point{{.ZM}}) error {
	if err := binary.Write(w, byteOrder, uint32(len(point{{.ZM}}ss))); err != nil {
		return err
	}
	for _, point{{.ZM}}s := range point{{.ZM}}ss {
		if err := writePoint{{.ZM}}s(w, byteOrder, point{{.ZM}}s); err != nil {
			return err
		}
	}
	return nil

}
{{end}}`

const lineString = `package geom
{{range .Dims}}
type LineString{{.ZM}} struct {
	Points []Point{{.ZM}}
}

func (lineString{{.ZM}} LineString{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}s(lineString{{.ZM}}.Points)
}
{{end}}`

const lineStringWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func lineString{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	point{{.ZM}}s, err := readPoint{{.ZM}}s(r, byteOrder)
	if err != nil {
		return nil, err
	}
	return geom.LineString{{.ZM}}{point{{.ZM}}s}, nil
}

func writeLineString{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, lineString{{.ZM}} geom.LineString{{.ZM}}) error {
	return writePoint{{.ZM}}s(w, byteOrder, lineString{{.ZM}}.Points)
}
{{end}}`

const polygon = `package geom
{{range .Dims}}
type Polygon{{.ZM}} struct {
	Rings [][]Point{{.ZM}}
}

func (polygon{{.ZM}} Polygon{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}ss(polygon{{.ZM}}.Rings)
}
{{end}}`

const polygonWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func polygon{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	var numRings uint32
	if err := binary.Read(r, byteOrder, &numRings); err != nil {
		return nil, err
	}
	ring{{.ZM}}s := make([][]geom.Point{{.ZM}}, numRings)
	for i := uint32(0); i < numRings; i++ {
		if point{{.ZM}}s, err := readPoint{{.ZM}}s(r, byteOrder); err != nil {
			return nil, err
		} else {
			ring{{.ZM}}s[i] = point{{.ZM}}s
		}
	}
	return geom.Polygon{{.ZM}}{ring{{.ZM}}s}, nil
}

func writePolygon{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, polygon{{.ZM}} geom.Polygon{{.ZM}}) error {
	return writePoint{{.ZM}}ss(w, byteOrder, polygon{{.ZM}}.Rings)
}
{{end}}`

const multiPoint = `package geom
{{range .Dims}}
type MultiPoint{{.ZM}} struct {
	Points []Point{{.ZM}}
}

func (multiPoint{{.ZM}} MultiPoint{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}s(multiPoint{{.ZM}}.Points)
}
{{end}}`

var types = []struct {
	filename string
	name     string
	template string
	Dims     []dim
}{
	{"geom/point.go", "Point", point, dims},
	{"geom/linestring.go", "LineString", lineString, dims},
	{"geom/polygon.go", "Polygon", polygon, dims},
	{"geom/multipoint.go", "MultiPoint", multiPoint, dims},
	{"geom/encoding/wkb/point.go", "Point", pointWKB, dims},
	{"geom/encoding/wkb/linestring.go", "LineString", lineStringWKB, dims},
	{"geom/encoding/wkb/polygon.go", "Polygon", polygonWKB, dims},
}

func main() {

	for _, typ := range types {
		t := template.Must(template.New(typ.name).Parse(typ.template))
		if w, err := os.Create(typ.filename); err == nil {
			if err = t.Execute(w, typ); err != nil {
				log.Println("executing template:", err)
			}
		} else {
			log.Println("creating:", err)
		}
	}

}
<commit_msg>Give templates unique names<commit_after>package main

import (
	"log"
	"os"
	"text/template"
)

type dim struct {
	Z  string
	M  string
	ZM string
}

var dims = []dim{
	{Z: "", M: "", ZM: ""},
	{Z: "Z", M: "", ZM: "Z"},
	{Z: "", M: "M", ZM: "M"},
	{Z: "Z", M: "M", ZM: "ZM"},
}

const point = `package geom
{{range .Dims}}
type Point{{.ZM}} struct {
	X float64
	Y float64{{with .Z}}
	Z float64{{end}}{{with .M}}
	M float64{{end}}
}

func (point{{.ZM}} Point{{.ZM}}) Bounds() *Bounds {
	return NewBoundsPoint{{.ZM}}(point{{.ZM}})
}
{{end}}`

const pointWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func point{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	point{{.ZM}} := geom.Point{{.ZM}}{}
	if err := binary.Read(r, byteOrder, &point{{.ZM}}); err != nil {
		return nil, err
	}
	return point{{.ZM}}, nil
}

func readPoint{{.ZM}}s(r io.Reader, byteOrder binary.ByteOrder) ([]geom.Point{{.ZM}}, error) {
	var numPoints uint32
	if err := binary.Read(r, byteOrder, &numPoints); err != nil {
		return nil, err
	}
	point{{.ZM}}s := make([]geom.Point{{.ZM}}, numPoints)
	if err := binary.Read(r, byteOrder, &point{{.ZM}}s); err != nil {
		return nil, err
	}
	return point{{.ZM}}s, nil
}

func writePoint{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}} geom.Point{{.ZM}}) error {
	return binary.Write(w, byteOrder, &point{{.ZM}})
}

func writePoint{{.ZM}}s(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}}s []geom.Point{{.ZM}}) error {
	if err := binary.Write(w, byteOrder, uint32(len(point{{.ZM}}s))); err != nil {
		return err
	}
	return binary.Write(w, byteOrder, &point{{.ZM}}s)
}

func writePoint{{.ZM}}ss(w io.Writer, byteOrder binary.ByteOrder, point{{.ZM}}ss [][]geom.Point{{.ZM}}) error {
	if err := binary.Write(w, byteOrder, uint32(len(point{{.ZM}}ss))); err != nil {
		return err
	}
	for _, point{{.ZM}}s := range point{{.ZM}}ss {
		if err := writePoint{{.ZM}}s(w, byteOrder, point{{.ZM}}s); err != nil {
			return err
		}
	}
	return nil

}
{{end}}`

const lineString = `package geom
{{range .Dims}}
type LineString{{.ZM}} struct {
	Points []Point{{.ZM}}
}

func (lineString{{.ZM}} LineString{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}s(lineString{{.ZM}}.Points)
}
{{end}}`

const lineStringWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func lineString{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	point{{.ZM}}s, err := readPoint{{.ZM}}s(r, byteOrder)
	if err != nil {
		return nil, err
	}
	return geom.LineString{{.ZM}}{point{{.ZM}}s}, nil
}

func writeLineString{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, lineString{{.ZM}} geom.LineString{{.ZM}}) error {
	return writePoint{{.ZM}}s(w, byteOrder, lineString{{.ZM}}.Points)
}
{{end}}`

const polygon = `package geom
{{range .Dims}}
type Polygon{{.ZM}} struct {
	Rings [][]Point{{.ZM}}
}

func (polygon{{.ZM}} Polygon{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}ss(polygon{{.ZM}}.Rings)
}
{{end}}`

const polygonWKB = `package wkb

import (
	"encoding/binary"
	"github.com/twpayne/gogeom/geom"
	"io"
)
{{range .Dims}}
func polygon{{.ZM}}Reader(r io.Reader, byteOrder binary.ByteOrder) (geom.T, error) {
	var numRings uint32
	if err := binary.Read(r, byteOrder, &numRings); err != nil {
		return nil, err
	}
	ring{{.ZM}}s := make([][]geom.Point{{.ZM}}, numRings)
	for i := uint32(0); i < numRings; i++ {
		if point{{.ZM}}s, err := readPoint{{.ZM}}s(r, byteOrder); err != nil {
			return nil, err
		} else {
			ring{{.ZM}}s[i] = point{{.ZM}}s
		}
	}
	return geom.Polygon{{.ZM}}{ring{{.ZM}}s}, nil
}

func writePolygon{{.ZM}}(w io.Writer, byteOrder binary.ByteOrder, polygon{{.ZM}} geom.Polygon{{.ZM}}) error {
	return writePoint{{.ZM}}ss(w, byteOrder, polygon{{.ZM}}.Rings)
}
{{end}}`

const multiPoint = `package geom
{{range .Dims}}
type MultiPoint{{.ZM}} struct {
	Points []Point{{.ZM}}
}

func (multiPoint{{.ZM}} MultiPoint{{.ZM}}) Bounds() *Bounds {
	return NewBounds().ExtendPoint{{.ZM}}s(multiPoint{{.ZM}}.Points)
}
{{end}}`

var types = []struct {
	filename string
	name     string
	template string
	Dims     []dim
}{
	{"geom/point.go", "Point", point, dims},
	{"geom/linestring.go", "LineString", lineString, dims},
	{"geom/polygon.go", "Polygon", polygon, dims},
	{"geom/multipoint.go", "MultiPoint", multiPoint, dims},
	{"geom/encoding/wkb/point.go", "PointWKB", pointWKB, dims},
	{"geom/encoding/wkb/linestring.go", "LineStringWKB", lineStringWKB, dims},
	{"geom/encoding/wkb/polygon.go", "PolygonWKB", polygonWKB, dims},
}

func main() {

	for _, typ := range types {
		t := template.Must(template.New(typ.name).Parse(typ.template))
		if w, err := os.Create(typ.filename); err == nil {
			if err = t.Execute(w, typ); err != nil {
				log.Println("executing template:", err)
			}
		} else {
			log.Println("creating:", err)
		}
	}

}
<|endoftext|>