<commit_before>/*******************************************************************************
* Copyright (C) Zenoss, Inc. 2013, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
*******************************************************************************/

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.
package agent

import (
	"encoding/json"
	"fmt"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/client"
	"log"
	"os/exec"
	"strings"
	"time"
)

// An instance of the control plane Agent.
type HostAgent struct {
	master          string               // the connection string to the master agent
	hostId          string               // the hostID of the current host
	currentServices map[string]*exec.Cmd // the current running services
}

// assert that this implemenents the Agent interface
var _ serviced.Agent = &HostAgent{}

// Create a new HostAgent given the connection string to the
func NewHostAgent(master string) (agent *HostAgent, err error) {
	agent = &HostAgent{}
	agent.master = master
	hostId, err := serviced.HostId()
	if err != nil {
		panic("Could not get hostid")
	}
	agent.hostId = hostId
	agent.currentServices = make(map[string]*exec.Cmd)
	go agent.start()
	return agent, err
}

// Update the current state of a service. client is the ControlPlane client,
// service is the reference to the service being updated, and serviceState is
// the actual service instance being updated.
func (a *HostAgent) updateCurrentState(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {
	// get docker status

	containerState, err := getDockerState(serviceState.DockerId)
	if err != nil {
		return err
	}
	if !containerState.State.Running {
		serviceState.Terminated = time.Now()
		var unused int
		err = controlClient.UpdateServiceState(*serviceState, &unused)
	}
	return
}

// Terminate a particular service instance (serviceState) on the localhost.
func (a *HostAgent) terminateInstance(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {
	// get docker status

	cmd := exec.Command("docker", "kill", serviceState.DockerId)
	err = cmd.Run()
	if err != nil {
		log.Printf("problem killing container instance %s", serviceState.DockerId)
		return err
	}
	serviceState.Terminated = time.Now()
	var unused int
	err = controlClient.UpdateServiceState(*serviceState, &unused)
	if err != nil {
		log.Printf("Problem updating service state: %v", err)
	}
	return
}

// Get the state of the docker container given the dockerId
func getDockerState(dockerId string) (containerState serviced.ContainerState, err error) {
	// get docker status

	cmd := exec.Command("docker", "inspect", dockerId)
	output, err := cmd.Output()
	if err != nil {
		log.Printf("problem getting docker state")
		return containerState, err
	}
	containerStates := make([]*serviced.ContainerState, 0)
	err = json.Unmarshal(output, &containerStates)
	if len(containerStates) < 1 {
		log.Printf("bad state  happened: %v,   \n\n\n%s", err, string(output))
		return containerState, serviced.ControlPlaneError{"no state"}
	}
	return *containerStates[0], err
}

// Start a service instance and update the CP with the state.
func (a *HostAgent) startService(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {

	cmdString := fmt.Sprintf("docker run -d %s %s", service.ImageId, service.Startup)
	log.Printf("Starting: %s", cmdString)

	cmd := exec.Command("bash", "-c", cmdString)
	output, err := cmd.Output()
	if err != nil {
		log.Printf("Problem starting service: %v, %s", err, string(output))
		return err
	}
	dockerId := strings.TrimSpace(string(output))
	serviceState.DockerId = dockerId
	containerState, err := getDockerState(dockerId)
	if err != nil {
		log.Printf("Problem getting service state :%v", err)
		return err
	}
	serviceState.Started = time.Now()
	serviceState.PrivateIp = containerState.NetworkSettings.IPAddress
	var unused int
	err = controlClient.UpdateServiceState(*serviceState, &unused)
	if err != nil {
		log.Printf("Problem updating service state: %v", err)
	}
	return err
}

// main loop of the HostAgent
func (a *HostAgent) start() {
	log.Printf("Starting HostAgent\n")
	for {
		// create a wrapping function so that client.Close() can be handled via defer
		func() {
			controlClient, err := client.NewControlClient(a.master)
			if err != nil {
				log.Printf("Could not start ControlPlane client %v", err)
				return
			}
			defer controlClient.Close()
			for {
				time.Sleep(time.Second * 10)
				var services []*serviced.Service
				// Get the services that should be running on this host
				err = controlClient.GetServicesForHost(a.hostId, &services)
				if err != nil {
					log.Printf("Could not get services for this host")
					break
				}

				// iterate over this host's services
				for _, service := range services {

					// find out if the master thinks there are
					var serviceStates []*serviced.ServiceState
					err = controlClient.GetServiceStates(service.Id, &serviceStates)
					if err != nil {
						if strings.Contains(err.Error(), "Not found") {
							continue
						}
						log.Printf("Got an error getting service states: %v", err)
						break
					}
					for _, serviceInstance := range serviceStates {
						switch {
						case serviceInstance.Started.Year() <= 1:
							err = a.startService(controlClient, service, serviceInstance)
						case serviceInstance.Started.Year() > 1 && serviceInstance.Terminated.Year() <= 1:
							err = a.updateCurrentState(controlClient, service, serviceInstance)
						case serviceInstance.Started.Year() > 1 && serviceInstance.Terminated.Year() == 2:
							err = a.terminateInstance(controlClient, service, serviceInstance)
						}
						if err != nil {
							log.Printf("Problem servicing state %s,  %v", service.Name, err)
						}
					}
				}
			}
		}()
	}
}

// Create a Host object from the host this function is running on.
func (a *HostAgent) GetInfo(unused int, host *serviced.Host) error {
	hostInfo, err := serviced.CurrentContextAsHost("UNKNOWN")
	if err != nil {
		return err
	}
	*host = *hostInfo
	return nil
}
<commit_msg>make comment make sense.<commit_after>/*******************************************************************************
* Copyright (C) Zenoss, Inc. 2013, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
*******************************************************************************/

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.
package agent

import (
	"encoding/json"
	"fmt"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/client"
	"log"
	"os/exec"
	"strings"
	"time"
)

// An instance of the control plane Agent.
type HostAgent struct {
	master          string               // the connection string to the master agent
	hostId          string               // the hostID of the current host
	currentServices map[string]*exec.Cmd // the current running services
}

// assert that this implemenents the Agent interface
var _ serviced.Agent = &HostAgent{}

// Create a new HostAgent given the connection string to the
func NewHostAgent(master string) (agent *HostAgent, err error) {
	agent = &HostAgent{}
	agent.master = master
	hostId, err := serviced.HostId()
	if err != nil {
		panic("Could not get hostid")
	}
	agent.hostId = hostId
	agent.currentServices = make(map[string]*exec.Cmd)
	go agent.start()
	return agent, err
}

// Update the current state of a service. client is the ControlPlane client,
// service is the reference to the service being updated, and serviceState is
// the actual service instance being updated.
func (a *HostAgent) updateCurrentState(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {
	// get docker status

	containerState, err := getDockerState(serviceState.DockerId)
	if err != nil {
		return err
	}
	if !containerState.State.Running {
		serviceState.Terminated = time.Now()
		var unused int
		err = controlClient.UpdateServiceState(*serviceState, &unused)
	}
	return
}

// Terminate a particular service instance (serviceState) on the localhost.
func (a *HostAgent) terminateInstance(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {
	// get docker status

	cmd := exec.Command("docker", "kill", serviceState.DockerId)
	err = cmd.Run()
	if err != nil {
		log.Printf("problem killing container instance %s", serviceState.DockerId)
		return err
	}
	serviceState.Terminated = time.Now()
	var unused int
	err = controlClient.UpdateServiceState(*serviceState, &unused)
	if err != nil {
		log.Printf("Problem updating service state: %v", err)
	}
	return
}

// Get the state of the docker container given the dockerId
func getDockerState(dockerId string) (containerState serviced.ContainerState, err error) {
	// get docker status

	cmd := exec.Command("docker", "inspect", dockerId)
	output, err := cmd.Output()
	if err != nil {
		log.Printf("problem getting docker state")
		return containerState, err
	}
	containerStates := make([]*serviced.ContainerState, 0)
	err = json.Unmarshal(output, &containerStates)
	if len(containerStates) < 1 {
		log.Printf("bad state  happened: %v,   \n\n\n%s", err, string(output))
		return containerState, serviced.ControlPlaneError{"no state"}
	}
	return *containerStates[0], err
}

// Start a service instance and update the CP with the state.
func (a *HostAgent) startService(controlClient *client.ControlClient, service *serviced.Service, serviceState *serviced.ServiceState) (err error) {

	cmdString := fmt.Sprintf("docker run -d %s %s", service.ImageId, service.Startup)
	log.Printf("Starting: %s", cmdString)

	cmd := exec.Command("bash", "-c", cmdString)
	output, err := cmd.Output()
	if err != nil {
		log.Printf("Problem starting service: %v, %s", err, string(output))
		return err
	}
	dockerId := strings.TrimSpace(string(output))
	serviceState.DockerId = dockerId
	containerState, err := getDockerState(dockerId)
	if err != nil {
		log.Printf("Problem getting service state :%v", err)
		return err
	}
	serviceState.Started = time.Now()
	serviceState.PrivateIp = containerState.NetworkSettings.IPAddress
	var unused int
	err = controlClient.UpdateServiceState(*serviceState, &unused)
	if err != nil {
		log.Printf("Problem updating service state: %v", err)
	}
	return err
}

// main loop of the HostAgent
func (a *HostAgent) start() {
	log.Printf("Starting HostAgent\n")
	for {
		// create a wrapping function so that client.Close() can be handled via defer
		func() {
			controlClient, err := client.NewControlClient(a.master)
			if err != nil {
				log.Printf("Could not start ControlPlane client %v", err)
				return
			}
			defer controlClient.Close()
			for {
				time.Sleep(time.Second * 10)
				var services []*serviced.Service
				// Get the services that should be running on this host
				err = controlClient.GetServicesForHost(a.hostId, &services)
				if err != nil {
					log.Printf("Could not get services for this host")
					break
				}

				// iterate over this host's services
				for _, service := range services {

					// find current service states defined on the master
					var serviceStates []*serviced.ServiceState
					err = controlClient.GetServiceStates(service.Id, &serviceStates)
					if err != nil {
						if strings.Contains(err.Error(), "Not found") {
							continue
						}
						log.Printf("Got an error getting service states: %v", err)
						break
					}
					for _, serviceInstance := range serviceStates {
						switch {
						case serviceInstance.Started.Year() <= 1:
							err = a.startService(controlClient, service, serviceInstance)
						case serviceInstance.Started.Year() > 1 && serviceInstance.Terminated.Year() <= 1:
							err = a.updateCurrentState(controlClient, service, serviceInstance)
						case serviceInstance.Started.Year() > 1 && serviceInstance.Terminated.Year() == 2:
							err = a.terminateInstance(controlClient, service, serviceInstance)
						}
						if err != nil {
							log.Printf("Problem servicing state %s,  %v", service.Name, err)
						}
					}
				}
			}
		}()
	}
}

// Create a Host object from the host this function is running on.
func (a *HostAgent) GetInfo(unused int, host *serviced.Host) error {
	hostInfo, err := serviced.CurrentContextAsHost("UNKNOWN")
	if err != nil {
		return err
	}
	*host = *hostInfo
	return nil
}
<|endoftext|>


<commit_before>package disk

import (
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"os"
)

var (
	crc32cTable       = crc32.MakeTable(crc32.Castagnoli)
	crc32Len          = int64(4)
	// ErrBadPayloadSize indicates the input payload size is invalid
	ErrBadPayloadSize = errors.New("disk: bad payload size")
	// ErrInvalidCRC indicates there is not CRC can be found in the block
	ErrInvalidCRC = errors.New("disk: not a valid CRC")
)

// ReadBlock reads a full block into p from rs. len(p) must be smaller than (bs - crc32Len).
// The checksum of the block is calculated and verified.
// ErrInvalidCRC is returned if the checksum is invalid.
func ReadBlock(rs io.ReadSeeker, p []byte, index, bs int64 ) error {
	if int64(len(p)) != bs-crc32Len {
		return ErrBadPayloadSize
	}
	buf := make([]byte, bs)
	rs.Seek(index*bs, os.SEEK_SET)
	n, err := rs.Read(buf)
	if err != nil && err != io.EOF {
		return err
	}
	// Cannot read crc
	if n < 4 {
		return ErrInvalidCRC
	}
	payload := buf[crc32Len:]
	crc := binary.BigEndian.Uint32(buf[:crc32Len])
	// Invalid crc
	if crc != crc32.Checksum(payload, crc32cTable) {
		return ErrInvalidCRC
	}
	copy(p, payload)
	return nil
}

// writeBlock writes a full or partial block into ws. len(p) must be smaller than (bs - crc32Len).
// Each block contains a crc32Len bytes crc32c of the payload and a (bs-crc32Len)
// bytes payload. Any error encountered is returned.
// It is caller's responsibility to ensure that only the last block in the file has
// len(p) < bs - crc32Len
func writeBlock(ws io.WriteSeeker, index, bs int64, p []byte) error {
	if int64(len(p)) > bs-crc32Len {
		return ErrBadPayloadSize
	}

	// seek to the beginning of the block
	_, err := ws.Seek(index*bs, os.SEEK_SET)
	if err != nil {
		return nil
	}

	// write crc32c
	// TODO: reuse buffer
	b := make([]byte, crc32Len)
	binary.BigEndian.PutUint32(b, crc32.Checksum(p, crc32cTable))
	_, err = ws.Write(b)
	if err != nil {
		return err
	}

	// write payload
	_, err = ws.Write(p)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>support partial read<commit_after>package disk

import (
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"os"
)

var (
	crc32cTable       = crc32.MakeTable(crc32.Castagnoli)
	crc32Len          = int64(4)
	// ErrBadPayloadSize indicates the input payload size is invalid
	ErrBadPayloadSize = errors.New("disk: bad payload size")
	// ErrBadCRC indicates there is not CRC can be found in the block
	ErrBadCRC = errors.New("disk: not a valid CRC")
)

// ReadBlock reads a full block into p from rs. len(p) must be smaller than (bs - crc32Len).
// The checksum of the block is calculated and verified.
// ErrBadCRC is returned if the checksum is invalid.
func ReadBlock(rs io.ReadSeeker, p []byte, index, bs int64) (int64, error) {
	if int64(len(p)) > bs-crc32Len {
		return 0, ErrBadPayloadSize
	}
	b := make([]byte, crc32Len)
	rs.Seek(index*bs, os.SEEK_SET)
	n, err := rs.Read(b)
	if err != nil && err != io.EOF {
		return 0, err
	}
	// Cannot read crc
	if n < 4 {
		return 0, ErrBadCRC
	}
	n, err = rs.Read(p)
	if err != nil && err != io.EOF {
		return 0, err
	}
	crc := binary.BigEndian.Uint32(b)
	// Invalid crc
	if crc != crc32.Checksum(p[:n], crc32cTable) {
		return 0, ErrBadCRC
	}
	return int64(n) - crc32Len, nil
}

// writeBlock writes a full or partial block into ws. len(p) must be smaller than (bs - crc32Len).
// Each block contains a crc32Len bytes crc32c of the payload and a (bs-crc32Len)
// bytes payload. Any error encountered is returned.
// It is caller's responsibility to ensure that only the last block in the file has
// len(p) < bs - crc32Len
func writeBlock(ws io.WriteSeeker, index, bs int64, p []byte) error {
	if int64(len(p)) > bs-crc32Len {
		return ErrBadPayloadSize
	}

	// seek to the beginning of the block
	_, err := ws.Seek(index*bs, os.SEEK_SET)
	if err != nil {
		return nil
	}

	// write crc32c
	// TODO: reuse buffer
	b := make([]byte, crc32Len)
	binary.BigEndian.PutUint32(b, crc32.Checksum(p, crc32cTable))
	_, err = ws.Write(b)
	if err != nil {
		return err
	}

	// write payload
	_, err = ws.Write(p)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package loadspec

import (
	"bufio"
	"encoding/json"
	"net/url"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/danielfireman/esperf/loadspec"
	"github.com/spf13/cobra"
)

var parseSlowlogCmd = &cobra.Command{
	Use:   "parseslowlog",
	Short: "Outputs a replayable loadspec based on the passed-in slowlog and parameters.",
	Long:  "Outputs a replayable loadspec based on the passed-in slowlog and parameters.",
	RunE: func(cmd *cobra.Command, args []string) error {
		// These constants need to be in sync with the regular expression bellow.
		const (
			logTypeField    = "log_type"
			hostField       = "host"
			timestampField  = "ts"
			indexField      = "index"
			typesField      = "types"
			searchTypeField = "search_type"
			sourceField     = "source"
			numFields       = 6
		)

		var urlArg string
		if len(args) > 0 {
			urlArg = args[0]
		}
		// Regular expression setup.
		// The solution is based on regexp's named matches. For each entry, we build a map of
		// of fields and values. This map is encoded as json and (buffered) written to stdout.
		re, err := regexp.Compile(`\[(?P<ts>[^]]+)\].?\[.*\].?\[(?P<log_type>[^]]+)\].?\[(?P<host>[^]]+)\].?\[(?P<index>[^]]+)\].?\[.*\].*types\[(?P<types>[^]]+)\].*search_type\[(?P<search_type>[^]]+)\].*source\[(?P<source>[^]]+)\]`)
		if err != nil {
			return err
		}
		subExpNames := re.SubexpNames()

		var entries loadspec.ByDelaySinceLastNanos
		fields := make(map[string]string, numFields)
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			// Building a map using named matches.
			matches := re.FindAllStringSubmatch(scanner.Text(), -1)[0]
			for i, n := range matches {
				// Removing the first match, which is the whole line.
				if i > 0 {
					fields[subExpNames[i]] = n
				}
			}
			// For now, only processing queries.
			if fields[logTypeField] != "index.search.slowlog.query" {
				continue
			}
			entry := loadspec.Entry{Source: fields[sourceField]}
			// Making timestamp relative to the previous one. Simulate inter-arrival time can be as easy
			// as a time.Sleep and trigger a goroutine.
			t, err := time.Parse(timeLayout, strings.Replace(fields[timestampField], ",", ".", 1))
			if err != nil {
				return err
			}
			// Keeping timestamp here for post-processing bellow.
			entry.DelaySinceLastNanos = t.UnixNano()
			// Host argument is treated as full URL. This keeps consistency between here and gen command.
			var u *url.URL
			if urlArg != "" {
				u, err = url.Parse(urlArg)
				if err != nil {
					return err
				}
			} else {
				path := []string{fields[hostField], fields[indexField], fields[typesField], "_search"}
				u, err = url.Parse(strings.Join(path, "/"))
				if err != nil {
					return err
				}
				q := u.Query()
				if fields[searchTypeField] != "" {
					q.Set("search_type", strings.ToLower(fields[searchTypeField]))
				}
				u.RawQuery = q.Encode()
			}
			entry.URL = u.String()
			entries = append(entries, &entry)
		}
		if err := scanner.Err(); err != nil {
			return err
		}
		// Slow log entries are not guaranteed to be timestamp ordered.
		sort.Sort(entries)

		// Writer and encoding configuration.
		writer := bufio.NewWriter(os.Stdout)
		defer writer.Flush()
		enc := json.NewEncoder(writer)
		var previousTimestamp, currTimestamp int64
		for i, e := range entries {
			currTimestamp = e.DelaySinceLastNanos
			if i == 0 {
				e.DelaySinceLastNanos = 0
			} else {
				e.DelaySinceLastNanos -= previousTimestamp
			}
			previousTimestamp = currTimestamp
			if err := enc.Encode(&e); err != nil {
				return err
			}
		}
		return nil
	},
}
<commit_msg>Fixing parseslowlog regular expression to deal properly with very complex sources<commit_after>package loadspec

import (
	"bufio"
	"encoding/json"
	"net/url"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"

	"github.com/danielfireman/esperf/loadspec"
	"github.com/spf13/cobra"
)

var parseSlowlogCmd = &cobra.Command{
	Use:   "parseslowlog",
	Short: "Outputs a replayable loadspec based on the passed-in slowlog and parameters.",
	Long:  "Outputs a replayable loadspec based on the passed-in slowlog and parameters.",
	RunE: func(cmd *cobra.Command, args []string) error {
		// These constants need to be in sync with the regular expression bellow.
		const (
			logTypeField    = "log_type"
			hostField       = "host"
			timestampField  = "ts"
			indexField      = "index"
			typesField      = "types"
			searchTypeField = "search_type"
			sourceField     = "source"
			numFields       = 6
		)

		var urlArg string
		if len(args) > 0 {
			urlArg = args[0]
		}
		// Regular expression setup.
		// The solution is based on regexp's named matches. For each entry, we build a map of
		// of fields and values. This map is encoded as json and (buffered) written to stdout.
		re, err := regexp.Compile(`\[(?P<ts>[^]]+)\].?\[.*\].?\[(?P<log_type>[^]]+)\].?\[(?P<host>[^]]+)\].?\[(?P<index>[^]]+)\].?\[.*\].*types\[(?P<types>[^]]+)\].*search_type\[(?P<search_type>[^]]+)\].*source\[(?P<source>.*)\], extra_source`)
		if err != nil {
			return err
		}
		subExpNames := re.SubexpNames()

		var entries loadspec.ByDelaySinceLastNanos
		fields := make(map[string]string, numFields)
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			// Building a map using named matches.
			matches := re.FindAllStringSubmatch(scanner.Text(), -1)[0]
			for i, n := range matches {
				// Removing the first match, which is the whole line.
				if i > 0 {
					fields[subExpNames[i]] = n
				}
			}
			// For now, only processing queries.
			if fields[logTypeField] != "index.search.slowlog.query" {
				continue
			}
			entry := loadspec.Entry{Source: fields[sourceField]}
			// Making timestamp relative to the previous one. Simulate inter-arrival time can be as easy
			// as a time.Sleep and trigger a goroutine.
			t, err := time.Parse(timeLayout, strings.Replace(fields[timestampField], ",", ".", 1))
			if err != nil {
				return err
			}
			// Keeping timestamp here for post-processing bellow.
			entry.DelaySinceLastNanos = t.UnixNano()
			// Host argument is treated as full URL. This keeps consistency between here and gen command.
			var u *url.URL
			if urlArg != "" {
				u, err = url.Parse(urlArg)
				if err != nil {
					return err
				}
			} else {
				path := []string{fields[hostField], fields[indexField], fields[typesField], "_search"}
				u, err = url.Parse(strings.Join(path, "/"))
				if err != nil {
					return err
				}
				q := u.Query()
				if fields[searchTypeField] != "" {
					q.Set("search_type", strings.ToLower(fields[searchTypeField]))
				}
				u.RawQuery = q.Encode()
			}
			entry.URL = u.String()
			entries = append(entries, &entry)
		}
		if err := scanner.Err(); err != nil {
			return err
		}
		// Slow log entries are not guaranteed to be timestamp ordered.
		sort.Sort(entries)

		// Writer and encoding configuration.
		writer := bufio.NewWriter(os.Stdout)
		defer writer.Flush()
		enc := json.NewEncoder(writer)
		var previousTimestamp, currTimestamp int64
		for i, e := range entries {
			currTimestamp = e.DelaySinceLastNanos
			if i == 0 {
				e.DelaySinceLastNanos = 0
			} else {
				e.DelaySinceLastNanos -= previousTimestamp
			}
			previousTimestamp = currTimestamp
			if err := enc.Encode(&e); err != nil {
				return err
			}
		}
		return nil
	},
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google LLC

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 cmd

import (
	"context"
	"fmt"
	"io"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// NewCmdBuild describes the CLI command to build artifacts.
func NewCmdBuild(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "build",
		Short: "Builds the artifacts",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return build(out, filename)
		},
	}
	AddRunDevFlags(cmd)
	return cmd
}

func build(out io.Writer, filename string) error {
	ctx := context.Background()

	config, err := readConfiguration(filename)
	if err != nil {
		return errors.Wrap(err, "reading configuration")
	}

	runner, err := runner.NewForConfig(opts, config)
	if err != nil {
		return errors.Wrap(err, "creating runner")
	}

	bRes, err := runner.Build(ctx, out, runner.Tagger, config.Build.Artifacts)
	if err != nil {
		return errors.Wrap(err, "build step")
	}

	for _, build := range bRes {
		fmt.Fprintln(out, build.ImageName, "->", build.Tag)
	}

	return err
}
<commit_msg>Add --output format flag to `skaffold build`<commit_after>/*
Copyright 2018 Google LLC

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 cmd

import (
	"context"
	"io"

	"github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/flags"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var buildFormatFlag = flags.NewTemplateFlag("{{range .Builds}}{{.ImageName}} -> {{.Tag}}\n{{end}}", BuildOutput{})

// NewCmdBuild describes the CLI command to build artifacts.
func NewCmdBuild(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "build",
		Short: "Builds the artifacts",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runBuild(out, filename)
		},
	}
	AddRunDevFlags(cmd)
	cmd.Flags().VarP(buildFormatFlag, "output", "o", buildFormatFlag.Usage())
	return cmd
}

// BuildOutput is the output of `skaffold build`.
type BuildOutput struct {
	Builds []build.Build
}

func runBuild(out io.Writer, filename string) error {
	ctx := context.Background()

	config, err := readConfiguration(filename)
	if err != nil {
		return errors.Wrap(err, "reading configuration")
	}

	runner, err := runner.NewForConfig(opts, config)
	if err != nil {
		return errors.Wrap(err, "creating runner")
	}

	bRes, err := runner.Build(ctx, out, runner.Tagger, config.Build.Artifacts)
	if err != nil {
		return errors.Wrap(err, "build step")
	}

	cmdOut := BuildOutput{Builds: bRes}
	if err := buildFormatFlag.Template().Execute(out, cmdOut); err != nil {
		return errors.Wrap(err, "executing template")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"

	"github.com/DataDog/datadog-go/statsd"
	dto "github.com/prometheus/client_model/go"
	"github.com/prometheus/common/expfmt"
)

func main() {
	flag.Parse()

	c, _ := statsd.New("127.0.0.1:8200")

	resp, _ := http.Get("http://localhost:9090/metrics")
	d := expfmt.NewDecoder(resp.Body, expfmt.FmtText)
	var mf dto.MetricFamily
	for {
		err := d.Decode(&mf)
		if err != nil {
			break
		}

		switch mf.GetType() {
		case dto.MetricType_COUNTER:
			for _, counter := range mf.GetMetric() {
				var tags []string
				labels := counter.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				c.Count(mf.GetName(), int64(counter.GetCounter().GetValue()), tags, 1.0)
			}
		case dto.MetricType_GAUGE:
			for _, gauge := range mf.GetMetric() {
				var tags []string
				labels := gauge.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				c.Gauge(mf.GetName(), float64(gauge.GetGauge().GetValue()), tags, 1.0)
			}
		case dto.MetricType_HISTOGRAM:
			for _, histo := range mf.GetMetric() {
				var tags []string
				labels := histo.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				hname := mf.GetName()
				summ := histo.GetSummary()
				c.Gauge(fmt.Sprintf("%s.sum", hname), summ.GetSampleSum(), tags, 1.0)
				c.Gauge(fmt.Sprintf("%s.count", hname), float64(summ.GetSampleCount()), tags, 1.0)
				for _, quantile := range summ.GetQuantile() {
					// TODO Fix this formatting
					c.Gauge(fmt.Sprintf("%s.%fpercentile", hname, quantile.GetQuantile()), quantile.GetValue(), tags, 1.0)
				}
			}
		}
	}
}
<commit_msg>Add flags for options.<commit_after>package main

import (
	"flag"
	"fmt"
	"math"
	"net/http"
	"time"

	"github.com/DataDog/datadog-go/statsd"
	"github.com/Sirupsen/logrus"
	dto "github.com/prometheus/client_model/go"
	"github.com/prometheus/common/expfmt"
)

var (
	debug       = flag.Bool("d", false, "Enable debug mode")
	metricsHost = flag.String("h", "http://localhost:9090/metrics", "The full URL — like 'http://localhost:9090/metrics' to query for Prometheus metrics.")
	interval    = flag.String("i", "10s", "The interval at which to query. Value must be parseable by time.ParseDuration (https://golang.org/pkg/time/#ParseDuration).")
	statsHost   = flag.String("s", "127.0.0.1:8126", "The host and port — like '127.0.0.1:8126' — to send our metrics to.")
)

func main() {
	flag.Parse()

	c, _ := statsd.New(*statsHost)

	if *debug {
		logrus.SetLevel(logrus.DebugLevel)
	}
	logrus.Debug("HELLO")

	i, err := time.ParseDuration(*interval)
	if err != nil {
		logrus.WithError(err).Fatalf("Failed to parse interval '%s'", *interval)
	}

	ticker := time.NewTicker(i)
	for _ = range ticker.C {
		collect(c)
	}
}

func collect(c *statsd.Client) {
	logrus.WithFields(logrus.Fields{
		"stats_host":   *statsHost,
		"metrics_host": *metricsHost,
	}).Debug("Beginning collection")

	resp, _ := http.Get(*metricsHost)
	d := expfmt.NewDecoder(resp.Body, expfmt.FmtText)
	var mf dto.MetricFamily
	for {
		err := d.Decode(&mf)
		if err != nil {
			logrus.WithError(err).Warn("Failed to decode a metric")
			break
		}

		switch mf.GetType() {
		case dto.MetricType_COUNTER:
			for _, counter := range mf.GetMetric() {
				var tags []string
				labels := counter.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				c.Count(mf.GetName(), int64(counter.GetCounter().GetValue()), tags, 1.0)
			}
		case dto.MetricType_GAUGE:
			for _, gauge := range mf.GetMetric() {
				var tags []string
				labels := gauge.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				c.Gauge(mf.GetName(), float64(gauge.GetGauge().GetValue()), tags, 1.0)
			}
		case dto.MetricType_HISTOGRAM, dto.MetricType_SUMMARY:
			for _, histo := range mf.GetMetric() {
				var tags []string
				labels := histo.GetLabel()
				for _, pair := range labels {
					tags = append(tags, fmt.Sprintf("%s:%s", pair.GetName(), pair.GetValue()))
				}
				hname := mf.GetName()
				summ := histo.GetSummary()
				c.Gauge(fmt.Sprintf("%s.sum", hname), summ.GetSampleSum(), tags, 1.0)
				c.Gauge(fmt.Sprintf("%s.count", hname), float64(summ.GetSampleCount()), tags, 1.0)
				for _, quantile := range summ.GetQuantile() {
					v := quantile.GetValue()
					if !math.IsNaN(v) {
						c.Gauge(fmt.Sprintf("%s.%dpercentile", hname, int(quantile.GetQuantile()*100)), v, tags, 1.0)
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package logrus

import (
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/burke/ttyutils"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
)

type TextFormatter struct {
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
	var serialized []byte

	levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]
	levelColor := blue

	if entry.Data["level"] == "warning" {
		levelColor = yellow
	} else if entry.Data["level"] == "fatal" ||
		entry.Data["level"] == "panic" {
		levelColor = red
	}

	if ttyutils.IsTerminal(os.Stdout.Fd()) {
		serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m[%04d] %-45s ", levelColor, levelText, miniTS(), entry.Data["msg"]))...)
	}

	keys := make([]string, 0)
	for k, _ := range entry.Data {
		if k != "level" && k != "time" && k != "msg" {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	first := true
	for _, k := range keys {
		v := entry.Data[k]
		if first {
			first = false
		} else {
			serialized = append(serialized, ' ')
		}
		serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m=%v", levelColor, k, v))...)
	}

	return append(serialized, '\n'), nil
}
<commit_msg>text_formatter: change to simpler k-v when no tty<commit_after>package logrus

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/burke/ttyutils"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
)

type TextFormatter struct {
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
	var serialized []byte

	if ttyutils.IsTerminal(os.Stdout.Fd()) {
		levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]

		levelColor := blue

		if entry.Data["level"] == "warning" {
			levelColor = yellow
		} else if entry.Data["level"] == "fatal" ||
			entry.Data["level"] == "panic" {
			levelColor = red
		}

		serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m[%04d] %-45s ", levelColor, levelText, miniTS(), entry.Data["msg"]))...)

		keys := make([]string, 0)
		for k, _ := range entry.Data {
			if k != "level" && k != "time" && k != "msg" {
				keys = append(keys, k)
			}
		}
		sort.Strings(keys)
		first := true
		for _, k := range keys {
			v := entry.Data[k]
			if first {
				first = false
			} else {
				serialized = append(serialized, ' ')
			}
			serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m=%v", levelColor, k, v))...)
		}
	} else {
		serialized = f.AppendKeyValue(serialized, "time", entry.Data["time"].(string))
		serialized = f.AppendKeyValue(serialized, "level", entry.Data["level"].(string))
		serialized = f.AppendKeyValue(serialized, "msg", entry.Data["msg"].(string))

		for key, value := range entry.Data {
			if key != "time" && key != "level" && key != "msg" {
				serialized = append(serialized, []byte(fmt.Sprintf("%s=%s ",
					f.ToString(key, false), f.ToString(value, true)))...)
			}
		}
	}

	return append(serialized, '\n'), nil
}

func (f *TextFormatter) AppendKeyValue(serialized []byte, key, value string) []byte {
	return append(serialized, []byte(fmt.Sprintf("%s=%s ",
		f.ToString(key, false), f.ToString(value, true)))...)
}

func (f *TextFormatter) ToString(value interface{}, escapeStrings bool) string {
	switch value.(type) {
	default:
		if escapeStrings {
			return fmt.Sprintf("'%s'", value)
		} else {
			return fmt.Sprintf("%s", value)
		}
	case int:
		return fmt.Sprintf("%s", strconv.Itoa(value.(int)))
	case uint64:
		return fmt.Sprintf("%s", strconv.FormatUint(value.(uint64), 10))
	case bool:
		return fmt.Sprintf("%s", strconv.FormatBool(value.(bool)))
	}
}
<|endoftext|>


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

package integration

// KubectlClusterManager represents a kubectl cluster
// Requires two test environments:
// kubectlcluster with the cluster name
// kubectluser with the cluster user name
type KubectlClusterManager struct {
	env *Environment
}

func (m *KubectlClusterManager) Name() string {
	return "kubectl"
}

func (m *KubectlClusterManager) Provisioner() string {
	return "kubernetes"
}

func (m *KubectlClusterManager) Start() *Result {
	return &Result{}
}

func (m *KubectlClusterManager) Delete() *Result {
	return &Result{}
}

func (m *KubectlClusterManager) certificateFiles() map[string]string {
	kubectl := NewCommand("kubectl", "config", "view", "-o").WithArgs
	res := kubectl("jsonpath='{.users[?(@.name == \"{{.kubectluser}}\")].user.client-certificate}'").Run(m.env)
	clientCert := res.Stdout.String()
	res = kubectl("jsonpath='{.users[?(@.name == \"{{.kubectluser}}\")].user.client-key}'").Run(m.env)
	clientKey := res.Stdout.String()
	res = kubectl("jsonpath='{.clusters[?(@.name == \"{{.kubectlcluster}}\")].cluster.certificate-authority}'").Run(m.env)
	caCert := res.Stdout.String()
	return map[string]string{
		"cacert":     caCert,
		"clientcert": clientCert,
		"clientkey":  clientKey,
	}
}

func (m *KubectlClusterManager) UpdateParams() ([]string, bool) {
	kubectl := NewCommand("kubectl").WithArgs
	res := kubectl("config", "view", "-o", "jsonpath='{.clusters[?(@.name == \"{{.kubectlcluster}}\")].cluster.server}'").Run(m.env)
	if res.Error != nil || res.ExitCode != 0 {
		return nil, false
	}
	certfiles := m.certificateFiles()
	return []string{"--addr", res.Stdout.String(), "--cacert", certfiles["cacert"], "--clientcert", certfiles["clientcert"], "--clientkey", certfiles["clientkey"]}, false
}
<commit_msg>integration: enable custom kubectl binary<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

// KubectlClusterManager represents a kubectl cluster
// Requires two test environments:
// kubectlcluster with the cluster name
// kubectluser with the cluster user name
type KubectlClusterManager struct {
	env *Environment
}

func (m *KubectlClusterManager) Name() string {
	return "kubectl"
}

func (m *KubectlClusterManager) Provisioner() string {
	return "kubernetes"
}

func (m *KubectlClusterManager) Start() *Result {
	return &Result{}
}

func (m *KubectlClusterManager) Delete() *Result {
	return &Result{}
}

func (m *KubectlClusterManager) certificateFiles() map[string]string {
	kubectl := NewCommand(m.binary(), "config", "view", "-o").WithArgs
	res := kubectl("jsonpath='{.users[?(@.name == \"{{.kubectluser}}\")].user.client-certificate}'").Run(m.env)
	clientCert := res.Stdout.String()
	res = kubectl("jsonpath='{.users[?(@.name == \"{{.kubectluser}}\")].user.client-key}'").Run(m.env)
	clientKey := res.Stdout.String()
	res = kubectl("jsonpath='{.clusters[?(@.name == \"{{.kubectlcluster}}\")].cluster.certificate-authority}'").Run(m.env)
	caCert := res.Stdout.String()
	return map[string]string{
		"cacert":     caCert,
		"clientcert": clientCert,
		"clientkey":  clientKey,
	}
}

func (m *KubectlClusterManager) UpdateParams() ([]string, bool) {
	kubectl := NewCommand(m.binary()).WithArgs
	res := kubectl("config", "view", "-o", "jsonpath='{.clusters[?(@.name == \"{{.kubectlcluster}}\")].cluster.server}'").Run(m.env)
	if res.Error != nil || res.ExitCode != 0 {
		return nil, false
	}
	certfiles := m.certificateFiles()
	return []string{"--addr", res.Stdout.String(), "--cacert", certfiles["cacert"], "--clientcert", certfiles["clientcert"], "--clientkey", certfiles["clientkey"]}, false
}

func (m *KubectlClusterManager) binary() string {
	binary := m.env.Get("kubectlbinary")
	if binary == "" {
		binary = "kubectl"
	}
	return binary
}
<|endoftext|>


<commit_before>package easybuf

import (
	"bytes"
	"errors"
	"fmt"
	"io"
)

// A Buffer is a direct array of bytes.
// Insertion is therefor O(n).
type Buffer struct {
	content []byte
	fname   string
}

// Load loads a buffer from a reader
func (b *Buffer) Load(from io.Reader) error {
	var buf bytes.Buffer
	n, err := io.Copy(&buf, from)

	if err != nil {
		return fmt.Errorf("buffer.Load: %d bytes read, %v", n, err)
	}
	b.content = buf.Bytes()
	return nil

}

// GetLine returns the nth line in the buffer, 0 indexed
func (b Buffer) GetLine(lineno int) (string, error) {
	return b.getLineHelper(lineno, lineno)
}

func (b Buffer) getLineHelper(lineno int, endresult int) (string, error) {
	i := bytes.IndexRune(b.content, '\n')
	if lineno == 0 {
		if i == -1 {
			i = len(b.content) - 1
		}
		return string(b.content[:i+1]), nil
	}
	if i == -1 {
		return "WAT", fmt.Errorf("Bad line request: %d", endresult)
	}
	t := b
	t.content = t.content[i+1:]
	return t.getLineHelper(lineno-1, endresult)
}

// Lines returns the number of lines in the buffer
func (b Buffer) Lines() int {
	if len(b.content) > 0 {
		return bytes.Count(b.content, []byte{'\n'}) + 1
	}
	return 0
}

func (b Buffer) Write(name string) error {
	return errors.New("easybuf.Buffer.Write: Unimplimented")
}

// WriteAt implements the io.WriterAt interface
func (b *Buffer) WriteAt(p []byte, off int64) (int, error) {
	b.content = append(
		b.content[:off],
		append(p, b.content[off:]...)...)
	return len(p), nil
}

// Delete deletes n bytes forwards from off
func (b *Buffer) Delete(n, off int64) {
	if off+n > int64(len(b.content)) {
		panic("This needs to be caught")
	}
	b.content = append(b.content[:off], b.content[off+n:]...)
}

// OffsetOf takes a cursor position with origin 0,0 and returns the byte offset
// of that position in the buffer
func (b *Buffer) OffsetOf(line, column int) int64 {
	var lineOff int64
	if line > 0 {
		lineOff = indexNth(b.content, '\n', line-1) + 1
	}

	if lineOff == -1 {
		return -1
	}

	return lineOff + int64(column)
}

func indexNth(s []byte, ch byte, n int) int64 {
	var seen int
	for i, c := range s {
		if c == ch {

			if seen == n {
				return int64(i)
			}
			seen++
		}
	}
	return -1
}
<commit_msg>Documentation, bitch<commit_after>package easybuf

import (
	"bytes"
	"errors"
	"fmt"
	"io"
)

// A Buffer is a direct array of bytes.
// Insertion is therefor O(n).
type Buffer struct {
	content []byte
	fname   string
}

// Load loads a buffer from a reader
func (b *Buffer) Load(from io.Reader) error {
	var buf bytes.Buffer
	n, err := io.Copy(&buf, from)

	if err != nil {
		return fmt.Errorf("buffer.Load: %d bytes read, %v", n, err)
	}
	b.content = buf.Bytes()
	return nil

}

// GetLine returns the nth line in the buffer, 0 indexed
func (b Buffer) GetLine(lineno int) (string, error) {
	return b.getLineHelper(lineno, lineno)
}

func (b Buffer) getLineHelper(lineno int, endresult int) (string, error) {
	i := bytes.IndexRune(b.content, '\n')
	if lineno == 0 {
		if i == -1 {
			i = len(b.content) - 1
		}
		return string(b.content[:i+1]), nil
	}
	if i == -1 {
		return "WAT", fmt.Errorf("Bad line request: %d", endresult)
	}
	t := b
	t.content = t.content[i+1:]
	return t.getLineHelper(lineno-1, endresult)
}

// Lines returns the number of lines in the buffer
func (b Buffer) Lines() int {
	if len(b.content) > 0 {
		return bytes.Count(b.content, []byte{'\n'}) + 1
	}
	return 0
}

func (b Buffer) Write(name string) error {
	return errors.New("easybuf.Buffer.Write: Unimplimented")
}

// WriteAt implements the io.WriterAt interface
func (b *Buffer) WriteAt(p []byte, off int64) (int, error) {
	b.content = append(
		b.content[:off],
		append(p, b.content[off:]...)...)
	return len(p), nil
}

// Delete deletes n bytes forwards from off
func (b *Buffer) Delete(n, off int64) {
	if off+n > int64(len(b.content)) {
		panic("This needs to be caught")
	}
	b.content = append(b.content[:off], b.content[off+n:]...)
}

// OffsetOf takes a cursor position with origin 0,0 and returns the byte offset
// of that position in the buffer
func (b *Buffer) OffsetOf(line, column int) int64 {
	var lineOff int64
	if line > 0 {
		lineOff = indexNth(b.content, '\n', line-1) + 1
	}

	if lineOff == -1 {
		return -1
	}

	return lineOff + int64(column)
}

// indexNth indexes the nth instance of ch in s, returning -1 if there is no nth instance
// This is based on the
func indexNth(s []byte, ch byte, n int) int64 {
	var seen int
	for i, c := range s {
		if c == ch {

			if seen == n {
				return int64(i)
			}
			seen++
		}
	}
	return -1
}
<|endoftext|>


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

package themes

var defaultTheme *Theme

func init() {

	const screenCss = `
html {
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    margin: 10px auto;
    padding: 1em;
    outline: 1300px solid #FAFAFA;
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 1em 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.collection>h1 {
    font-size: 1.2em;
}

.collection>ol {
    list-style: none;
    padding: 0;
    margin: 0 0 0 15px;
}

.collection>ol>li {
    display: block;
    margin: 0 0 15px 0;
}

.collection>ol>li>h2 {
    font-size: 1.0em;
    font-weight: bold;
    margin: 0;
}

.csv
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}
.csv thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}
.csv td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}
.csv tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%
    };
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%
    };
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%
    };
}

@media print {
    * {
        background: transparent !important;
        color: black !important;
        filter: none !important;
        -ms-filter: none !important;
    }

    body {
        font-size: 12pt;
        max-width: 100%;
        width: 100%
        outline: none;
    }

    a, a:visited {
        text-decoration: underline;
    }

    hr {
        height: 1px;
        border: 0;
        border-bottom: 1px solid black;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }

    abbr[title]:after {
        content: " (" attr(title) ")";
    }

    .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
        content: "";
    }

    pre, blockquote {
        border: 1px solid #999;
        padding-right: 1em;
        page-break-inside: avoid;
    }

    tr, img {
        page-break-inside: avoid;
    }

    img {
        max-width: 95% !important;
    }

    @page :left {
        margin: 15mm 20mm 15mm 10mm;
    }

    @page :right {
        margin: 15mm 10mm 15mm 20mm;
    }

    p, h2, h3 {
        orphans: 3;
        widows: 3;
    }

    h2, h3 {
        page-break-after: avoid;
    };
}`

	const autoupdateJs = `
$(function() {

    // check if websockets are supported
    if (!window["WebSocket"]) {
        console.log("Your browser does not support WebSockets.");
        return;
    }

    /**
     * Get the currently opened web route
     * @return string The currently opened web route (e.g. "/documents/Sample Document/index.html")
     */
    var getCurrentRoute = function() {
        var url = document.location.pathname;
        return decodeURI(url.replace(/^\/+/, ""));
    };

    /**
     * Get the Url for the web socket connection
     * @return string The url for the web socket connection (e.g. "ws://example.com:8080/ws")
     */
    var getWebSocketUrl = function() {
        routeParameter = "route=" + getCurrentRoute();
        host = document.location.host;
        webSocketHandler = "/ws";
        websocketUrl = "ws://" + host + webSocketHandler + "?" + routeParameter;
        return websocketUrl;
    };

    var connection = new WebSocket(getWebSocketUrl());

    connection.onclose = function(evt) {
        console.log("Connection closed.");
    };

    connection.onopen = function() {
        console.log("Connection established.")
    };

    connection.onmessage = function(evt) {

        // validate event data
        if (typeof(evt) !== 'object' || typeof(evt.data) !== 'string') {
            console.log("Invalid data from server.");
            return;
        }

        // unwrap the message
        message = JSON.parse(evt.data);

        // check if all required fields are present
        if (message === null || typeof(message) !== 'object' || typeof(message.route) !== 'string' || message.model === null || typeof(message.model) !== 'object') {
            console.log("Invalid response format.", message);
            return;
        }

        // check if update is applicable for the current route
        if (message.route !== getCurrentRoute()) {
            return;
        }

        // check the model structure
        var model = message.model;
        if (typeof(model.content) !== 'string' || typeof(model.description) !== 'string' || typeof(model.title) !== 'string') {
            console.log("Cannot update the view with the given model object. Missing some required fields.", model);
            return;
        }

        // update the title
        $('title').html(model.title);
        $('.title').html(model.title);

        // update the description
        $('.description').html(model.description);

        // update the content
        $('.content').html(model.content);

        // update sub entries (if available)
        if (model.subEntries === null || typeof(model.subEntries) !== 'object') {
            return;
        }

        var entries = model.subEntries;
        var existingEntries = $(".subentries>.subentry");
        var numberOfExistingEntries = existingEntries.length;
        var numberOfNewEntries = entries.length;

        var fallbackEntryTemplate = "

";

        for (var i = 0; i < numberOfNewEntries; i++) {
            var index = i + 1;
            var newEntry = entries[i];

            // get the item to update
            var entryToUpdate;
            if (index <= numberOfExistingEntries) {

                // use an existing item
                entryToUpdate = existingEntries[i];

            } else {

                // create a new item
                var entryTemplate = fallbackEntryTemplate;
                if (numberOfExistingEntries > 0) {

                    // use the first entry for the template
                    entryTemplate = existingEntries[0].html();

                }

                // append the template
                entryToUpdate = $(entryTemplate);
                $(".subentries").append(entryToUpdate);
            }

            // update the title text
            $(entryToUpdate).find(".subentry-link:first").html(newEntry.title);

            // update the title link
            $(entryToUpdate).find(".subentry-link:first").attr("href", newEntry.relativeRoute);

            // update the description
            $(entryToUpdate).find(".subentry-description:first").html(newEntry.description);
        }

    };
});`

	defaultTheme = &Theme{
		Name: "default",
		Files: []*ThemeFile{
			&ThemeFile{
				Filename: "screen.css",
				Content:  screenCss,
			},
			&ThemeFile{
				Filename: "autoupdate.js",
				Content:  autoupdateJs,
			},
		},
	}
}
<commit_msg>Changed the autoupdate.js so that it automatically reconnects itself after the connection has been closed (see: http://stackoverflow.com/questions/3780511/reconnection-of-client-when-server-reboots-in-websocket).<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package themes

var defaultTheme *Theme

func init() {

	const screenCss = `
html {
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    margin: 10px auto;
    padding: 1em;
    outline: 1300px solid #FAFAFA;
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 1em 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.collection>h1 {
    font-size: 1.2em;
}

.collection>ol {
    list-style: none;
    padding: 0;
    margin: 0 0 0 15px;
}

.collection>ol>li {
    display: block;
    margin: 0 0 15px 0;
}

.collection>ol>li>h2 {
    font-size: 1.0em;
    font-weight: bold;
    margin: 0;
}

.csv
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}
.csv thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}
.csv td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}
.csv tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%
    };
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%
    };
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%
    };
}

@media print {
    * {
        background: transparent !important;
        color: black !important;
        filter: none !important;
        -ms-filter: none !important;
    }

    body {
        font-size: 12pt;
        max-width: 100%;
        width: 100%
        outline: none;
    }

    a, a:visited {
        text-decoration: underline;
    }

    hr {
        height: 1px;
        border: 0;
        border-bottom: 1px solid black;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }

    abbr[title]:after {
        content: " (" attr(title) ")";
    }

    .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
        content: "";
    }

    pre, blockquote {
        border: 1px solid #999;
        padding-right: 1em;
        page-break-inside: avoid;
    }

    tr, img {
        page-break-inside: avoid;
    }

    img {
        max-width: 95% !important;
    }

    @page :left {
        margin: 15mm 20mm 15mm 10mm;
    }

    @page :right {
        margin: 15mm 10mm 15mm 20mm;
    }

    p, h2, h3 {
        orphans: 3;
        widows: 3;
    }

    h2, h3 {
        page-break-after: avoid;
    };
}`

	const autoupdateJs = `
$(function() {

    // check if websockets are supported
    if (!window["WebSocket"]) {
        console.log("Your browser does not support WebSockets.");
        return;
    }

    /**
     * Get the currently opened web route
     * @return string The currently opened web route (e.g. "/documents/Sample Document/index.html")
     */
    var getCurrentRoute = function() {
        var url = document.location.pathname;
        return decodeURI(url.replace(/^\/+/, ""));
    };

    /**
     * Get the Url for the web socket connection
     * @return string The url for the web socket connection (e.g. "ws://example.com:8080/ws")
     */
    var getWebSocketUrl = function() {
        routeParameter = "route=" + getCurrentRoute();
        host = document.location.host;
        webSocketHandler = "/ws";
        websocketUrl = "ws://" + host + webSocketHandler + "?" + routeParameter;
        return websocketUrl;
    };

    /**
     * Connect to the server
     * @param string webSocketUrl The url of the web-socket to connect to
     */
    var connect = function(webSocketUrl) {
        var reconnectionTimeInSeconds = 3;
        var connection = new WebSocket(webSocketUrl);

        connection.onclose = function(evt) {
            console.log("Connection closed. Trying to reconnect in " + reconnectionTimeInSeconds + " seconds.");

            setTimeout(function() {

                console.log("Reconnecting");
                connect(webSocketUrl);

            }, (reconnectionTimeInSeconds * 1000));
        };

        connection.onopen = function() {
            console.log("Connection established.")
        };

        connection.onmessage = function(evt) {

            // validate event data
            if (typeof(evt) !== 'object' || typeof(evt.data) !== 'string') {
                console.log("Invalid data from server.");
                return;
            }

            // unwrap the message
            message = JSON.parse(evt.data);

            // check if all required fields are present
            if (message === null || typeof(message) !== 'object' || typeof(message.route) !== 'string' || message.model === null || typeof(message.model) !== 'object') {
                console.log("Invalid response format.", message);
                return;
            }

            // check if update is applicable for the current route
            if (message.route !== getCurrentRoute()) {
                console.log("no match", message);
                return;
            }

            console.log("match", message);

            // check the model structure
            var model = message.model;
            if (typeof(model.content) !== 'string' || typeof(model.description) !== 'string' || typeof(model.title) !== 'string') {
                console.log("Cannot update the view with the given model object. Missing some required fields.", model);
                return;
            }

            // update the title
            $('title').html(model.title);
            $('.title').html(model.title);

            // update the description
            $('.description').html(model.description);

            // update the content
            $('.content').html(model.content);

            // update sub entries (if available)
            if (model.subEntries === null || typeof(model.subEntries) !== 'object') {
                return;
            }

            var entries = model.subEntries;
            var existingEntries = $(".subentries>.subentry");
            var numberOfExistingEntries = existingEntries.length;
            var numberOfNewEntries = entries.length;

            var fallbackEntryTemplate = "

";

            for (var i = 0; i < numberOfNewEntries; i++) {
                var index = i + 1;
                var newEntry = entries[i];

                // get the item to update
                var entryToUpdate;
                if (index <= numberOfExistingEntries) {

                    // use an existing item
                    entryToUpdate = existingEntries[i];

                } else {

                    // create a new item
                    var entryTemplate = fallbackEntryTemplate;
                    if (numberOfExistingEntries > 0) {

                        // use the first entry for the template
                        entryTemplate = existingEntries[0].html();

                    }

                    // append the template
                    entryToUpdate = $(entryTemplate);
                    $(".subentries").append(entryToUpdate);
                }

                // update the title text
                $(entryToUpdate).find(".subentry-link:first").html(newEntry.title);

                // update the title link
                $(entryToUpdate).find(".subentry-link:first").attr("href", newEntry.relativeRoute);

                // update the description
                $(entryToUpdate).find(".subentry-description:first").html(newEntry.description);
            }

        };
    };

    // establish the connection
    connect(getWebSocketUrl());
});`

	defaultTheme = &Theme{
		Name: "default",
		Files: []*ThemeFile{
			&ThemeFile{
				Filename: "screen.css",
				Content:  screenCss,
			},
			&ThemeFile{
				Filename: "autoupdate.js",
				Content:  autoupdateJs,
			},
		},
	}
}
<|endoftext|>


<commit_before>package alias

import (
	"regexp"
	"strconv"
	"strings"

	"../interpreter"
)

type Callable interface {
	String() string
	Call(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error)
}

type AliasFunc struct {
	BaseStr string
}

func New(baseStr string) *AliasFunc {
	return &AliasFunc{baseStr}
}

func (this *AliasFunc) String() string {
	return this.BaseStr
}

func (this *AliasFunc) Call(cmd *interpreter.Interpreter) (next interpreter.ErrorLevel, err error) {
	isReplaced := false
	cmdline := paramMatch.ReplaceAllStringFunc(this.BaseStr, func(s string) string {
		if s == "$*" {
			isReplaced = true
			return quoteAndJoin(cmd.Args[1:])
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && int(i) < len(cmd.Args) {
				return cmd.Args[i]
			}
		}
		return s
	})

	if !isReplaced {
		buffer := make([]byte, 0, 200)
		buffer = append(buffer, this.BaseStr...)
		buffer = append(buffer, ' ')
		buffer = append(buffer, quoteAndJoin(cmd.Args[1:])...)
		cmdline = string(buffer)
	}
	it := cmd.Clone()
	it.HookCount = cmd.HookCount + 1
	next, err = it.Interpret(cmdline)
	return
}

var Table = map[string]Callable{}
var paramMatch = regexp.MustCompile("\\$(\\*|[0-9]+)")

func quoteAndJoin(list []string) string {
	buffer := make([]byte, 0, 100)
	for i, value := range list {
		if i > 0 {
			buffer = append(buffer, ' ')
		}
		if strings.IndexByte(value, ' ') >= 0 {
			buffer = append(buffer, '"')
			buffer = append(buffer, value...)
			buffer = append(buffer, '"')
		} else {
			buffer = append(buffer, value...)
		}
	}
	return string(buffer)
}

var nextHook interpreter.HookT

func hook(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error) {
	if cmd.HookCount > 5 {
		return nextHook(cmd)
	}
	callee, ok := Table[strings.ToLower(cmd.Args[0])]
	if !ok {
		return nextHook(cmd)
	}
	next, err := callee.Call(cmd)
	return next, err
}

func Init() {
	nextHook = interpreter.SetHook(hook)
}
<commit_msg>Stop too many loop for alias-expanding (for #82)<commit_after>package alias

import (
	"regexp"
	"strconv"
	"strings"

	"../conio"
	"../interpreter"
)

type Callable interface {
	String() string
	Call(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error)
}

type AliasFunc struct {
	BaseStr string
}

func New(baseStr string) *AliasFunc {
	return &AliasFunc{baseStr}
}

func (this *AliasFunc) String() string {
	return this.BaseStr
}

func (this *AliasFunc) Call(cmd *interpreter.Interpreter) (next interpreter.ErrorLevel, err error) {
	isReplaced := false
	cmdline := paramMatch.ReplaceAllStringFunc(this.BaseStr, func(s string) string {
		if s == "$*" {
			isReplaced = true
			return quoteAndJoin(cmd.Args[1:])
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && int(i) < len(cmd.Args) {
				return cmd.Args[i]
			}
		}
		return s
	})

	if !isReplaced {
		buffer := make([]byte, 0, 200)
		buffer = append(buffer, this.BaseStr...)
		buffer = append(buffer, ' ')
		buffer = append(buffer, quoteAndJoin(cmd.Args[1:])...)
		cmdline = string(buffer)
	}
	it := cmd.Clone()

	newargs := conio.SplitQ(cmdline)
	if strings.EqualFold(newargs[0], cmd.Args[0]) {
		it.HookCount = 100
	} else {
		it.HookCount = cmd.HookCount + 1
	}
	next, err = it.Interpret(cmdline)
	return
}

var Table = map[string]Callable{}
var paramMatch = regexp.MustCompile("\\$(\\*|[0-9]+)")

func quoteAndJoin(list []string) string {
	buffer := make([]byte, 0, 100)
	for i, value := range list {
		if i > 0 {
			buffer = append(buffer, ' ')
		}
		if strings.IndexByte(value, ' ') >= 0 {
			buffer = append(buffer, '"')
			buffer = append(buffer, value...)
			buffer = append(buffer, '"')
		} else {
			buffer = append(buffer, value...)
		}
	}
	return string(buffer)
}

var nextHook interpreter.HookT

func hook(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error) {
	if cmd.HookCount > 5 {
		return nextHook(cmd)
	}
	callee, ok := Table[strings.ToLower(cmd.Args[0])]
	if !ok {
		return nextHook(cmd)
	}
	next, err := callee.Call(cmd)
	return next, err
}

func Init() {
	nextHook = interpreter.SetHook(hook)
}
<|endoftext|>


<commit_before>package alias

import "bytes"
import "os/exec"
import "regexp"
import "strconv"
import "strings"
import "io"

import . "./table"
import "../commands"
import "../interpreter"

var paramMatch = regexp.MustCompile("\\$(\\*|[0-9]+)")

func Hook(cmd *exec.Cmd, IsBackground bool, closer io.Closer) (interpreter.NextT, error) {
	baseStr, ok := Table[strings.ToLower(cmd.Args[0])]
	if !ok {
		return interpreter.THROUGH, nil
	}
	isReplaced := false
	cmdline := paramMatch.ReplaceAllStringFunc(baseStr, func(s string) string {
		if s == "$*" {
			isReplaced = true
			return strings.Join(cmd.Args[1:], " ")
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && int(i) < len(cmd.Args) {
				return cmd.Args[i]
			}
		}
		return s
	})

	if !isReplaced {
		var buffer bytes.Buffer
		buffer.WriteString(baseStr)

		for _, arg := range cmd.Args[1:] {
			buffer.WriteRune(' ')
			buffer.WriteString(arg)
		}

		cmdline = buffer.String()
	}
	var stdio interpreter.Stdio
	stdio.Stdin = cmd.Stdin
	stdio.Stdout = cmd.Stdout
	stdio.Stderr = cmd.Stderr
	nextT, err := interpreter.Interpret(
		cmdline,
		commands.Exec,
		&stdio)
	if nextT != interpreter.THROUGH && closer != nil {
		closer.Close()
	}
	return nextT, err
}
<commit_msg>Fix #11 alias で展開する時に引数を "" で囲むようにした。<commit_after>package alias

import "bytes"
import "os/exec"
import "regexp"
import "strconv"
import "strings"
import "io"

import . "./table"
import "../commands"
import "../interpreter"

var paramMatch = regexp.MustCompile("\\$(\\*|[0-9]+)")

func quoteAndJoin(list []string) string {
	var buffer bytes.Buffer
	for _, value := range list {
		if buffer.Len() > 0 {
			buffer.WriteRune(' ')
		}
		buffer.WriteRune('"')
		buffer.WriteString(value)
		buffer.WriteRune('"')
	}
	return buffer.String()
}

func Hook(cmd *exec.Cmd, IsBackground bool, closer io.Closer) (interpreter.NextT, error) {
	baseStr, ok := Table[strings.ToLower(cmd.Args[0])]
	if !ok {
		return interpreter.THROUGH, nil
	}
	isReplaced := false
	cmdline := paramMatch.ReplaceAllStringFunc(baseStr, func(s string) string {
		if s == "$*" {
			isReplaced = true
			return quoteAndJoin(cmd.Args[1:])
		}
		i, err := strconv.ParseInt(s[1:], 10, 0)
		if err == nil {
			isReplaced = true
			if 0 <= i && int(i) < len(cmd.Args) {
				return cmd.Args[i]
			}
		}
		return s
	})

	if !isReplaced {
		var buffer bytes.Buffer
		buffer.WriteString(baseStr)
		buffer.WriteRune(' ')
		buffer.WriteString(quoteAndJoin(cmd.Args[1:]))
		cmdline = buffer.String()
	}
	var stdio interpreter.Stdio
	stdio.Stdin = cmd.Stdin
	stdio.Stdout = cmd.Stdout
	stdio.Stderr = cmd.Stderr
	nextT, err := interpreter.Interpret(
		cmdline,
		commands.Exec,
		&stdio)
	if nextT != interpreter.THROUGH && closer != nil {
		closer.Close()
	}
	return nextT, err
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import "golang.org/x/net/context"

// A Store knows how to store blobs for later retrieval.
type Store interface {
	// Store the blob, returning a score with which it can later be retrieved.
	Store(
		ctx context.Context,
		blob []byte) (s Score, err error)

	// Return true only if the supplied score is durable in the blob store.
	// Implementations may choose to return false if the information is not
	// available.
	Contains(ctx context.Context, score Score) (b bool)

	// Load a previously-stored blob.
	Load(ctx context.Context, s Score) (blob []byte, err error)
}
<commit_msg>Updated the blob.Store interface.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import "golang.org/x/net/context"

// A Store knows how to store blobs for later retrieval.
type Store interface {
	// Store a blob, returning a score with which it can later be retrieved.
	Store(
		ctx context.Context,
		req *StoreRequest) (s Score, err error)

	// Return true only if the supplied score is durable in the blob store.
	// Implementations may choose to return false if the information is not
	// available.
	Contains(ctx context.Context, score Score) (b bool)

	// Load a previously-stored blob.
	Load(ctx context.Context, s Score) (blob []byte, err error)
}

type StoreRequest struct {
	// The blob data to be stored.
	blob []byte
}
<|endoftext|>


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

package io

import (
	"errors"
	"github.com/tsuru/tsuru/log"
	"io"
	"sync"
	"time"
)

type keepAliveWriter struct {
	w         io.Writer
	interval  time.Duration
	ping      chan bool
	done      chan bool
	msg       []byte
	lastByte  byte
	withError bool
	writeLock sync.Mutex
}

func NewKeepAliveWriter(w io.Writer, interval time.Duration, msg string) *keepAliveWriter {
	writer := &keepAliveWriter{w: w, interval: interval, msg: append([]byte(msg), '\n')}
	writer.ping = make(chan bool)
	writer.done = make(chan bool)
	go writer.keepAlive()
	return writer
}

func (w *keepAliveWriter) writeInterval() {
	w.writeLock.Lock()
	defer w.writeLock.Unlock()
	msg := []byte{}
	if w.lastByte != '\n' {
		msg = []byte("\n")
	}
	msg = append(msg, w.msg...)
	numBytes, err := w.w.Write(msg)
	if err != nil {
		log.Debugf("Error writing keepalive, exiting loop: %s", err.Error())
		w.withError = true
		return
	}
	if numBytes != len(msg) {
		log.Debugf("Short write on keepalive, exiting loop.")
		w.withError = true
		return
	}
}

func (w *keepAliveWriter) keepAlive() {
	for {
		select {
		case <-w.ping:
		case <-w.done:
			return
		case <-time.After(w.interval):
			if w.writeInterval(); w.withError {
				return
			}
		}
	}
}

func (w *keepAliveWriter) Write(b []byte) (int, error) {
	if len(b) == 0 {
		return 0, nil
	}
	w.writeLock.Lock()
	defer w.writeLock.Unlock()
	if w.withError {
		return 0, errors.New("Error in previous write.")
	}
	if w.ping != nil {
		w.ping <- true
	}
	w.lastByte = b[len(b)-1]
	written, err := w.w.Write(b)
	if err != nil {
		if w.done != nil {
			close(w.done)
			w.done = nil
		}
		if w.ping != nil {
			close(w.ping)
			w.ping = nil
		}
	}
	return written, err
}
<commit_msg>io: fix for race conditions in keepalivewriter<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package io

import (
	"io"
	"sync"
	"time"

	"github.com/tsuru/tsuru/log"
)

type keepAliveWriter struct {
	w         io.Writer
	interval  time.Duration
	ping      chan bool
	done      chan bool
	msg       []byte
	lastByte  byte
	running   bool
	writeLock sync.Mutex
}

func NewKeepAliveWriter(w io.Writer, interval time.Duration, msg string) *keepAliveWriter {
	writer := &keepAliveWriter{w: w, interval: interval, msg: append([]byte(msg), '\n')}
	writer.ping = make(chan bool)
	writer.done = make(chan bool)
	writer.running = true
	go writer.keepAlive()
	return writer
}

func (w *keepAliveWriter) writeInterval() {
	w.writeLock.Lock()
	defer w.writeLock.Unlock()
	msg := []byte{}
	if w.lastByte != '\n' {
		msg = []byte("\n")
	}
	msg = append(msg, w.msg...)
	numBytes, err := w.w.Write(msg)
	if err != nil {
		log.Debugf("Error writing keepalive, exiting loop: %s", err.Error())
		w.stop()
	} else if numBytes != len(msg) {
		log.Debugf("Short write on keepalive, exiting loop.")
		w.stop()
	}
}

func (w *keepAliveWriter) stop() {
	if !w.running {
		return
	}
	w.running = false
	close(w.done)
	close(w.ping)
}

func (w *keepAliveWriter) keepAlive() {
	for {
		select {
		case <-w.ping:
		case <-w.done:
			return
		case <-time.After(w.interval):
			w.writeInterval()
		}
	}
}

func (w *keepAliveWriter) Write(b []byte) (int, error) {
	if len(b) == 0 {
		return 0, nil
	}
	w.writeLock.Lock()
	defer w.writeLock.Unlock()
	if w.running {
		w.ping <- true
	}
	w.lastByte = b[len(b)-1]
	written, err := w.w.Write(b)
	if err != nil {
		w.stop()
	}
	return written, err
}
<|endoftext|>


<commit_before>package edn

import . "testing"
import ll "container/list"

func assertEqual(expect, actual interface{}, t *T) {
	if expect != actual {
		t.Errorf("Expecting %+v, received %+v", expect, actual)
	}
}

func TestVectorString(t *T) {
	vec := make(Vector, 0)
	assertEqual("[]", vec.String(), t)

	vec = append(vec, Int(1))
	assertEqual("[1]", vec.String(), t)

	vec = append(vec, make(Vector, 0), String("abc"))
	assertEqual(`[1 [] "abc"]`, vec.String(), t)
}

func TestListString(t *T) {
	list := new(List)
	ll := (*ll.List)(list)

	assertEqual("()", list.String(), t)

	ll.PushBack(Int(1))
	assertEqual("(1)", list.String(), t)

	ll.PushBack(make(Vector, 0))
	ll.PushBack(String("abc"))
	assertEqual("(1 [] \"abc\")", list.String(), t)
}

func TestMapString(t *T) {
	_map := make(Map)
	assertEqual("{}", _map.String(), t)

	_map[String("test")] = Vector{String("value1"), String("value2")}
	assertEqual(`{"test" ["value1" "value2"]}`, _map.String(), t)
}

func TestSetString(t *T) {
	set := make(Set)
	assertEqual("#{}", set.String(), t)

	set.Insert(String("abc"))
	assertEqual(`#{"abc"}`, set.String(), t)

	set.Insert(Int(123))
	assertEqual(`#{"abc" 123}`, set.String(), t)

	// TODO: This causes a runtime panic. Mutable types (maps, vectors, etc) can't
	//       be map keys in Go. Since the sets are backed by a Map, it blows up :(
	//
	//       Look into https://code.google.com/p/gohash/
	//
	// set.Insert(Vector{Int(1), Int(2), Map{String("foo"): Int(17)}})
}
<commit_msg>Comment out flaky test<commit_after>package edn

import . "testing"
import ll "container/list"

func assertEqual(expect, actual interface{}, t *T) {
	if expect != actual {
		t.Errorf("Expecting %+v, received %+v", expect, actual)
	}
}

func TestVectorString(t *T) {
	vec := make(Vector, 0)
	assertEqual("[]", vec.String(), t)

	vec = append(vec, Int(1))
	assertEqual("[1]", vec.String(), t)

	vec = append(vec, make(Vector, 0), String("abc"))
	assertEqual(`[1 [] "abc"]`, vec.String(), t)
}

func TestListString(t *T) {
	list := new(List)
	ll := (*ll.List)(list)

	assertEqual("()", list.String(), t)

	ll.PushBack(Int(1))
	assertEqual("(1)", list.String(), t)

	ll.PushBack(make(Vector, 0))
	ll.PushBack(String("abc"))
	assertEqual("(1 [] \"abc\")", list.String(), t)
}

func TestMapString(t *T) {
	_map := make(Map)
	assertEqual("{}", _map.String(), t)

	_map[String("test")] = Vector{String("value1"), String("value2")}
	assertEqual(`{"test" ["value1" "value2"]}`, _map.String(), t)
}

func TestSetString(t *T) {
	set := make(Set)
	assertEqual("#{}", set.String(), t)

	set.Insert(String("abc"))
	assertEqual(`#{"abc"}`, set.String(), t)

	// Unstable test because sets/maps are unordered and enumerated in a
	// random order:
	//
	// set.Insert(Int(123))
	// assertEqual(`#{"abc" 123}`, set.String(), t)

	// TODO: This causes a runtime panic. Mutable types (maps, vectors, etc) can't
	//       be map keys in Go. Since the sets are backed by a Map, it blows up :(
	//
	//       Look into https://code.google.com/p/gohash/
	//
	// set.Insert(Vector{Int(1), Int(2), Map{String("foo"): Int(17)}})
}
<|endoftext|>