<commit_before>// Copyright 2018 the u-root 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 qemu provides a Go API for starting QEMU VMs.
//
// qemu is mainly suitable for running QEMU-based integration tests.
//
// The environment variable `UROOT_QEMU` overrides the path to QEMU and the
// first few arguments (defaults to "qemu"). For example, I use:
//
//     UROOT_QEMU='qemu-system-x86_64 -L . -m 4096 -enable-kvm'
//
// For CI, this environment variable is set in `.circleci/images/integration/Dockerfile`.
package qemu

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	expect "github.com/google/goexpect"
)

// DefaultTimeout for `Expect` and `ExpectRE` functions.
var DefaultTimeout = 7 * time.Second

// TimeoutMultiplier increases all timeouts proportionally. Useful when running
// QEMU on a slow machine.
var TimeoutMultiplier = 1.0

func init() {
	if timeoutMultS := os.Getenv("UROOT_QEMU_TIMEOUT_X"); len(timeoutMultS) > 0 {
		t, err := strconv.ParseFloat(timeoutMultS, 64)
		if err == nil {
			TimeoutMultiplier = t
		}
	}
}

// Options are VM start-up parameters.
type Options struct {
	// QEMUPath is the path to the QEMU binary to invoke.
	//
	// If left unspecified, the UROOT_QEMU env var will be used.
	// If the env var is unspecified, "qemu" is the default.
	QEMUPath string

	// Path to the kernel to boot.
	Kernel string

	// Path to the initramfs.
	Initramfs string

	// Extra kernel command-line arguments.
	KernelArgs string

	// Where to send serial output.
	SerialOutput io.WriteCloser

	// Timeout is the expect timeout.
	Timeout time.Duration

	// Devices are devices to expose to the QEMU VM.
	Devices []Device
}

// Start starts a QEMU VM.
func (o *Options) Start() (*VM, error) {
	cmdline, err := o.Cmdline()
	if err != nil {
		return nil, err
	}

	gExpect, ch, err := expect.SpawnWithArgs(cmdline, -1,
		expect.Tee(o.SerialOutput),
		expect.PartialMatch(true),
		expect.CheckDuration(2*time.Millisecond))
	if err != nil {
		return nil, err
	}
	return &VM{
		Options: o,
		errCh:   ch,
		cmdline: cmdline,
		gExpect: gExpect,
	}, nil
}

// cmdline returns the command line arguments used to start QEMU. These
// arguments are derived from the given QEMU struct.
func (o *Options) Cmdline() ([]string, error) {
	var args []string
	if len(o.QEMUPath) > 0 {
		args = append(args, o.QEMUPath)
	} else {
		// Read first few arguments for env.
		env := os.Getenv("UROOT_QEMU")
		if env == "" {
			env = "qemu" // default
		}
		args = append(args, strings.Fields(env)...)
	}

	// Disable graphics because we are using serial.
	args = append(args, "-nographic")

	// Arguments passed to the kernel:
	//
	// - earlyprintk=ttyS0: print very early debug messages to the serial
	// - console=ttyS0: /dev/console points to /dev/ttyS0 (the serial port)
	// - o.KernelArgs: extra, optional kernel arguments
	// - args required by devices
	for _, dev := range o.Devices {
		if dev != nil {
			if a := dev.KArgs(); a != nil {
				o.KernelArgs += " " + strings.Join(a, " ")
			}
		}
	}
	if len(o.Kernel) != 0 {
		args = append(args, "-kernel", o.Kernel)
		if len(o.KernelArgs) != 0 {
			args = append(args, "-append", o.KernelArgs)
		}
	} else if len(o.KernelArgs) != 0 {
		err := fmt.Errorf("kernel args are required but cannot be added due to bootloader")
		return nil, err
	}
	if len(o.Initramfs) != 0 {
		args = append(args, "-initrd", o.Initramfs)
	}

	for _, dev := range o.Devices {
		if dev != nil {
			if c := dev.Cmdline(); c != nil {
				args = append(args, c...)
			}
		}
	}
	return args, nil
}

// VM is a running QEMU virtual machine.
type VM struct {
	Options *Options
	cmdline []string
	errCh   <-chan error
	gExpect *expect.GExpect
}

// Wait waits for the VM to exit.
func (v *VM) Wait() error {
	return <-v.errCh
}

// Cmdline is the command-line the VM was started with.
func (v *VM) Cmdline() []string {
	// Maybe return a copy?
	return v.cmdline
}

// CmdlineQuoted quotes any of QEMU's command line arguments containing a space
// so it is easy to copy-n-paste into a shell for debugging.
func (v *VM) CmdlineQuoted() string {
	args := make([]string, len(v.cmdline))
	for i, arg := range v.cmdline {
		if strings.ContainsAny(arg, " \t\n") {
			args[i] = fmt.Sprintf("'%s'", arg)
		} else {
			args[i] = arg
		}
	}
	return strings.Join(args, " ")
}

// Close stops QEMU.
func (v *VM) Close() {
	v.gExpect.Close()
	v.gExpect = nil
	// Ensure the logs are closed by waiting the complete end
	<-v.errCh
}

// Send sends a string to QEMU's serial.
func (v *VM) Send(in string) {
	v.gExpect.Send(in)
}

func (v *VM) TimeoutOr() time.Duration {
	if v.Options.Timeout == 0 {
		return DefaultTimeout
	}
	return v.Options.Timeout
}

// Expect returns an error if the given string is not found in vEMU's serial
// output within `DefaultTimeout`.
func (v *VM) Expect(search string) error {
	return v.ExpectTimeout(search, v.TimeoutOr())
}

// ExpectTimeout returns an error if the given string is not found in vEMU's serial
// output within the given timeout.
func (v *VM) ExpectTimeout(search string, timeout time.Duration) error {
	_, err := v.ExpectRETimeout(regexp.MustCompile(regexp.QuoteMeta(search)), timeout)
	return err
}

// ExpectRE returns an error if the given regular expression is not found in
// vEMU's serial output within `DefaultTimeout`. The matched string is
// returned.
func (v *VM) ExpectRE(pattern *regexp.Regexp) (string, error) {
	return v.ExpectRETimeout(pattern, v.TimeoutOr())
}

// ExpectRETimeout returns an error if the given regular expression is not
// found in vEMU's serial output within the given timeout. The matched string
// is returned.
func (v *VM) ExpectRETimeout(pattern *regexp.Regexp, timeout time.Duration) (string, error) {
	scaled := time.Duration(float64(timeout) * TimeoutMultiplier)
	str, _, err := v.gExpect.Expect(pattern, scaled)
	return str, err
}
<commit_msg>qemu: fix typo<commit_after>// Copyright 2018 the u-root 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 qemu provides a Go API for starting QEMU VMs.
//
// qemu is mainly suitable for running QEMU-based integration tests.
//
// The environment variable `UROOT_QEMU` overrides the path to QEMU and the
// first few arguments (defaults to "qemu"). For example, I use:
//
//     UROOT_QEMU='qemu-system-x86_64 -L . -m 4096 -enable-kvm'
//
// For CI, this environment variable is set in `.circleci/images/integration/Dockerfile`.
package qemu

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	expect "github.com/google/goexpect"
)

// DefaultTimeout for `Expect` and `ExpectRE` functions.
var DefaultTimeout = 7 * time.Second

// TimeoutMultiplier increases all timeouts proportionally. Useful when running
// QEMU on a slow machine.
var TimeoutMultiplier = 1.0

func init() {
	if timeoutMultS := os.Getenv("UROOT_QEMU_TIMEOUT_X"); len(timeoutMultS) > 0 {
		t, err := strconv.ParseFloat(timeoutMultS, 64)
		if err == nil {
			TimeoutMultiplier = t
		}
	}
}

// Options are VM start-up parameters.
type Options struct {
	// QEMUPath is the path to the QEMU binary to invoke.
	//
	// If left unspecified, the UROOT_QEMU env var will be used.
	// If the env var is unspecified, "qemu" is the default.
	QEMUPath string

	// Path to the kernel to boot.
	Kernel string

	// Path to the initramfs.
	Initramfs string

	// Extra kernel command-line arguments.
	KernelArgs string

	// Where to send serial output.
	SerialOutput io.WriteCloser

	// Timeout is the expect timeout.
	Timeout time.Duration

	// Devices are devices to expose to the QEMU VM.
	Devices []Device
}

// Start starts a QEMU VM.
func (o *Options) Start() (*VM, error) {
	cmdline, err := o.Cmdline()
	if err != nil {
		return nil, err
	}

	gExpect, ch, err := expect.SpawnWithArgs(cmdline, -1,
		expect.Tee(o.SerialOutput),
		expect.PartialMatch(true),
		expect.CheckDuration(2*time.Millisecond))
	if err != nil {
		return nil, err
	}
	return &VM{
		Options: o,
		errCh:   ch,
		cmdline: cmdline,
		gExpect: gExpect,
	}, nil
}

// Cmdline returns the command line arguments used to start QEMU. These
// arguments are derived from the given QEMU struct.
func (o *Options) Cmdline() ([]string, error) {
	var args []string
	if len(o.QEMUPath) > 0 {
		args = append(args, o.QEMUPath)
	} else {
		// Read first few arguments for env.
		env := os.Getenv("UROOT_QEMU")
		if env == "" {
			env = "qemu" // default
		}
		args = append(args, strings.Fields(env)...)
	}

	// Disable graphics because we are using serial.
	args = append(args, "-nographic")

	// Arguments passed to the kernel:
	//
	// - earlyprintk=ttyS0: print very early debug messages to the serial
	// - console=ttyS0: /dev/console points to /dev/ttyS0 (the serial port)
	// - o.KernelArgs: extra, optional kernel arguments
	// - args required by devices
	for _, dev := range o.Devices {
		if dev != nil {
			if a := dev.KArgs(); a != nil {
				o.KernelArgs += " " + strings.Join(a, " ")
			}
		}
	}
	if len(o.Kernel) != 0 {
		args = append(args, "-kernel", o.Kernel)
		if len(o.KernelArgs) != 0 {
			args = append(args, "-append", o.KernelArgs)
		}
	} else if len(o.KernelArgs) != 0 {
		err := fmt.Errorf("kernel args are required but cannot be added due to bootloader")
		return nil, err
	}
	if len(o.Initramfs) != 0 {
		args = append(args, "-initrd", o.Initramfs)
	}

	for _, dev := range o.Devices {
		if dev != nil {
			if c := dev.Cmdline(); c != nil {
				args = append(args, c...)
			}
		}
	}
	return args, nil
}

// VM is a running QEMU virtual machine.
type VM struct {
	Options *Options
	cmdline []string
	errCh   <-chan error
	gExpect *expect.GExpect
}

// Wait waits for the VM to exit.
func (v *VM) Wait() error {
	return <-v.errCh
}

// Cmdline is the command-line the VM was started with.
func (v *VM) Cmdline() []string {
	// Maybe return a copy?
	return v.cmdline
}

// CmdlineQuoted quotes any of QEMU's command line arguments containing a space
// so it is easy to copy-n-paste into a shell for debugging.
func (v *VM) CmdlineQuoted() string {
	args := make([]string, len(v.cmdline))
	for i, arg := range v.cmdline {
		if strings.ContainsAny(arg, " \t\n") {
			args[i] = fmt.Sprintf("'%s'", arg)
		} else {
			args[i] = arg
		}
	}
	return strings.Join(args, " ")
}

// Close stops QEMU.
func (v *VM) Close() {
	v.gExpect.Close()
	v.gExpect = nil
	// Ensure the logs are closed by waiting the complete end
	<-v.errCh
}

// Send sends a string to QEMU's serial.
func (v *VM) Send(in string) {
	v.gExpect.Send(in)
}

func (v *VM) TimeoutOr() time.Duration {
	if v.Options.Timeout == 0 {
		return DefaultTimeout
	}
	return v.Options.Timeout
}

// Expect returns an error if the given string is not found in vEMU's serial
// output within `DefaultTimeout`.
func (v *VM) Expect(search string) error {
	return v.ExpectTimeout(search, v.TimeoutOr())
}

// ExpectTimeout returns an error if the given string is not found in vEMU's serial
// output within the given timeout.
func (v *VM) ExpectTimeout(search string, timeout time.Duration) error {
	_, err := v.ExpectRETimeout(regexp.MustCompile(regexp.QuoteMeta(search)), timeout)
	return err
}

// ExpectRE returns an error if the given regular expression is not found in
// vEMU's serial output within `DefaultTimeout`. The matched string is
// returned.
func (v *VM) ExpectRE(pattern *regexp.Regexp) (string, error) {
	return v.ExpectRETimeout(pattern, v.TimeoutOr())
}

// ExpectRETimeout returns an error if the given regular expression is not
// found in vEMU's serial output within the given timeout. The matched string
// is returned.
func (v *VM) ExpectRETimeout(pattern *regexp.Regexp, timeout time.Duration) (string, error) {
	scaled := time.Duration(float64(timeout) * TimeoutMultiplier)
	str, _, err := v.gExpect.Expect(pattern, scaled)
	return str, err
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 (
	"log"
	"net/http"

	"juju.net.nz/x/pipoint"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/api"
	"gobot.io/x/gobot/platforms/mavlink"
	"gobot.io/x/gobot/platforms/mqtt"
)

func main() {
	p := pipoint.NewPiPoint()

	mav := mavlink.NewUDPAdaptor(":14550")
	driver := mavlink.NewDriver(mav)

	// TODO(michaelh): make configurable.
	mq := mqtt.NewAdaptor("tls://iot.juju.net.nz:8883", "pipoint")
	mq.SetAutoReconnect(true)
	p.AddMQTT(mq)

	http.HandleFunc("/metrics", p.Params.Metrics)

	master := gobot.NewMaster()
	a := api.NewAPI(master)
	a.Start()

	robot := gobot.NewRobot("pipoint",
		[]gobot.Connection{mav, mq},
		[]gobot.Device{driver},
		func() {
			go p.Run()
			driver.On(driver.Event(mavlink.MessageEvent), p.Message)
		})

	master.AddRobot(robot)
	log.Println("Start")
	master.Start()
}
<commit_msg>pipoint: make the MQTT server and Mavlink port configurable.<commit_after>// Copyright 2017 Google Inc.
//
// 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 (
	"flag"
	"net/http"

	"juju.net.nz/x/pipoint"

	"gobot.io/x/gobot"
	"gobot.io/x/gobot/api"
	"gobot.io/x/gobot/platforms/mavlink"
	"gobot.io/x/gobot/platforms/mqtt"
)

func main() {
	mqttUrl := flag.String("mqtt.url", "", "URI of the MQTT server, such as tls://iot.juju.net.nz:8883")
	mavAddr := flag.String("mavlink.address", ":14550", "Address to listen on for Mavlink messages")

	flag.Parse()

	var cons []gobot.Connection
	var drivers []gobot.Device

	pi := pipoint.NewPiPoint()

	if mavAddr != nil && *mavAddr != "" {
		mav := mavlink.NewUDPAdaptor(*mavAddr)
		cons = append(cons, mav)
		driver := mavlink.NewDriver(mav)
		drivers = append(drivers, driver)
		driver.On(driver.Event(mavlink.MessageEvent), pi.Message)
	}

	if mqttUrl != nil && *mqttUrl != "" {
		mq := mqtt.NewAdaptor(*mqttUrl, "pipoint")
		cons = append(cons, mq)
		mq.SetAutoReconnect(true)
		pi.AddMQTT(mq)
	}

	http.HandleFunc("/metrics", pi.Params.Metrics)

	master := gobot.NewMaster()
	a := api.NewAPI(master)
	a.Start()

	robot := gobot.NewRobot("pipoint",
		cons, drivers,
		func() {
			go pi.Run()
		})

	master.AddRobot(robot)
	master.Start()
}
<|endoftext|>


<commit_before>package local

import (
	"math"

	"github.com/ready-steady/adapt/algorithm/external"
)

// Target is a function to be interpolated.
type Target interface {
	// Dimensions returns the number of inputs and outputs.
	Dimensions() (uint, uint)

	// Continue decides if the interpolation process should go on.
	Continue(*external.Progress) bool

	// Compute evaluates the target function at a point.
	Compute([]float64, []float64)

	// Score assigns a score to a location.
	Score(*Location) float64
}

// Location contains information about a spacial location.
type Location struct {
	Index   []uint64  // Index of the grid node
	Volume  float64   // Volume of the basis function
	Value   []float64 // Target-function value
	Surplus []float64 // Hierarchical surplus
}

// BasicTarget is a basic target satisfying the Target interface.
type BasicTarget struct {
	ContinueHandler func(*external.Progress) bool
	ComputeHandler  func([]float64, []float64) // != nil
	ScoreHandler    func(*Location) float64

	ni uint
	no uint

	absolute float64
}

// NewTarget creates a basic target.
func NewTarget(inputs, outputs uint, absolute float64,
	compute func([]float64, []float64)) *BasicTarget {

	return &BasicTarget{
		ni: inputs,
		no: outputs,

		absolute: absolute,

		ComputeHandler: compute,
	}
}

func (self *BasicTarget) Dimensions() (uint, uint) {
	return self.ni, self.no
}

func (self *BasicTarget) Continue(progress *external.Progress) bool {
	if self.ContinueHandler != nil {
		return self.ContinueHandler(progress)
	} else {
		return true
	}
}

func (self *BasicTarget) Compute(node, value []float64) {
	self.ComputeHandler(node, value)
}

func (self *BasicTarget) Score(location *Location) (score float64) {
	if self.ScoreHandler != nil {
		score = self.ScoreHandler(location)
	} else {
		for _, ε := range location.Surplus {
			if math.Abs(ε) > self.absolute {
				score = 1.0
				break
			}
		}
	}
	return
}
<commit_msg>a/local: make a cosmetic adjustment<commit_after>package local

import (
	"math"

	"github.com/ready-steady/adapt/algorithm/external"
)

// Target is a function to be interpolated.
type Target interface {
	// Dimensions returns the number of inputs and outputs.
	Dimensions() (uint, uint)

	// Continue decides if the interpolation process should go on.
	Continue(*external.Progress) bool

	// Compute evaluates the target function at a point.
	Compute([]float64, []float64)

	// Score assigns a score to a location.
	Score(*Location) float64
}

// Location contains information about a spacial location.
type Location struct {
	Index   []uint64  // Index of the grid node
	Volume  float64   // Volume of the basis function
	Value   []float64 // Target-function value
	Surplus []float64 // Hierarchical surplus
}

// BasicTarget is a basic target satisfying the Target interface.
type BasicTarget struct {
	ContinueHandler func(*external.Progress) bool
	ComputeHandler  func([]float64, []float64) // != nil
	ScoreHandler    func(*Location) float64

	ni uint
	no uint

	absolute float64
}

// NewTarget creates a basic target.
func NewTarget(inputs, outputs uint, absolute float64,
	compute func([]float64, []float64)) *BasicTarget {

	return &BasicTarget{
		ComputeHandler: compute,

		ni: inputs,
		no: outputs,

		absolute: absolute,
	}
}

func (self *BasicTarget) Dimensions() (uint, uint) {
	return self.ni, self.no
}

func (self *BasicTarget) Continue(progress *external.Progress) bool {
	if self.ContinueHandler != nil {
		return self.ContinueHandler(progress)
	} else {
		return true
	}
}

func (self *BasicTarget) Compute(node, value []float64) {
	self.ComputeHandler(node, value)
}

func (self *BasicTarget) Score(location *Location) (score float64) {
	if self.ScoreHandler != nil {
		score = self.ScoreHandler(location)
	} else {
		for _, ε := range location.Surplus {
			if math.Abs(ε) > self.absolute {
				score = 1.0
				break
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package cli

import (
	"errors"
	"io"
	"math"
	"time"

	koliutil "github.com/kolibox/koli/pkg/cli/util"
	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/api/validation"
	"k8s.io/kubernetes/pkg/client/restclient"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
)

var (
	logsExample = dedent.Dedent(`
		# Return snapshot logs from pod nginx with only one container
		kubectl logs nginx

		# Return snapshot of previous terminated ruby container logs from pod web-1
		kubectl logs -p -c ruby web-1

		# Begin streaming the logs of the ruby container in pod web-1
		kubectl logs -f -c ruby web-1

		# Display only the most recent 20 lines of output in pod nginx
		kubectl logs --tail=20 nginx

		# Show all logs from pod nginx written in the last hour
		kubectl logs --since=1h nginx`)
)

// LogsOptions .
type LogsOptions struct {
	Namespace   string
	ResourceArg string
	Options     runtime.Object

	Mapper       meta.RESTMapper
	Typer        runtime.ObjectTyper
	ClientMapper resource.ClientMapper
	Decoder      runtime.Decoder

	Object        runtime.Object
	LogsForObject func(object, options runtime.Object) (*restclient.Request, error)

	Out io.Writer
}

// NewCmdLogs creates a new pod logs command
func NewCmdLogs(comm *koliutil.CommandParams) *cobra.Command {
	options := &LogsOptions{}
	cmd := &cobra.Command{
		Use:     "logs [-f] [-p] POD [-c CONTAINER]",
		Short:   "Print the logs for a container in a pod",
		Long:    "Print the logs for a container in a pod. If the pod has only one container, the container name is optional.",
		Example: logsExample,
		PreRun: func(cmd *cobra.Command, args []string) {

		},
		Run: func(cmd *cobra.Command, args []string) {
			comm.Cmd = cmd
			cmdutil.CheckErr(options.Complete(comm, args))
			if err := options.Validate(); err != nil {
				cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
			}
			_, err := options.RunLogs()
			cmdutil.CheckErr(err)
		},
		Aliases: []string{"log"},
	}
	cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
	cmd.Flags().Bool("timestamps", false, "Include timestamps on each line in the log output")
	cmd.Flags().Int64("limit-bytes", 0, "Maximum bytes of logs to return. Defaults to no limit.")
	cmd.Flags().BoolP("previous", "p", false, "If true, print the logs for the previous instance of the container in a pod if it exists.")
	cmd.Flags().Int64("tail", -1, "Lines of recent log file to display. Defaults to -1, showing all log lines.")
	cmd.Flags().String("since-time", "", "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.")
	cmd.Flags().Duration("since", 0, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.")
	cmd.Flags().StringP("container", "c", "", "Print the logs of this container")

	cmd.Flags().Bool("interactive", false, "If true, prompt the user for input when required.")
	cmd.Flags().MarkDeprecated("interactive", "This flag is no longer respected and there is no replacement.")
	cmdutil.AddInclude3rdPartyFlags(cmd)
	return cmd
}

// Complete .
func (o *LogsOptions) Complete(comm *koliutil.CommandParams, args []string) error {
	cmd, f, out := comm.Cmd, comm.KFactory(), comm.Out
	containerName := cmdutil.GetFlagString(cmd, "container")
	switch len(args) {
	case 0:
		return cmdutil.UsageError(cmd, "POD is required for logs")
	case 1:
		o.ResourceArg = args[0]
	case 2:
		if cmd.Flag("container").Changed {
			return cmdutil.UsageError(cmd, "only one of -c, [CONTAINER] arg is allowed")
		}
		o.ResourceArg = args[0]
		containerName = args[1]
	default:
		return cmdutil.UsageError(cmd, "logs POD [-c CONTAINER]")
	}
	var err error
	koliutil.SetNamespacePrefix(cmd.Flag("namespace"), comm.User().ID)
	o.Namespace, err = comm.Factory.DefaultNamespace(cmd, true)
	if err != nil {
		return err
	}

	logOptions := &api.PodLogOptions{
		Container:  containerName,
		Follow:     cmdutil.GetFlagBool(cmd, "follow"),
		Previous:   cmdutil.GetFlagBool(cmd, "previous"),
		Timestamps: cmdutil.GetFlagBool(cmd, "timestamps"),
	}
	if sinceTime := cmdutil.GetFlagString(cmd, "since-time"); len(sinceTime) > 0 {
		t, err := api.ParseRFC3339(sinceTime, unversioned.Now)
		if err != nil {
			return err
		}
		logOptions.SinceTime = &t
	}
	if limit := cmdutil.GetFlagInt64(cmd, "limit-bytes"); limit != 0 {
		logOptions.LimitBytes = &limit
	}
	if tail := cmdutil.GetFlagInt64(cmd, "tail"); tail != -1 {
		logOptions.TailLines = &tail
	}
	if sinceSeconds := cmdutil.GetFlagDuration(cmd, "since"); sinceSeconds != 0 {
		// round up to the nearest second
		sec := int64(math.Ceil(float64(sinceSeconds) / float64(time.Second)))
		logOptions.SinceSeconds = &sec
	}
	o.Options = logOptions
	o.LogsForObject = f.LogsForObject
	o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
	o.Out = out

	mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
	decoder := f.Decoder(true)
	if o.Object == nil {
		infos, err := resource.NewBuilder(mapper, typer, o.ClientMapper, decoder).
			NamespaceParam(o.Namespace).DefaultNamespace().
			ResourceNames("pods", o.ResourceArg).
			SingleResourceType().
			Do().Infos()
		if err != nil {
			return err
		}
		if len(infos) != 1 {
			return errors.New("expected a resource")
		}
		o.Object = infos[0].Object
	}

	return nil
}

// Validate .
func (o LogsOptions) Validate() error {
	if len(o.ResourceArg) == 0 {
		return errors.New("a pod must be specified")
	}
	logsOptions, ok := o.Options.(*api.PodLogOptions)
	if !ok {
		return errors.New("unexpected logs options object")
	}
	if errs := validation.ValidatePodLogOptions(logsOptions); len(errs) > 0 {
		return errs.ToAggregate()
	}

	return nil
}

// RunLogs retrieves a pod log
func (o LogsOptions) RunLogs() (int64, error) {
	req, err := o.LogsForObject(o.Object, o.Options)
	if err != nil {
		return 0, err
	}

	readCloser, err := req.Stream()
	if err != nil {
		return 0, err
	}
	defer readCloser.Close()

	return io.Copy(o.Out, readCloser)
}
<commit_msg>fix verify error<commit_after>package cli

import (
	"errors"
	"io"
	"math"
	"time"

	koliutil "github.com/kolibox/koli/pkg/cli/util"
	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/api/validation"
	"k8s.io/kubernetes/pkg/client/restclient"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
)

var (
	logsExample = dedent.Dedent(`
		# Return snapshot logs from pod nginx with only one container
		kubectl logs nginx

		# Return snapshot of previous terminated ruby container logs from pod web-1
		kubectl logs -p -c ruby web-1

		# Begin streaming the logs of the ruby container in pod web-1
		kubectl logs -f -c ruby web-1

		# Display only the most recent 20 lines of output in pod nginx
		kubectl logs --tail=20 nginx

		# Show all logs from pod nginx written in the last hour
		kubectl logs --since=1h nginx`)
)

// LogsOptions .
type LogsOptions struct {
	Namespace   string
	ResourceArg string
	Options     runtime.Object

	Mapper       meta.RESTMapper
	Typer        runtime.ObjectTyper
	ClientMapper resource.ClientMapper
	Decoder      runtime.Decoder

	Object        runtime.Object
	LogsForObject func(object, options runtime.Object) (*restclient.Request, error)

	Out io.Writer
}

// NewCmdLogs creates a new pod logs command
func NewCmdLogs(comm *koliutil.CommandParams) *cobra.Command {
	options := &LogsOptions{}
	cmd := &cobra.Command{
		Use:     "logs [-f] [-p] POD [-c CONTAINER]",
		Short:   "Print the logs for a container in a pod",
		Long:    "Print the logs for a container in a pod. If the pod has only one container, the container name is optional.",
		Example: logsExample,
		PreRun: func(cmd *cobra.Command, args []string) {

		},
		Run: func(cmd *cobra.Command, args []string) {
			comm.Cmd = cmd
			cmdutil.CheckErr(options.Complete(comm, args))
			if err := options.Validate(); err != nil {
				cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
			}
			_, err := options.RunLogs()
			cmdutil.CheckErr(err)
		},
		Aliases: []string{"log"},
	}
	cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
	cmd.Flags().Bool("timestamps", false, "Include timestamps on each line in the log output")
	cmd.Flags().Int64("limit-bytes", 0, "Maximum bytes of logs to return. Defaults to no limit.")
	cmd.Flags().BoolP("previous", "p", false, "If true, print the logs for the previous instance of the container in a pod if it exists.")
	cmd.Flags().Int64("tail", -1, "Lines of recent log file to display. Defaults to -1, showing all log lines.")
	cmd.Flags().String("since-time", "", "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.")
	cmd.Flags().Duration("since", 0, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.")
	cmd.Flags().StringP("container", "c", "", "Print the logs of this container")

	cmd.Flags().Bool("interactive", false, "If true, prompt the user for input when required.")
	cmd.Flags().MarkDeprecated("interactive", "This flag is no longer respected and there is no replacement.")
	cmdutil.AddInclude3rdPartyFlags(cmd)
	return cmd
}

// Complete .
func (o *LogsOptions) Complete(comm *koliutil.CommandParams, args []string) error {
	cmd, f, out := comm.Cmd, comm.KFactory(), comm.Out
	containerName := cmdutil.GetFlagString(cmd, "container")
	switch len(args) {
	case 0:
		return cmdutil.UsageError(cmd, "POD is required for logs")
	case 1:
		o.ResourceArg = args[0]
	case 2:
		if cmd.Flag("container").Changed {
			return cmdutil.UsageError(cmd, "only one of -c, [CONTAINER] arg is allowed")
		}
		o.ResourceArg = args[0]
		containerName = args[1]
	default:
		return cmdutil.UsageError(cmd, "logs POD [-c CONTAINER]")
	}

	err := koliutil.SetNamespacePrefix(cmd.Flag("namespace"), comm.User().ID)
	if err != nil {
		return err
	}
	o.Namespace, err = comm.Factory.DefaultNamespace(cmd, true)
	if err != nil {
		return err
	}

	logOptions := &api.PodLogOptions{
		Container:  containerName,
		Follow:     cmdutil.GetFlagBool(cmd, "follow"),
		Previous:   cmdutil.GetFlagBool(cmd, "previous"),
		Timestamps: cmdutil.GetFlagBool(cmd, "timestamps"),
	}
	if sinceTime := cmdutil.GetFlagString(cmd, "since-time"); len(sinceTime) > 0 {
		t, err := api.ParseRFC3339(sinceTime, unversioned.Now)
		if err != nil {
			return err
		}
		logOptions.SinceTime = &t
	}
	if limit := cmdutil.GetFlagInt64(cmd, "limit-bytes"); limit != 0 {
		logOptions.LimitBytes = &limit
	}
	if tail := cmdutil.GetFlagInt64(cmd, "tail"); tail != -1 {
		logOptions.TailLines = &tail
	}
	if sinceSeconds := cmdutil.GetFlagDuration(cmd, "since"); sinceSeconds != 0 {
		// round up to the nearest second
		sec := int64(math.Ceil(float64(sinceSeconds) / float64(time.Second)))
		logOptions.SinceSeconds = &sec
	}
	o.Options = logOptions
	o.LogsForObject = f.LogsForObject
	o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
	o.Out = out

	mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd))
	decoder := f.Decoder(true)
	if o.Object == nil {
		infos, err := resource.NewBuilder(mapper, typer, o.ClientMapper, decoder).
			NamespaceParam(o.Namespace).DefaultNamespace().
			ResourceNames("pods", o.ResourceArg).
			SingleResourceType().
			Do().Infos()
		if err != nil {
			return err
		}
		if len(infos) != 1 {
			return errors.New("expected a resource")
		}
		o.Object = infos[0].Object
	}

	return nil
}

// Validate .
func (o LogsOptions) Validate() error {
	if len(o.ResourceArg) == 0 {
		return errors.New("a pod must be specified")
	}
	logsOptions, ok := o.Options.(*api.PodLogOptions)
	if !ok {
		return errors.New("unexpected logs options object")
	}
	if errs := validation.ValidatePodLogOptions(logsOptions); len(errs) > 0 {
		return errs.ToAggregate()
	}

	return nil
}

// RunLogs retrieves a pod log
func (o LogsOptions) RunLogs() (int64, error) {
	req, err := o.LogsForObject(o.Object, o.Options)
	if err != nil {
		return 0, err
	}

	readCloser, err := req.Stream()
	if err != nil {
		return 0, err
	}
	defer readCloser.Close()

	return io.Copy(o.Out, readCloser)
}
<|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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

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

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<commit_msg>fixes #363 add int validation for min/max<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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

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

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// MaximumIn validates if a number is smaller than a given maximum
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumInt(path, in, max, exclusive)
	}
	return nil
}

// MaximumUint validates if a number is smaller than a given maximum
func MaximumUin(path, in string, data, max uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumUint(path, in, max, exclusive)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MinimumInt validates if a number is smaller than a given minimum
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumInt(path, in, min, exclusive)
	}
	return nil
}

// MinimumUint validates if a number is smaller than a given minimum
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumUint(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<|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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

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

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// MaximumIn validates if a number is smaller than a given maximum
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumInt(path, in, max, exclusive)
	}
	return nil
}

// MaximumUint validates if a number is smaller than a given maximum
func MaximumUin(path, in string, data, max uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumUint(path, in, max, exclusive)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MinimumInt validates if a number is smaller than a given minimum
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumInt(path, in, min, exclusive)
	}
	return nil
}

// MinimumUint validates if a number is smaller than a given minimum
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumUint(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<commit_msg>fix linting errors<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 validate

import (
	"reflect"
	"regexp"
	"unicode/utf8"

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

// Enum validates if the data is a member of the enum
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
	val := reflect.ValueOf(enum)
	if val.Kind() != reflect.Slice {
		return nil
	}

	var values []interface{}
	for i := 0; i < val.Len(); i++ {
		ele := val.Index(i)
		enumValue := ele.Interface()
		if data != nil && reflect.DeepEqual(data, enumValue) {
			return nil
		}
		values = append(values, enumValue)
	}
	return errors.EnumFail(path, in, data, values)
}

// MinItems validates that there are at least n items in a slice
func MinItems(path, in string, size, min int64) *errors.Validation {
	if size < min {
		return errors.TooFewItems(path, in, min)
	}
	return nil
}

// MaxItems validates that there are at most n items in a slice
func MaxItems(path, in string, size, max int64) *errors.Validation {
	if size > max {
		return errors.TooManyItems(path, in, max)
	}
	return nil
}

// UniqueItems validates that the provided slice has unique elements
func UniqueItems(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return nil
	}
	var unique []interface{}
	for i := 0; i < val.Len(); i++ {
		v := val.Index(i).Interface()
		for _, u := range unique {
			if reflect.DeepEqual(v, u) {
				return errors.DuplicateItems(path, in)
			}
		}
		unique = append(unique, v)
	}
	return nil
}

// MinLength validates a string for minimum length
func MinLength(path, in, data string, minLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen < minLength {
		return errors.TooShort(path, in, minLength)
	}
	return nil
}

// MaxLength validates a string for maximum length
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
	strLen := int64(utf8.RuneCount([]byte(data)))
	if strLen > maxLength {
		return errors.TooLong(path, in, maxLength)
	}
	return nil
}

// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
	val := reflect.ValueOf(data)
	if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredString validates a string for requiredness
func RequiredString(path, in, data string) *errors.Validation {
	if data == "" {
		return errors.Required(path, in)
	}
	return nil
}

// RequiredNumber validates a number for requiredness
func RequiredNumber(path, in string, data float64) *errors.Validation {
	if data == 0 {
		return errors.Required(path, in)
	}
	return nil
}

// Pattern validates a string against a regular expression
func Pattern(path, in, data, pattern string) *errors.Validation {
	re := regexp.MustCompile(pattern)
	if !re.MatchString(data) {
		return errors.FailedPattern(path, in, pattern)
	}
	return nil
}

// MaximumInt validates if a number is smaller than a given maximum
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumInt(path, in, max, exclusive)
	}
	return nil
}

// MaximumUint validates if a number is smaller than a given maximum
func MaximumUint(path, in string, data, max uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximumUint(path, in, max, exclusive)
	}
	return nil
}

// Maximum validates if a number is smaller than a given maximum
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
	if (!exclusive && data > max) || (exclusive && data >= max) {
		return errors.ExceedsMaximum(path, in, max, exclusive)
	}
	return nil
}

// Minimum validates if a number is smaller than a given minimum
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimum(path, in, min, exclusive)
	}
	return nil
}

// MinimumInt validates if a number is smaller than a given minimum
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumInt(path, in, min, exclusive)
	}
	return nil
}

// MinimumUint validates if a number is smaller than a given minimum
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
	if (!exclusive && data < min) || (exclusive && data <= min) {
		return errors.ExceedsMinimumUint(path, in, min, exclusive)
	}
	return nil
}

// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
	if !swag.IsFloat64AJSONInteger(data / factor) {
		return errors.NotMultipleOf(path, in, factor)
	}
	return nil
}

// FormatOf validates if a string matches a format in the format registry
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
	if registry == nil {
		registry = strfmt.Default
	}
	if ok := registry.ContainsName(format); !ok {
		return errors.InvalidTypeName(format)
	}
	if ok := registry.Validates(format, data); !ok {
		return errors.InvalidType(path, in, format, data)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 *  Bulldozer Framework
 *  Copyright (C) DesertBit
 */

package template

const errorTemplateText = ``
<commit_msg>further progress<commit_after><|endoftext|>


<commit_before>package softlayer

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"github.ibm.com/riethm/gopherlayer.git/datatypes"
	"github.ibm.com/riethm/gopherlayer.git/services"
	"github.ibm.com/riethm/gopherlayer.git/session"
	"github.ibm.com/riethm/gopherlayer.git/sl"
)

func resourceSoftLayerSSHKey() *schema.Resource {
	return &schema.Resource{
		Create:   resourceSoftLayerSSHKeyCreate,
		Read:     resourceSoftLayerSSHKeyRead,
		Update:   resourceSoftLayerSSHKeyUpdate,
		Delete:   resourceSoftLayerSSHKeyDelete,
		Exists:   resourceSoftLayerSSHKeyExists,
		Importer: &schema.ResourceImporter{},

		Schema: map[string]*schema.Schema{
			"id": &schema.Schema{
				Type:     schema.TypeInt,
				Computed: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"public_key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"fingerprint": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"notes": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  nil,
			},
		},
	}
}

func resourceSoftLayerSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	// Build up our creation options
	opts := datatypes.Security_Ssh_Key{
		Label: sl.String(d.Get("name").(string)),
		Key:   sl.String(d.Get("public_key").(string)),
	}

	if notes, ok := d.GetOk("notes"); ok {
		opts.Notes = sl.String(notes.(string))
	}

	res, err := service.CreateObject(&opts)
	if err != nil {
		return fmt.Errorf("Error creating SSH Key: %s", err)
	}

	d.SetId(strconv.Itoa(*res.Id))
	log.Printf("[INFO] SSH Key: %d", *res.Id)

	return resourceSoftLayerSSHKeyRead(d, meta)
}

func resourceSoftLayerSSHKeyRead(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, _ := strconv.Atoi(d.Id())

	key, err := service.Id(keyId).GetObject()
	if err != nil {
		// If the key is somehow already destroyed, mark as
		// succesfully gone
		if strings.Contains(err.Error(), "404 Not Found") {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving SSH key: %s", err)
	}

	d.Set("id", *key.Id)
	d.Set("name", *key.Label)
	d.Set("public_key", strings.TrimSpace(*key.Key))
	d.Set("fingerprint", *key.Fingerprint)
	d.Set("notes", *key.Notes)

	return nil
}

func resourceSoftLayerSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, _ := strconv.Atoi(d.Id())

	key, err := service.Id(keyId).GetObject()
	if err != nil {
		return fmt.Errorf("Error retrieving SSH key: %s", err)
	}

	if d.HasChange("name") {
		key.Label = sl.String(d.Get("name").(string))
	}

	if d.HasChange("notes") {
		key.Notes = sl.String(d.Get("notes").(string))
	}

	_, err = service.Id(keyId).EditObject(&key)
	if err != nil {
		return fmt.Errorf("Error editing SSH key: %s", err)
	}
	return nil
}

func resourceSoftLayerSSHKeyDelete(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	id, err := strconv.Atoi(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting SSH Key: %s", err)
	}

	log.Printf("[INFO] Deleting SSH key: %d", id)
	_, err = service.Id(id).DeleteObject()
	if err != nil {
		return fmt.Errorf("Error deleting SSH key: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSoftLayerSSHKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, err := strconv.Atoi(d.Id())
	if err != nil {
		return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err)
	}

	result, err := service.Id(keyId).GetObject()
	return result.Id != nil && err == nil && *result.Id == keyId, nil
}
<commit_msg>Check ssh key notes before dereferencing them<commit_after>package softlayer

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"github.ibm.com/riethm/gopherlayer.git/datatypes"
	"github.ibm.com/riethm/gopherlayer.git/services"
	"github.ibm.com/riethm/gopherlayer.git/session"
	"github.ibm.com/riethm/gopherlayer.git/sl"
)

func resourceSoftLayerSSHKey() *schema.Resource {
	return &schema.Resource{
		Create:   resourceSoftLayerSSHKeyCreate,
		Read:     resourceSoftLayerSSHKeyRead,
		Update:   resourceSoftLayerSSHKeyUpdate,
		Delete:   resourceSoftLayerSSHKeyDelete,
		Exists:   resourceSoftLayerSSHKeyExists,
		Importer: &schema.ResourceImporter{},

		Schema: map[string]*schema.Schema{
			"id": &schema.Schema{
				Type:     schema.TypeInt,
				Computed: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"public_key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"fingerprint": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"notes": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  nil,
			},
		},
	}
}

func resourceSoftLayerSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	// Build up our creation options
	opts := datatypes.Security_Ssh_Key{
		Label: sl.String(d.Get("name").(string)),
		Key:   sl.String(d.Get("public_key").(string)),
	}

	if notes, ok := d.GetOk("notes"); ok {
		opts.Notes = sl.String(notes.(string))
	}

	res, err := service.CreateObject(&opts)
	if err != nil {
		return fmt.Errorf("Error creating SSH Key: %s", err)
	}

	d.SetId(strconv.Itoa(*res.Id))
	log.Printf("[INFO] SSH Key: %d", *res.Id)

	return resourceSoftLayerSSHKeyRead(d, meta)
}

func resourceSoftLayerSSHKeyRead(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, _ := strconv.Atoi(d.Id())

	key, err := service.Id(keyId).GetObject()
	if err != nil {
		// If the key is somehow already destroyed, mark as
		// succesfully gone
		if strings.Contains(err.Error(), "404 Not Found") {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving SSH key: %s", err)
	}

	d.Set("id", *key.Id)
	d.Set("name", *key.Label)
	d.Set("public_key", strings.TrimSpace(*key.Key))
	d.Set("fingerprint", *key.Fingerprint)

	if key.Notes != nil {
		d.Set("notes", *key.Notes)
	}

	return nil
}

func resourceSoftLayerSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, _ := strconv.Atoi(d.Id())

	key, err := service.Id(keyId).GetObject()
	if err != nil {
		return fmt.Errorf("Error retrieving SSH key: %s", err)
	}

	if d.HasChange("name") {
		key.Label = sl.String(d.Get("name").(string))
	}

	if d.HasChange("notes") {
		key.Notes = sl.String(d.Get("notes").(string))
	}

	_, err = service.Id(keyId).EditObject(&key)
	if err != nil {
		return fmt.Errorf("Error editing SSH key: %s", err)
	}
	return nil
}

func resourceSoftLayerSSHKeyDelete(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	id, err := strconv.Atoi(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting SSH Key: %s", err)
	}

	log.Printf("[INFO] Deleting SSH key: %d", id)
	_, err = service.Id(id).DeleteObject()
	if err != nil {
		return fmt.Errorf("Error deleting SSH key: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSoftLayerSSHKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	sess := meta.(*session.Session)
	service := services.GetSecuritySshKeyService(sess)

	keyId, err := strconv.Atoi(d.Id())
	if err != nil {
		return false, fmt.Errorf("Not a valid ID, must be an integer: %s", err)
	}

	result, err := service.Id(keyId).GetObject()
	return result.Id != nil && err == nil && *result.Id == keyId, nil
}
<|endoftext|>


<commit_before>package termite

import (
	"fmt"
	"os"
	"log"
	"sync"
	"rpc"
	"github.com/hanwen/go-fuse/fuse"
	"strings"
	"path/filepath"
)

type RpcFs struct {
	StatFsFs fuse.FileSystem
	fuse.DefaultFileSystem
	cache *ContentCache

	client *rpc.Client

	// Roots that we should try to fetch locally.
	localRoots []string

	// Should be acquired before attrMutex if applicable.
	dirMutex     sync.RWMutex
	dirFetchCond *sync.Cond
	dirFetchMap  map[string]bool
	directories  map[string]*DirResponse

	fetchMutex sync.Mutex
	fetchCond  *sync.Cond
	fetchMap   map[string]bool

	attrMutex    sync.RWMutex
	attrCond     *sync.Cond
	attrFetchMap map[string]bool
	attrResponse map[string]*FileAttr
}

func NewRpcFs(server *rpc.Client, cache *ContentCache) *RpcFs {
	me := &RpcFs{}
	me.client = server

	me.directories = make(map[string]*DirResponse)
	me.dirFetchMap = map[string]bool{}
	me.dirFetchCond = sync.NewCond(&me.dirMutex)

	me.attrResponse = make(map[string]*FileAttr)
	me.attrFetchMap = map[string]bool{}
	me.attrCond = sync.NewCond(&me.attrMutex)

	me.cache = cache
	me.fetchMap = make(map[string]bool)
	me.fetchCond = sync.NewCond(&me.fetchMutex)

	return me
}

func (me *RpcFs) Update(req *UpdateRequest, resp *UpdateResponse) os.Error {
	me.updateFiles(req.Files)
	return nil
}

func (me *RpcFs) updateFiles(files []*FileAttr) {
	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()

	for _, r := range files {
		p := strings.TrimLeft(r.Path, string(filepath.Separator))
		copy := *r
		me.attrResponse[p] = &copy
		if r.Deletion() {
			me.directories[p] = nil, false
		}

		d, basename := filepath.Split(p)
		d = strings.TrimRight(d, string(filepath.Separator))
		if dir, ok := me.directories[d]; ok {
			if r.Deletion() {
				dir.NameModeMap[basename] = 0, false
			} else {
				dir.NameModeMap[basename] = r.Mode ^ 0777
			}
		}
	}
}

func (me *RpcFs) GetDir(name string) *DirResponse {
	me.dirMutex.RLock()
	r, ok := me.directories[name]
	me.dirMutex.RUnlock()
	if ok {
		return r
	}

	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()
	for me.dirFetchMap[name] && me.directories[name] == nil {
		me.dirFetchCond.Wait()
	}

	r, ok = me.directories[name]
	if ok {
		return r
	}

	me.dirFetchMap[name] = true
	me.dirMutex.Unlock()

	req := &DirRequest{Name: "/" + name}
	rep := &DirResponse{}
	err := me.client.Call("FsServer.ReadDir", req, rep)

	me.dirMutex.Lock()
	me.dirFetchMap[name] = false, false
	me.dirFetchCond.Broadcast()
	if err != nil {
		log.Fatal("GetDir error:", err)
	}

	if rep.Status.Ok() {
		// TODO - caching for negative responses too.
		me.directories[name] = rep
	}

	return rep
}

func (me *RpcFs) FetchHash(size int64, key string) os.Error {
	me.fetchMutex.Lock()
	defer me.fetchMutex.Unlock()
	for me.fetchMap[key] && !me.cache.HasHash(key) {
		me.fetchCond.Wait()
	}

	if me.cache.HasHash(key) {
		return nil
	}
	me.fetchMap[key] = true
	me.fetchMutex.Unlock()

	err := me.fetchOnce(key)

	me.fetchMutex.Lock()
	me.fetchMap[key] = false, false
	me.fetchCond.Broadcast()

	return err
}

func (me *RpcFs) fetchOnce(hash string) os.Error {
	// TODO - should save in smaller chunks.
	return FetchBetweenContentServers(me.client, "FsServer.FileContent", hash,
		me.cache)
}

func (me *RpcFs) getFileAttr(name string) *FileAttr {
	me.attrMutex.RLock()
	result, ok := me.attrResponse[name]
	me.attrMutex.RUnlock()
	if ok {
		return result
	}

	dir, base := filepath.Split(name)
	dir = strings.TrimRight(dir, "/")
	dirResp := me.GetDir(dir)
	code := dirResp.Status
	if code.Ok() {
		if _, ok := dirResp.NameModeMap[base]; !ok {
			code = fuse.ENOENT
		}
	}
	if !code.Ok() {
		me.attrMutex.Lock()
		defer me.attrMutex.Unlock()
		fa := &FileAttr{
			Status: code,
			Path:   name,
		}
		me.attrResponse[name] = fa
		return fa
	}

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()
	for me.attrFetchMap[name] && me.attrResponse[name] == nil {
		me.attrCond.Wait()
	}
	result, ok = me.attrResponse[name]
	if ok {
		return result
	}
	me.attrFetchMap[name] = true
	me.attrMutex.Unlock()

	abs := "/" + name
	req := &AttrRequest{Name: abs}
	rep := &AttrResponse{}
	err := me.client.Call("FsServer.GetAttr", req, rep)

	me.attrMutex.Lock()
	me.attrFetchMap[name] = false, false
	if err != nil {
		// fatal?
		log.Println("GetAttr error:", err)
		return nil
	}

	var wanted *FileAttr
	for _, attr := range rep.Attrs {
		me.considerSaveLocal(attr)
		me.attrResponse[strings.TrimLeft(attr.Path, "/")] = attr
		if attr.Path == abs {
			wanted = attr
		}
	}
	me.attrCond.Broadcast()

	return wanted
}

func (me *RpcFs) considerSaveLocal(attr *FileAttr) {
	absPath := attr.Path
	if !attr.Status.Ok() || !attr.FileInfo.IsRegular() {
		return
	}
	found := false
	for _, root := range me.localRoots {
		if HasDirPrefix(absPath, root) {
			found = true
		}
	}
	if !found {
		return
	}

	fi, _ := os.Lstat(absPath)
	if fi == nil {
		return
	}
	if EncodeFileInfo(*fi) != EncodeFileInfo(*attr.FileInfo) {
		return
	}

	// Avoid fetching local data; this assumes that most paths
	// will be the same between master and worker.  We mimick
	// fsserver's logic, so that we don't have nasty surprises
	// when running server and master on the same machine.
	if HasDirPrefix(absPath, "/usr") && !HasDirPrefix(absPath, "/usr/local") {
		me.cache.SaveImmutablePath(absPath)
	}
}

////////////////////////////////////////////////////////////////
// FS API

func (me *RpcFs) String() string {
	return "RpcFs"
}

func (me *RpcFs) OpenDir(name string, context *fuse.Context) (chan fuse.DirEntry, fuse.Status) {
	r := me.GetDir(name)
	if !r.Status.Ok() {
		return nil, r.Status
	}

	c := make(chan fuse.DirEntry, len(r.NameModeMap))
	for k, mode := range r.NameModeMap {
		c <- fuse.DirEntry{
			Name: k,
			Mode: mode,
		}
	}
	close(c)
	return c, fuse.OK
}

type rpcFsFile struct {
	fuse.File
	os.FileInfo
}

func (me *rpcFsFile) GetAttr() (*os.FileInfo, fuse.Status) {
	return &me.FileInfo, fuse.OK
}

func (me *rpcFsFile) String() string {
	return fmt.Sprintf("rpcFsFile(%s)", me.File.String())
}

func (me *RpcFs) Open(name string, flags uint32, context *fuse.Context) (fuse.File, fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EPERM
	}
	a := me.getFileAttr(name)
	if a == nil {
		return nil, fuse.ENOENT
	}
	if !a.Status.Ok() {
		return nil, a.Status
	}

	if contents := me.cache.ContentsIfLoaded(a.Hash); contents != nil {
		return &fuse.WithFlags{
			File: &rpcFsFile{
				fuse.NewDataFile(contents),
				*a.FileInfo,
			},
			FuseFlags: fuse.FOPEN_KEEP_CACHE,
		}, fuse.OK
	}

	p := me.cache.Path(a.Hash)
	if _, err := os.Lstat(p); fuse.OsErrorToErrno(err) == fuse.ENOENT {
		log.Printf("Fetching contents for file %s: %x", name, a.Hash)
		err = me.FetchHash(a.FileInfo.Size, a.Hash)
		if err != nil {
			log.Fatal("Error fetching contents: ", err)
		}
	}

	f, err := os.Open(p)
	if err != nil {
		return nil, fuse.OsErrorToErrno(err)
	}

	return &fuse.WithFlags{
		File: &rpcFsFile{
			&fuse.ReadOnlyFile{&fuse.LoopbackFile{File: f}},
			*a.FileInfo,
		},
		FuseFlags: fuse.FOPEN_KEEP_CACHE,
	}, fuse.OK
}

func (me *RpcFs) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
	a := me.getFileAttr(name)
	if a == nil {
		return "", fuse.ENOENT
	}

	if !a.Status.Ok() {
		return "", a.Status
	}
	if !a.FileInfo.IsSymlink() {
		return "", fuse.EINVAL
	}

	return a.Link, fuse.OK
}

func (me *RpcFs) GetAttr(name string, context *fuse.Context) (*os.FileInfo, fuse.Status) {
	if name == "" {
		return &os.FileInfo{
			Mode: fuse.S_IFDIR | 0755,
		}, fuse.OK
	}

	r := me.getFileAttr(name)
	if r == nil {
		return nil, fuse.ENOENT
	}

	return r.FileInfo, r.Status
}

// TODO - fix this in go-fuse instead.
func (me *RpcFs) StatFs() *fuse.StatfsOut {
	if me.StatFsFs != nil {
		return me.StatFsFs.StatFs()
	}
	return nil
}

func (me *RpcFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	if mode == fuse.F_OK {
		_, code := me.GetAttr(name, context)
		return code
	}
	if mode & fuse.W_OK != 0 {
		return fuse.EACCES
	}
	return fuse.OK
}

<commit_msg>Statfs updates for new go-fuse.<commit_after>package termite

import (
	"fmt"
	"os"
	"log"
	"sync"
	"rpc"
	"github.com/hanwen/go-fuse/fuse"
	"strings"
	"path/filepath"
)

type RpcFs struct {
	fuse.DefaultFileSystem
	cache *ContentCache

	client *rpc.Client

	// Roots that we should try to fetch locally.
	localRoots []string

	// Should be acquired before attrMutex if applicable.
	dirMutex     sync.RWMutex
	dirFetchCond *sync.Cond
	dirFetchMap  map[string]bool
	directories  map[string]*DirResponse

	fetchMutex sync.Mutex
	fetchCond  *sync.Cond
	fetchMap   map[string]bool

	attrMutex    sync.RWMutex
	attrCond     *sync.Cond
	attrFetchMap map[string]bool
	attrResponse map[string]*FileAttr
}

func NewRpcFs(server *rpc.Client, cache *ContentCache) *RpcFs {
	me := &RpcFs{}
	me.client = server

	me.directories = make(map[string]*DirResponse)
	me.dirFetchMap = map[string]bool{}
	me.dirFetchCond = sync.NewCond(&me.dirMutex)

	me.attrResponse = make(map[string]*FileAttr)
	me.attrFetchMap = map[string]bool{}
	me.attrCond = sync.NewCond(&me.attrMutex)

	me.cache = cache
	me.fetchMap = make(map[string]bool)
	me.fetchCond = sync.NewCond(&me.fetchMutex)

	return me
}

func (me *RpcFs) Update(req *UpdateRequest, resp *UpdateResponse) os.Error {
	me.updateFiles(req.Files)
	return nil
}

func (me *RpcFs) updateFiles(files []*FileAttr) {
	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()

	for _, r := range files {
		p := strings.TrimLeft(r.Path, string(filepath.Separator))
		copy := *r
		me.attrResponse[p] = &copy
		if r.Deletion() {
			me.directories[p] = nil, false
		}

		d, basename := filepath.Split(p)
		d = strings.TrimRight(d, string(filepath.Separator))
		if dir, ok := me.directories[d]; ok {
			if r.Deletion() {
				dir.NameModeMap[basename] = 0, false
			} else {
				dir.NameModeMap[basename] = r.Mode ^ 0777
			}
		}
	}
}

func (me *RpcFs) GetDir(name string) *DirResponse {
	me.dirMutex.RLock()
	r, ok := me.directories[name]
	me.dirMutex.RUnlock()
	if ok {
		return r
	}

	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()
	for me.dirFetchMap[name] && me.directories[name] == nil {
		me.dirFetchCond.Wait()
	}

	r, ok = me.directories[name]
	if ok {
		return r
	}

	me.dirFetchMap[name] = true
	me.dirMutex.Unlock()

	req := &DirRequest{Name: "/" + name}
	rep := &DirResponse{}
	err := me.client.Call("FsServer.ReadDir", req, rep)

	me.dirMutex.Lock()
	me.dirFetchMap[name] = false, false
	me.dirFetchCond.Broadcast()
	if err != nil {
		log.Fatal("GetDir error:", err)
	}

	if rep.Status.Ok() {
		// TODO - caching for negative responses too.
		me.directories[name] = rep
	}

	return rep
}

func (me *RpcFs) FetchHash(size int64, key string) os.Error {
	me.fetchMutex.Lock()
	defer me.fetchMutex.Unlock()
	for me.fetchMap[key] && !me.cache.HasHash(key) {
		me.fetchCond.Wait()
	}

	if me.cache.HasHash(key) {
		return nil
	}
	me.fetchMap[key] = true
	me.fetchMutex.Unlock()

	err := me.fetchOnce(key)

	me.fetchMutex.Lock()
	me.fetchMap[key] = false, false
	me.fetchCond.Broadcast()

	return err
}

func (me *RpcFs) fetchOnce(hash string) os.Error {
	// TODO - should save in smaller chunks.
	return FetchBetweenContentServers(me.client, "FsServer.FileContent", hash,
		me.cache)
}

func (me *RpcFs) getFileAttr(name string) *FileAttr {
	me.attrMutex.RLock()
	result, ok := me.attrResponse[name]
	me.attrMutex.RUnlock()
	if ok {
		return result
	}

	dir, base := filepath.Split(name)
	dir = strings.TrimRight(dir, "/")
	dirResp := me.GetDir(dir)
	code := dirResp.Status
	if code.Ok() {
		if _, ok := dirResp.NameModeMap[base]; !ok {
			code = fuse.ENOENT
		}
	}
	if !code.Ok() {
		me.attrMutex.Lock()
		defer me.attrMutex.Unlock()
		fa := &FileAttr{
			Status: code,
			Path:   name,
		}
		me.attrResponse[name] = fa
		return fa
	}

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()
	for me.attrFetchMap[name] && me.attrResponse[name] == nil {
		me.attrCond.Wait()
	}
	result, ok = me.attrResponse[name]
	if ok {
		return result
	}
	me.attrFetchMap[name] = true
	me.attrMutex.Unlock()

	abs := "/" + name
	req := &AttrRequest{Name: abs}
	rep := &AttrResponse{}
	err := me.client.Call("FsServer.GetAttr", req, rep)

	me.attrMutex.Lock()
	me.attrFetchMap[name] = false, false
	if err != nil {
		// fatal?
		log.Println("GetAttr error:", err)
		return nil
	}

	var wanted *FileAttr
	for _, attr := range rep.Attrs {
		me.considerSaveLocal(attr)
		me.attrResponse[strings.TrimLeft(attr.Path, "/")] = attr
		if attr.Path == abs {
			wanted = attr
		}
	}
	me.attrCond.Broadcast()

	return wanted
}

func (me *RpcFs) considerSaveLocal(attr *FileAttr) {
	absPath := attr.Path
	if !attr.Status.Ok() || !attr.FileInfo.IsRegular() {
		return
	}
	found := false
	for _, root := range me.localRoots {
		if HasDirPrefix(absPath, root) {
			found = true
		}
	}
	if !found {
		return
	}

	fi, _ := os.Lstat(absPath)
	if fi == nil {
		return
	}
	if EncodeFileInfo(*fi) != EncodeFileInfo(*attr.FileInfo) {
		return
	}

	// Avoid fetching local data; this assumes that most paths
	// will be the same between master and worker.  We mimick
	// fsserver's logic, so that we don't have nasty surprises
	// when running server and master on the same machine.
	if HasDirPrefix(absPath, "/usr") && !HasDirPrefix(absPath, "/usr/local") {
		me.cache.SaveImmutablePath(absPath)
	}
}

////////////////////////////////////////////////////////////////
// FS API

func (me *RpcFs) String() string {
	return "RpcFs"
}

func (me *RpcFs) OpenDir(name string, context *fuse.Context) (chan fuse.DirEntry, fuse.Status) {
	r := me.GetDir(name)
	if !r.Status.Ok() {
		return nil, r.Status
	}

	c := make(chan fuse.DirEntry, len(r.NameModeMap))
	for k, mode := range r.NameModeMap {
		c <- fuse.DirEntry{
			Name: k,
			Mode: mode,
		}
	}
	close(c)
	return c, fuse.OK
}

type rpcFsFile struct {
	fuse.File
	os.FileInfo
}

func (me *rpcFsFile) GetAttr() (*os.FileInfo, fuse.Status) {
	return &me.FileInfo, fuse.OK
}

func (me *rpcFsFile) String() string {
	return fmt.Sprintf("rpcFsFile(%s)", me.File.String())
}

func (me *RpcFs) Open(name string, flags uint32, context *fuse.Context) (fuse.File, fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EPERM
	}
	a := me.getFileAttr(name)
	if a == nil {
		return nil, fuse.ENOENT
	}
	if !a.Status.Ok() {
		return nil, a.Status
	}

	if contents := me.cache.ContentsIfLoaded(a.Hash); contents != nil {
		return &fuse.WithFlags{
			File: &rpcFsFile{
				fuse.NewDataFile(contents),
				*a.FileInfo,
			},
			FuseFlags: fuse.FOPEN_KEEP_CACHE,
		}, fuse.OK
	}

	p := me.cache.Path(a.Hash)
	if _, err := os.Lstat(p); fuse.OsErrorToErrno(err) == fuse.ENOENT {
		log.Printf("Fetching contents for file %s: %x", name, a.Hash)
		err = me.FetchHash(a.FileInfo.Size, a.Hash)
		if err != nil {
			log.Fatal("Error fetching contents: ", err)
		}
	}

	f, err := os.Open(p)
	if err != nil {
		return nil, fuse.OsErrorToErrno(err)
	}

	return &fuse.WithFlags{
		File: &rpcFsFile{
			&fuse.ReadOnlyFile{&fuse.LoopbackFile{File: f}},
			*a.FileInfo,
		},
		FuseFlags: fuse.FOPEN_KEEP_CACHE,
	}, fuse.OK
}

func (me *RpcFs) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
	a := me.getFileAttr(name)
	if a == nil {
		return "", fuse.ENOENT
	}

	if !a.Status.Ok() {
		return "", a.Status
	}
	if !a.FileInfo.IsSymlink() {
		return "", fuse.EINVAL
	}

	return a.Link, fuse.OK
}

func (me *RpcFs) GetAttr(name string, context *fuse.Context) (*os.FileInfo, fuse.Status) {
	if name == "" {
		return &os.FileInfo{
			Mode: fuse.S_IFDIR | 0755,
		}, fuse.OK
	}

	r := me.getFileAttr(name)
	if r == nil {
		return nil, fuse.ENOENT
	}

	return r.FileInfo, r.Status
}

func (me *RpcFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
	if mode == fuse.F_OK {
		_, code := me.GetAttr(name, context)
		return code
	}
	if mode & fuse.W_OK != 0 {
		return fuse.EACCES
	}
	return fuse.OK
}

<|endoftext|>


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

package plotter

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"image/color"
)

var (
	// DefaultGridLineStyle is the default style for grid lines.
	DefaultGridLineStyle = plot.LineStyle{
		Color: color.Gray{128},
		Width: vg.Points(0.25),
	}
)

// Grid implements the plot.Plotter interface, drawing
// a set of grid lines at the major tick marks.
type Grid struct {
	// Vertical is the style of the vertical lines.
	Vertical plot.LineStyle

	// Horizantal is the style of the horizontal lines.
	// If the radius is <= 0 or the color is nil.
	Horizontal plot.LineStyle
}

// NewGrid returns a new grid with both vertical and
// horizontal lines using the default grid line style.
func NewGrid() *Grid {
	return &Grid{
		Vertical:   DefaultGridLineStyle,
		Horizontal: DefaultGridLineStyle,
	}
}

// Plot implements the plot.Plotter interface.
func (g *Grid) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)

	if g.Vertical.Color == nil {
		goto horiz
	}
	for _, tk := range plt.X.Tick.Marker(plt.X.Min, plt.X.Max) {
		if tk.IsMinor() {
			continue
		}
		x := trX(tk.Value)
		da.StrokeLine2(g.Vertical, x, da.Min.Y, x, da.Min.Y+da.Size.Y)
	}

horiz:
	if g.Horizontal.Color == nil {
		return
	}
	for _, tk := range plt.Y.Tick.Marker(plt.Y.Min, plt.Y.Max) {
		if tk.IsMinor() {
			continue
		}
		y := trY(tk.Value)
		da.StrokeLine2(g.Vertical, da.Min.X, y, da.Min.X+da.Size.X, y)
	}
}
<commit_msg>Fix some small bugs in the Grid plotter.<commit_after>// Copyright 2012 The Plotinum Authors. All rights reserved.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.

package plotter

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"image/color"
)

var (
	// DefaultGridLineStyle is the default style for grid lines.
	DefaultGridLineStyle = plot.LineStyle{
		Color: color.Gray{128},
		Width: vg.Points(0.25),
	}
)

// Grid implements the plot.Plotter interface, drawing
// a set of grid lines at the major tick marks.
type Grid struct {
	// Vertical is the style of the vertical lines.
	Vertical plot.LineStyle

	// Horizantal is the style of the horizontal lines.
	Horizontal plot.LineStyle
}

// NewGrid returns a new grid with both vertical and
// horizontal lines using the default grid line style.
func NewGrid() *Grid {
	return &Grid{
		Vertical:   DefaultGridLineStyle,
		Horizontal: DefaultGridLineStyle,
	}
}

// Plot implements the plot.Plotter interface.
func (g *Grid) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)

	if g.Vertical.Color == nil {
		goto horiz
	}
	for _, tk := range plt.X.Tick.Marker(plt.X.Min, plt.X.Max) {
		if tk.IsMinor() {
			continue
		}
		x := trX(tk.Value)
		da.StrokeLine2(g.Vertical, x, da.Min.Y, x, da.Min.Y+da.Size.Y)
	}

horiz:
	if g.Horizontal.Color == nil {
		return
	}
	for _, tk := range plt.Y.Tick.Marker(plt.Y.Min, plt.Y.Max) {
		if tk.IsMinor() {
			continue
		}
		y := trY(tk.Value)
		da.StrokeLine2(g.Horizontal, da.Min.X, y, da.Min.X+da.Size.X, y)
	}
}
<|endoftext|>


<commit_before>// Package main defines a solution for the task defined in README.md
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"sync"
)

// Cell represents a square in the game board.
type Cell struct {
	X int64 `json:"x"`
	Y int64 `json:"y"`
}

// Neighbours returns all neighbours on the board for this particular cell.
func (c *Cell) Neighbours() (ret [8]Cell) {

	nbrs := [][2]int64{
		{-1, -1}, {0, -1}, {1, -1},
		{-1, 0}, {1, 0},
		{-1, 1}, {0, 1}, {1, 1},
	}

	for ind, nbr := range nbrs {
		ret[ind].X = c.X + nbr[0]
		ret[ind].Y = c.Y + nbr[1]
	}

	return
}

// GameOfLifeHandler represents a http.Handler which defines the behaviour of a
// Conaway's Game of Life board via various HTTP endpoints.
type GameOfLifeHandler struct {

	// GameOfLifeHandler is also a mutex. This is so in order to protect the sensitive
	// map of living cells against write operations from different threads.
	sync.RWMutex

	// This handler multiplexer is used to decompose the task in different handlers for
	// each path defined in the task.
	mux *http.ServeMux

	// cells is a collection of all living cells in the current generation.
	// A map of cells is used because most of the operations are about searching for
	// living cells.
	cells map[Cell]struct{}

	generation int64
}

// NewGameOfLifeHandler returns a new GameOfLifeHandler which is prepopulated with cells passed
// in `cells`. It initializes the handler by creating a http.ServerMux and populating with the
// appropriate callbacks.
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
	gofh := &GameOfLifeHandler{}
	gofh.cells = make(map[Cell]struct{})

	for _, coords := range cells {
		cell := Cell{X: coords[0], Y: coords[1]}
		gofh.cells[cell] = struct{}{}
	}

	gofh.mux = http.NewServeMux()
	gofh.mux.HandleFunc("/cell/status/", RestrictMethodHandler("GET", gofh.handleCellStatus))
	gofh.mux.HandleFunc("/generation/", RestrictMethodHandler("GET", gofh.handleGeneration))
	gofh.mux.HandleFunc("/generation/evolve/", RestrictMethodHandler("POST", gofh.handleEvolve))
	gofh.mux.HandleFunc("/reset/", RestrictMethodHandler("POST", gofh.handleReset))
	gofh.mux.HandleFunc("/cells/", RestrictMethodHandler("POST", gofh.handleAddCells))

	return gofh
}

// ServeHTTP implements the http.Handler interface. It just calls the request multiplexer
// which will find the correct callback for this request.
func (gofh *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	gofh.mux.ServeHTTP(w, r)
}

func (gofh *GameOfLifeHandler) handleGeneration(w http.ResponseWriter, r *http.Request) {
	gofh.RLock()
	defer gofh.RUnlock()

	living := make([][2]int64, 0, len(gofh.cells))

	for cell, _ := range gofh.cells {
		living = append(living, [2]int64{cell.X, cell.Y})
	}

	// This annonymous is used only for its json attributes' tags. This way we can leave
	// the JSON creation to the standard library. It is way safer than trying to generate
	// correct json ourselves.
	resp := &struct {
		Gen    int64      `json:"generation"`
		Living [][2]int64 `json:"living"`
	}{
		Gen:    gofh.generation,
		Living: living,
	}

	respBytes, err := json.Marshal(resp)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error marshalling results: %s", err)
		return
	}

	if _, err := w.Write(respBytes); err != nil {
		// At point we cannot send a different Status Code and we cannot continue to write
		// in the response. The only sante thing is to log the error.
		log.Printf("Error writing response: %s", err)
	}
}

func (gofh *GameOfLifeHandler) handleEvolve(w http.ResponseWriter, r *http.Request) {

	// We will work without mutating the old board. This would have been very difficult. Instead,
	// a new board is created. Every cell which should be alive in the next generation will
	// be added to this new board.
	newBoard := make(map[Cell]struct{})

	// One of the rules says we have to spawn dead cells with appropriate number of neighbours.
	// We have to decide which dead cells to consider for spawning. Obviosuly, we cannot try
	// with all dead cells since they are infinate. We can make the observation that only
	// dead cells which have a living neighbour can spawn. So this map will keep exactly such cells.
	// Note that are using a map in order to remove any duplications.
	interestingDead := make(map[Cell]struct{})

	gofh.Lock()
	defer gofh.Unlock()

	// A small helper function which counts how many of the cells in the argument are alive.
	livingCells := func(neighbours [8]Cell) (count uint8) {
		for _, nbr := range neighbours {
			if _, ok := gofh.cells[nbr]; ok {
				count += 1
			}
		}
		return
	}

	// First pass. We decide which alive cells should live to see the next generation and
	// simultaniously populate the interestingDead map.
	for aliveCell, _ := range gofh.cells {
		neighbours := aliveCell.Neighbours()
		livingCount := livingCells(neighbours)

		if livingCount == 2 || livingCount == 3 {
			newBoard[aliveCell] = struct{}{} // stayes alive
		}

		for _, nbr := range neighbours {
			interestingDead[nbr] = struct{}{}
		}
	}

	// Second pass. We have all the dead cells which can possibly spawn.
	for deadCell, _ := range interestingDead {
		neighbours := deadCell.Neighbours()

		if livingCells(neighbours) == 3 {
			newBoard[deadCell] = struct{}{} // spawns
		}
	}

	// And it is here when we make the switch.
	gofh.cells = newBoard
	gofh.generation += 1
	w.WriteHeader(http.StatusNoContent)
}

func (gofh *GameOfLifeHandler) handleReset(w http.ResponseWriter, r *http.Request) {
	gofh.Lock()
	defer gofh.Unlock()

	gofh.generation = 0
	gofh.cells = make(map[Cell]struct{})
	w.WriteHeader(http.StatusNoContent)
}

func (gofh *GameOfLifeHandler) handleAddCells(w http.ResponseWriter, r *http.Request) {

	reqBytes, err := ioutil.ReadAll(r.Body)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error reading the request body: %s", err)
		return
	}

	defer r.Body.Close()

	added := []Cell{}

	if err := json.Unmarshal(reqBytes, &added); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error unmarshalling the request body: %s", err)
		return
	}

	gofh.Lock()
	defer gofh.Unlock()

	for _, cell := range added {
		gofh.cells[cell] = struct{}{}
	}

	w.WriteHeader(http.StatusCreated)
}

func (gofh *GameOfLifeHandler) handleCellStatus(w http.ResponseWriter, r *http.Request) {

	if err := r.ParseForm(); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	x, y := r.Form.Get("x"), r.Form.Get("y")

	intX, err := strconv.ParseInt(x, 10, 64)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	intY, err := strconv.ParseInt(y, 10, 64)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	cell := Cell{X: intX, Y: intY}

	gofh.RLock()
	defer gofh.RUnlock()

	if _, ok := gofh.cells[cell]; ok {
		fmt.Fprint(w, `{"alive": true}`)
	} else {
		fmt.Fprint(w, `{"alive": false}`)
	}
}

// RestrictMethodHandler is used as a decorator to restrict a http.HandlerFunction to only one
// HTTP method. Every other method will get Method Not Allowed as a response.
func RestrictMethodHandler(method string, handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != method {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		handler(w, r)
	}
}
<commit_msg>Task 05: generation evoling does not block reading<commit_after>// Package main defines a solution for the task defined in README.md
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"sync"
)

// Cell represents a square in the game board.
type Cell struct {
	X int64 `json:"x"`
	Y int64 `json:"y"`
}

// Neighbours returns all neighbours on the board for this particular cell.
func (c *Cell) Neighbours() (ret [8]Cell) {

	nbrs := [][2]int64{
		{-1, -1}, {0, -1}, {1, -1},
		{-1, 0}, {1, 0},
		{-1, 1}, {0, 1}, {1, 1},
	}

	for ind, nbr := range nbrs {
		ret[ind].X = c.X + nbr[0]
		ret[ind].Y = c.Y + nbr[1]
	}

	return
}

// GameOfLifeHandler represents a http.Handler which defines the behaviour of a
// Conaway's Game of Life board via various HTTP endpoints.
type GameOfLifeHandler struct {

	// GameOfLifeHandler is also a mutex. This is so in order to protect the sensitive
	// map of living cells against write operations from different threads.
	sync.RWMutex

	// writeMutex is used for synchronizing operations which change the current board during
	// the change.
	writeMutex sync.Mutex

	// This handler multiplexer is used to decompose the task in different handlers for
	// each path defined in the task.
	mux *http.ServeMux

	// cells is a collection of all living cells in the current generation.
	// A map of cells is used because most of the operations are about searching for
	// living cells.
	cells map[Cell]struct{}

	generation int64
}

// NewGameOfLifeHandler returns a new GameOfLifeHandler which is prepopulated with cells passed
// in `cells`. It initializes the handler by creating a http.ServerMux and populating with the
// appropriate callbacks.
func NewGameOfLifeHandler(cells [][2]int64) *GameOfLifeHandler {
	gofh := &GameOfLifeHandler{}
	gofh.cells = make(map[Cell]struct{})

	for _, coords := range cells {
		cell := Cell{X: coords[0], Y: coords[1]}
		gofh.cells[cell] = struct{}{}
	}

	gofh.mux = http.NewServeMux()
	gofh.mux.HandleFunc("/cell/status/", RestrictMethodHandler("GET", gofh.handleCellStatus))
	gofh.mux.HandleFunc("/generation/", RestrictMethodHandler("GET", gofh.handleGeneration))
	gofh.mux.HandleFunc("/generation/evolve/", RestrictMethodHandler("POST", gofh.handleEvolve))
	gofh.mux.HandleFunc("/reset/", RestrictMethodHandler("POST", gofh.handleReset))
	gofh.mux.HandleFunc("/cells/", RestrictMethodHandler("POST", gofh.handleAddCells))

	return gofh
}

// ServeHTTP implements the http.Handler interface. It just calls the request multiplexer
// which will find the correct callback for this request.
func (gofh *GameOfLifeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	gofh.mux.ServeHTTP(w, r)
}

func (gofh *GameOfLifeHandler) handleGeneration(w http.ResponseWriter, r *http.Request) {
	gofh.RLock()
	defer gofh.RUnlock()

	living := make([][2]int64, 0, len(gofh.cells))

	for cell, _ := range gofh.cells {
		living = append(living, [2]int64{cell.X, cell.Y})
	}

	// This annonymous is used only for its json attributes' tags. This way we can leave
	// the JSON creation to the standard library. It is way safer than trying to generate
	// correct json ourselves.
	resp := &struct {
		Gen    int64      `json:"generation"`
		Living [][2]int64 `json:"living"`
	}{
		Gen:    gofh.generation,
		Living: living,
	}

	respBytes, err := json.Marshal(resp)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error marshalling results: %s", err)
		return
	}

	if _, err := w.Write(respBytes); err != nil {
		// At point we cannot send a different Status Code and we cannot continue to write
		// in the response. The only sante thing is to log the error.
		log.Printf("Error writing response: %s", err)
	}
}

func (gofh *GameOfLifeHandler) handleEvolve(w http.ResponseWriter, r *http.Request) {

	// We will work without mutating the old board. This would have been very difficult. Instead,
	// a new board is created. Every cell which should be alive in the next generation will
	// be added to this new board.
	newBoard := make(map[Cell]struct{})
	oldBoard := make(map[Cell]struct{})

	// One of the rules says we have to spawn dead cells with appropriate number of neighbours.
	// We have to decide which dead cells to consider for spawning. Obviosuly, we cannot try
	// with all dead cells since they are infinate. We can make the observation that only
	// dead cells which have a living neighbour can spawn. So this map will keep exactly such cells.
	// Note that are using a map in order to remove any duplications.
	interestingDead := make(map[Cell]struct{})

	// A small helper function which counts how many of the cells in the argument are alive.
	livingCells := func(neighbours [8]Cell) (count uint8) {
		for _, nbr := range neighbours {
			if _, ok := oldBoard[nbr]; ok {
				count += 1
			}
		}
		return
	}

	gofh.writeMutex.Lock()
	defer gofh.writeMutex.Unlock()

	gofh.RLock()
	for aliveCell, _ := range gofh.cells {
		oldBoard[aliveCell] = struct{}{}
	}
	gofh.RUnlock()

	// First pass. We decide which alive cells should live to see the next generation and
	// simultaniously populate the interestingDead map.
	for aliveCell, _ := range oldBoard {
		neighbours := aliveCell.Neighbours()
		livingCount := livingCells(neighbours)

		if livingCount == 2 || livingCount == 3 {
			newBoard[aliveCell] = struct{}{} // stayes alive
		}

		for _, nbr := range neighbours {
			interestingDead[nbr] = struct{}{}
		}
	}

	// Second pass. We have all the dead cells which can possibly spawn.
	for deadCell, _ := range interestingDead {
		neighbours := deadCell.Neighbours()

		if livingCells(neighbours) == 3 {
			newBoard[deadCell] = struct{}{} // spawns
		}
	}

	gofh.Lock()
	defer gofh.Unlock()

	// And it is here when we make the switch.
	gofh.cells = newBoard
	gofh.generation += 1
	w.WriteHeader(http.StatusNoContent)
}

func (gofh *GameOfLifeHandler) handleReset(w http.ResponseWriter, r *http.Request) {
	gofh.writeMutex.Lock()
	defer gofh.writeMutex.Unlock()

	gofh.Lock()
	defer gofh.Unlock()

	gofh.generation = 0
	gofh.cells = make(map[Cell]struct{})
	w.WriteHeader(http.StatusNoContent)
}

func (gofh *GameOfLifeHandler) handleAddCells(w http.ResponseWriter, r *http.Request) {

	reqBytes, err := ioutil.ReadAll(r.Body)

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Error reading the request body: %s", err)
		return
	}

	defer r.Body.Close()

	added := []Cell{}

	if err := json.Unmarshal(reqBytes, &added); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error unmarshalling the request body: %s", err)
		return
	}

	gofh.writeMutex.Lock()
	defer gofh.writeMutex.Unlock()

	gofh.Lock()
	defer gofh.Unlock()

	for _, cell := range added {
		gofh.cells[cell] = struct{}{}
	}

	w.WriteHeader(http.StatusCreated)
}

func (gofh *GameOfLifeHandler) handleCellStatus(w http.ResponseWriter, r *http.Request) {

	if err := r.ParseForm(); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	x, y := r.Form.Get("x"), r.Form.Get("y")

	intX, err := strconv.ParseInt(x, 10, 64)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	intY, err := strconv.ParseInt(y, 10, 64)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	cell := Cell{X: intX, Y: intY}

	gofh.RLock()
	defer gofh.RUnlock()

	if _, ok := gofh.cells[cell]; ok {
		fmt.Fprint(w, `{"alive": true}`)
	} else {
		fmt.Fprint(w, `{"alive": false}`)
	}
}

// RestrictMethodHandler is used as a decorator to restrict a http.HandlerFunction to only one
// HTTP method. Every other method will get Method Not Allowed as a response.
func RestrictMethodHandler(method string, handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != method {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		handler(w, r)
	}
}
<|endoftext|>