<commit_before>// Package obj allows simple parsing of Wavefront OBJ files
// into slices of vertices, normals and elements.
package obj

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

// Parse a vertex (normal) string, a list of whitespace-separated
// floating point numbers.
func parseVertex(t []string) []float32 {
	x, _ := strconv.ParseFloat(t[0], 32)
	y, _ := strconv.ParseFloat(t[1], 32)
	z, _ := strconv.ParseFloat(t[2], 32)

	return []float32{float32(x), float32(y), float32(z)}
}

// Parse an element string, a list of whitespace-separated elements.
// Elements are of the form "<vi>/<ti>/<ni>" where indices are the
// vertex, texture coordinate and normal, respectively.
func parseElement(t []string) []int32 {
	e := make([]int32, len(t))

	for i := 0; i < len(t); i++ {
		f := strings.Split(t[i], "/")
		// for now, just grab the vertex index
		x, _ := strconv.ParseInt(f[0], 10, 32)
		e[i] = int32(x) - 1 // convert to 0-indexing
	}

	// convert quads to triangles
	if len(t) > 3 {
		e = append(e, e[0], e[2])
	}

	return e
}

func Parse(filename string) ([]float32, []int32) {
	fp, _ := os.Open(filename)
	scanner := bufio.NewScanner(fp)

	vertices := []float32{}
	normals := []float32{}
	elements := []int32{}

	for scanner.Scan() {
		toks := strings.Fields(strings.TrimSpace(scanner.Text()))

		switch toks[0] {
		case "v":
			vertices = append(vertices, parseVertex(toks[1:])...)
		case "vn":
			normals = append(normals, parseVertex(toks[1:])...)
		case "f":
			elements = append(elements, parseElement(toks[1:])...)
		}
	}

	return vertices, elements
}
<commit_msg>Parse out vertices and normals<commit_after>// Package obj allows simple parsing of Wavefront OBJ files
// into slices of vertices, normals and elements.
package obj

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

// Parse a vertex (normal) string, a list of whitespace-separated
// floating point numbers.
func parseVertex(t []string) []float32 {
	x, _ := strconv.ParseFloat(t[0], 32)
	y, _ := strconv.ParseFloat(t[1], 32)
	z, _ := strconv.ParseFloat(t[2], 32)

	return []float32{float32(x), float32(y), float32(z)}
}

// Parse an element string, a list of whitespace-separated elements.
// Elements are of the form "<vi>/<ti>/<ni>" where indices are the
// vertex, texture coordinate and normal, respectively.
func parseElement(t []string) [][3]int32 {
	e := make([][3]int32, len(t))

	for i := 0; i < len(t); i++ {
		f := strings.Split(t[i], "/")

		for j := 0; j < len(f); j++ {
			// for now, just grab the vertex index
			if x, err := strconv.ParseInt(f[j], 10, 32); err == nil {
				e[i][j] = int32(x) - 1 // convert to 0-indexing
			} else {
				e[i][j] = -1
			}
		}
	}

	// convert quads to triangles
	if len(t) > 3 {
		e = append(e, e[0], e[2])
	}

	return e
}

func Parse(filename string) ([]float32, []float32) {
	fp, _ := os.Open(filename)
	scanner := bufio.NewScanner(fp)

	vertices := [][]float32{}
	normals := [][]float32{}
	elements := [][3]int32{}

	vertOut := []float32{}
	normOut := []float32{}

	for scanner.Scan() {
		toks := strings.Fields(strings.TrimSpace(scanner.Text()))

		switch toks[0] {
		case "v":
			vertices = append(vertices, parseVertex(toks[1:]))
		case "vn":
			normals = append(normals, parseVertex(toks[1:]))
		case "f":
			elements = append(elements, parseElement(toks[1:])...)
		}
	}

	for _, e := range elements {
		if e[0] >= 0 {
			vertOut = append(vertOut, vertices[e[0]]...)
		}
		if e[2] >= 0 {
			normOut = append(normOut, normals[e[2]]...)
		}
	}

	return vertOut, normOut
}
<|endoftext|>


<commit_before>package oci

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/cri-o/utils"
	"github.com/opencontainers/runtime-spec/specs-go"
)

// New creates a new Runtime with options provided
func New(runtimePath string, containerDir string) (*Runtime, error) {
	r := &Runtime{
		name:         filepath.Base(runtimePath),
		path:         runtimePath,
		containerDir: containerDir,
	}
	return r, nil
}

// Runtime stores the information about a oci runtime
type Runtime struct {
	name         string
	path         string
	containerDir string
}

// syncInfo is used to return data from monitor process to daemon
type syncInfo struct {
	Pid int `json:"pid"`
}

// Name returns the name of the OCI Runtime
func (r *Runtime) Name() string {
	return r.name
}

// Path returns the full path the OCI Runtime executable
func (r *Runtime) Path() string {
	return r.path
}

// ContainerDir returns the path to the base directory for storing container configurations
func (r *Runtime) ContainerDir() string {
	return r.containerDir
}

// Version returns the version of the OCI Runtime
func (r *Runtime) Version() (string, error) {
	runtimeVersion, err := getOCIVersion(r.path, "-v")
	if err != nil {
		return "", err
	}
	return runtimeVersion, nil
}

func getOCIVersion(name string, args ...string) (string, error) {
	out, err := utils.ExecCmd(name, args...)
	if err != nil {
		return "", err
	}

	firstLine := out[:strings.Index(out, "\n")]
	v := firstLine[strings.LastIndex(firstLine, " ")+1:]
	return v, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container) error {
	parentPipe, childPipe, err := newPipe()
	if err != nil {
		return fmt.Errorf("error creating socket pair: %v", err)
	}
	defer parentPipe.Close()

	args := []string{"-c", c.name}
	args = append(args, "-r", r.path)
	if c.terminal {
		args = append(args, "-t")
	}

	cmd := exec.Command("conmon", args...)
	cmd.Dir = c.bundlePath
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe)
	// 0, 1 and 2 are stdin, stdout and stderr
	cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))

	err = cmd.Start()
	if err != nil {
		childPipe.Close()
		return err
	}

	// We don't need childPipe on the parent side
	childPipe.Close()

	// Wait to get container pid from conmon
	// TODO(mrunalp): Add a timeout here
	var si *syncInfo
	if err := json.NewDecoder(parentPipe).Decode(&si); err != nil {
		return fmt.Errorf("reading pid from init pipe: %v", err)
	}
	logrus.Infof("Received container pid: %v", si.Pid)
	return nil
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "start", c.name); err != nil {
		return err
	}
	c.state.Started = time.Now()
	return nil
}

// StopContainer stops a container.
func (r *Runtime) StopContainer(c *Container) error {
	// TODO: Check if it is still running after some time and send SIGKILL
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", c.name)
}

// DeleteContainer deletes a container.
func (r *Runtime) DeleteContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "delete", c.name)
}

// UpdateStatus refreshes the status of the container.
func (r *Runtime) UpdateStatus(c *Container) error {
	c.stateLock.Lock()
	defer c.stateLock.Unlock()
	out, err := exec.Command(r.path, "state", c.name).Output()
	if err != nil {
		return fmt.Errorf("error getting container state for %s: %s: %v", c.name, err, out)
	}
	stateReader := bytes.NewReader(out)
	if err := json.NewDecoder(stateReader).Decode(&c.state); err != nil {
		return fmt.Errorf("failed to decode container status for %s: %s", c.name, err)
	}

	if c.state.Status == "stopped" {
		exitFilePath := filepath.Join(c.bundlePath, "exit")
		fi, err := os.Stat(exitFilePath)
		if err != nil {
			return fmt.Errorf("failed to find container exit file: %v", err)
		}
		st := fi.Sys().(*syscall.Stat_t)
		c.state.Finished = time.Unix(st.Ctim.Sec, st.Ctim.Nsec)

		statusCodeStr, err := ioutil.ReadFile(exitFilePath)
		if err != nil {
			return fmt.Errorf("failed to read exit file: %v", err)
		}
		statusCode, err := strconv.Atoi(string(statusCodeStr))
		if err != nil {
			return fmt.Errorf("status code conversion failed: %v", err)
		}
		c.state.ExitCode = int32(utils.StatusToExitCode(statusCode))
	}

	return nil
}

// ContainerStatus returns the state of a container.
func (r *Runtime) ContainerStatus(c *Container) *ContainerState {
	c.stateLock.Lock()
	defer c.stateLock.Unlock()
	return c.state
}

// Container respresents a runtime container.
type Container struct {
	name       string
	bundlePath string
	logPath    string
	labels     map[string]string
	sandbox    string
	terminal   bool
	state      *ContainerState
	stateLock  sync.Mutex
}

// ContainerState represents the status of a container.
type ContainerState struct {
	specs.State
	Created  time.Time `json:"created"`
	Started  time.Time `json:"started"`
	Finished time.Time `json:"finished"`
	ExitCode int32     `json:"exitCode"`
}

// NewContainer creates a container object.
func NewContainer(name string, bundlePath string, logPath string, labels map[string]string, sandbox string, terminal bool) (*Container, error) {
	c := &Container{
		name:       name,
		bundlePath: bundlePath,
		logPath:    logPath,
		labels:     labels,
		sandbox:    sandbox,
		terminal:   terminal,
	}
	return c, nil
}

// Name returns the name of the container.
func (c *Container) Name() string {
	return c.name
}

// BundlePath returns the bundlePath of the container.
func (c *Container) BundlePath() string {
	return c.bundlePath
}

// LogPath returns the log path of the container.
func (c *Container) LogPath() string {
	return c.logPath
}

// Labels returns the labels of the container.
func (c *Container) Labels() map[string]string {
	return c.labels
}

// Sandbox returns the sandbox name of the container.
func (c *Container) Sandbox() string {
	return c.sandbox
}

// NetNsPath returns the path to the network namespace of the container.
func (c *Container) NetNsPath() (string, error) {
	if c.state == nil {
		return "", fmt.Errorf("container state is not populated")
	}
	return fmt.Sprintf("/proc/%d/ns/net", c.state.Pid), nil
}

// newPipe creates a unix socket pair for communication
func newPipe() (parent *os.File, child *os.File, err error) {
	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
	if err != nil {
		return nil, nil, err
	}
	return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
}
<commit_msg>Make sure that the container stops when StopContainer API is called<commit_after>package oci

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/cri-o/utils"
	"github.com/opencontainers/runtime-spec/specs-go"
	"golang.org/x/sys/unix"
)

// New creates a new Runtime with options provided
func New(runtimePath string, containerDir string) (*Runtime, error) {
	r := &Runtime{
		name:         filepath.Base(runtimePath),
		path:         runtimePath,
		containerDir: containerDir,
	}
	return r, nil
}

// Runtime stores the information about a oci runtime
type Runtime struct {
	name         string
	path         string
	containerDir string
}

// syncInfo is used to return data from monitor process to daemon
type syncInfo struct {
	Pid int `json:"pid"`
}

// Name returns the name of the OCI Runtime
func (r *Runtime) Name() string {
	return r.name
}

// Path returns the full path the OCI Runtime executable
func (r *Runtime) Path() string {
	return r.path
}

// ContainerDir returns the path to the base directory for storing container configurations
func (r *Runtime) ContainerDir() string {
	return r.containerDir
}

// Version returns the version of the OCI Runtime
func (r *Runtime) Version() (string, error) {
	runtimeVersion, err := getOCIVersion(r.path, "-v")
	if err != nil {
		return "", err
	}
	return runtimeVersion, nil
}

func getOCIVersion(name string, args ...string) (string, error) {
	out, err := utils.ExecCmd(name, args...)
	if err != nil {
		return "", err
	}

	firstLine := out[:strings.Index(out, "\n")]
	v := firstLine[strings.LastIndex(firstLine, " ")+1:]
	return v, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container) error {
	parentPipe, childPipe, err := newPipe()
	if err != nil {
		return fmt.Errorf("error creating socket pair: %v", err)
	}
	defer parentPipe.Close()

	args := []string{"-c", c.name}
	args = append(args, "-r", r.path)
	if c.terminal {
		args = append(args, "-t")
	}

	cmd := exec.Command("conmon", args...)
	cmd.Dir = c.bundlePath
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe)
	// 0, 1 and 2 are stdin, stdout and stderr
	cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))

	err = cmd.Start()
	if err != nil {
		childPipe.Close()
		return err
	}

	// We don't need childPipe on the parent side
	childPipe.Close()

	// Wait to get container pid from conmon
	// TODO(mrunalp): Add a timeout here
	var si *syncInfo
	if err := json.NewDecoder(parentPipe).Decode(&si); err != nil {
		return fmt.Errorf("reading pid from init pipe: %v", err)
	}
	logrus.Infof("Received container pid: %v", si.Pid)
	return nil
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "start", c.name); err != nil {
		return err
	}
	c.state.Started = time.Now()
	return nil
}

// StopContainer stops a container.
func (r *Runtime) StopContainer(c *Container) error {
	if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", c.name); err != nil {
		return err
	}
	i := 0
	for {
		if i == 1000 {
			err := unix.Kill(c.state.Pid, syscall.SIGKILL)
			if err != nil && err != syscall.ESRCH {
				return fmt.Errorf("failed to kill process: %v", err)
			}
		}
		// Check if the process is still around
		err := unix.Kill(c.state.Pid, 0)
		if err == syscall.ESRCH {
			break
		}
		time.Sleep(10 * time.Millisecond)
		i++
	}

	return nil
}

// DeleteContainer deletes a container.
func (r *Runtime) DeleteContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "delete", c.name)
}

// UpdateStatus refreshes the status of the container.
func (r *Runtime) UpdateStatus(c *Container) error {
	c.stateLock.Lock()
	defer c.stateLock.Unlock()
	out, err := exec.Command(r.path, "state", c.name).Output()
	if err != nil {
		return fmt.Errorf("error getting container state for %s: %s: %v", c.name, err, out)
	}
	stateReader := bytes.NewReader(out)
	if err := json.NewDecoder(stateReader).Decode(&c.state); err != nil {
		return fmt.Errorf("failed to decode container status for %s: %s", c.name, err)
	}

	if c.state.Status == "stopped" {
		exitFilePath := filepath.Join(c.bundlePath, "exit")
		fi, err := os.Stat(exitFilePath)
		if err != nil {
			return fmt.Errorf("failed to find container exit file: %v", err)
		}
		st := fi.Sys().(*syscall.Stat_t)
		c.state.Finished = time.Unix(st.Ctim.Sec, st.Ctim.Nsec)

		statusCodeStr, err := ioutil.ReadFile(exitFilePath)
		if err != nil {
			return fmt.Errorf("failed to read exit file: %v", err)
		}
		statusCode, err := strconv.Atoi(string(statusCodeStr))
		if err != nil {
			return fmt.Errorf("status code conversion failed: %v", err)
		}
		c.state.ExitCode = int32(utils.StatusToExitCode(statusCode))
	}

	return nil
}

// ContainerStatus returns the state of a container.
func (r *Runtime) ContainerStatus(c *Container) *ContainerState {
	c.stateLock.Lock()
	defer c.stateLock.Unlock()
	return c.state
}

// Container respresents a runtime container.
type Container struct {
	name       string
	bundlePath string
	logPath    string
	labels     map[string]string
	sandbox    string
	terminal   bool
	state      *ContainerState
	stateLock  sync.Mutex
}

// ContainerState represents the status of a container.
type ContainerState struct {
	specs.State
	Created  time.Time `json:"created"`
	Started  time.Time `json:"started"`
	Finished time.Time `json:"finished"`
	ExitCode int32     `json:"exitCode"`
}

// NewContainer creates a container object.
func NewContainer(name string, bundlePath string, logPath string, labels map[string]string, sandbox string, terminal bool) (*Container, error) {
	c := &Container{
		name:       name,
		bundlePath: bundlePath,
		logPath:    logPath,
		labels:     labels,
		sandbox:    sandbox,
		terminal:   terminal,
	}
	return c, nil
}

// Name returns the name of the container.
func (c *Container) Name() string {
	return c.name
}

// BundlePath returns the bundlePath of the container.
func (c *Container) BundlePath() string {
	return c.bundlePath
}

// LogPath returns the log path of the container.
func (c *Container) LogPath() string {
	return c.logPath
}

// Labels returns the labels of the container.
func (c *Container) Labels() map[string]string {
	return c.labels
}

// Sandbox returns the sandbox name of the container.
func (c *Container) Sandbox() string {
	return c.sandbox
}

// NetNsPath returns the path to the network namespace of the container.
func (c *Container) NetNsPath() (string, error) {
	if c.state == nil {
		return "", fmt.Errorf("container state is not populated")
	}
	return fmt.Sprintf("/proc/%d/ns/net", c.state.Pid), nil
}

// newPipe creates a unix socket pair for communication
func newPipe() (parent *os.File, child *os.File, err error) {
	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
	if err != nil {
		return nil, nil, err
	}
	return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"unicode"

	"github.com/nsf/termbox-go"
)

type FieldEditor struct {
	value      []rune
	cursor_pos int
	last_value string
	width      int
	fixed      int
	overwrite  bool
}

func (field_editor *FieldEditor) handleKeyEvent(event termbox.Event) (string, bool) {
	is_done := false

	if event.Ch == 0 && len(field_editor.value) == 0 {
		field_editor.setValue([]rune(field_editor.last_value))
	}

	if field_editor.fixed > 0 {
		if len(field_editor.value) > field_editor.fixed {
			field_editor.setValue(field_editor.value[:field_editor.fixed])
		}
	}

	if event.Key == termbox.KeyEnter {
		is_done = true
	} else if event.Key == termbox.KeyEsc {
		is_done = true
		field_editor.value = nil
	} else if event.Key == termbox.KeyArrowLeft {
		if field_editor.cursor_pos > 0 {
			field_editor.cursor_pos--
		}
	} else if event.Key == termbox.KeyArrowUp || event.Key == termbox.KeyCtrlA {
		field_editor.cursor_pos = 0
	} else if event.Key == termbox.KeyArrowRight {
		if field_editor.cursor_pos < len(field_editor.value) {
			field_editor.cursor_pos++
		}
	} else if event.Key == termbox.KeyArrowDown || event.Key == termbox.KeyCtrlE {
		field_editor.cursor_pos = len(field_editor.value)
	} else if event.Key == termbox.KeyCtrlH || event.Key == termbox.KeyBackspace {
		field_editor.delete()
	} else if event.Key == termbox.KeyCtrlK {
		field_editor.setValue(make([]rune, 0))
	} else if unicode.IsPrint(event.Ch) {
		field_editor.insert(event.Ch)
	} else if event.Key == termbox.KeySpace {
		field_editor.insert(' ')
	}
	return string(field_editor.value), is_done
}

func (field_editor *FieldEditor) setValue (value []rune) {
	field_editor.value = value
	if field_editor.cursor_pos > len(field_editor.value) {
		field_editor.cursor_pos = len(field_editor.value)
	}
}

func (field_editor *FieldEditor) insert(r rune) {
	if field_editor.overwrite && field_editor.cursor_pos < len(field_editor.value) {
		field_editor.value[field_editor.cursor_pos] = r
	} else {
		if field_editor.fixed > 0 && field_editor.cursor_pos == field_editor.fixed {
			return
		}
		pos := field_editor.cursor_pos
		field_editor.value = append(field_editor.value[:pos], append([]rune{r}, field_editor.value[pos:]...)...)
	}
	field_editor.cursor_pos++
}

func (field_editor *FieldEditor) delete() {
	pos := field_editor.cursor_pos
	if pos == 0 {
		return
	} else if pos < len(field_editor.value) {
		field_editor.value = append(field_editor.value[:pos-1], field_editor.value[pos:]...)
	} else {
		field_editor.value = field_editor.value[:pos-1]
	}

	field_editor.cursor_pos--
}

func (field_editor *FieldEditor) drawFieldValueAtPoint(style Style, x, y int) int {
	termbox.SetCursor(x+1+field_editor.cursor_pos, y)
	if len(field_editor.value) > 0 || len(field_editor.last_value) == 0 {
		return drawStringAtPoint(fmt.Sprintf(" %-*s ", field_editor.width, string(field_editor.value)), x, y,
			style.field_editor_fg, style.field_editor_bg)
	} else {
		return drawStringAtPoint(fmt.Sprintf(" %-*s ", field_editor.width, field_editor.last_value), x, y,
			style.field_editor_last_fg, style.field_editor_last_bg)
	}
}
<commit_msg>field_editor: refactor cursor movement.<commit_after>package main

import (
	"fmt"
	"unicode"

	"github.com/nsf/termbox-go"
)

type FieldEditor struct {
	value      []rune
	cursor_pos int
	last_value string
	width      int
	fixed      int
	overwrite  bool
}

func (field_editor *FieldEditor) handleKeyEvent(event termbox.Event) (string, bool) {
	is_done := false

	if event.Ch == 0 && len(field_editor.value) == 0 {
		field_editor.setValue([]rune(field_editor.last_value))
	}

	if field_editor.fixed > 0 {
		if len(field_editor.value) > field_editor.fixed {
			field_editor.setValue(field_editor.value[:field_editor.fixed])
		}
	}

	if event.Key == termbox.KeyEnter {
		is_done = true
	} else if event.Key == termbox.KeyEsc {
		is_done = true
		field_editor.value = nil
	} else if event.Key == termbox.KeyArrowLeft {
		field_editor.moveCursor(-1)
	} else if event.Key == termbox.KeyArrowUp || event.Key == termbox.KeyCtrlA {
		field_editor.cursor_pos = 0
	} else if event.Key == termbox.KeyArrowRight {
		field_editor.moveCursor(1)
	} else if event.Key == termbox.KeyArrowDown || event.Key == termbox.KeyCtrlE {
		field_editor.setCursorPos(len(field_editor.value))
	} else if event.Key == termbox.KeyCtrlH || event.Key == termbox.KeyBackspace {
		field_editor.delete()
	} else if event.Key == termbox.KeyCtrlK {
		field_editor.setValue(make([]rune, 0))
	} else if unicode.IsPrint(event.Ch) {
		field_editor.insert(event.Ch)
	} else if event.Key == termbox.KeySpace {
		field_editor.insert(' ')
	}
	return string(field_editor.value), is_done
}

func (field_editor *FieldEditor) setValue (value []rune) {
	field_editor.value = value
	if field_editor.cursor_pos > len(field_editor.value) {
		field_editor.setCursorPos(len(field_editor.value))
	}
}

func (field_editor *FieldEditor) setCursorPos (pos int) {
	if pos < 0 {
		pos = 0
	} else if field_editor.fixed > 0 && pos >= field_editor.fixed {
		pos = field_editor.fixed - 1
	}
	if pos > len(field_editor.value) {
		pos = len(field_editor.value)
	}

	field_editor.cursor_pos = pos
}

func (field_editor *FieldEditor) moveCursor (delta int) {
	field_editor.setCursorPos(field_editor.cursor_pos + delta)
}

func (field_editor *FieldEditor) insert(r rune) {
	if field_editor.overwrite && field_editor.cursor_pos < len(field_editor.value) {
		field_editor.value[field_editor.cursor_pos] = r
	} else {
		if field_editor.fixed > 0 && field_editor.cursor_pos == field_editor.fixed {
			return
		}
		pos := field_editor.cursor_pos
		field_editor.value = append(field_editor.value[:pos], append([]rune{r}, field_editor.value[pos:]...)...)
	}

	field_editor.moveCursor(1)
}

func (field_editor *FieldEditor) delete() {
	pos := field_editor.cursor_pos
	if pos == 0 {
		return
	} else if pos < len(field_editor.value) {
		field_editor.value = append(field_editor.value[:pos-1], field_editor.value[pos:]...)
	} else {
		field_editor.value = field_editor.value[:pos-1]
	}

	field_editor.moveCursor(-1)
}

func (field_editor *FieldEditor) drawFieldValueAtPoint(style Style, x, y int) int {
	termbox.SetCursor(x+1+field_editor.cursor_pos, y)
	if len(field_editor.value) > 0 || len(field_editor.last_value) == 0 {
		return drawStringAtPoint(fmt.Sprintf(" %-*s ", field_editor.width, string(field_editor.value)), x, y,
			style.field_editor_fg, style.field_editor_bg)
	} else {
		return drawStringAtPoint(fmt.Sprintf(" %-*s ", field_editor.width, field_editor.last_value), x, y,
			style.field_editor_last_fg, style.field_editor_last_bg)
	}
}
<|endoftext|>


<commit_before>package main

// commandline tool to grab, scrape and output a news article
//
// can grab article via http or from a file (raw html or the
// first response in a .warc)
//

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"errors"
	"flag"
	"fmt"
	"github.com/bcampbell/arts/arts"
	"github.com/bcampbell/warc"
	"golang.org/x/net/html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

func main() {
	var debug string
	var parseOnly bool
	flag.StringVar(&debug, "d", "", "log debug info to stderr (h=headline, c=content, a=authors d=dates u=urls s=cruft all=hcadus)")
	flag.BoolVar(&parseOnly, "parse", false, "just dump the parsed html and exit")
	var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Println("Usage: ", os.Args[0], "<article url>")
		os.Exit(1)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// set up the debug logging
	debug = strings.ToLower(debug)
	if debug == "name" {
		debug = ""
	}
	if debug == "all" {
		debug = "hcadus"
	}
	for _, flag := range debug {
		switch flag {
		case 'h':
			arts.Debug.HeadlineLogger = log.New(os.Stderr, "", 0)
		case 'c':
			arts.Debug.ContentLogger = log.New(os.Stderr, "", 0)
		case 'a':
			arts.Debug.AuthorsLogger = log.New(os.Stderr, "", 0)
		case 'd':
			arts.Debug.DatesLogger = log.New(os.Stderr, "", 0)
		case 'u':
			arts.Debug.URLLogger = log.New(os.Stderr, "", 0)
		case 's':
			arts.Debug.CruftLogger = log.New(os.Stderr, "", 0)
		}
	}

	var rawHTML []byte
	var artURL string

	srcName := flag.Arg(0)
	u, err := url.Parse(srcName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s is not url: %s", srcName, err)
		os.Exit(1)
	}

	var in io.ReadCloser
	switch strings.ToLower(u.Scheme) {
	case "http", "https":
		artURL = srcName
		in, err = openHttp(srcName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: http fetch failed: %s", err)
			os.Exit(1)
		}
		rawHTML, err = ioutil.ReadAll(in)
		in.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: read failed: %s", err)
			os.Exit(1)
		}
	case "file", "":

		foo := strings.ToLower(u.Path)
		if strings.HasSuffix(foo, ".warc") || strings.HasSuffix(foo, ".warc.gz") {
			// it's a warc file
			rawHTML, artURL, err = fromWARC(u.Path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: warc read failed: %s", err)
				os.Exit(1)
			}
		} else {
			// treat as plain html file (url will suck)
			in, err = os.Open(u.Path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: open failed: %s", err)
				os.Exit(1)
			}
			rawHTML, err = ioutil.ReadAll(in)
			in.Close()
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: read failed: %s", err)
				os.Exit(1)
			}
		}
	}

	root, err := arts.ParseHTML(rawHTML)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: html parsing failed: %s", err)
		os.Exit(1)
	}

	if parseOnly {
		err = html.Render(os.Stdout, root)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: html render failed: %s", err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	art, err := arts.ExtractFromTree(root, artURL)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: extraction failed: %s", err)
		os.Exit(1)
	}

	err = dumpArt(os.Stdout, art)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: dumping article to stdout: %s", err)
		os.Exit(1)
	}
}

// fetch html from a WARC file
// returns: html, url, err
func fromWARC(filename string) ([]byte, string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, "", err
	}
	defer f.Close()

	var in io.Reader
	if filepath.Ext(filename) == ".gz" {
		gin, err := gzip.NewReader(f)
		if err != nil {
			return nil, "", err
		}
		defer gin.Close()
		in = gin
	} else {
		in = f
	}

	warcReader := warc.NewReader(in)
	for {
		//	fmt.Printf("WARC\n")
		rec, err := warcReader.ReadRecord()
		if err != nil {
			return nil, "", fmt.Errorf("Error reading %s: %s", filename, err)
		}
		if rec.Header.Get("Warc-Type") != "response" {
			continue
		}
		reqURL := rec.Header.Get("Warc-Target-Uri")
		// parse response, grab raw html
		rdr := bufio.NewReader(bytes.NewReader(rec.Block))
		response, err := http.ReadResponse(rdr, nil)
		if err != nil {
			return nil, "", fmt.Errorf("Error parsing response: %s", err)
		}
		defer response.Body.Close()
		if response.StatusCode != 200 {
			return nil, "", fmt.Errorf("HTTP error: %d", response.StatusCode)
		}
		rawHTML, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, "", err
		}
		return rawHTML, reqURL, err
	}
}

func openHttp(artURL string) (io.ReadCloser, error) {

	client := &http.Client{}

	req, err := http.NewRequest("GET", artURL, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Accept", "*/*")
	req.Header.Set("User-Agent", `Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0`)
	//	req.Header.Set("User-Agent", "curl/7.47.0")

	response, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Request failed: %s", response.Status))
	}
	return response.Body, nil
}
<commit_msg>scrapetool: fix up warc uri bracketing uncertainty<commit_after>package main

// commandline tool to grab, scrape and output a news article
//
// can grab article via http or from a file (raw html or the
// first response in a .warc)
//

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"errors"
	"flag"
	"fmt"
	"github.com/bcampbell/arts/arts"
	"github.com/bcampbell/warc"
	"golang.org/x/net/html"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

func main() {
	var debug string
	var parseOnly bool
	flag.StringVar(&debug, "d", "", "log debug info to stderr (h=headline, c=content, a=authors d=dates u=urls s=cruft all=hcadus)")
	flag.BoolVar(&parseOnly, "parse", false, "just dump the parsed html and exit")
	var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Println("Usage: ", os.Args[0], "<article url>")
		os.Exit(1)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// set up the debug logging
	debug = strings.ToLower(debug)
	if debug == "name" {
		debug = ""
	}
	if debug == "all" {
		debug = "hcadus"
	}
	for _, flag := range debug {
		switch flag {
		case 'h':
			arts.Debug.HeadlineLogger = log.New(os.Stderr, "", 0)
		case 'c':
			arts.Debug.ContentLogger = log.New(os.Stderr, "", 0)
		case 'a':
			arts.Debug.AuthorsLogger = log.New(os.Stderr, "", 0)
		case 'd':
			arts.Debug.DatesLogger = log.New(os.Stderr, "", 0)
		case 'u':
			arts.Debug.URLLogger = log.New(os.Stderr, "", 0)
		case 's':
			arts.Debug.CruftLogger = log.New(os.Stderr, "", 0)
		}
	}

	var rawHTML []byte
	var artURL string

	srcName := flag.Arg(0)
	u, err := url.Parse(srcName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s is not url: %s", srcName, err)
		os.Exit(1)
	}

	var in io.ReadCloser
	switch strings.ToLower(u.Scheme) {
	case "http", "https":
		artURL = srcName
		in, err = openHttp(srcName)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: http fetch failed: %s", err)
			os.Exit(1)
		}
		rawHTML, err = ioutil.ReadAll(in)
		in.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: read failed: %s", err)
			os.Exit(1)
		}
	case "file", "":

		foo := strings.ToLower(u.Path)
		if strings.HasSuffix(foo, ".warc") || strings.HasSuffix(foo, ".warc.gz") {
			// it's a warc file
			rawHTML, artURL, err = fromWARC(u.Path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: warc read failed: %s", err)
				os.Exit(1)
			}
		} else {
			// treat as plain html file (url will suck)
			in, err = os.Open(u.Path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: open failed: %s", err)
				os.Exit(1)
			}
			rawHTML, err = ioutil.ReadAll(in)
			in.Close()
			if err != nil {
				fmt.Fprintf(os.Stderr, "ERROR: read failed: %s", err)
				os.Exit(1)
			}
		}
	}

	root, err := arts.ParseHTML(rawHTML)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: html parsing failed: %s", err)
		os.Exit(1)
	}

	if parseOnly {
		err = html.Render(os.Stdout, root)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: html render failed: %s", err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	art, err := arts.ExtractFromTree(root, artURL)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: extraction failed: %s", err)
		os.Exit(1)
	}

	err = dumpArt(os.Stdout, art)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: dumping article to stdout: %s", err)
		os.Exit(1)
	}
}

// fetch html from a WARC file
// returns: html, url, err
func fromWARC(filename string) ([]byte, string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, "", err
	}
	defer f.Close()

	var in io.Reader
	if filepath.Ext(filename) == ".gz" {
		gin, err := gzip.NewReader(f)
		if err != nil {
			return nil, "", err
		}
		defer gin.Close()
		in = gin
	} else {
		in = f
	}

	warcReader := warc.NewReader(in)
	for {
		//	fmt.Printf("WARC\n")
		rec, err := warcReader.ReadRecord()
		if err != nil {
			return nil, "", fmt.Errorf("Error reading %s: %s", filename, err)
		}
		if rec.Header.Get("Warc-Type") != "response" {
			continue
		}
		//reqURL := rec.Header.Get("Warc-Target-Uri")
		reqURL := rec.TargetURI() // get "Warc-Target-Uri", stripping any angle-brackets
		// parse response, grab raw html
		rdr := bufio.NewReader(bytes.NewReader(rec.Block))
		response, err := http.ReadResponse(rdr, nil)
		if err != nil {
			return nil, "", fmt.Errorf("Error parsing response: %s", err)
		}
		defer response.Body.Close()
		if response.StatusCode != 200 {
			return nil, "", fmt.Errorf("HTTP error: %d", response.StatusCode)
		}
		rawHTML, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, "", err
		}
		return rawHTML, reqURL, err
	}
}

func openHttp(artURL string) (io.ReadCloser, error) {

	client := &http.Client{}

	req, err := http.NewRequest("GET", artURL, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Accept", "*/*")
	req.Header.Set("User-Agent", `Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0`)
	//	req.Header.Set("User-Agent", "curl/7.47.0")

	response, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Request failed: %s", response.Status))
	}
	return response.Body, nil
}
<|endoftext|>


<commit_before>package main

// gdsh option parsing - a custom parser is implemented because the
// few packages I checked out didn't do what I want, or ended up being
// really clunky to do some of the uglier bits of what gdsh needs

import (
	"fmt"
	"log"
	"os"
	"strings"
)

type GdshOptions struct {
	List         string            // --list/-l
	Next         bool              // --next
	Reset        bool              // --reset
	Verbose      bool              // --verbose/-v
	Comment      string            // --comment
	InclRe       string            // --include
	ExclRe       string            // --exclude
	Key          string            // --key/-i
	User         string            // --user
	Node         string            // --node/-h
	Command      string            // --command/-c
	Script       string            // --script/-s
	BgJob        bool              // --background/-b
	RemoteLog    string            // --remote-log/-r
	RemoteScript string            // --remote-script-path
	Env          map[string]string // --env/-e key=val
	Args         []string          // leftover arguments for subcommands
}

var usageText = `
HELP!
`

func printUsage() {
	fmt.Printf("%s", usageText)
}

func deleteArg(index int) (args []string, deleted string) {
	args = make([]string, len(os.Args)-1)

	offset := 0
	for i := range os.Args {
		if i == index {
			deleted = os.Args[i]
			offset = 1
			continue
		}
		args[i-offset] = os.Args[i]
	}

	return
}

func parseArgs(args []string, command string) (opt GdshOptions) {
	env := map[string]string{}

	// defaults
	opt = GdshOptions{
		List:         "default",
		Next:         false,
		Reset:        false,
		Verbose:      false,
		Comment:      "",
		InclRe:       "",
		ExclRe:       "",
		Key:          "",
		Node:         "",
		Command:      "",
		Script:       "",
		BgJob:        false,
		RemoteLog:    "",
		RemoteScript: "",
		Env:          env,
	}

	if opt.User == "" {
		opt.User = UserIdToUsername(os.Geteuid())
		if opt.User == "" {
			log.Fatal("Could not determine username. Use --user or fix your /etc/passwd.")
		}
	}

	skip := true
	cont := false
	for i, arg := range args {
		if skip {
			skip = false
			continue
		}

		switch arg {
		case "--list", "-l":
			opt.List = args[i+1]
			skip = true
		case "next", "--next":
			opt.Next = true
			cont = true
		case "reset", "--reset":
			opt.Reset = true
			cont = true
		case "--comment":
			opt.Comment = args[i+1]
			skip = true
		case "--verbose", "-v":
			opt.Verbose = true
			cont = true
		case "--key", "-i":
			opt.Key = args[i+1]
			skip = true
		case "--node", "-n":
			opt.Node = args[i+1]
			skip = true
		case "--incl":
			opt.InclRe = args[i+1]
			skip = true
		case "--excl":
			opt.ExclRe = args[i+1]
			skip = true
		case "--root":
			opt.User = "root"
			cont = true
		case "--user":
			opt.User = args[i+1]
			skip = true
		case "--help":
			printUsage()
			os.Exit(0)
		case "--env", "-e":
			parts := strings.SplitN(strings.Trim(args[i+1], " \t"), "=", 2)
			env[parts[0]] = parts[1]
			skip = true
		}

		switch command {
		case "run":
			switch arg {
			case "--command", "-c":
				opt.Command = args[i+1]
				skip = true
			case "--script", "-s":
				opt.Script = args[i+1]
				skip = true
			case "--background":
				opt.BgJob = true
				cont = true
			}
		}

		if skip || cont {
			continue
		}

		opt.Args = append(opt.Args, arg)
	}

	switch command {
	case "run":
		if opt.Command != "" && opt.Script != "" {
			log.Fatal("--script/-s and --command/-c are mutually exclusive!")
		}
	}

	return
}

// sshAddressList loads the requested node list and returns a string list
// of address:port strings that can be used with ssh.go
func (opt *GdshOptions) sshAddressList() (list []string) {
	list = []string{}
	nodes := loadListByName(opt.List)

	for _, node := range nodes {
		list = append(list, fmt.Sprintf("%s:22", node.Address))
	}

	return list
}

// vim: ts=4 sw=4 noet tw=120 softtabstop=4
<commit_msg>remove dead code<commit_after>package main

// gdsh option parsing - a custom parser is implemented because the
// few packages I checked out didn't do what I want, or ended up being
// really clunky to do some of the uglier bits of what gdsh needs

import (
	"fmt"
	"log"
	"os"
	"strings"
)

type GdshOptions struct {
	List         string            // --list/-l
	Next         bool              // --next
	Reset        bool              // --reset
	Verbose      bool              // --verbose/-v
	Comment      string            // --comment
	InclRe       string            // --include
	ExclRe       string            // --exclude
	Key          string            // --key/-i
	User         string            // --user
	Node         string            // --node/-h
	Command      string            // --command/-c
	Script       string            // --script/-s
	BgJob        bool              // --background/-b
	RemoteLog    string            // --remote-log/-r
	RemoteScript string            // --remote-script-path
	Env          map[string]string // --env/-e key=val
	Args         []string          // leftover arguments for subcommands
}

var usageText = `
HELP!
`

func printUsage() {
	fmt.Printf("%s", usageText)
}

func deleteArg(index int) (args []string, deleted string) {
	args = make([]string, len(os.Args)-1)

	offset := 0
	for i := range os.Args {
		if i == index {
			deleted = os.Args[i]
			offset = 1
			continue
		}
		args[i-offset] = os.Args[i]
	}

	return
}

func parseArgs(args []string, command string) (opt GdshOptions) {
	env := map[string]string{}

	// defaults
	opt = GdshOptions{
		List:         "default",
		Next:         false,
		Reset:        false,
		Verbose:      false,
		Comment:      "",
		InclRe:       "",
		ExclRe:       "",
		Key:          "",
		Node:         "",
		Command:      "",
		Script:       "",
		BgJob:        false,
		RemoteLog:    "",
		RemoteScript: "",
		Env:          env,
	}

	if opt.User == "" {
		opt.User = UserIdToUsername(os.Geteuid())
		if opt.User == "" {
			log.Fatal("Could not determine username. Use --user or fix your /etc/passwd.")
		}
	}

	skip := true
	cont := false
	for i, arg := range args {
		if skip {
			skip = false
			continue
		}

		switch arg {
		case "--list", "-l":
			opt.List = args[i+1]
			skip = true
		case "next", "--next":
			opt.Next = true
			cont = true
		case "reset", "--reset":
			opt.Reset = true
			cont = true
		case "--comment":
			opt.Comment = args[i+1]
			skip = true
		case "--verbose", "-v":
			opt.Verbose = true
			cont = true
		case "--key", "-i":
			opt.Key = args[i+1]
			skip = true
		case "--node", "-n":
			opt.Node = args[i+1]
			skip = true
		case "--incl":
			opt.InclRe = args[i+1]
			skip = true
		case "--excl":
			opt.ExclRe = args[i+1]
			skip = true
		case "--root":
			opt.User = "root"
			cont = true
		case "--user":
			opt.User = args[i+1]
			skip = true
		case "--help":
			printUsage()
			os.Exit(0)
		case "--env", "-e":
			parts := strings.SplitN(strings.Trim(args[i+1], " \t"), "=", 2)
			env[parts[0]] = parts[1]
			skip = true
		}

		switch command {
		case "run":
			switch arg {
			case "--command", "-c":
				opt.Command = args[i+1]
				skip = true
			case "--script", "-s":
				opt.Script = args[i+1]
				skip = true
			case "--background":
				opt.BgJob = true
				cont = true
			}
		}

		if skip || cont {
			continue
		}

		opt.Args = append(opt.Args, arg)
	}

	switch command {
	case "run":
		if opt.Command != "" && opt.Script != "" {
			log.Fatal("--script/-s and --command/-c are mutually exclusive!")
		}
	}

	return
}

// vim: ts=4 sw=4 noet tw=120 softtabstop=4
<|endoftext|>


<commit_before>package bimg

/*
#cgo pkg-config: vips
#include "vips/vips.h"
*/
import "C"

const (
	// Quality defines the default JPEG quality to be used.
	Quality = 80
	// MaxSize defines the maximum pixels width or height supported.
	MaxSize = 16383
)

// Gravity represents the image gravity value.
type Gravity int

const (
	// GravityCentre represents the centre value used for image gravity orientation.
	GravityCentre Gravity = iota
	// GravityNorth represents the north value used for image gravity orientation.
	GravityNorth
	// GravityEast represents the east value used for image gravity orientation.
	GravityEast
	// GravitySouth represents the south value used for image gravity orientation.
	GravitySouth
	// GravityWest represents the west value used for image gravity orientation.
	GravityWest
	// GravitySmart enables libvips Smart Crop algorithm for image gravity orientation.
	GravitySmart
)

// Interpolator represents the image interpolation value.
type Interpolator int

const (
	// Bicubic interpolation value.
	Bicubic Interpolator = iota
	// Bilinear interpolation value.
	Bilinear
	// Nohalo interpolation value.
	Nohalo
)

var interpolations = map[Interpolator]string{
	Bicubic:  "bicubic",
	Bilinear: "bilinear",
	Nohalo:   "nohalo",
}

func (i Interpolator) String() string {
	return interpolations[i]
}

// Angle represents the image rotation angle value.
type Angle int

const (
	// D0 represents the rotation angle 0 degrees.
	D0 Angle = 0
	// D45 represents the rotation angle 90 degrees.
	D45 Angle = 45
	// D90 represents the rotation angle 90 degrees.
	D90 Angle = 90
	// D135 represents the rotation angle 90 degrees.
	D135 Angle = 135
	// D180 represents the rotation angle 180 degrees.
	D180 Angle = 180
	// D235 represents the rotation angle 235 degrees.
	D235 Angle = 235
	// D270 represents the rotation angle 270 degrees.
	D270 Angle = 270
	// D315 represents the rotation angle 180 degrees.
	D315 Angle = 315
)

// Direction represents the image direction value.
type Direction int

const (
	// Horizontal represents the orizontal image direction value.
	Horizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
	// Vertical represents the vertical image direction value.
	Vertical Direction = C.VIPS_DIRECTION_VERTICAL
)

// Interpretation represents the image interpretation type.
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int

const (
	// InterpretationError points to the libvips interpretation error type.
	InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
	// InterpretationMultiband points to its libvips interpretation equivalent type.
	InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
	// InterpretationBW points to its libvips interpretation equivalent type.
	InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
	// InterpretationCMYK points to its libvips interpretation equivalent type.
	InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
	// InterpretationRGB points to its libvips interpretation equivalent type.
	InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
	// InterpretationSRGB points to its libvips interpretation equivalent type.
	InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
	// InterpretationRGB16 points to its libvips interpretation equivalent type.
	InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
	// InterpretationGREY16 points to its libvips interpretation equivalent type.
	InterpretationGREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
	// InterpretationScRGB points to its libvips interpretation equivalent type.
	InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
	// InterpretationLAB points to its libvips interpretation equivalent type.
	InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
	// InterpretationXYZ points to its libvips interpretation equivalent type.
	InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
)

// Extend represents the image extend mode, used when the edges
// of an image are extended, you can specify how you want the extension done.
// See: http://www.vips.ecs.soton.ac.uk/supported/8.4/doc/html/libvips/libvips-conversion.html#VIPS-EXTEND-BACKGROUND:CAPS
type Extend int

const (
	// ExtendBlack extend with black (all 0) pixels mode.
	ExtendBlack Extend = C.VIPS_EXTEND_BLACK
	// ExtendCopy copy the image edges.
	ExtendCopy Extend = C.VIPS_EXTEND_COPY
	// ExtendRepeat repeat the whole image.
	ExtendRepeat Extend = C.VIPS_EXTEND_REPEAT
	// ExtendMirror mirror the whole image.
	ExtendMirror Extend = C.VIPS_EXTEND_MIRROR
	// ExtendWhite extend with white (all bits set) pixels.
	ExtendWhite Extend = C.VIPS_EXTEND_WHITE
	// ExtendBackground with colour from the background property.
	ExtendBackground Extend = C.VIPS_EXTEND_BACKGROUND
	// ExtendLast extend with last pixel.
	ExtendLast Extend = C.VIPS_EXTEND_LAST
)

// WatermarkFont defines the default watermark font to be used.
var WatermarkFont = "sans 10"

// Color represents a traditional RGB color scheme.
type Color struct {
	R, G, B uint8
}

// ColorBlack is a shortcut to black RGB color representation.
var ColorBlack = Color{0, 0, 0}

// Watermark represents the text-based watermark supported options.
type Watermark struct {
	Width       int
	DPI         int
	Margin      int
	Opacity     float32
	NoReplicate bool
	Text        string
	Font        string
	Background  Color
}

// WatermarkImage represents the image-based watermark supported options.
type WatermarkImage struct {
	Left    int
	Top     int
	Buf     []byte
	Opacity float32
}

// GaussianBlur represents the gaussian image transformation values.
type GaussianBlur struct {
	Sigma   float64
	MinAmpl float64
}

// Sharpen represents the image sharp transformation options.
type Sharpen struct {
	Radius int
	X1     float64
	Y2     float64
	Y3     float64
	M1     float64
	M2     float64
}

// Options represents the supported image transformation options.
type Options struct {
	Height         int
	Width          int
	AreaHeight     int
	AreaWidth      int
	Top            int
	Left           int
	Quality        int
	Compression    int
	Zoom           int
	Crop           bool
	SmartCrop      bool // Deprecated
	Enlarge        bool
	Embed          bool
	Flip           bool
	Flop           bool
	Force          bool
	NoAutoRotate   bool
	NoProfile      bool
	Interlace      bool
	StripMetadata  bool
	Trim           bool
	Extend         Extend
	Rotate         Angle
	Background     Color
	Gravity        Gravity
	Watermark      Watermark
	WatermarkImage WatermarkImage
	Type           ImageType
	Interpolator   Interpolator
	Interpretation Interpretation
	GaussianBlur   GaussianBlur
	Sharpen        Sharpen
	OutputICC      string
}
<commit_msg>Add nearest-neighbour interpolation<commit_after>package bimg

/*
#cgo pkg-config: vips
#include "vips/vips.h"
*/
import "C"

const (
	// Quality defines the default JPEG quality to be used.
	Quality = 80
	// MaxSize defines the maximum pixels width or height supported.
	MaxSize = 16383
)

// Gravity represents the image gravity value.
type Gravity int

const (
	// GravityCentre represents the centre value used for image gravity orientation.
	GravityCentre Gravity = iota
	// GravityNorth represents the north value used for image gravity orientation.
	GravityNorth
	// GravityEast represents the east value used for image gravity orientation.
	GravityEast
	// GravitySouth represents the south value used for image gravity orientation.
	GravitySouth
	// GravityWest represents the west value used for image gravity orientation.
	GravityWest
	// GravitySmart enables libvips Smart Crop algorithm for image gravity orientation.
	GravitySmart
)

// Interpolator represents the image interpolation value.
type Interpolator int

const (
	// Bicubic interpolation value.
	Bicubic Interpolator = iota
	// Bilinear interpolation value.
	Bilinear
	// Nohalo interpolation value.
	Nohalo
	// Nearest neighbour interpolation value.
	Nearest
)

var interpolations = map[Interpolator]string{
	Bicubic:  "bicubic",
	Bilinear: "bilinear",
	Nohalo:   "nohalo",
	Nearest:  "nearest",
}

func (i Interpolator) String() string {
	return interpolations[i]
}

// Angle represents the image rotation angle value.
type Angle int

const (
	// D0 represents the rotation angle 0 degrees.
	D0 Angle = 0
	// D45 represents the rotation angle 90 degrees.
	D45 Angle = 45
	// D90 represents the rotation angle 90 degrees.
	D90 Angle = 90
	// D135 represents the rotation angle 90 degrees.
	D135 Angle = 135
	// D180 represents the rotation angle 180 degrees.
	D180 Angle = 180
	// D235 represents the rotation angle 235 degrees.
	D235 Angle = 235
	// D270 represents the rotation angle 270 degrees.
	D270 Angle = 270
	// D315 represents the rotation angle 180 degrees.
	D315 Angle = 315
)

// Direction represents the image direction value.
type Direction int

const (
	// Horizontal represents the orizontal image direction value.
	Horizontal Direction = C.VIPS_DIRECTION_HORIZONTAL
	// Vertical represents the vertical image direction value.
	Vertical Direction = C.VIPS_DIRECTION_VERTICAL
)

// Interpretation represents the image interpretation type.
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int

const (
	// InterpretationError points to the libvips interpretation error type.
	InterpretationError Interpretation = C.VIPS_INTERPRETATION_ERROR
	// InterpretationMultiband points to its libvips interpretation equivalent type.
	InterpretationMultiband Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
	// InterpretationBW points to its libvips interpretation equivalent type.
	InterpretationBW Interpretation = C.VIPS_INTERPRETATION_B_W
	// InterpretationCMYK points to its libvips interpretation equivalent type.
	InterpretationCMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
	// InterpretationRGB points to its libvips interpretation equivalent type.
	InterpretationRGB Interpretation = C.VIPS_INTERPRETATION_RGB
	// InterpretationSRGB points to its libvips interpretation equivalent type.
	InterpretationSRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
	// InterpretationRGB16 points to its libvips interpretation equivalent type.
	InterpretationRGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
	// InterpretationGREY16 points to its libvips interpretation equivalent type.
	InterpretationGREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
	// InterpretationScRGB points to its libvips interpretation equivalent type.
	InterpretationScRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
	// InterpretationLAB points to its libvips interpretation equivalent type.
	InterpretationLAB Interpretation = C.VIPS_INTERPRETATION_LAB
	// InterpretationXYZ points to its libvips interpretation equivalent type.
	InterpretationXYZ Interpretation = C.VIPS_INTERPRETATION_XYZ
)

// Extend represents the image extend mode, used when the edges
// of an image are extended, you can specify how you want the extension done.
// See: http://www.vips.ecs.soton.ac.uk/supported/8.4/doc/html/libvips/libvips-conversion.html#VIPS-EXTEND-BACKGROUND:CAPS
type Extend int

const (
	// ExtendBlack extend with black (all 0) pixels mode.
	ExtendBlack Extend = C.VIPS_EXTEND_BLACK
	// ExtendCopy copy the image edges.
	ExtendCopy Extend = C.VIPS_EXTEND_COPY
	// ExtendRepeat repeat the whole image.
	ExtendRepeat Extend = C.VIPS_EXTEND_REPEAT
	// ExtendMirror mirror the whole image.
	ExtendMirror Extend = C.VIPS_EXTEND_MIRROR
	// ExtendWhite extend with white (all bits set) pixels.
	ExtendWhite Extend = C.VIPS_EXTEND_WHITE
	// ExtendBackground with colour from the background property.
	ExtendBackground Extend = C.VIPS_EXTEND_BACKGROUND
	// ExtendLast extend with last pixel.
	ExtendLast Extend = C.VIPS_EXTEND_LAST
)

// WatermarkFont defines the default watermark font to be used.
var WatermarkFont = "sans 10"

// Color represents a traditional RGB color scheme.
type Color struct {
	R, G, B uint8
}

// ColorBlack is a shortcut to black RGB color representation.
var ColorBlack = Color{0, 0, 0}

// Watermark represents the text-based watermark supported options.
type Watermark struct {
	Width       int
	DPI         int
	Margin      int
	Opacity     float32
	NoReplicate bool
	Text        string
	Font        string
	Background  Color
}

// WatermarkImage represents the image-based watermark supported options.
type WatermarkImage struct {
	Left    int
	Top     int
	Buf     []byte
	Opacity float32
}

// GaussianBlur represents the gaussian image transformation values.
type GaussianBlur struct {
	Sigma   float64
	MinAmpl float64
}

// Sharpen represents the image sharp transformation options.
type Sharpen struct {
	Radius int
	X1     float64
	Y2     float64
	Y3     float64
	M1     float64
	M2     float64
}

// Options represents the supported image transformation options.
type Options struct {
	Height         int
	Width          int
	AreaHeight     int
	AreaWidth      int
	Top            int
	Left           int
	Quality        int
	Compression    int
	Zoom           int
	Crop           bool
	SmartCrop      bool // Deprecated
	Enlarge        bool
	Embed          bool
	Flip           bool
	Flop           bool
	Force          bool
	NoAutoRotate   bool
	NoProfile      bool
	Interlace      bool
	StripMetadata  bool
	Trim           bool
	Extend         Extend
	Rotate         Angle
	Background     Color
	Gravity        Gravity
	Watermark      Watermark
	WatermarkImage WatermarkImage
	Type           ImageType
	Interpolator   Interpolator
	Interpretation Interpretation
	GaussianBlur   GaussianBlur
	Sharpen        Sharpen
	OutputICC      string
}
<|endoftext|>


<commit_before>package ratgo

// #cgo LDFLAGS: -lrocksdb -lrt
// #include <stdlib.h>
// #include "leveldb/c.h"
import "C"

// FilterPolicy is a factory type that allows the RocksDB database to create a
// filter, such as a bloom filter, that is stored in the sstables and used by
// DB.Get to reduce reads.
//
// An instance of this struct may be supplied to Options when opening a
// DB. Typical usage is to call NewBloomFilter to get an instance.
//
// To prevent memory leaks, a FilterPolicy must have Close called on it when
// it is no longer needed by the program.

// Advanced user may want to impletement their own filter policy.
type FilterPolicy struct {
	Policy *C.leveldb_filterpolicy_t
}

// NewBloomFilter creates a filter policy that will create a bloom filter when
// necessary with the given number of bits per key.
//
// See the FilterPolicy documentation for more.
func NewBloomFilter(bitsPerKey int) *FilterPolicy {
	policy := C.leveldb_filterpolicy_create_bloom(C.int(bitsPerKey))
	return &FilterPolicy{policy}
}

func (fp *FilterPolicy) Close() {
	C.leveldb_filterpolicy_destroy(fp.Policy)
}
<commit_msg>filter_policy<commit_after>package ratgo

// #cgo LDFLAGS: -lrocksdb -lrt
// #include <stdlib.h>
// #include "rocksdb/c.h"
import "C"

// FilterPolicy is a factory type that allows the RocksDB database to create a
// filter, such as a bloom filter, that is stored in the sstables and used by
// DB.Get to reduce reads.
//
// An instance of this struct may be supplied to Options when opening a
// DB. Typical usage is to call NewBloomFilter to get an instance.
//
// To prevent memory leaks, a FilterPolicy must have Close called on it when
// it is no longer needed by the program.

// Advanced user may want to impletement their own filter policy.
type FilterPolicy struct {
	Policy *C.leveldb_filterpolicy_t
}

// NewBloomFilter creates a filter policy that will create a bloom filter when
// necessary with the given number of bits per key.
//
// See the FilterPolicy documentation for more.
func NewBloomFilter(bitsPerKey int) *FilterPolicy {
	policy := C.leveldb_filterpolicy_create_bloom(C.int(bitsPerKey))
	return &FilterPolicy{policy}
}

func (fp *FilterPolicy) Close() {
	C.leveldb_filterpolicy_destroy(fp.Policy)
}
<|endoftext|>


<commit_before>package vollocal

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"

	"context"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/voldriver"
	"code.cloudfoundry.org/voldriver/driverhttp"
	"code.cloudfoundry.org/volman"
)

type dockerDriverDiscoverer struct {
	logger        lager.Logger
	driverFactory DockerDriverFactory

	driverRegistry volman.PluginRegistry
	driverPaths    []string
}

func NewDockerDriverDiscoverer(logger lager.Logger, driverRegistry volman.PluginRegistry, driverPaths []string) volman.Discoverer {
	return &dockerDriverDiscoverer{
		logger:        logger,
		driverFactory: NewDockerDriverFactory(),

		driverRegistry: driverRegistry,
		driverPaths:    driverPaths,
	}
}

func NewDockerDriverDiscovererWithDriverFactory(logger lager.Logger, driverRegistry volman.PluginRegistry, driverPaths []string, factory DockerDriverFactory) volman.Discoverer {
	return &dockerDriverDiscoverer{
		logger:        logger,
		driverFactory: factory,

		driverRegistry: driverRegistry,
		driverPaths:    driverPaths,
	}
}

func (r *dockerDriverDiscoverer) Discover(logger lager.Logger) (map[string]volman.Plugin, error) {
	logger = logger.Session("discover")
	logger.Debug("start")
	logger.Info("discovering-drivers", lager.Data{"driver-paths": r.driverPaths})
	defer logger.Debug("end")

	endpoints := make(map[string]volman.Plugin)

	for _, driverPath := range r.driverPaths {
		//precedence order: sock -> spec -> json
		spec_types := [3]string{"sock", "spec", "json"}
		for _, spec_type := range spec_types {
			matchingDriverSpecs, err := r.getMatchingDriverSpecs(logger, driverPath, spec_type)

			if err != nil {
				// untestable on linux, does glob work differently on windows???
				return map[string]volman.Plugin{}, fmt.Errorf("Volman configured with an invalid driver path '%s', error occured list files (%s)", driverPath, err.Error())
			}
			if len(matchingDriverSpecs) > 0 {
				logger.Debug("driver-specs", lager.Data{"drivers": matchingDriverSpecs})
				var existing map[string]volman.Plugin
				if r.driverRegistry != nil {
					existing = r.driverRegistry.Plugins()
					logger.Debug("existing-drivers", lager.Data{"len": len(existing)})
				}

				endpoints = r.insertIfAliveAndNotFound(logger, endpoints, driverPath, matchingDriverSpecs, existing)
			}
		}
	}
	return endpoints, nil
}

func (r *dockerDriverDiscoverer) getMatchingDriverSpecs(logger lager.Logger, path string, pattern string) ([]string, error) {
	logger.Debug("binaries", lager.Data{"path": path, "pattern": pattern})
	matchingDriverSpecs, err := filepath.Glob(path + string(os.PathSeparator) + "*." + pattern)
	if err != nil { // untestable on linux, does glob work differently on windows???
		return nil, fmt.Errorf("Volman configured with an invalid driver path '%s', error occured list files (%s)", path, err.Error())
	}
	return matchingDriverSpecs, nil

}

func (r *dockerDriverDiscoverer) insertIfAliveAndNotFound(logger lager.Logger, endpoints map[string]volman.Plugin, driverPath string, specs []string, existing map[string]volman.Plugin) map[string]volman.Plugin {
	logger = logger.Session("insert-if-not-found")
	logger.Debug("start")
	defer logger.Debug("end")

	var plugin volman.Plugin
	var ok bool
	var re *regexp.Regexp

	for _, spec := range specs {
		if runtime.GOOS == "windows" {
			re = regexp.MustCompile(`([^\]*\)?([^\]*)\.(sock|spec|json)$`)
		} else {
			re = regexp.MustCompile(`([^/]*/)?([^/]*)\.(sock|spec|json)$`)
		}

		segs2 := re.FindAllStringSubmatch(spec, 1)
		if len(segs2) <= 0 {
			continue
		}
		specName := segs2[0][2]
		specFile := segs2[0][2] + "." + segs2[0][3]
		logger.Debug("insert-unique-spec", lager.Data{"specname": specName})

		_, ok = endpoints[specName]
		if !ok {
			plugin, ok = existing[specName]
			if ok == true {
				driverSpec, err := voldriver.ReadDriverSpec(logger, specName, driverPath, specFile)
				if err != nil {
					logger.Error("error-reading-driver-spec", err)
					continue
				}
				pluginSpec := volman.PluginSpec{
					Name:    driverSpec.Name,
					Address: driverSpec.Address,
				}
				if driverSpec.TLSConfig != nil {
					pluginSpec.TLSConfig = &volman.TLSConfig{
						InsecureSkipVerify: driverSpec.TLSConfig.InsecureSkipVerify,
						CAFile:             driverSpec.TLSConfig.CAFile,
						CertFile:           driverSpec.TLSConfig.CertFile,
						KeyFile:            driverSpec.TLSConfig.KeyFile,
					}
				}
				if !plugin.Matches(logger, pluginSpec) {
					logger.Info("existing-driver-mismatch", lager.Data{"specName": specName, "address": driverSpec.Address, "tls": driverSpec.TLSConfig})
					plugin = nil
				}
			}

			if plugin == nil {
				logger.Info("creating-driver", lager.Data{"specName": specName, "driver-path": driverPath, "specFile": specFile})
				driver, err := r.driverFactory.DockerDriver(logger, specName, driverPath, specFile)
				if err != nil {
					logger.Error("error-creating-driver", err)
					continue
				}

				plugin = driverhttp.NewDockerPluginWithDriver(driver)

				env := driverhttp.NewHttpDriverEnv(logger, context.TODO())
				resp := driver.Activate(env)
				if resp.Err != "" {
					logger.Info("skipping-non-responsive-driver", lager.Data{"specname": specName})
					continue
				} else {
					driverImplementsErr := fmt.Errorf("driver-implements: %#v", resp.Implements)
					if len(resp.Implements) == 0 {
						logger.Error("driver-incorrect", driverImplementsErr)
						continue
					}

					if !driverImplements("VolumeDriver", resp.Implements) {
						logger.Error("driver-incorrect", driverImplementsErr)
						continue
					}
				}
			}
			logger.Info("new-driver", lager.Data{"name": specName})
			endpoints[specName] = plugin
		}
	}
	return endpoints
}
<commit_msg>fix the regex for windows OS match<commit_after>package vollocal

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"

	"context"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/voldriver"
	"code.cloudfoundry.org/voldriver/driverhttp"
	"code.cloudfoundry.org/volman"
)

type dockerDriverDiscoverer struct {
	logger        lager.Logger
	driverFactory DockerDriverFactory

	driverRegistry volman.PluginRegistry
	driverPaths    []string
}

func NewDockerDriverDiscoverer(logger lager.Logger, driverRegistry volman.PluginRegistry, driverPaths []string) volman.Discoverer {
	return &dockerDriverDiscoverer{
		logger:        logger,
		driverFactory: NewDockerDriverFactory(),

		driverRegistry: driverRegistry,
		driverPaths:    driverPaths,
	}
}

func NewDockerDriverDiscovererWithDriverFactory(logger lager.Logger, driverRegistry volman.PluginRegistry, driverPaths []string, factory DockerDriverFactory) volman.Discoverer {
	return &dockerDriverDiscoverer{
		logger:        logger,
		driverFactory: factory,

		driverRegistry: driverRegistry,
		driverPaths:    driverPaths,
	}
}

func (r *dockerDriverDiscoverer) Discover(logger lager.Logger) (map[string]volman.Plugin, error) {
	logger = logger.Session("discover")
	logger.Debug("start")
	logger.Info("discovering-drivers", lager.Data{"driver-paths": r.driverPaths})
	defer logger.Debug("end")

	endpoints := make(map[string]volman.Plugin)

	for _, driverPath := range r.driverPaths {
		//precedence order: sock -> spec -> json
		spec_types := [3]string{"sock", "spec", "json"}
		for _, spec_type := range spec_types {
			matchingDriverSpecs, err := r.getMatchingDriverSpecs(logger, driverPath, spec_type)

			if err != nil {
				// untestable on linux, does glob work differently on windows???
				return map[string]volman.Plugin{}, fmt.Errorf("Volman configured with an invalid driver path '%s', error occured list files (%s)", driverPath, err.Error())
			}
			if len(matchingDriverSpecs) > 0 {
				logger.Debug("driver-specs", lager.Data{"drivers": matchingDriverSpecs})
				var existing map[string]volman.Plugin
				if r.driverRegistry != nil {
					existing = r.driverRegistry.Plugins()
					logger.Debug("existing-drivers", lager.Data{"len": len(existing)})
				}

				endpoints = r.insertIfAliveAndNotFound(logger, endpoints, driverPath, matchingDriverSpecs, existing)
			}
		}
	}
	return endpoints, nil
}

func (r *dockerDriverDiscoverer) getMatchingDriverSpecs(logger lager.Logger, path string, pattern string) ([]string, error) {
	logger.Debug("binaries", lager.Data{"path": path, "pattern": pattern})
	matchingDriverSpecs, err := filepath.Glob(path + string(os.PathSeparator) + "*." + pattern)
	if err != nil { // untestable on linux, does glob work differently on windows???
		return nil, fmt.Errorf("Volman configured with an invalid driver path '%s', error occured list files (%s)", path, err.Error())
	}
	return matchingDriverSpecs, nil

}

func (r *dockerDriverDiscoverer) insertIfAliveAndNotFound(logger lager.Logger, endpoints map[string]volman.Plugin, driverPath string, specs []string, existing map[string]volman.Plugin) map[string]volman.Plugin {
	logger = logger.Session("insert-if-not-found")
	logger.Debug("start")
	defer logger.Debug("end")

	var plugin volman.Plugin
	var ok bool
	var re *regexp.Regexp

	for _, spec := range specs {
		if runtime.GOOS == "windows" {
			re = regexp.MustCompile(`([^\\]*\\)?([^\\]*)\.(sock|spec|json)$`)
		} else {
			re = regexp.MustCompile(`([^/]*/)?([^/]*)\.(sock|spec|json)$`)
		}

		segs2 := re.FindAllStringSubmatch(spec, 1)
		if len(segs2) <= 0 {
			continue
		}
		specName := segs2[0][2]
		specFile := segs2[0][2] + "." + segs2[0][3]
		logger.Debug("insert-unique-spec", lager.Data{"specname": specName})

		_, ok = endpoints[specName]
		if !ok {
			plugin, ok = existing[specName]
			if ok == true {
				driverSpec, err := voldriver.ReadDriverSpec(logger, specName, driverPath, specFile)
				if err != nil {
					logger.Error("error-reading-driver-spec", err)
					continue
				}
				pluginSpec := volman.PluginSpec{
					Name:    driverSpec.Name,
					Address: driverSpec.Address,
				}
				if driverSpec.TLSConfig != nil {
					pluginSpec.TLSConfig = &volman.TLSConfig{
						InsecureSkipVerify: driverSpec.TLSConfig.InsecureSkipVerify,
						CAFile:             driverSpec.TLSConfig.CAFile,
						CertFile:           driverSpec.TLSConfig.CertFile,
						KeyFile:            driverSpec.TLSConfig.KeyFile,
					}
				}
				if !plugin.Matches(logger, pluginSpec) {
					logger.Info("existing-driver-mismatch", lager.Data{"specName": specName, "address": driverSpec.Address, "tls": driverSpec.TLSConfig})
					plugin = nil
				}
			}

			if plugin == nil {
				logger.Info("creating-driver", lager.Data{"specName": specName, "driver-path": driverPath, "specFile": specFile})
				driver, err := r.driverFactory.DockerDriver(logger, specName, driverPath, specFile)
				if err != nil {
					logger.Error("error-creating-driver", err)
					continue
				}

				plugin = driverhttp.NewDockerPluginWithDriver(driver)

				env := driverhttp.NewHttpDriverEnv(logger, context.TODO())
				resp := driver.Activate(env)
				if resp.Err != "" {
					logger.Info("skipping-non-responsive-driver", lager.Data{"specname": specName})
					continue
				} else {
					driverImplementsErr := fmt.Errorf("driver-implements: %#v", resp.Implements)
					if len(resp.Implements) == 0 {
						logger.Error("driver-incorrect", driverImplementsErr)
						continue
					}

					if !driverImplements("VolumeDriver", resp.Implements) {
						logger.Error("driver-incorrect", driverImplementsErr)
						continue
					}
				}
			}
			logger.Info("new-driver", lager.Data{"name": specName})
			endpoints[specName] = plugin
		}
	}
	return endpoints
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	verbose bool
	src     string
	dst     string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) toCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func (p *Package) Verbose(enable bool) {
	p.verbose = enable
}

func (p *Package) installed() bool {
	_, err := os.Stat(p.dst)
	return err == nil
}

func (p *Package) Install(out io.Writer) error {
	if p.installed() {
		return nil
	}
	c := p.toCommand()
	w := bytes.NewBuffer(make([]byte, 0))
	c.Stderr = w
	if out != nil && p.verbose {
		c.Stdout = out
		c.Stderr = out
		_, err := fmt.Fprintln(out, strings.Join(c.Args, " "))
		if err != nil {
			return err
		}
	}
	if err := c.Run(); err != nil {
		return fmt.Errorf("%s\n%s",
			err.Error(), strings.TrimRight(w.String(), "\n"))
	}
	return nil
}

func (p *Package) Remove(out io.Writer) error {
	if p.installed() {
		return nil
	}
	if out != nil && p.verbose {
		_, err := fmt.Fprintln(out, "rm -r", p.dst)
		if err != nil {
			return err
		}
	}
	return os.RemoveAll(p.dst)
}
<commit_msg>Implement Update<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	verbose bool
	src     string
	dst     string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) toCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func (p *Package) Verbose(enable bool) {
	p.verbose = enable
}

func (p *Package) installed() bool {
	_, err := os.Stat(p.dst)
	return err == nil
}

func (p *Package) Install(out io.Writer) error {
	if p.installed() {
		return nil
	}
	c := p.toCommand()
	w := bytes.NewBuffer(make([]byte, 0))
	c.Stderr = w
	if out != nil && p.verbose {
		c.Stdout = out
		c.Stderr = out
		_, err := fmt.Fprintln(out, strings.Join(c.Args, " "))
		if err != nil {
			return err
		}
	}
	if err := c.Run(); err != nil {
		return fmt.Errorf("%s\n%s",
			err.Error(), strings.TrimRight(w.String(), "\n"))
	}
	return nil
}

func (p *Package) Remove(out io.Writer) error {
	if p.installed() {
		return nil
	}
	if out != nil && p.verbose {
		_, err := fmt.Fprintln(out, "rm -r", p.dst)
		if err != nil {
			return err
		}
	}
	return os.RemoveAll(p.dst)
}

func (p *Package) Update(out io.Writer) error {
	if p.installed() {
		if err := p.Remove(out); err != nil {
			return err
		}
	}
	return p.Install(out)
}
<|endoftext|>


<commit_before>package smutje

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/gfrey/smutje/connection"
	"github.com/gfrey/smutje/logger"
	"github.com/gfrey/smutje/parser"
	"github.com/pkg/errors"
)

type smPackage struct {
	Name string
	ID   string

	Attributes smAttributes
	Scripts    []smScript

	state   []string
	isDirty bool
}

func newPackage(parentID, path string, attrs smAttributes, n *parser.AstNode) (*smPackage, error) {
	if n.Type != parser.AstPackage {
		return nil, fmt.Errorf("expected package node, got %s", n.Type)
	}

	pkg := new(smPackage)
	pkg.Name = n.Name

	pkg.ID = n.ID
	if parentID != "" {
		pkg.ID = parentID + "." + n.ID
	}

	pkg.Attributes = attrs.Copy()
	for _, child := range n.Children {
		switch child.Type {
		case parser.AstAttributes:
			attrs, err := newAttributes(child)
			if err != nil {
				return nil, err
			}
			pkg.Attributes, err = attrs.Merge(pkg.Attributes)
			if err != nil {
				return nil, err
			}
		case parser.AstScript:
			child.ID = pkg.ID + "_" + strconv.Itoa(len(pkg.Scripts))
			script, err := newScript(path, child)
			if err != nil {
				return nil, err
			}
			pkg.Scripts = append(pkg.Scripts, script)
		case parser.AstText:
		// ignore
		default:
			return nil, fmt.Errorf("unexpected node found: %s", n.Type)
		}
	}

	return pkg, nil
}

func (pkg *smPackage) Prepare(client connection.Client, attrs smAttributes) (err error) {
	if client != nil { // If a virtual resource doesn't exist yet, the client is nil!
		pkg.state, err = pkg.readPackageState(client)
		if err != nil {
			return fmt.Errorf("failed to read target state: %s", err)
		}
	}

	hash := ""
	for i, s := range pkg.Scripts {
		sattrs, err := attrs.Merge(pkg.Attributes)
		if err != nil {
			return err
		}
		hash, err = s.Prepare(sattrs, hash)
		if err != nil {
			return err
		}
		if i >= len(pkg.state) || hash != pkg.state[i] {
			pkg.isDirty = true
		}
	}

	return nil
}

func (pkg *smPackage) Provision(l logger.Logger, client connection.Client) (err error) {
	l = l.Tag(pkg.ID)

	oldState := pkg.state
	pkg.state = make([]string, len(pkg.Scripts))

	allCached := true

	defer func() {
		if allCached {
			return
		}

		e := pkg.writeTargetState(client)
		if err == nil {
			err = e
		}
	}()

	for i, s := range pkg.Scripts {
		hash := s.Hash()

		if allCached && i < len(oldState) && oldState[i][1:] == hash {
			l.Printf("step %d cached", i)
			pkg.state[i] = "." + hash
			continue
		}

		allCached = false
		if err = s.Exec(l, client); err != nil {
			l.Printf("failed in %s", hash)
			pkg.state[i] = "-" + hash
			pkg.state = pkg.state[:i+1]
			return err
		}
		pkg.state[i] = "+" + hash
	}
	return nil
}

func (pkg *smPackage) readPackageState(client connection.Client) ([]string, error) {
	sess, err := client.NewSession()
	if err != nil {
		return nil, err
	}
	defer sess.Close()

	stdout, err := sess.StdoutPipe()
	if err != nil {
		return nil, err
	}

	fname := fmt.Sprintf("/var/lib/smutje/%s.log", pkg.ID)
	cmd := fmt.Sprintf(`bash -c "if [[ -f %[1]q ]]; then cat %[1]s; else mkdir -p /var/lib/smutje; fi"`, fname)
	if err := sess.Start(cmd); err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, stdout); err != nil {
		return nil, err
	}

	if err := sess.Wait(); err != nil {
		return nil, err
	}

	state := []string{}
	sc := bufio.NewScanner(buf)
	for sc.Scan() {
		l := sc.Text()
		switch l[0] {
		case '+', '.':
			state = append(state, l)
		case '-':
			//ignore
		default:
			return nil, fmt.Errorf("invalid token read: %s", l)
		}
	}
	return state, sc.Err()
}

func (pkg *smPackage) writeTargetState(client connection.Client) error {
	sess, err := client.NewSession()
	if err != nil {
		return err
	}
	defer sess.Close()

	stdin, err := sess.StdinPipe()
	if err != nil {
		return errors.Wrap(err, "failed to receive stdin pipe")
	}

	tstamp := time.Now().UTC().Format("20060102T150405")
	filename := fmt.Sprintf("/var/lib/smutje/%s.%s.log", pkg.ID, tstamp)
	cmd := fmt.Sprintf(`bash -c "cat - > %[1]s && ln -sf %[1]s /var/lib/smutje/%[2]s.log"`, filename, pkg.ID)
	if err := sess.Start(cmd); err != nil {
		return err
	}

	if _, err := io.WriteString(stdin, strings.Join(pkg.state, "\n")+"\n"); err != nil {
		return errors.Wrap(err, "failed to send script to target")
	}
	stdin.Close()
	return sess.Wait()
}
<commit_msg>Fix some more error handling<commit_after>package smutje

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/gfrey/smutje/connection"
	"github.com/gfrey/smutje/logger"
	"github.com/gfrey/smutje/parser"
	"github.com/pkg/errors"
)

type smPackage struct {
	Name string
	ID   string

	Attributes smAttributes
	Scripts    []smScript

	state   []string
	isDirty bool
}

func newPackage(parentID, path string, attrs smAttributes, n *parser.AstNode) (*smPackage, error) {
	if n.Type != parser.AstPackage {
		return nil, fmt.Errorf("expected package node, got %s", n.Type)
	}

	pkg := new(smPackage)
	pkg.Name = n.Name

	pkg.ID = n.ID
	if parentID != "" {
		pkg.ID = parentID + "." + n.ID
	}

	pkg.Attributes = attrs.Copy()
	for _, child := range n.Children {
		switch child.Type {
		case parser.AstAttributes:
			attrs, err := newAttributes(child)
			if err != nil {
				return nil, err
			}
			pkg.Attributes, err = attrs.Merge(pkg.Attributes)
			if err != nil {
				return nil, err
			}
		case parser.AstScript:
			child.ID = pkg.ID + "_" + strconv.Itoa(len(pkg.Scripts))
			script, err := newScript(path, child)
			if err != nil {
				return nil, err
			}
			pkg.Scripts = append(pkg.Scripts, script)
		case parser.AstText:
		// ignore
		default:
			return nil, errors.Errorf("unexpected node found: %s", n.Type)
		}
	}

	return pkg, nil
}

func (pkg *smPackage) Prepare(client connection.Client, attrs smAttributes) (err error) {
	if client != nil { // If a virtual resource doesn't exist yet, the client is nil!
		pkg.state, err = pkg.readPackageState(client)
		if err != nil {
			return errors.Errorf("failed to read target state: %s", err)
		}
	}

	hash := ""
	for i, s := range pkg.Scripts {
		sattrs, err := attrs.Merge(pkg.Attributes)
		if err != nil {
			return err
		}
		hash, err = s.Prepare(sattrs, hash)
		if err != nil {
			return err
		}
		if i >= len(pkg.state) || hash != pkg.state[i] {
			pkg.isDirty = true
		}
	}

	return nil
}

func (pkg *smPackage) Provision(l logger.Logger, client connection.Client) (err error) {
	l = l.Tag(pkg.ID)

	oldState := pkg.state
	pkg.state = make([]string, len(pkg.Scripts))

	allCached := true

	defer func() {
		if allCached {
			return
		}

		e := pkg.writeTargetState(client)
		if err == nil {
			err = e
		}
	}()

	for i, s := range pkg.Scripts {
		hash := s.Hash()

		if allCached && i < len(oldState) && oldState[i][1:] == hash {
			l.Printf("step %d cached", i)
			pkg.state[i] = "." + hash
			continue
		}

		allCached = false
		if err = s.Exec(l, client); err != nil {
			l.Printf("failed in %s", hash)
			pkg.state[i] = "-" + hash
			pkg.state = pkg.state[:i+1]
			return err
		}
		pkg.state[i] = "+" + hash
	}
	return nil
}

func (pkg *smPackage) readPackageState(client connection.Client) ([]string, error) {
	sess, err := client.NewSession()
	if err != nil {
		return nil, err
	}
	defer sess.Close()

	stdout, err := sess.StdoutPipe()
	if err != nil {
		return nil, err
	}

	fname := fmt.Sprintf("/var/lib/smutje/%s.log", pkg.ID)
	cmd := fmt.Sprintf(`bash -c "if [[ -f %[1]q ]]; then cat %[1]s; else mkdir -p /var/lib/smutje; fi"`, fname)
	if err := sess.Start(cmd); err != nil {
		return nil, err
	}

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, stdout); err != nil {
		return nil, errors.Wrap(err, "failed to copy output of command")
	}

	if err := sess.Wait(); err != nil {
		return nil, err
	}

	state := []string{}
	sc := bufio.NewScanner(buf)
	for sc.Scan() {
		l := sc.Text()
		switch l[0] {
		case '+', '.':
			state = append(state, l)
		case '-':
			//ignore
		default:
			return nil, errors.Errorf("invalid token read: %s", l)
		}
	}
	return state, errors.Wrap(sc.Err(), "failed to scan output")
}

func (pkg *smPackage) writeTargetState(client connection.Client) error {
	sess, err := client.NewSession()
	if err != nil {
		return err
	}
	defer sess.Close()

	stdin, err := sess.StdinPipe()
	if err != nil {
		return errors.Wrap(err, "failed to receive stdin pipe")
	}

	tstamp := time.Now().UTC().Format("20060102T150405")
	filename := fmt.Sprintf("/var/lib/smutje/%s.%s.log", pkg.ID, tstamp)
	cmd := fmt.Sprintf(`bash -c "cat - > %[1]s && ln -sf %[1]s /var/lib/smutje/%[2]s.log"`, filename, pkg.ID)
	if err := sess.Start(cmd); err != nil {
		return err
	}

	if _, err := io.WriteString(stdin, strings.Join(pkg.state, "\n")+"\n"); err != nil {
		return errors.Wrap(err, "failed to send script to target")
	}
	stdin.Close()
	return sess.Wait()
}
<|endoftext|>


<commit_before>package scanner

import (
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"syscall"
	"time"

	"github.com/Symantec/Dominator/lib/concurrent"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/image"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
)

func loadImageDataBase(baseDir string, objSrv objectserver.FullObjectServer,
	masterMode bool, logger log.Logger) (*ImageDataBase, error) {
	fi, err := os.Stat(baseDir)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("Cannot stat: %s: %s\n", baseDir, err))
	}
	if !fi.IsDir() {
		return nil, errors.New(fmt.Sprintf("%s is not a directory\n", baseDir))
	}
	imdb := &ImageDataBase{
		baseDir:         baseDir,
		directoryMap:    make(map[string]image.DirectoryMetadata),
		imageMap:        make(map[string]*image.Image),
		addNotifiers:    make(notifiers),
		deleteNotifiers: make(notifiers),
		mkdirNotifiers:  make(makeDirectoryNotifiers),
		objectServer:    objSrv,
		masterMode:      masterMode,
		logger:          logger,
	}
	state := concurrent.NewState(0)
	startTime := time.Now()
	var rusageStart, rusageStop syscall.Rusage
	syscall.Getrusage(syscall.RUSAGE_SELF, &rusageStart)
	if err := imdb.scanDirectory(".", state, logger); err != nil {
		return nil, err
	}
	if err := state.Reap(); err != nil {
		return nil, err
	}
	if logger != nil {
		plural := ""
		if imdb.CountImages() != 1 {
			plural = "s"
		}
		syscall.Getrusage(syscall.RUSAGE_SELF, &rusageStop)
		userTime := time.Duration(rusageStop.Utime.Sec)*time.Second +
			time.Duration(rusageStop.Utime.Usec)*time.Microsecond -
			time.Duration(rusageStart.Utime.Sec)*time.Second -
			time.Duration(rusageStart.Utime.Usec)*time.Microsecond
		logger.Printf("Loaded %d image%s in %s (%s user CPUtime)\n",
			imdb.CountImages(), plural, time.Since(startTime), userTime)
	}
	imdb.unreferencedObjects, err = loadUnreferencedObjects(
		path.Join(baseDir, unreferencedObjectsFile))
	if err != nil {
		return nil, errors.New("error loading unreferenced objects list: " +
			err.Error())
	}
	imdb.regenerateUnreferencedObjectsList()
	if ads, ok := objSrv.(objectserver.AddCallbackSetter); ok {
		ads.SetAddCallback(imdb.garbageCollectorAddCallback)
	}
	if gcs, ok := objSrv.(objectserver.GarbageCollectorSetter); ok {
		gcs.SetGarbageCollector(imdb.garbageCollector)
	}
	go imdb.periodicGarbageCollector()
	return imdb, nil
}

func (imdb *ImageDataBase) scanDirectory(dirname string,
	state *concurrent.State, logger log.Logger) error {
	directoryMetadata, err := imdb.readDirectoryMetadata(dirname)
	if err != nil {
		return err
	}
	imdb.directoryMap[dirname] = directoryMetadata
	file, err := os.Open(path.Join(imdb.baseDir, dirname))
	if err != nil {
		return err
	}
	names, err := file.Readdirnames(-1)
	file.Close()
	if err != nil {
		return err
	}
	for _, name := range names {
		if len(name) > 0 && name[0] == '.' {
			continue // Skip hidden paths.
		}
		filename := path.Join(dirname, name)
		var stat syscall.Stat_t
		err := syscall.Lstat(path.Join(imdb.baseDir, filename), &stat)
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err
		}
		if stat.Mode&syscall.S_IFMT == syscall.S_IFDIR {
			err = imdb.scanDirectory(filename, state, logger)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFREG && stat.Size > 0 {
			err = state.GoRun(func() error {
				return imdb.loadFile(filename, logger)
			})
		}
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err
		}
	}
	return nil
}

func (imdb *ImageDataBase) readDirectoryMetadata(dirname string) (
	image.DirectoryMetadata, error) {
	file, err := os.Open(path.Join(imdb.baseDir, dirname, metadataFile))
	if err != nil {
		if os.IsNotExist(err) {
			return image.DirectoryMetadata{}, nil
		}
		return image.DirectoryMetadata{}, err
	}
	defer file.Close()
	reader := fsutil.NewChecksumReader(file)
	decoder := gob.NewDecoder(reader)
	metadata := image.DirectoryMetadata{}
	if err := decoder.Decode(&metadata); err != nil {
		return image.DirectoryMetadata{}, fmt.Errorf(
			"unable to read directory metadata for \"%s\": %s", dirname, err)
	}
	return metadata, reader.VerifyChecksum()
}

func (imdb *ImageDataBase) loadFile(filename string, logger log.Logger) error {
	pathname := path.Join(imdb.baseDir, filename)
	file, err := os.Open(pathname)
	if err != nil {
		return err
	}
	defer file.Close()
	reader := fsutil.NewChecksumReader(file)
	decoder := gob.NewDecoder(reader)
	var image image.Image
	if err := decoder.Decode(&image); err != nil {
		return err
	}
	if err := reader.VerifyChecksum(); err != nil {
		if err == fsutil.ErrorChecksumMismatch {
			logger.Printf("Checksum mismatch for image: %s\n", filename)
			return nil
		}
		if err != io.EOF {
			return err
		}
	}
	if imageIsExpired(&image) {
		imdb.logger.Printf("Deleting already expired image: %s\n", filename)
		return os.Remove(pathname)
	}
	image.FileSystem.RebuildInodePointers()
	if err := image.Verify(); err != nil {
		return err
	}
	imdb.scheduleExpiration(&image, filename)
	imdb.Lock()
	defer imdb.Unlock()
	imdb.imageMap[filename] = &image
	return nil
}
<commit_msg>Fix panic when imageserver expires images before loading unref object DB.<commit_after>package scanner

import (
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"syscall"
	"time"

	"github.com/Symantec/Dominator/lib/concurrent"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/image"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
)

func loadImageDataBase(baseDir string, objSrv objectserver.FullObjectServer,
	masterMode bool, logger log.Logger) (*ImageDataBase, error) {
	fi, err := os.Stat(baseDir)
	if err != nil {
		return nil, errors.New(
			fmt.Sprintf("Cannot stat: %s: %s\n", baseDir, err))
	}
	if !fi.IsDir() {
		return nil, errors.New(fmt.Sprintf("%s is not a directory\n", baseDir))
	}
	imdb := &ImageDataBase{
		baseDir:         baseDir,
		directoryMap:    make(map[string]image.DirectoryMetadata),
		imageMap:        make(map[string]*image.Image),
		addNotifiers:    make(notifiers),
		deleteNotifiers: make(notifiers),
		mkdirNotifiers:  make(makeDirectoryNotifiers),
		objectServer:    objSrv,
		masterMode:      masterMode,
		logger:          logger,
	}
	imdb.unreferencedObjects, err = loadUnreferencedObjects(
		path.Join(baseDir, unreferencedObjectsFile))
	if err != nil {
		return nil, errors.New("error loading unreferenced objects list: " +
			err.Error())
	}
	state := concurrent.NewState(0)
	startTime := time.Now()
	var rusageStart, rusageStop syscall.Rusage
	syscall.Getrusage(syscall.RUSAGE_SELF, &rusageStart)
	if err := imdb.scanDirectory(".", state, logger); err != nil {
		return nil, err
	}
	if err := state.Reap(); err != nil {
		return nil, err
	}
	if logger != nil {
		plural := ""
		if imdb.CountImages() != 1 {
			plural = "s"
		}
		syscall.Getrusage(syscall.RUSAGE_SELF, &rusageStop)
		userTime := time.Duration(rusageStop.Utime.Sec)*time.Second +
			time.Duration(rusageStop.Utime.Usec)*time.Microsecond -
			time.Duration(rusageStart.Utime.Sec)*time.Second -
			time.Duration(rusageStart.Utime.Usec)*time.Microsecond
		logger.Printf("Loaded %d image%s in %s (%s user CPUtime)\n",
			imdb.CountImages(), plural, time.Since(startTime), userTime)
	}
	imdb.regenerateUnreferencedObjectsList()
	if ads, ok := objSrv.(objectserver.AddCallbackSetter); ok {
		ads.SetAddCallback(imdb.garbageCollectorAddCallback)
	}
	if gcs, ok := objSrv.(objectserver.GarbageCollectorSetter); ok {
		gcs.SetGarbageCollector(imdb.garbageCollector)
	}
	go imdb.periodicGarbageCollector()
	return imdb, nil
}

func (imdb *ImageDataBase) scanDirectory(dirname string,
	state *concurrent.State, logger log.Logger) error {
	directoryMetadata, err := imdb.readDirectoryMetadata(dirname)
	if err != nil {
		return err
	}
	imdb.directoryMap[dirname] = directoryMetadata
	file, err := os.Open(path.Join(imdb.baseDir, dirname))
	if err != nil {
		return err
	}
	names, err := file.Readdirnames(-1)
	file.Close()
	if err != nil {
		return err
	}
	for _, name := range names {
		if len(name) > 0 && name[0] == '.' {
			continue // Skip hidden paths.
		}
		filename := path.Join(dirname, name)
		var stat syscall.Stat_t
		err := syscall.Lstat(path.Join(imdb.baseDir, filename), &stat)
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err
		}
		if stat.Mode&syscall.S_IFMT == syscall.S_IFDIR {
			err = imdb.scanDirectory(filename, state, logger)
		} else if stat.Mode&syscall.S_IFMT == syscall.S_IFREG && stat.Size > 0 {
			err = state.GoRun(func() error {
				return imdb.loadFile(filename, logger)
			})
		}
		if err != nil {
			if err == syscall.ENOENT {
				continue
			}
			return err
		}
	}
	return nil
}

func (imdb *ImageDataBase) readDirectoryMetadata(dirname string) (
	image.DirectoryMetadata, error) {
	file, err := os.Open(path.Join(imdb.baseDir, dirname, metadataFile))
	if err != nil {
		if os.IsNotExist(err) {
			return image.DirectoryMetadata{}, nil
		}
		return image.DirectoryMetadata{}, err
	}
	defer file.Close()
	reader := fsutil.NewChecksumReader(file)
	decoder := gob.NewDecoder(reader)
	metadata := image.DirectoryMetadata{}
	if err := decoder.Decode(&metadata); err != nil {
		return image.DirectoryMetadata{}, fmt.Errorf(
			"unable to read directory metadata for \"%s\": %s", dirname, err)
	}
	return metadata, reader.VerifyChecksum()
}

func (imdb *ImageDataBase) loadFile(filename string, logger log.Logger) error {
	pathname := path.Join(imdb.baseDir, filename)
	file, err := os.Open(pathname)
	if err != nil {
		return err
	}
	defer file.Close()
	reader := fsutil.NewChecksumReader(file)
	decoder := gob.NewDecoder(reader)
	var image image.Image
	if err := decoder.Decode(&image); err != nil {
		return err
	}
	if err := reader.VerifyChecksum(); err != nil {
		if err == fsutil.ErrorChecksumMismatch {
			logger.Printf("Checksum mismatch for image: %s\n", filename)
			return nil
		}
		if err != io.EOF {
			return err
		}
	}
	if imageIsExpired(&image) {
		imdb.logger.Printf("Deleting already expired image: %s\n", filename)
		return os.Remove(pathname)
	}
	image.FileSystem.RebuildInodePointers()
	if err := image.Verify(); err != nil {
		return err
	}
	imdb.scheduleExpiration(&image, filename)
	imdb.Lock()
	defer imdb.Unlock()
	imdb.imageMap[filename] = &image
	return nil
}
<|endoftext|>