<commit_before>package syntax

import (
	"regexp"
	"unicode/utf8"

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

func init() {
	Languages["go"] = Language{
		Syntax{"string", regexp.MustCompile(`^(?m)".*?[^\\]"`), termbox.ColorRed, termbox.ColorBlack},
		Syntax{"rune", regexp.MustCompile(`^(?m)'.*?[^\\]'`), termbox.ColorYellow, termbox.ColorBlack},
		Syntax{"comment", regexp.MustCompile(`^(?m)//.*`), termbox.ColorMagenta, termbox.ColorBlack},
		Syntax{"multi line comment", regexp.MustCompile(`^(?s)/[*].*?[*]/`), termbox.ColorMagenta, termbox.ColorBlack},
		Syntax{"trailing spaces", regexp.MustCompile(`^(?m)[ \t]+$`), termbox.ColorBlack, termbox.ColorYellow},
	}
}

type Syntax struct {
	Name string
	Re   *regexp.Regexp
	Fg   termbox.Attribute
	Bg   termbox.Attribute
}

func (s Syntax) NewMatch(start, end Pos) Match {
	return Match{Name: s.Name, Start: start, End: end, Fg: s.Fg, Bg: s.Bg}
}

type Language []Syntax

var Languages = make(map[string]Language)

func (l Language) Parse(text []byte) []Match {
	c := NewCursor(text)
	matches := []Match{}
Loop:
	for {
		for _, syn := range l {
			ms := syn.Re.FindSubmatch(c.Remain())
			if ms != nil {
				m := ms[0]
				if len(ms) == 2 {
					m = ms[1]
				}
				if string(m) == "" {
					continue
				}
				start := c.Pos()
				c.Skip(len(m))
				end := c.Pos()
				matches = append(matches, syn.NewMatch(start, end))
				continue Loop
			}
		}
		if !c.Advance() {
			break
		}
	}
	return matches
}

type Cursor struct {
	text []byte
	b    int // byte offset
	l    int // line offset
	o    int // byte in line offset
}

func NewCursor(text []byte) *Cursor {
	return &Cursor{text: text}
}

func (c *Cursor) Pos() Pos {
	return Pos{c.l, c.o}
}

func (c *Cursor) Remain() []byte {
	if c.l == len(c.text) {
		return []byte("")
	}
	return c.text[c.b:]
}

func (c *Cursor) Advance() bool {
	if c.b == len(c.text) {
		return false
	}
	c.next()
	return true
}

func (c *Cursor) Skip(b int) {
	i := 0
	for i < b {
		_, size := c.next()
		i += size
	}
}

func (c *Cursor) next() (r rune, size int) {
	r, size = utf8.DecodeRune(c.Remain())
	c.b += size
	c.o += size
	if r == '\n' {
		c.l += 1
		c.o = 0
	}
	return r, size
}

type Match struct {
	Name  string
	Start Pos
	End   Pos
	Fg    termbox.Attribute
	Bg    termbox.Attribute
}

type Pos struct {
	L int
	O int
}
<commit_msg>tune for loop codes<commit_after>package syntax

import (
	"regexp"
	"unicode/utf8"

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

func init() {
	Languages["go"] = Language{
		Syntax{"string", regexp.MustCompile(`^(?m)".*?[^\\]"`), termbox.ColorRed, termbox.ColorBlack},
		Syntax{"rune", regexp.MustCompile(`^(?m)'.*?[^\\]'`), termbox.ColorYellow, termbox.ColorBlack},
		Syntax{"comment", regexp.MustCompile(`^(?m)//.*`), termbox.ColorMagenta, termbox.ColorBlack},
		Syntax{"multi line comment", regexp.MustCompile(`^(?s)/[*].*?[*]/`), termbox.ColorMagenta, termbox.ColorBlack},
		Syntax{"trailing spaces", regexp.MustCompile(`^(?m)[ \t]+$`), termbox.ColorBlack, termbox.ColorYellow},
	}
}

type Syntax struct {
	Name string
	Re   *regexp.Regexp
	Fg   termbox.Attribute
	Bg   termbox.Attribute
}

func (s Syntax) NewMatch(start, end Pos) Match {
	return Match{Name: s.Name, Start: start, End: end, Fg: s.Fg, Bg: s.Bg}
}

type Language []Syntax

var Languages = make(map[string]Language)

func (l Language) Parse(text []byte) []Match {
	c := NewCursor(text)
	matches := []Match{}
Loop:
	for {
		for _, syn := range l {
			ms := syn.Re.FindSubmatch(c.Remain())
			if ms == nil {
				continue
			}
			m := ms[0]
			if len(ms) == 2 {
				m = ms[1]
			}
			if string(m) == "" {
				continue
			}
			start := c.Pos()
			c.Skip(len(m))
			end := c.Pos()
			matches = append(matches, syn.NewMatch(start, end))
			continue Loop
		}
		if !c.Advance() {
			break
		}
	}
	return matches
}

type Cursor struct {
	text []byte
	b    int // byte offset
	l    int // line offset
	o    int // byte in line offset
}

func NewCursor(text []byte) *Cursor {
	return &Cursor{text: text}
}

func (c *Cursor) Pos() Pos {
	return Pos{c.l, c.o}
}

func (c *Cursor) Remain() []byte {
	if c.l == len(c.text) {
		return []byte("")
	}
	return c.text[c.b:]
}

func (c *Cursor) Advance() bool {
	if c.b == len(c.text) {
		return false
	}
	c.next()
	return true
}

func (c *Cursor) Skip(b int) {
	i := 0
	for i < b {
		_, size := c.next()
		i += size
	}
}

func (c *Cursor) next() (r rune, size int) {
	r, size = utf8.DecodeRune(c.Remain())
	c.b += size
	c.o += size
	if r == '\n' {
		c.l += 1
		c.o = 0
	}
	return r, size
}

type Match struct {
	Name  string
	Start Pos
	End   Pos
	Fg    termbox.Attribute
	Bg    termbox.Attribute
}

type Pos struct {
	L int
	O int
}
<|endoftext|>


<commit_before>package sys

import "runtime"

func DumpStack() string {
	buf := make([]byte, 1024)
	for runtime.Stack(buf, true) == cap(buf) {
		buf = make([]byte, cap(buf)*2)
	}
	return string(buf)
}
<commit_msg>sys: Fix DumpStack to return the correct part of the buffer.<commit_after>package sys

import "runtime"

const dumpStackBufSizeInit = 4096

func DumpStack() string {
	buf := make([]byte, dumpStackBufSizeInit)
	for {
		n := runtime.Stack(buf, true)
		if n < cap(buf) {
			return string(buf[:n])
		}
		buf = make([]byte, cap(buf)*2)
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of the libvirt-go project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Copyright (c) 2013 Alex Zorin
 * Copyright (C) 2016 Red Hat, Inc.
 *
 */

package libvirt

/*
#cgo pkg-config: libvirt
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <stdlib.h>
#include "storage_volume_compat.h"
*/
import "C"

import (
	"unsafe"
)

type StorageVolCreateFlags int

const (
	STORAGE_VOL_CREATE_PREALLOC_METADATA = StorageVolCreateFlags(C.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA)
	STORAGE_VOL_CREATE_REFLINK           = StorageVolCreateFlags(C.VIR_STORAGE_VOL_CREATE_REFLINK)
)

type StorageVolDeleteFlags int

const (
	STORAGE_VOL_DELETE_NORMAL         = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_NORMAL)         // Delete metadata only (fast)
	STORAGE_VOL_DELETE_ZEROED         = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_ZEROED)         // Clear all data to zeros (slow)
	STORAGE_VOL_DELETE_WITH_SNAPSHOTS = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS) // Force removal of volume, even if in use
)

type StorageVolResizeFlags int

const (
	STORAGE_VOL_RESIZE_ALLOCATE = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_ALLOCATE) // force allocation of new size
	STORAGE_VOL_RESIZE_DELTA    = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_DELTA)    // size is relative to current
	STORAGE_VOL_RESIZE_SHRINK   = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_SHRINK)   // allow decrease in capacity
)

type StorageVolType int

const (
	STORAGE_VOL_FILE    = StorageVolType(C.VIR_STORAGE_VOL_FILE)    // Regular file based volumes
	STORAGE_VOL_BLOCK   = StorageVolType(C.VIR_STORAGE_VOL_BLOCK)   // Block based volumes
	STORAGE_VOL_DIR     = StorageVolType(C.VIR_STORAGE_VOL_DIR)     // Directory-passthrough based volume
	STORAGE_VOL_NETWORK = StorageVolType(C.VIR_STORAGE_VOL_NETWORK) //Network volumes like RBD (RADOS Block Device)
	STORAGE_VOL_NETDIR  = StorageVolType(C.VIR_STORAGE_VOL_NETDIR)  // Network accessible directory that can contain other network volumes
	STORAGE_VOL_PLOOP   = StorageVolType(C.VIR_STORAGE_VOL_PLOOP)   // Ploop directory based volumes
)

type StorageVolWipeAlgorithm int

const (
	STORAGE_VOL_WIPE_ALG_ZERO       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_ZERO)       // 1-pass, all zeroes
	STORAGE_VOL_WIPE_ALG_NNSA       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_NNSA)       // 4-pass NNSA Policy Letter NAP-14.1-C (XVI-8)
	STORAGE_VOL_WIPE_ALG_DOD        = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_DOD)        // 4-pass DoD 5220.22-M section 8-306 procedure
	STORAGE_VOL_WIPE_ALG_BSI        = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_BSI)        // 9-pass method recommended by the German Center of Security in Information Technologies
	STORAGE_VOL_WIPE_ALG_GUTMANN    = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_GUTMANN)    // The canonical 35-pass sequence
	STORAGE_VOL_WIPE_ALG_SCHNEIER   = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER)   // 7-pass method described by Bruce Schneier in "Applied Cryptography" (1996)
	STORAGE_VOL_WIPE_ALG_PFITZNER7  = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7)  // 7-pass random
	STORAGE_VOL_WIPE_ALG_PFITZNER33 = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33) // 33-pass random
	STORAGE_VOL_WIPE_ALG_RANDOM     = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_RANDOM)     // 1-pass random
	STORAGE_VOL_WIPE_ALG_TRIM       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_TRIM)       // Trim the underlying storage
)

type StorageXMLFlags int

const (
	STORAGE_XML_INACTIVE = StorageXMLFlags(C.VIR_STORAGE_XML_INACTIVE)
)

type StorageVolInfoFlags int

const (
	STORAGE_VOL_USE_ALLOCATION = StorageVolInfoFlags(C.VIR_STORAGE_VOL_USE_ALLOCATION)
	STORAGE_VOL_GET_PHYSICAL   = StorageVolInfoFlags(C.VIR_STORAGE_VOL_GET_PHYSICAL)
)

type StorageVolUploadFlags int

const (
	STORAGE_VOL_UPLOAD_SPARSE_STREAM = StorageVolUploadFlags(C.VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM)
)

type StorageVolDownloadFlags int

const (
	STORAGE_VOL_DOWNLOAD_SPARSE_STREAM = StorageVolDownloadFlags(C.VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM)
)

type StorageVol struct {
	ptr C.virStorageVolPtr
}

type StorageVolInfo struct {
	Type       StorageVolType
	Capacity   uint64
	Allocation uint64
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolDelete
func (v *StorageVol) Delete(flags StorageVolDeleteFlags) error {
	result := C.virStorageVolDelete(v.ptr, C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolFree
func (v *StorageVol) Free() error {
	ret := C.virStorageVolFree(v.ptr)
	if ret == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolRef
func (c *StorageVol) Ref() error {
	ret := C.virStorageVolRef(c.ptr)
	if ret == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetInfo
func (v *StorageVol) GetInfo() (*StorageVolInfo, error) {
	var cinfo C.virStorageVolInfo
	result := C.virStorageVolGetInfo(v.ptr, &cinfo)
	if result == -1 {
		return nil, GetLastError()
	}
	return &StorageVolInfo{
		Type:       StorageVolType(cinfo._type),
		Capacity:   uint64(cinfo.capacity),
		Allocation: uint64(cinfo.allocation),
	}, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetInfoFlags
func (v *StorageVol) GetInfoFlags(flags StorageVolInfoFlags) (*StorageVolInfo, error) {
	if C.LIBVIR_VERSION_NUMBER < 3000000 {
		return nil, GetNotImplementedError("virStorageVolGetInfoFlags")
	}

	var cinfo C.virStorageVolInfo
	result := C.virStorageVolGetInfoFlagsCompat(v.ptr, &cinfo, C.uint(flags))
	if result == -1 {
		return nil, GetLastError()
	}
	return &StorageVolInfo{
		Type:       StorageVolType(cinfo._type),
		Capacity:   uint64(cinfo.capacity),
		Allocation: uint64(cinfo.allocation),
	}, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetKey
func (v *StorageVol) GetKey() (string, error) {
	key := C.virStorageVolGetKey(v.ptr)
	if key == nil {
		return "", GetLastError()
	}
	return C.GoString(key), nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetName
func (v *StorageVol) GetName() (string, error) {
	name := C.virStorageVolGetName(v.ptr)
	if name == nil {
		return "", GetLastError()
	}
	return C.GoString(name), nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetPath
func (v *StorageVol) GetPath() (string, error) {
	result := C.virStorageVolGetPath(v.ptr)
	if result == nil {
		return "", GetLastError()
	}
	path := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return path, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetXMLDesc
func (v *StorageVol) GetXMLDesc(flags uint32) (string, error) {
	result := C.virStorageVolGetXMLDesc(v.ptr, C.uint(flags))
	if result == nil {
		return "", GetLastError()
	}
	xml := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return xml, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolResize
func (v *StorageVol) Resize(capacity uint64, flags StorageVolResizeFlags) error {
	result := C.virStorageVolResize(v.ptr, C.ulonglong(capacity), C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolWipe
func (v *StorageVol) Wipe(flags uint32) error {
	result := C.virStorageVolWipe(v.ptr, C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}
// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolWipePattern
func (v *StorageVol) WipePattern(algorithm StorageVolWipeAlgorithm, flags uint32) error {
	result := C.virStorageVolWipePattern(v.ptr, C.uint(algorithm), C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolUpload
func (v *StorageVol) Upload(stream *Stream, offset, length uint64, flags StorageVolUploadFlags) error {
	if C.virStorageVolUpload(v.ptr, stream.ptr, C.ulonglong(offset),
		C.ulonglong(length), C.uint(flags)) == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolDownload
func (v *StorageVol) Download(stream *Stream, offset, length uint64, flags StorageVolDownloadFlags) error {
	if C.virStorageVolDownload(v.ptr, stream.ptr, C.ulonglong(offset),
		C.ulonglong(length), C.uint(flags)) == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStoragePoolLookupByVolume
func (v *StorageVol) LookupPoolByVolume() (*StoragePool, error) {
	poolPtr := C.virStoragePoolLookupByVolume(v.ptr)
	if poolPtr == nil {
		return nil, GetLastError()
	}
	return &StoragePool{ptr: poolPtr}, nil
}
<commit_msg>storage volume: add missin blank line<commit_after>/*
 * This file is part of the libvirt-go project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Copyright (c) 2013 Alex Zorin
 * Copyright (C) 2016 Red Hat, Inc.
 *
 */

package libvirt

/*
#cgo pkg-config: libvirt
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <stdlib.h>
#include "storage_volume_compat.h"
*/
import "C"

import (
	"unsafe"
)

type StorageVolCreateFlags int

const (
	STORAGE_VOL_CREATE_PREALLOC_METADATA = StorageVolCreateFlags(C.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA)
	STORAGE_VOL_CREATE_REFLINK           = StorageVolCreateFlags(C.VIR_STORAGE_VOL_CREATE_REFLINK)
)

type StorageVolDeleteFlags int

const (
	STORAGE_VOL_DELETE_NORMAL         = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_NORMAL)         // Delete metadata only (fast)
	STORAGE_VOL_DELETE_ZEROED         = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_ZEROED)         // Clear all data to zeros (slow)
	STORAGE_VOL_DELETE_WITH_SNAPSHOTS = StorageVolDeleteFlags(C.VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS) // Force removal of volume, even if in use
)

type StorageVolResizeFlags int

const (
	STORAGE_VOL_RESIZE_ALLOCATE = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_ALLOCATE) // force allocation of new size
	STORAGE_VOL_RESIZE_DELTA    = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_DELTA)    // size is relative to current
	STORAGE_VOL_RESIZE_SHRINK   = StorageVolResizeFlags(C.VIR_STORAGE_VOL_RESIZE_SHRINK)   // allow decrease in capacity
)

type StorageVolType int

const (
	STORAGE_VOL_FILE    = StorageVolType(C.VIR_STORAGE_VOL_FILE)    // Regular file based volumes
	STORAGE_VOL_BLOCK   = StorageVolType(C.VIR_STORAGE_VOL_BLOCK)   // Block based volumes
	STORAGE_VOL_DIR     = StorageVolType(C.VIR_STORAGE_VOL_DIR)     // Directory-passthrough based volume
	STORAGE_VOL_NETWORK = StorageVolType(C.VIR_STORAGE_VOL_NETWORK) //Network volumes like RBD (RADOS Block Device)
	STORAGE_VOL_NETDIR  = StorageVolType(C.VIR_STORAGE_VOL_NETDIR)  // Network accessible directory that can contain other network volumes
	STORAGE_VOL_PLOOP   = StorageVolType(C.VIR_STORAGE_VOL_PLOOP)   // Ploop directory based volumes
)

type StorageVolWipeAlgorithm int

const (
	STORAGE_VOL_WIPE_ALG_ZERO       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_ZERO)       // 1-pass, all zeroes
	STORAGE_VOL_WIPE_ALG_NNSA       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_NNSA)       // 4-pass NNSA Policy Letter NAP-14.1-C (XVI-8)
	STORAGE_VOL_WIPE_ALG_DOD        = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_DOD)        // 4-pass DoD 5220.22-M section 8-306 procedure
	STORAGE_VOL_WIPE_ALG_BSI        = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_BSI)        // 9-pass method recommended by the German Center of Security in Information Technologies
	STORAGE_VOL_WIPE_ALG_GUTMANN    = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_GUTMANN)    // The canonical 35-pass sequence
	STORAGE_VOL_WIPE_ALG_SCHNEIER   = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER)   // 7-pass method described by Bruce Schneier in "Applied Cryptography" (1996)
	STORAGE_VOL_WIPE_ALG_PFITZNER7  = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7)  // 7-pass random
	STORAGE_VOL_WIPE_ALG_PFITZNER33 = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33) // 33-pass random
	STORAGE_VOL_WIPE_ALG_RANDOM     = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_RANDOM)     // 1-pass random
	STORAGE_VOL_WIPE_ALG_TRIM       = StorageVolWipeAlgorithm(C.VIR_STORAGE_VOL_WIPE_ALG_TRIM)       // Trim the underlying storage
)

type StorageXMLFlags int

const (
	STORAGE_XML_INACTIVE = StorageXMLFlags(C.VIR_STORAGE_XML_INACTIVE)
)

type StorageVolInfoFlags int

const (
	STORAGE_VOL_USE_ALLOCATION = StorageVolInfoFlags(C.VIR_STORAGE_VOL_USE_ALLOCATION)
	STORAGE_VOL_GET_PHYSICAL   = StorageVolInfoFlags(C.VIR_STORAGE_VOL_GET_PHYSICAL)
)

type StorageVolUploadFlags int

const (
	STORAGE_VOL_UPLOAD_SPARSE_STREAM = StorageVolUploadFlags(C.VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM)
)

type StorageVolDownloadFlags int

const (
	STORAGE_VOL_DOWNLOAD_SPARSE_STREAM = StorageVolDownloadFlags(C.VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM)
)

type StorageVol struct {
	ptr C.virStorageVolPtr
}

type StorageVolInfo struct {
	Type       StorageVolType
	Capacity   uint64
	Allocation uint64
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolDelete
func (v *StorageVol) Delete(flags StorageVolDeleteFlags) error {
	result := C.virStorageVolDelete(v.ptr, C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolFree
func (v *StorageVol) Free() error {
	ret := C.virStorageVolFree(v.ptr)
	if ret == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolRef
func (c *StorageVol) Ref() error {
	ret := C.virStorageVolRef(c.ptr)
	if ret == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetInfo
func (v *StorageVol) GetInfo() (*StorageVolInfo, error) {
	var cinfo C.virStorageVolInfo
	result := C.virStorageVolGetInfo(v.ptr, &cinfo)
	if result == -1 {
		return nil, GetLastError()
	}
	return &StorageVolInfo{
		Type:       StorageVolType(cinfo._type),
		Capacity:   uint64(cinfo.capacity),
		Allocation: uint64(cinfo.allocation),
	}, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetInfoFlags
func (v *StorageVol) GetInfoFlags(flags StorageVolInfoFlags) (*StorageVolInfo, error) {
	if C.LIBVIR_VERSION_NUMBER < 3000000 {
		return nil, GetNotImplementedError("virStorageVolGetInfoFlags")
	}

	var cinfo C.virStorageVolInfo
	result := C.virStorageVolGetInfoFlagsCompat(v.ptr, &cinfo, C.uint(flags))
	if result == -1 {
		return nil, GetLastError()
	}
	return &StorageVolInfo{
		Type:       StorageVolType(cinfo._type),
		Capacity:   uint64(cinfo.capacity),
		Allocation: uint64(cinfo.allocation),
	}, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetKey
func (v *StorageVol) GetKey() (string, error) {
	key := C.virStorageVolGetKey(v.ptr)
	if key == nil {
		return "", GetLastError()
	}
	return C.GoString(key), nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetName
func (v *StorageVol) GetName() (string, error) {
	name := C.virStorageVolGetName(v.ptr)
	if name == nil {
		return "", GetLastError()
	}
	return C.GoString(name), nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetPath
func (v *StorageVol) GetPath() (string, error) {
	result := C.virStorageVolGetPath(v.ptr)
	if result == nil {
		return "", GetLastError()
	}
	path := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return path, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolGetXMLDesc
func (v *StorageVol) GetXMLDesc(flags uint32) (string, error) {
	result := C.virStorageVolGetXMLDesc(v.ptr, C.uint(flags))
	if result == nil {
		return "", GetLastError()
	}
	xml := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return xml, nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolResize
func (v *StorageVol) Resize(capacity uint64, flags StorageVolResizeFlags) error {
	result := C.virStorageVolResize(v.ptr, C.ulonglong(capacity), C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolWipe
func (v *StorageVol) Wipe(flags uint32) error {
	result := C.virStorageVolWipe(v.ptr, C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolWipePattern
func (v *StorageVol) WipePattern(algorithm StorageVolWipeAlgorithm, flags uint32) error {
	result := C.virStorageVolWipePattern(v.ptr, C.uint(algorithm), C.uint(flags))
	if result == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolUpload
func (v *StorageVol) Upload(stream *Stream, offset, length uint64, flags StorageVolUploadFlags) error {
	if C.virStorageVolUpload(v.ptr, stream.ptr, C.ulonglong(offset),
		C.ulonglong(length), C.uint(flags)) == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStorageVolDownload
func (v *StorageVol) Download(stream *Stream, offset, length uint64, flags StorageVolDownloadFlags) error {
	if C.virStorageVolDownload(v.ptr, stream.ptr, C.ulonglong(offset),
		C.ulonglong(length), C.uint(flags)) == -1 {
		return GetLastError()
	}
	return nil
}

// See also https://libvirt.org/html/libvirt-libvirt-storage.html#virStoragePoolLookupByVolume
func (v *StorageVol) LookupPoolByVolume() (*StoragePool, error) {
	poolPtr := C.virStoragePoolLookupByVolume(v.ptr)
	if poolPtr == nil {
		return nil, GetLastError()
	}
	return &StoragePool{ptr: poolPtr}, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"regexp"
	"strings"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSIAMInstanceProfile_importBasic(t *testing.T) {
	resourceName := "aws_iam_instance_profile.test"
	rName := acctest.RandString(5)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSInstanceProfileDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfilePrefixNameConfig(rName),
			},

			{
				ResourceName:            resourceName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"name_prefix"},
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_basic(t *testing.T) {
	var conf iam.GetInstanceProfileOutput

	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsIamInstanceProfileConfig(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
				),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_withRoleNotRoles(t *testing.T) {
	var conf iam.GetInstanceProfileOutput

	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfileWithRoleSpecified(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
				),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_missingRoleThrowsError(t *testing.T) {
	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccAwsIamInstanceProfileConfigMissingRole(rName),
				ExpectError: regexp.MustCompile("Either `roles` or `role` must be specified when creating an IAM Instance Profile"),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_namePrefix(t *testing.T) {
	var conf iam.GetInstanceProfileOutput
	rName := acctest.RandString(5)

	resource.Test(t, resource.TestCase{
		PreCheck:        func() { testAccPreCheck(t) },
		IDRefreshName:   "aws_iam_instance_profile.test",
		IDRefreshIgnore: []string{"name_prefix"},
		Providers:       testAccProviders,
		CheckDestroy:    testAccCheckAWSInstanceProfileDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfilePrefixNameConfig(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
					testAccCheckAWSInstanceProfileGeneratedNamePrefix(
						"aws_iam_instance_profile.test", "test-"),
				),
			},
		},
	})
}

func testAccCheckAWSInstanceProfileGeneratedNamePrefix(resource, prefix string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		r, ok := s.RootModule().Resources[resource]
		if !ok {
			return fmt.Errorf("Resource not found")
		}
		name, ok := r.Primary.Attributes["name"]
		if !ok {
			return fmt.Errorf("Name attr not found: %#v", r.Primary.Attributes)
		}
		if !strings.HasPrefix(name, prefix) {
			return fmt.Errorf("Name: %q, does not have prefix: %q", name, prefix)
		}
		return nil
	}
}

func testAccCheckAWSInstanceProfileDestroy(s *terraform.State) error {
	iamconn := testAccProvider.Meta().(*AWSClient).iamconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_iam_instance_profile" {
			continue
		}

		// Try to get role
		_, err := iamconn.GetInstanceProfile(&iam.GetInstanceProfileInput{
			InstanceProfileName: aws.String(rs.Primary.ID),
		})
		if err == nil {
			return fmt.Errorf("still exist.")
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "NoSuchEntity" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSInstanceProfileExists(n string, res *iam.GetInstanceProfileOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No Instance Profile name is set")
		}

		iamconn := testAccProvider.Meta().(*AWSClient).iamconn

		resp, err := iamconn.GetInstanceProfile(&iam.GetInstanceProfileInput{
			InstanceProfileName: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		*res = *resp

		return nil
	}
}

func testAccAwsIamInstanceProfileConfig(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name = "test"
	roles = ["${aws_iam_role.test.name}"]
}`, rName)
}

func testAccAwsIamInstanceProfileConfigMissingRole(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_instance_profile" "test" {
	name = "test-%s"
}`, rName)
}

func testAccAWSInstanceProfilePrefixNameConfig(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name_prefix = "test-"
	roles = ["${aws_iam_role.test.name}"]
}`, rName)
}

func testAccAWSInstanceProfileWithRoleSpecified(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name_prefix = "test-"
	role = "${aws_iam_role.test.name}"
}`, rName)
}
<commit_msg>provider/aws: Fix-up TestAccAWSIAMInstanceProfile_missingRoleThrowsError<commit_after>package aws

import (
	"fmt"
	"regexp"
	"strings"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSIAMInstanceProfile_importBasic(t *testing.T) {
	resourceName := "aws_iam_instance_profile.test"
	rName := acctest.RandString(5)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSInstanceProfileDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfilePrefixNameConfig(rName),
			},

			{
				ResourceName:            resourceName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"name_prefix"},
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_basic(t *testing.T) {
	var conf iam.GetInstanceProfileOutput

	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsIamInstanceProfileConfig(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
				),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_withRoleNotRoles(t *testing.T) {
	var conf iam.GetInstanceProfileOutput

	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfileWithRoleSpecified(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
				),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_missingRoleThrowsError(t *testing.T) {
	rName := acctest.RandString(5)
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccAwsIamInstanceProfileConfigMissingRole(rName),
				ExpectError: regexp.MustCompile(regexp.QuoteMeta("Either `role` or `roles` (deprecated) must be specified when creating an IAM Instance Profile")),
			},
		},
	})
}

func TestAccAWSIAMInstanceProfile_namePrefix(t *testing.T) {
	var conf iam.GetInstanceProfileOutput
	rName := acctest.RandString(5)

	resource.Test(t, resource.TestCase{
		PreCheck:        func() { testAccPreCheck(t) },
		IDRefreshName:   "aws_iam_instance_profile.test",
		IDRefreshIgnore: []string{"name_prefix"},
		Providers:       testAccProviders,
		CheckDestroy:    testAccCheckAWSInstanceProfileDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSInstanceProfilePrefixNameConfig(rName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSInstanceProfileExists("aws_iam_instance_profile.test", &conf),
					testAccCheckAWSInstanceProfileGeneratedNamePrefix(
						"aws_iam_instance_profile.test", "test-"),
				),
			},
		},
	})
}

func testAccCheckAWSInstanceProfileGeneratedNamePrefix(resource, prefix string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		r, ok := s.RootModule().Resources[resource]
		if !ok {
			return fmt.Errorf("Resource not found")
		}
		name, ok := r.Primary.Attributes["name"]
		if !ok {
			return fmt.Errorf("Name attr not found: %#v", r.Primary.Attributes)
		}
		if !strings.HasPrefix(name, prefix) {
			return fmt.Errorf("Name: %q, does not have prefix: %q", name, prefix)
		}
		return nil
	}
}

func testAccCheckAWSInstanceProfileDestroy(s *terraform.State) error {
	iamconn := testAccProvider.Meta().(*AWSClient).iamconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_iam_instance_profile" {
			continue
		}

		// Try to get role
		_, err := iamconn.GetInstanceProfile(&iam.GetInstanceProfileInput{
			InstanceProfileName: aws.String(rs.Primary.ID),
		})
		if err == nil {
			return fmt.Errorf("still exist.")
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "NoSuchEntity" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSInstanceProfileExists(n string, res *iam.GetInstanceProfileOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No Instance Profile name is set")
		}

		iamconn := testAccProvider.Meta().(*AWSClient).iamconn

		resp, err := iamconn.GetInstanceProfile(&iam.GetInstanceProfileInput{
			InstanceProfileName: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		*res = *resp

		return nil
	}
}

func testAccAwsIamInstanceProfileConfig(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name = "test"
	roles = ["${aws_iam_role.test.name}"]
}`, rName)
}

func testAccAwsIamInstanceProfileConfigMissingRole(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_instance_profile" "test" {
	name = "test-%s"
}`, rName)
}

func testAccAWSInstanceProfilePrefixNameConfig(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name_prefix = "test-"
	roles = ["${aws_iam_role.test.name}"]
}`, rName)
}

func testAccAWSInstanceProfileWithRoleSpecified(rName string) string {
	return fmt.Sprintf(`
resource "aws_iam_role" "test" {
	name = "test-%s"
	assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_instance_profile" "test" {
	name_prefix = "test-"
	role = "${aws_iam_role.test.name}"
}`, rName)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

func destroyHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("destroy %s unit", key)
	if err := fleetClient.Destroy(key); err != nil {
		// log.Printf("unit destroy error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func startHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("start %s unit", key)
	if err := fleetClient.Start(key); err != nil {
		// log.Printf("unit start error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func stopHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("stop %s unit", key)
	if err := fleetClient.Stop(key); err != nil {
		// log.Printf("unit stop error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func loadHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("load %s unit", key)
	if err := fleetClient.Load(key); err != nil {
		// log.Printf("unit load error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func uploadUnitHandler(w http.ResponseWriter, req *http.Request) {
	file, header, err := req.FormFile("file")
	defer file.Close()

	serviceFile := fmt.Sprintf("%s/%s", tempDir, header.Filename)
	out, err := os.Create(serviceFile)
	if err != nil {
		log.Printf("Open file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	defer out.Close()

	// write the content from POST to the file
	_, err = io.Copy(out, file)
	if err != nil {
		fmt.Fprintln(w, err)
	}

	err = fleetClient.Submit(header.Filename, serviceFile)
	if err != nil {
		// log.Printf("Fleet submit error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})

}

func submitUnitHandler(w http.ResponseWriter, req *http.Request) {
	name := req.FormValue("name")
	service := req.FormValue("service")

	if _, err := os.Stat(tempDir); os.IsNotExist(err) {
		os.Mkdir(tempDir, 0755)
	}

	serviceFile := fmt.Sprintf("%s/%s", tempDir, name)
	lines := strings.Split(string(service), "\\n")

	fo, err := os.Create(serviceFile)
	if err != nil {
		log.Printf("Open file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}

	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	for _, str := range lines {
		fmt.Fprintln(fo, str)
	}

	err = fleetClient.Submit(name, serviceFile)
	if err != nil {
		// log.Printf("Fleet submit error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func machineAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.MachineAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.StatusAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	status, _ := fleetClient.StatusUnit(key)
	renderer.JSON(w, http.StatusOK, status)
}

// websocket handler

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// write journal message
	key := mux.Vars(r)["id"]
	output, _ := fleetClient.JournalF(key)
	for line := range output {
		conn.WriteMessage(websocket.TextMessage, []byte(line))
	}
}
<commit_msg>edit submitUnitHandler function - fix json parsing<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

func destroyHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("destroy %s unit", key)
	if err := fleetClient.Destroy(key); err != nil {
		// log.Printf("unit destroy error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func startHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("start %s unit", key)
	if err := fleetClient.Start(key); err != nil {
		// log.Printf("unit start error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func stopHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("stop %s unit", key)
	if err := fleetClient.Stop(key); err != nil {
		// log.Printf("unit stop error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func loadHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	log.Printf("load %s unit", key)
	if err := fleetClient.Load(key); err != nil {
		// log.Printf("unit load error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func uploadUnitHandler(w http.ResponseWriter, req *http.Request) {
	file, header, err := req.FormFile("file")
	defer file.Close()

	serviceFile := fmt.Sprintf("%s/%s", tempDir, header.Filename)
	out, err := os.Create(serviceFile)
	if err != nil {
		log.Printf("Open file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}
	defer out.Close()

	// write the content from POST to the file
	_, err = io.Copy(out, file)
	if err != nil {
		fmt.Fprintln(w, err)
	}

	err = fleetClient.Submit(header.Filename, serviceFile)
	if err != nil {
		// log.Printf("Fleet submit error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})

}

func submitUnitHandler(w http.ResponseWriter, req *http.Request) {
	type UnitForm struct {
		Name    string `json:"name"`
		Service string `json:"service"`
	}

	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		log.Printf("read request body error : %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}

	var t UnitForm
	dec := json.NewDecoder(strings.NewReader(string(body)))
	dec.Decode(&t)
	if err != nil {
		log.Printf("json decode error : %s", err)
	}

	if _, err := os.Stat(tempDir); err != nil {
		log.Printf("err: %s", err)
	} else if os.IsNotExist(err) {
		os.Mkdir(tempDir, 0755)
	}

	serviceFile := fmt.Sprintf("%s/%s", tempDir, t.Name)
	lines := strings.Split(string(t.Service), "\\n")

	fo, err := os.Create(serviceFile)
	if err != nil {
		log.Printf("Open file errpr: %s", err)
		renderer.JSON(w, http.StatusBadRequest, err)
		return
	}

	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	for _, str := range lines {
		fmt.Fprintln(fo, str)
	}

	err = fleetClient.Submit(t.Name, serviceFile)
	if err != nil {
		// log.Printf("Fleet submit error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}

	if err := fleetClient.Start(t.Name); err != nil {
		// log.Printf("unit start error: %s", err)
		// renderer.JSON(w, http.StatusBadRequest, err)
		// return
	}
	renderer.JSON(w, http.StatusOK, map[string]string{"result": "success"})
}

func machineAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.MachineAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusAllHandler(w http.ResponseWriter, req *http.Request) {
	status, _ := fleetClient.StatusAll()
	renderer.JSON(w, http.StatusOK, status)
}

func statusHandler(w http.ResponseWriter, req *http.Request) {
	key := mux.Vars(req)["id"]
	status, _ := fleetClient.StatusUnit(key)
	renderer.JSON(w, http.StatusOK, status)
}

// websocket handler

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// write journal message
	key := mux.Vars(r)["id"]
	output, _ := fleetClient.JournalF(key)
	for line := range output {
		conn.WriteMessage(websocket.TextMessage, []byte(line))
	}
}
<|endoftext|>


<commit_before>package logging

import (
	"bytes"
	"io"
	"sync"
	"text/template"
	"time"
)

const (
	DefaultTimeLayout = "2006-01-02 15:04:05"
	DefaultFormat     = "[{{.TimeString}}] {{.Level}} {{.Message}}\n"
	DefaultBufSize    = 1024
)

type Handler interface {
	SetBufSize(int)
	SetLevel(LogLevel)
	SetLevelString(string)
	SetLevelRange(LogLevel, LogLevel)
	SetLevelRangeString(string, string)
	SetTimeLayout(string)
	SetFormat(string) error
	SetFilter(func(*Record) bool)
	Emit(Record)
	Panic(bool)
}

type Record struct {
	Time       time.Time
	TimeString string
	Level      LogLevel
	Message    string
}

type BaseHandler struct {
	Mutex      sync.Mutex
	Writer     io.WriteCloser
	Level      LogLevel
	LRange     *LevelRange
	TimeLayout string
	Tmpl       *template.Template
	Buffer     chan *Record
	BufSize    int
	Filter     func(*Record) bool
	Before     func(io.ReadWriter)
	After      func(int64)
	GotError   func(error)
}

func NewBaseHandler(out io.WriteCloser, level LogLevel, layout, format string) (*BaseHandler, error) {
	h := &BaseHandler{
		Writer:     out,
		Level:      level,
		TimeLayout: layout,
	}
	if err := h.SetFormat(format); err != nil {
		return nil, err
	}
	h.BufSize = DefaultBufSize
	go h.WriteRecord()
	return h, nil
}

func (h *BaseHandler) SetBufSize(size int) {
	h.BufSize = size
	close(h.Buffer)
}

func (h *BaseHandler) SetLevel(level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Level = level
}

func (h *BaseHandler) SetLevelString(s string) {
	h.SetLevel(StringToLogLevel(s))
}

func (h *BaseHandler) SetLevelRange(min_level, max_level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.LRange = &LevelRange{min_level, max_level}
}

func (h *BaseHandler) SetLevelRangeString(smin, smax string) {
	h.SetLevelRange(StringToLogLevel(smin), StringToLogLevel(smax))
}

func (h *BaseHandler) SetTimeLayout(layout string) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.TimeLayout = layout
}

func (h *BaseHandler) SetFormat(format string) error {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	tmpl, err := template.New("tmpl").Parse(format)
	if err != nil {
		return err
	}
	h.Tmpl = tmpl
	return nil
}

func (h *BaseHandler) SetFilter(f func(*Record) bool) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Filter = f
}

func (h *BaseHandler) Emit(rd Record) {
	if h.LRange != nil {
		if !h.LRange.Contain(rd.Level) {
			return
		}
	} else if h.Level > rd.Level {
		return
	}
	h.Buffer <- &rd
}

func (h *BaseHandler) PanicError(err error) {
	if err != nil {
		panic(err)
	}
}

func (h *BaseHandler) IgnoreError(error) {
}

func (h *BaseHandler) Panic(b bool) {
	if b {
		h.GotError = h.PanicError
	} else {
		h.GotError = h.IgnoreError
	}
}

func (h *BaseHandler) WriteRecord() {
	rd := &Record{}
	buf := bytes.NewBuffer(nil)
	h.Buffer = make(chan *Record, h.BufSize)
	for {
		rd = <-h.Buffer
		if rd == nil {
			go h.WriteRecord()
			break
		}
		if h.Filter != nil && h.Filter(rd) {
			continue
		}
		if h.Writer == nil {
			continue
		}
		buf.Reset()
		rd.TimeString = rd.Time.Format(h.TimeLayout)
		if err := h.Tmpl.Execute(buf, rd); err != nil {
			h.GotError(err)
			continue
		}
		if h.Before != nil {
			h.Before(buf)
		}
		n, err := io.Copy(h.Writer, buf)
		if err != nil {
			h.GotError(err)
		}
		if h.After != nil {
			h.After(int64(n))
		}
	}
}
<commit_msg>make chan before go<commit_after>package logging

import (
	"bytes"
	"io"
	"sync"
	"text/template"
	"time"
)

const (
	DefaultTimeLayout = "2006-01-02 15:04:05"
	DefaultFormat     = "[{{.TimeString}}] {{.Level}} {{.Message}}\n"
	DefaultBufSize    = 1024
)

type Handler interface {
	SetBufSize(int)
	SetLevel(LogLevel)
	SetLevelString(string)
	SetLevelRange(LogLevel, LogLevel)
	SetLevelRangeString(string, string)
	SetTimeLayout(string)
	SetFormat(string) error
	SetFilter(func(*Record) bool)
	Emit(Record)
	Panic(bool)
}

type Record struct {
	Time       time.Time
	TimeString string
	Level      LogLevel
	Message    string
}

type BaseHandler struct {
	Mutex      sync.Mutex
	Writer     io.WriteCloser
	Level      LogLevel
	LRange     *LevelRange
	TimeLayout string
	Tmpl       *template.Template
	Buffer     chan *Record
	BufSize    int
	Filter     func(*Record) bool
	Before     func(io.ReadWriter)
	After      func(int64)
	GotError   func(error)
}

func NewBaseHandler(out io.WriteCloser, level LogLevel, layout, format string) (*BaseHandler, error) {
	h := &BaseHandler{
		Writer:     out,
		Level:      level,
		TimeLayout: layout,
	}
	if err := h.SetFormat(format); err != nil {
		return nil, err
	}
	h.BufSize = DefaultBufSize
	h.Buffer = make(chan *Record, h.BufSize)
	go h.WriteRecord()
	return h, nil
}

func (h *BaseHandler) SetBufSize(size int) {
	h.BufSize = size
	close(h.Buffer)
}

func (h *BaseHandler) SetLevel(level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Level = level
}

func (h *BaseHandler) SetLevelString(s string) {
	h.SetLevel(StringToLogLevel(s))
}

func (h *BaseHandler) SetLevelRange(min_level, max_level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.LRange = &LevelRange{min_level, max_level}
}

func (h *BaseHandler) SetLevelRangeString(smin, smax string) {
	h.SetLevelRange(StringToLogLevel(smin), StringToLogLevel(smax))
}

func (h *BaseHandler) SetTimeLayout(layout string) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.TimeLayout = layout
}

func (h *BaseHandler) SetFormat(format string) error {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	tmpl, err := template.New("tmpl").Parse(format)
	if err != nil {
		return err
	}
	h.Tmpl = tmpl
	return nil
}

func (h *BaseHandler) SetFilter(f func(*Record) bool) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Filter = f
}

func (h *BaseHandler) Emit(rd Record) {
	if h.LRange != nil {
		if !h.LRange.Contain(rd.Level) {
			return
		}
	} else if h.Level > rd.Level {
		return
	}
	h.Buffer <- &rd
}

func (h *BaseHandler) PanicError(err error) {
	if err != nil {
		panic(err)
	}
}

func (h *BaseHandler) IgnoreError(error) {
}

func (h *BaseHandler) Panic(b bool) {
	if b {
		h.GotError = h.PanicError
	} else {
		h.GotError = h.IgnoreError
	}
}

func (h *BaseHandler) WriteRecord() {
	rd := &Record{}
	buf := bytes.NewBuffer(nil)
	for {
		rd = <-h.Buffer
		if rd == nil {
			h.Buffer = make(chan *Record, h.BufSize)
			go h.WriteRecord()
			break
		}
		if h.Filter != nil && h.Filter(rd) {
			continue
		}
		if h.Writer == nil {
			continue
		}
		buf.Reset()
		rd.TimeString = rd.Time.Format(h.TimeLayout)
		if err := h.Tmpl.Execute(buf, rd); err != nil {
			h.GotError(err)
			continue
		}
		if h.Before != nil {
			h.Before(buf)
		}
		n, err := io.Copy(h.Writer, buf)
		if err != nil {
			h.GotError(err)
		}
		if h.After != nil {
			h.After(int64(n))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"io"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strings"
	"time"
	"unicode"

	"github.com/chzyer/readline"
	"github.com/knq/dburl"
	"github.com/knq/xoutil"
	"github.com/olekukonko/tablewriter"
)

const (
	notConnected = "(not connected)"
)

// Handler is a cli input handler.
type Handler struct {
	args        *Args
	interactive bool

	u  *dburl.URL
	db *sql.DB
}

// Prompt returns the base input prompt.
func (h *Handler) Prompt() string {
	if !h.interactive {
		return ""
	}

	s := notConnected

	if h.db != nil {
		s = h.u.Short()
	}

	return s + "=> "
}

// Cont returns the continuation prompt.
func (h *Handler) Cont() string {
	if !h.interactive {
		return ""
	}

	s := notConnected

	if h.db != nil {
		s = h.u.Short()
	}

	return s + "-> "
}

// Open handles opening a specified database URL.
func (h *Handler) Open(urlstr string) error {
	if urlstr == "" {
		return nil
	}

	// parse dsn
	var err error
	h.u, err = dburl.Parse(urlstr)
	switch {
	case err == dburl.ErrInvalidDatabaseScheme:
		if fi, err := os.Stat(urlstr); err == nil {
			// TODO: add support for postgres unix domain sockets
			switch {
			case fi.Mode()|os.ModeNamedPipe != 0:
				return h.Open("mysql+unix:" + urlstr)

			default:
				// it is a file, so reattempt to open it with sqlite3
				return h.Open("sqlite3:" + urlstr)
			}
		}

	case err != nil:
		return err
	}

	// check driver
	if !drivers[h.u.Driver] {
		if h.u.Driver == "ora" {
			return ErrOracleDriverNotAvailable
		}
		return fmt.Errorf("driver '%s' is not available for '%s'", h.u.Driver, h.u.Scheme)
	}

	// add connection parameters for databases
	dsn := h.u.DSN
	dsn = h.addQueryParam(dsn, "mysql", "parseTime", "true")
	dsn = h.addQueryParam(dsn, "mysql", "loc", "Local")
	dsn = h.addQueryParam(dsn, "sqlite3", "loc", "auto")

	//log.Printf(">>> dsn: %s", dsn)

	// connect
	h.db, err = sql.Open(h.u.Driver, dsn)
	return err
}

// addQueryParam conditionally adds a ?name=val style query parameter to the
// end of a DSN if the connected database driver matches the supplied driver
// name.
func (h *Handler) addQueryParam(dsn, driver, name, val string) string {
	if h.u.Driver == driver {
		if !strings.Contains(dsn, name+"=") {
			s := "?"
			if strings.Contains(dsn, "?") {
				s = "&"
			}
			return dsn + s + name + "=" + val
		}
	}

	return dsn
}

// Execute executes a sql query against the connected database.
func (h *Handler) Execute(w io.Writer, sqlstr string) error {
	if h.db == nil {
		return ErrNotConnected
	}

	if h.u.Driver == "ora" {
		sqlstr = strings.TrimSuffix(sqlstr, ";")
	}

	// select
	if s := strings.TrimLeftFunc(sqlstr, unicode.IsSpace); len(s) >= 5 {
		i := strings.IndexFunc(s, unicode.IsSpace)
		if i == -1 {
			i = len(s)
		}

		z := strings.ToUpper(s[:i])
		if z == "SELECT" ||
			(h.u.Driver == "sqlite3" && z == "PRAGMA" && !strings.ContainsRune(s[i:], '=')) {
			return h.Query(w, sqlstr)
		}
	}

	// exec
	res, err := h.db.Exec(sqlstr)
	if err != nil {
		return err
	}

	// get count
	count, err := res.RowsAffected()
	if err != nil {
		return err
	}

	// print name
	name := "EXEC"
	if i := strings.Index(sqlstr, " "); i >= 0 {
		name = strings.ToUpper(sqlstr[:i])
	}
	fmt.Fprint(w, name)

	// print count
	if count > 0 {
		fmt.Fprintf(w, " %d", count)
	}

	fmt.Fprint(w, "\n")

	return nil
}

var allcapsRE = regexp.MustCompile(`^[A-Z_]+$`)

// Query executes a query against the database.
func (h *Handler) Query(w io.Writer, sqlstr string) error {
	// run query
	q, err := h.db.Query(sqlstr)
	if err != nil {
		return err
	}
	defer q.Close()

	// get column names
	cols, err := q.Columns()
	if err != nil {
		return err
	}

	// fix display column names
	for i, s := range cols {
		s = strings.TrimSpace(s)
		if len(s) == 0 {
			cols[i] = fmt.Sprintf("col%d", i)
		}

		// fix case on oracle column names
		if h.u.Driver == "ora" && allcapsRE.MatchString(cols[i]) {
			cols[i] = strings.ToLower(cols[i])
		}
	}

	// create output table
	t := tablewriter.NewWriter(w)
	t.SetAutoFormatHeaders(false)
	t.SetBorder(false)
	t.SetHeader(cols)

	clen := len(cols)
	var rows int
	if clen != 0 {
		for q.Next() {
			r := make([]interface{}, clen)
			for i := range r {
				r[i] = new(interface{})
			}

			err = q.Scan(r...)
			if err != nil {
				return err
			}

			row := make([]string, clen)
			for n, z := range r {
				j := z.(*interface{})

				//log.Printf(">>> %s: %s", cols[n], reflect.TypeOf(*j))

				switch x := (*j).(type) {
				case []byte:
					if h.u.Driver == "sqlite3" {
						row[n] = h.sqlite3Parse(x)
					} else {
						row[n] = string(x)
					}

				case string:
					row[n] = x

				case time.Time:
					row[n] = x.Format(time.RFC3339Nano)

				case fmt.Stringer:
					row[n] = x.String()

				default:
					row[n] = fmt.Sprintf("%v", *j)
				}

			}
			t.Append(row)
			rows++
		}
	}

	t.Render()
	fmt.Fprintf(w, "(%d rows)\n\n", rows)

	return nil
}

// sqlite3Parse will convert buf matching a time format to a time, and will
// format it according to the handler time settings.
//
// TODO: only do this if the type of the column is a timestamp type.
func (h *Handler) sqlite3Parse(buf []byte) string {
	s := string(buf)
	if s != "" && strings.TrimSpace(s) != "" {
		t := &xoutil.SqTime{}
		err := t.Scan(buf)
		if err == nil {
			return t.Format(time.RFC3339Nano)
		}
	}

	return s
}

// HistoryFile returns the name of the history file.
func (h *Handler) HistoryFile() string {
	u, err := user.Current()
	if err != nil {
		panic(err)
	}

	return filepath.Join(u.HomeDir, ".usql_history")
}

// DisplayHelp displays the help message.
func (h *Handler) DisplayHelp(w io.Writer) {
	io.WriteString(w, helpDesc)
}

// Close closes the database connection if it is open.
func (h *Handler) Close() error {
	if h.db != nil {
		err := h.db.Close()

		h.db = nil
		h.u = nil

		return err
	}

	return nil
}

// Run handles stuff
func (h *Handler) Run() error {
	var err error

	// open
	err = h.Open(h.args.DSN)
	if err != nil {
		return err
	}

	//log.Printf(">>> commands: %v", h.args.Commands)

	// short circuit if commands provided
	if len(h.args.Commands) > 0 {
		return h.RunCommands()
	}

	// create readline instance
	l, err := readline.NewEx(&readline.Config{
		Prompt:                 h.Prompt(),
		HistoryFile:            h.HistoryFile(),
		DisableAutoSaveHistory: true,
		InterruptPrompt:        "^C",
		HistorySearchFold:      true,
		FuncFilterInputRune: func(r rune) (rune, bool) {
			if r == readline.CharCtrlZ {
				return r, false
			}
			return r, true
		},
	})
	if err != nil {
		return err
	}
	defer l.Close()

	if h.interactive {
		fmt.Fprint(l.Stdout(), cliDesc)
	}

	// process input
	var multi bool
	var stmt []string
	for {
		line, err := l.Readline()
		switch {
		case err == readline.ErrInterrupt:
			stmt = stmt[:0]
			multi = false
			l.SetPrompt(h.Prompt())
			continue

		case err != nil:
			return nil
		}

		z := strings.TrimSpace(line)
		if !multi {
			switch {
			case z == "help":
				h.DisplayHelp(l.Stdout())
				continue

			case z == `\q`:
				l.SaveHistory(line)
				return nil

			case strings.HasPrefix(line, `\c `):
				l.SaveHistory(line)

				err = h.Close()
				if err != nil {
					return err
				}

				urlstr := strings.TrimSpace(line[2:])
				err = h.Open(urlstr)
				if err != nil {
					fmt.Fprintf(l.Stderr(), "error: could not connect to `%s`: %v\n", urlstr, err)
				}

				l.SetPrompt(h.Prompt())
				continue

			case z == `\Z`:
				l.SaveHistory(line)

				err = h.Close()
				if err != nil {
					return err
				}

				l.SetPrompt(h.Prompt())
				continue
			}
		}

		stmt = append(stmt, line)

		if len(z) == 0 {
			continue
		}
		if !strings.HasSuffix(z, ";") {
			multi = true
			l.SetPrompt(h.Cont())
			continue
		}

		s := strings.Join(stmt, "\n")
		l.SaveHistory(s)
		l.SetPrompt(h.Prompt())

		err = h.Execute(l.Stdout(), s)
		if err != nil {
			fmt.Fprintf(l.Stderr(), "error: %v\n", err)
		}

		stmt = stmt[:0]
		multi = false
	}
}

// RunCommands runs the argument commands.
func (h *Handler) RunCommands() error {
	var err error
	for _, c := range h.args.Commands {
		err = h.Execute(os.Stdout, c)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Fixing issue with mysql unix domain sockets and standardizing error output<commit_after>package main

import (
	"database/sql"
	"fmt"
	"io"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strings"
	"time"
	"unicode"

	"github.com/chzyer/readline"
	"github.com/knq/dburl"
	"github.com/knq/xoutil"
	"github.com/olekukonko/tablewriter"
)

const (
	notConnected = "(not connected)"
)

// Handler is a cli input handler.
type Handler struct {
	args        *Args
	interactive bool

	u  *dburl.URL
	db *sql.DB
}

// Prompt returns the base input prompt.
func (h *Handler) Prompt() string {
	if !h.interactive {
		return ""
	}

	s := notConnected

	if h.db != nil {
		s = h.u.Short()
	}

	return s + "=> "
}

// Cont returns the continuation prompt.
func (h *Handler) Cont() string {
	if !h.interactive {
		return ""
	}

	s := notConnected

	if h.db != nil {
		s = h.u.Short()
	}

	return s + "-> "
}

// Open handles opening a specified database URL.
func (h *Handler) Open(urlstr string) error {
	if urlstr == "" {
		return nil
	}

	// parse dsn
	var err error
	h.u, err = dburl.Parse(urlstr)
	switch {
	case err == dburl.ErrInvalidDatabaseScheme:
		if fi, err := os.Stat(urlstr); err == nil {
			// TODO: add support for postgres unix domain sockets
			switch {
			case fi.Mode()&os.ModeSocket != 0:
				return h.Open("mysql+unix:" + urlstr)

			default:
				// it is a file, so reattempt to open it with sqlite3
				return h.Open("sqlite3:" + urlstr)
			}
		}

	case err != nil:
		return err
	}

	// check driver
	if !drivers[h.u.Driver] {
		if h.u.Driver == "ora" {
			return ErrOracleDriverNotAvailable
		}
		return fmt.Errorf("driver '%s' is not available for '%s'", h.u.Driver, h.u.Scheme)
	}

	// add connection parameters for databases
	dsn := h.u.DSN
	dsn = h.addQueryParam(dsn, "mysql", "parseTime", "true")
	dsn = h.addQueryParam(dsn, "mysql", "loc", "Local")
	dsn = h.addQueryParam(dsn, "sqlite3", "loc", "auto")

	//log.Printf(">>> dsn: %s", dsn)

	// connect
	h.db, err = sql.Open(h.u.Driver, dsn)
	return err
}

// addQueryParam conditionally adds a ?name=val style query parameter to the
// end of a DSN if the connected database driver matches the supplied driver
// name.
func (h *Handler) addQueryParam(dsn, driver, name, val string) string {
	if h.u.Driver == driver {
		if !strings.Contains(dsn, name+"=") {
			s := "?"
			if strings.Contains(dsn, "?") {
				s = "&"
			}
			return dsn + s + name + "=" + val
		}
	}

	return dsn
}

// Execute executes a sql query against the connected database.
func (h *Handler) Execute(w io.Writer, sqlstr string) error {
	if h.db == nil {
		return ErrNotConnected
	}

	if h.u.Driver == "ora" {
		sqlstr = strings.TrimSuffix(sqlstr, ";")
	}

	// select
	if s := strings.TrimLeftFunc(sqlstr, unicode.IsSpace); len(s) >= 5 {
		i := strings.IndexFunc(s, unicode.IsSpace)
		if i == -1 {
			i = len(s)
		}

		z := strings.ToUpper(s[:i])
		if z == "SELECT" ||
			(h.u.Driver == "sqlite3" && z == "PRAGMA" && !strings.ContainsRune(s[i:], '=')) {
			return h.Query(w, sqlstr)
		}
	}

	// exec
	res, err := h.db.Exec(sqlstr)
	if err != nil {
		return err
	}

	// get count
	count, err := res.RowsAffected()
	if err != nil {
		return err
	}

	// print name
	name := "EXEC"
	if i := strings.Index(sqlstr, " "); i >= 0 {
		name = strings.ToUpper(sqlstr[:i])
	}
	fmt.Fprint(w, name)

	// print count
	if count > 0 {
		fmt.Fprintf(w, " %d", count)
	}

	fmt.Fprint(w, "\n")

	return nil
}

var allcapsRE = regexp.MustCompile(`^[A-Z_]+$`)

// Query executes a query against the database.
func (h *Handler) Query(w io.Writer, sqlstr string) error {
	// run query
	q, err := h.db.Query(sqlstr)
	if err != nil {
		return err
	}
	defer q.Close()

	// get column names
	cols, err := q.Columns()
	if err != nil {
		return err
	}

	// fix display column names
	for i, s := range cols {
		s = strings.TrimSpace(s)
		if len(s) == 0 {
			cols[i] = fmt.Sprintf("col%d", i)
		}

		// fix case on oracle column names
		if h.u.Driver == "ora" && allcapsRE.MatchString(cols[i]) {
			cols[i] = strings.ToLower(cols[i])
		}
	}

	// create output table
	t := tablewriter.NewWriter(w)
	t.SetAutoFormatHeaders(false)
	t.SetBorder(false)
	t.SetHeader(cols)

	clen := len(cols)
	var rows int
	if clen != 0 {
		for q.Next() {
			r := make([]interface{}, clen)
			for i := range r {
				r[i] = new(interface{})
			}

			err = q.Scan(r...)
			if err != nil {
				return err
			}

			row := make([]string, clen)
			for n, z := range r {
				j := z.(*interface{})

				//log.Printf(">>> %s: %s", cols[n], reflect.TypeOf(*j))

				switch x := (*j).(type) {
				case []byte:
					if h.u.Driver == "sqlite3" {
						row[n] = h.sqlite3Parse(x)
					} else {
						row[n] = string(x)
					}

				case string:
					row[n] = x

				case time.Time:
					row[n] = x.Format(time.RFC3339Nano)

				case fmt.Stringer:
					row[n] = x.String()

				default:
					row[n] = fmt.Sprintf("%v", *j)
				}

			}
			t.Append(row)
			rows++
		}
	}

	t.Render()
	fmt.Fprintf(w, "(%d rows)\n\n", rows)

	return nil
}

// sqlite3Parse will convert buf matching a time format to a time, and will
// format it according to the handler time settings.
//
// TODO: only do this if the type of the column is a timestamp type.
func (h *Handler) sqlite3Parse(buf []byte) string {
	s := string(buf)
	if s != "" && strings.TrimSpace(s) != "" {
		t := &xoutil.SqTime{}
		err := t.Scan(buf)
		if err == nil {
			return t.Format(time.RFC3339Nano)
		}
	}

	return s
}

// HistoryFile returns the name of the history file.
func (h *Handler) HistoryFile() string {
	u, err := user.Current()
	if err != nil {
		panic(err)
	}

	return filepath.Join(u.HomeDir, ".usql_history")
}

// DisplayHelp displays the help message.
func (h *Handler) DisplayHelp(w io.Writer) {
	io.WriteString(w, helpDesc)
}

// Close closes the database connection if it is open.
func (h *Handler) Close() error {
	if h.db != nil {
		err := h.db.Close()

		h.db = nil
		h.u = nil

		return err
	}

	return nil
}

// Run handles stuff
func (h *Handler) Run() error {
	var err error

	// open
	err = h.Open(h.args.DSN)
	if err != nil {
		return err
	}

	//log.Printf(">>> commands: %v", h.args.Commands)

	// short circuit if commands provided
	if len(h.args.Commands) > 0 {
		return h.RunCommands()
	}

	// create readline instance
	l, err := readline.NewEx(&readline.Config{
		Prompt:                 h.Prompt(),
		HistoryFile:            h.HistoryFile(),
		DisableAutoSaveHistory: true,
		InterruptPrompt:        "^C",
		HistorySearchFold:      true,
		FuncFilterInputRune: func(r rune) (rune, bool) {
			if r == readline.CharCtrlZ {
				return r, false
			}
			return r, true
		},
	})
	if err != nil {
		return err
	}
	defer l.Close()

	if h.interactive {
		fmt.Fprint(l.Stdout(), cliDesc)
	}

	// process input
	var multi bool
	var stmt []string
	for {
		line, err := l.Readline()
		switch {
		case err == readline.ErrInterrupt:
			stmt = stmt[:0]
			multi = false
			l.SetPrompt(h.Prompt())
			continue

		case err != nil:
			return nil
		}

		z := strings.TrimSpace(line)
		if !multi {
			switch {
			case z == "help":
				h.DisplayHelp(l.Stdout())
				continue

			case z == `\q`:
				l.SaveHistory(line)
				return nil

			case strings.HasPrefix(line, `\c `):
				l.SaveHistory(line)

				err = h.Close()
				if err != nil {
					return err
				}

				urlstr := strings.TrimSpace(line[2:])
				err = h.Open(urlstr)
				if err != nil {
					fmt.Fprintf(l.Stderr(), "error: could not connect to database: %v\n", err)
				}

				l.SetPrompt(h.Prompt())
				continue

			case z == `\Z`:
				l.SaveHistory(line)

				err = h.Close()
				if err != nil {
					return err
				}

				l.SetPrompt(h.Prompt())
				continue
			}
		}

		stmt = append(stmt, line)

		if len(z) == 0 {
			continue
		}
		if !strings.HasSuffix(z, ";") {
			multi = true
			l.SetPrompt(h.Cont())
			continue
		}

		s := strings.Join(stmt, "\n")
		l.SaveHistory(s)
		l.SetPrompt(h.Prompt())

		err = h.Execute(l.Stdout(), s)
		if err != nil {
			// attempt to clean up and standardize errors
			s := strings.TrimSpace(err.Error())
			prefix := h.u.Driver
			if h.u.Driver == "postgres" {
				prefix = "pq"
			}
			if !strings.HasPrefix(s, prefix+":") {
				s = h.u.Driver + ": " + s
			}

			fmt.Fprintf(l.Stderr(), "error: "+s+"\n")
		}

		stmt = stmt[:0]
		multi = false
	}
}

// RunCommands runs the argument commands.
func (h *Handler) RunCommands() error {
	var err error
	for _, c := range h.args.Commands {
		err = h.Execute(os.Stdout, c)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

// Package system implements SVG rendering of Lindenmayer systems
package system

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
	"os"
	"unicode"
)

// A rewriteSet is a set of rules for replacing variables with sequences.
type rewriteSet map[byte][]byte

// A System is a representation of a Lindenmayer system (L-system).
type System struct {
	axiom []byte     // Initial state of the system.
	rules rewriteSet // Rules for rewriting variables.
	angle float64    // Turn angle, in radians.
	start float64    // Initial direction, in radians (standard position).
	turn  bool       // Turn initial direction (used for dragon).
	base  float64    // Base b in y ~ b^x where y is size and x is depth.
	min   int        // Number of initial depths to skip.
	max   int        // Maximum depth of recursion.
}

// cacheRender is like render but caches results to disk for better performance.
func (s *System) cacheRender(depth int) [][]vector {
	name := s.name()
	if name == "" {
		return s.render(depth)
	}

	filename := fmt.Sprintf("cache/%s-%d.gob", name, depth)
	_, err := os.Stat(filename)
	if err == nil {
		log.Println("Cache hit:", filename)
		file, err := os.Open(filename)
		if err != nil {
			log.Println("File open error:", err)
			return s.render(depth)
		}
		defer file.Close()

		var segments [][]vector
		err = gob.NewDecoder(file).Decode(&segments)
		if err != nil {
			log.Println("Gob decode error:", err)
			return s.render(depth)
		}
		return segments
	}
	if os.IsNotExist(err) {
		log.Println("Cache miss:", filename)
		segments := s.render(depth)
		file, err := os.Create(filename)
		if err != nil {
			log.Println("File create error:", err)
			return segments
		}
		defer file.Close()

		gob.NewEncoder(file).Encode(segments)
		return segments
	}

	log.Println("File stat error:", err)
	return s.render(depth)
}

// render draws the curve for the system at the given depth of recursion. It
// returns a list of polygonal lines as a 2D slice of points.
func (s *System) render(depth int) [][]vector {
	var buf bytes.Buffer
	s.expand(s.axiom, depth, &buf)
	return s.execute(buf.Bytes(), depth)
}

// expand recursively expands seq using the system's rules, stopping when the
// level reaches zero. It writes the results into buf.
func (s *System) expand(seq []byte, level int, buf *bytes.Buffer) {
	if level == 0 {
		buf.Write(seq)
		return
	}

	for _, sym := range seq {
		if replacement, ok := s.rules[sym]; ok {
			s.expand(replacement, level-1, buf)
		} else {
			buf.WriteByte(sym)
		}
	}
}

// execute performs the instructions in seq, ignoring symbols with no special
// meaning. It returns a list of polygonal lines, each one being a sequence of
// points that the were visited.
func (s *System) execute(seq []byte, depth int) [][]vector {
	var segments [][]vector
	var stack []turtle
	turt := s.initialTurtle(depth)
	points := []vector{turt.pos}

	for _, sym := range seq {
		if unicode.IsUpper(rune(sym)) {
			turt.advance()
			points = append(points, turt.pos)
			continue
		}
		switch sym {
		case '+':
			turt.turnCCW()
		case '-':
			turt.turnCW()
		case '[':
			stack = append(stack, turt)
		case ']':
			last := len(stack) - 1
			turt = stack[last]
			stack = stack[:last]
			if len(points) > 0 {
				segments = append(segments, points)
			}
			points = []vector{turt.pos}
		}
	}

	if len(points) > 0 {
		segments = append(segments, points)
	}
	return segments
}
<commit_msg>Let's see if this works on Heroku<commit_after>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

// Package system implements SVG rendering of Lindenmayer systems
package system

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
	"os"
	"unicode"
)

// A rewriteSet is a set of rules for replacing variables with sequences.
type rewriteSet map[byte][]byte

// A System is a representation of a Lindenmayer system (L-system).
type System struct {
	axiom []byte     // Initial state of the system.
	rules rewriteSet // Rules for rewriting variables.
	angle float64    // Turn angle, in radians.
	start float64    // Initial direction, in radians (standard position).
	turn  bool       // Turn initial direction (used for dragon).
	base  float64    // Base b in y ~ b^x where y is size and x is depth.
	min   int        // Number of initial depths to skip.
	max   int        // Maximum depth of recursion.
}

// cacheRender is like render but caches results to disk for better performance.
func (s *System) cacheRender(depth int) [][]vector {
	name := s.name()
	if name == "" {
		return s.render(depth)
	}

	filename := fmt.Sprintf("/app/cache/%s-%d.gob", name, depth)
	_, err := os.Stat(filename)
	if err == nil {
		log.Println("Cache hit:", filename)
		file, err := os.Open(filename)
		if err != nil {
			log.Println("File open error:", err)
			return s.render(depth)
		}
		defer file.Close()

		var segments [][]vector
		err = gob.NewDecoder(file).Decode(&segments)
		if err != nil {
			log.Println("Gob decode error:", err)
			return s.render(depth)
		}
		return segments
	}
	if os.IsNotExist(err) {
		log.Println("Cache miss:", filename)
		segments := s.render(depth)
		file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
		if err != nil {
			log.Println("File create error:", err)
			return segments
		}
		defer file.Close()

		gob.NewEncoder(file).Encode(segments)
		return segments
	}

	log.Println("File stat error:", err)
	return s.render(depth)
}

// render draws the curve for the system at the given depth of recursion. It
// returns a list of polygonal lines as a 2D slice of points.
func (s *System) render(depth int) [][]vector {
	var buf bytes.Buffer
	s.expand(s.axiom, depth, &buf)
	return s.execute(buf.Bytes(), depth)
}

// expand recursively expands seq using the system's rules, stopping when the
// level reaches zero. It writes the results into buf.
func (s *System) expand(seq []byte, level int, buf *bytes.Buffer) {
	if level == 0 {
		buf.Write(seq)
		return
	}

	for _, sym := range seq {
		if replacement, ok := s.rules[sym]; ok {
			s.expand(replacement, level-1, buf)
		} else {
			buf.WriteByte(sym)
		}
	}
}

// execute performs the instructions in seq, ignoring symbols with no special
// meaning. It returns a list of polygonal lines, each one being a sequence of
// points that the were visited.
func (s *System) execute(seq []byte, depth int) [][]vector {
	var segments [][]vector
	var stack []turtle
	turt := s.initialTurtle(depth)
	points := []vector{turt.pos}

	for _, sym := range seq {
		if unicode.IsUpper(rune(sym)) {
			turt.advance()
			points = append(points, turt.pos)
			continue
		}
		switch sym {
		case '+':
			turt.turnCCW()
		case '-':
			turt.turnCW()
		case '[':
			stack = append(stack, turt)
		case ']':
			last := len(stack) - 1
			turt = stack[last]
			stack = stack[:last]
			if len(points) > 0 {
				segments = append(segments, points)
			}
			points = []vector{turt.pos}
		}
	}

	if len(points) > 0 {
		segments = append(segments, points)
	}
	return segments
}
<|endoftext|>


<commit_before>package supervisor

import (
	"errors"
	"fmt"
	"github.com/kolo/xmlrpc"
)

const (
	apiVersion string = "3.0"
)

func makeParams(params ...interface{}) xmlrpc.Params {
	return xmlrpc.Params{params}
}

type SupervisorState struct {
	StateCode int64
	StateName string
}

func newSupervisorState(result xmlrpc.Struct) *SupervisorState {
	state := new(SupervisorState)
	state.StateCode = result["statecode"].(int64)
	state.StateName = result["statename"].(string)
	return state
}

func (state SupervisorState) String() string {
	return fmt.Sprintf(`SupervisorState{%d, "%s"}`, state.StateCode, state.StateName)
}

type ProcessInfo struct {
	Name          string
	Description   string
	Group         string
	Start         int64
	Stop          int64
	Now           int64
	State         int64
	StateName     string
	SpawnErr      string
	ExitStatus    int64
	Logfile       string
	StdoutLogfile string
	StderrLogfile string
	PID           int64
}

func newProcessInfo(result xmlrpc.Struct) *ProcessInfo {
	info := new(ProcessInfo)
	info.Name = result["name"].(string)
	info.Description = result["description"].(string)
	info.Group = result["group"].(string)
	info.Start = result["start"].(int64)
	info.Stop = result["stop"].(int64)
	info.Now = result["now"].(int64)
	info.State = result["state"].(int64)
	info.StateName = result["statename"].(string)
	info.SpawnErr = result["spawnerr"].(string)
	info.ExitStatus = result["exitstatus"].(int64)
	info.Logfile = result["logfile"].(string)
	info.StdoutLogfile = result["stdout_logfile"].(string)
	info.StderrLogfile = result["stderr_logfile"].(string)
	info.PID = result["pid"].(int64)
	return info
}

func (info ProcessInfo) String() string {
	return fmt.Sprintf(`ProcessInfo{"%s", %d, "%s"}`, info.Name, info.PID, info.StateName)
}

type ProcessStatus struct {
	Name        string
	Description string
	Group       string
	Status      int64
}

func newProcessStatus(result xmlrpc.Struct) *ProcessStatus {
	status := new(ProcessStatus)
	status.Name = result["name"].(string)
	status.Description = result["description"].(string)
	status.Group = result["group"].(string)
	status.Status = result["status"].(int64)
	return status
}

func (status ProcessStatus) String() string {
	return fmt.Sprintf(`ProcessStatus("%s", %d)`, status.Name, status.Status)
}

type ProcessTail struct {
	Log      string
	Offset   int64
	Overflow bool
}

func newProcessTail(result []interface{}) *ProcessTail {
	tail := new(ProcessTail)
	tail.Log = result[0].(string)
	tail.Offset = result[1].(int64)
	tail.Overflow = result[2].(bool)
	return tail
}

func (tail ProcessTail) String() string {
	return tail.Log
}

type Client struct {
	RpcClient  *xmlrpc.Client
	ApiVersion string
}

// NewClient creates a new supervisor RPC client.
func NewClient(url string) (client *Client, err error) {
	var rpc *xmlrpc.Client
	if rpc, err = xmlrpc.NewClient(url, nil); err != nil {
		return
	}

	version := ""
	if err = rpc.Call("supervisor.getAPIVersion", nil, &version); err != nil {
		return
	}
	if version != apiVersion {
		err = errors.New(fmt.Sprintf("want Supervisor API version %s, got %s instead", apiVersion, version))
		return
	}
	client = &Client{rpc, version}
	return
}

// Close the client.
func (client Client) Close() error {
	return client.RpcClient.Close()
}

// GetSupervisorVersion returns the Supervisor version we connect to.
func (client Client) GetSupervisorVersion() (version string, err error) {
	err = client.RpcClient.Call("supervisor.getSupervisorVersion", nil, &version)
	return
}

// GetIdentification returns the Supervisor ID string.
func (client Client) GetIdentification() (id string, err error) {
	err = client.RpcClient.Call("supervisor.getIdentification", nil, &id)
	return
}

// GetState returns the Supervisor process state.
func (client Client) GetState() (state *SupervisorState, err error) {
	result := xmlrpc.Struct{}
	if err = client.RpcClient.Call("supervisor.getState", nil, &result); err == nil {
		state = newSupervisorState(result)
	}
	return
}

// GetPID returns the Supervisor process PID.
func (client Client) GetPID() (pid int64, err error) {
	err = client.RpcClient.Call("supervisor.getPID", nil, &pid)
	return
}

// ClearLog clears the Supervisor process log.
func (client Client) ClearLog() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearLog", nil, &result)
	return
}

// Shutdown shuts down the Supervisor process.
func (client Client) Shutdown() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.shutdown", nil, &result)
	return
}

// Restart restarts the Supervisor process.
func (client Client) Restart() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.restart", nil, &result)
	return
}

// GetProcessInfo retrieves information for a particular Supervisor process.
func (client Client) GetProcessInfo(name string) (info *ProcessInfo, err error) {
	result := xmlrpc.Struct{}
	if err = client.RpcClient.Call("supervisor.getProcessInfo", name, &result); err == nil {
		info = newProcessInfo(result)
	}
	return
}

// GetAllProcessInfo retrieves information for all Supervisor processes.
func (client Client) GetAllProcessInfo() (info []*ProcessInfo, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.getAllProcessInfo", nil, &results); err == nil {
		info = make([]*ProcessInfo, len(results))
		for i, result := range results {
			info[i] = newProcessInfo(result.(xmlrpc.Struct))
		}
	}
	return
}

// StartProcess tells Supervisor to start the named process.
func (client Client) StartProcess(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.startProcess", params, &result)
	return
}

// StopProcess tells Supervisor to stop the named process.
func (client Client) StopProcess(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.stopProcess", params, &result)
	return
}

// StartAllProcesses tells Supervisor to start all stopped processes.
func (client Client) StartAllProcesses(wait bool) (info []*ProcessStatus, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.startAllProcesses", wait, &results); err == nil {
		info = make([]*ProcessStatus, len(results))
		for i, result := range results {
			info[i] = newProcessStatus(result.(xmlrpc.Struct))
		}
	}
	return
}

// StopAllProcesses teslls Supervisor to stop all running processes.
func (client Client) StopAllProcesses(wait bool) (info []*ProcessStatus, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.stopAllProcesses", wait, &results); err == nil {
		info = make([]*ProcessStatus, len(results))
		for i, result := range results {
			info[i] = newProcessStatus(result.(xmlrpc.Struct))
		}
	}
	return
}

// StartProcessGroup tells Supervisor to start all stopped processes in the named group.
func (client Client) StartProcessGroup(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.startProcessGroup", params, &result)
	return
}

// StopProcessGroup tells Supervisor to start all stopped processes in the named group.
func (client Client) StopProcessGroup(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.stopProcessGroup", params, &result)
	return
}

// SendProcessStdin send data to the stdin of a running process.
func (client Client) SendProcessStdin(name string, chars string) (result bool, err error) {
	params := makeParams(name, chars)
	err = client.RpcClient.Call("supervisor.sendProcessStdin", params, &result)
	return
}

// SendRemoteCommEvent sends an event to Supervisor processes listening to RemoveCommunicationEvents..
func (client Client) SendRemoteCommEvent(typeKey string, data string) (result bool, err error) {
	params := makeParams(typeKey, data)
	err = client.RpcClient.Call("supervisor.sendRemoteCommEvent", params, &result)
	return
}

// AddProcessGroup adds a configured process group to Supervisor.
func (client Client) AddProcessGroup(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.addProcessGroup", name, &result)
	return
}

// RemoveProcessGroup removes a configured process group from Supervisor.
func (client Client) RemoveProcessGroup(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.removeProcessGroup", name, &result)
	return
}

// ReadLog reads the Supervisor process log.
func (client Client) ReadLog(offset int64, length int64) (log string, err error) {
	params := makeParams(offset, length)
	err = client.RpcClient.Call("supervisor.readLog", params, &log)
	return
}

// ReadProcessStdoutLog reads the stdout log for the named process.
func (client Client) ReadProcessStdoutLog(name string, offset int64, length int64) (log string, err error) {
	params := makeParams(name, offset, length)
	err = client.RpcClient.Call("supervisor.readProcessStdoutLog", params, &log)
	return
}

// ReadProcessStderrLog reads the stderr log for the named process.
func (client Client) ReadProcessStderrLog(name string, offset int64, length int64) (log string, err error) {
	params := makeParams(name, offset, length)
	err = client.RpcClient.Call("supervisor.readProcessStderrLog", params, &log)
	return
}

// TailProcessStdoutLog reads the stdout log for the named process.
func (client Client) TailProcessStdoutLog(name string, offset int64, length int64) (tail *ProcessTail, err error) {
	params := makeParams(name, offset, length)
	result := make([]interface{}, 0, 3)
	if err = client.RpcClient.Call("supervisor.tailProcessStdoutLog", params, &result); err == nil {
		tail = newProcessTail(result)
	}
	return
}

// TailProcessStderrLog reads the stderr log for the named process.
func (client Client) TailProcessStderrLog(name string, offset int64, length int64) (tail *ProcessTail, err error) {
	params := makeParams(name, offset, length)
	result := make([]interface{}, 0, 3)
	if err = client.RpcClient.Call("supervisor.tailProcessStderrLog", params, &result); err == nil {
		tail = newProcessTail(result)
	}
	return
}

// ClearProcessLogs clears all logs for the named process.
func (client Client) ClearProcessLogs(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearProcessLogs", name, &result)
	return
}

// ClearAllProcessLogs clears all logs all processes.
func (client Client) ClearAllProcessLogs(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearAllProcessLogs", name, &result)
	return
}
<commit_msg>Have NewClient Return Client instead of *Client.<commit_after>package supervisor

import (
	"errors"
	"fmt"
	"github.com/kolo/xmlrpc"
)

const (
	apiVersion string = "3.0"
)

func makeParams(params ...interface{}) xmlrpc.Params {
	return xmlrpc.Params{params}
}

type SupervisorState struct {
	StateCode int64
	StateName string
}

func newSupervisorState(result xmlrpc.Struct) *SupervisorState {
	state := new(SupervisorState)
	state.StateCode = result["statecode"].(int64)
	state.StateName = result["statename"].(string)
	return state
}

func (state SupervisorState) String() string {
	return fmt.Sprintf(`SupervisorState{%d, "%s"}`, state.StateCode, state.StateName)
}

type ProcessInfo struct {
	Name          string
	Description   string
	Group         string
	Start         int64
	Stop          int64
	Now           int64
	State         int64
	StateName     string
	SpawnErr      string
	ExitStatus    int64
	Logfile       string
	StdoutLogfile string
	StderrLogfile string
	PID           int64
}

func newProcessInfo(result xmlrpc.Struct) *ProcessInfo {
	info := new(ProcessInfo)
	info.Name = result["name"].(string)
	info.Description = result["description"].(string)
	info.Group = result["group"].(string)
	info.Start = result["start"].(int64)
	info.Stop = result["stop"].(int64)
	info.Now = result["now"].(int64)
	info.State = result["state"].(int64)
	info.StateName = result["statename"].(string)
	info.SpawnErr = result["spawnerr"].(string)
	info.ExitStatus = result["exitstatus"].(int64)
	info.Logfile = result["logfile"].(string)
	info.StdoutLogfile = result["stdout_logfile"].(string)
	info.StderrLogfile = result["stderr_logfile"].(string)
	info.PID = result["pid"].(int64)
	return info
}

func (info ProcessInfo) String() string {
	return fmt.Sprintf(`ProcessInfo{"%s", %d, "%s"}`, info.Name, info.PID, info.StateName)
}

type ProcessStatus struct {
	Name        string
	Description string
	Group       string
	Status      int64
}

func newProcessStatus(result xmlrpc.Struct) *ProcessStatus {
	status := new(ProcessStatus)
	status.Name = result["name"].(string)
	status.Description = result["description"].(string)
	status.Group = result["group"].(string)
	status.Status = result["status"].(int64)
	return status
}

func (status ProcessStatus) String() string {
	return fmt.Sprintf(`ProcessStatus("%s", %d)`, status.Name, status.Status)
}

type ProcessTail struct {
	Log      string
	Offset   int64
	Overflow bool
}

func newProcessTail(result []interface{}) *ProcessTail {
	tail := new(ProcessTail)
	tail.Log = result[0].(string)
	tail.Offset = result[1].(int64)
	tail.Overflow = result[2].(bool)
	return tail
}

func (tail ProcessTail) String() string {
	return tail.Log
}

type Client struct {
	RpcClient  *xmlrpc.Client
	ApiVersion string
}

// NewClient creates a new supervisor RPC client.
func NewClient(url string) (client Client, err error) {
	var rpc *xmlrpc.Client
	if rpc, err = xmlrpc.NewClient(url, nil); err != nil {
		return
	}

	version := ""
	if err = rpc.Call("supervisor.getAPIVersion", nil, &version); err != nil {
		return
	}
	if version != apiVersion {
		err = errors.New(fmt.Sprintf("want Supervisor API version %s, got %s instead", apiVersion, version))
		return
	}
	client = Client{rpc, version}
	return
}

// Close the client.
func (client Client) Close() error {
	return client.RpcClient.Close()
}

// GetSupervisorVersion returns the Supervisor version we connect to.
func (client Client) GetSupervisorVersion() (version string, err error) {
	err = client.RpcClient.Call("supervisor.getSupervisorVersion", nil, &version)
	return
}

// GetIdentification returns the Supervisor ID string.
func (client Client) GetIdentification() (id string, err error) {
	err = client.RpcClient.Call("supervisor.getIdentification", nil, &id)
	return
}

// GetState returns the Supervisor process state.
func (client Client) GetState() (state *SupervisorState, err error) {
	result := xmlrpc.Struct{}
	if err = client.RpcClient.Call("supervisor.getState", nil, &result); err == nil {
		state = newSupervisorState(result)
	}
	return
}

// GetPID returns the Supervisor process PID.
func (client Client) GetPID() (pid int64, err error) {
	err = client.RpcClient.Call("supervisor.getPID", nil, &pid)
	return
}

// ClearLog clears the Supervisor process log.
func (client Client) ClearLog() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearLog", nil, &result)
	return
}

// Shutdown shuts down the Supervisor process.
func (client Client) Shutdown() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.shutdown", nil, &result)
	return
}

// Restart restarts the Supervisor process.
func (client Client) Restart() (result bool, err error) {
	err = client.RpcClient.Call("supervisor.restart", nil, &result)
	return
}

// GetProcessInfo retrieves information for a particular Supervisor process.
func (client Client) GetProcessInfo(name string) (info *ProcessInfo, err error) {
	result := xmlrpc.Struct{}
	if err = client.RpcClient.Call("supervisor.getProcessInfo", name, &result); err == nil {
		info = newProcessInfo(result)
	}
	return
}

// GetAllProcessInfo retrieves information for all Supervisor processes.
func (client Client) GetAllProcessInfo() (info []*ProcessInfo, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.getAllProcessInfo", nil, &results); err == nil {
		info = make([]*ProcessInfo, len(results))
		for i, result := range results {
			info[i] = newProcessInfo(result.(xmlrpc.Struct))
		}
	}
	return
}

// StartProcess tells Supervisor to start the named process.
func (client Client) StartProcess(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.startProcess", params, &result)
	return
}

// StopProcess tells Supervisor to stop the named process.
func (client Client) StopProcess(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.stopProcess", params, &result)
	return
}

// StartAllProcesses tells Supervisor to start all stopped processes.
func (client Client) StartAllProcesses(wait bool) (info []*ProcessStatus, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.startAllProcesses", wait, &results); err == nil {
		info = make([]*ProcessStatus, len(results))
		for i, result := range results {
			info[i] = newProcessStatus(result.(xmlrpc.Struct))
		}
	}
	return
}

// StopAllProcesses teslls Supervisor to stop all running processes.
func (client Client) StopAllProcesses(wait bool) (info []*ProcessStatus, err error) {
	var results []interface{}
	if err = client.RpcClient.Call("supervisor.stopAllProcesses", wait, &results); err == nil {
		info = make([]*ProcessStatus, len(results))
		for i, result := range results {
			info[i] = newProcessStatus(result.(xmlrpc.Struct))
		}
	}
	return
}

// StartProcessGroup tells Supervisor to start all stopped processes in the named group.
func (client Client) StartProcessGroup(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.startProcessGroup", params, &result)
	return
}

// StopProcessGroup tells Supervisor to start all stopped processes in the named group.
func (client Client) StopProcessGroup(name string, wait bool) (result bool, err error) {
	params := makeParams(name, wait)
	err = client.RpcClient.Call("supervisor.stopProcessGroup", params, &result)
	return
}

// SendProcessStdin send data to the stdin of a running process.
func (client Client) SendProcessStdin(name string, chars string) (result bool, err error) {
	params := makeParams(name, chars)
	err = client.RpcClient.Call("supervisor.sendProcessStdin", params, &result)
	return
}

// SendRemoteCommEvent sends an event to Supervisor processes listening to RemoveCommunicationEvents..
func (client Client) SendRemoteCommEvent(typeKey string, data string) (result bool, err error) {
	params := makeParams(typeKey, data)
	err = client.RpcClient.Call("supervisor.sendRemoteCommEvent", params, &result)
	return
}

// AddProcessGroup adds a configured process group to Supervisor.
func (client Client) AddProcessGroup(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.addProcessGroup", name, &result)
	return
}

// RemoveProcessGroup removes a configured process group from Supervisor.
func (client Client) RemoveProcessGroup(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.removeProcessGroup", name, &result)
	return
}

// ReadLog reads the Supervisor process log.
func (client Client) ReadLog(offset int64, length int64) (log string, err error) {
	params := makeParams(offset, length)
	err = client.RpcClient.Call("supervisor.readLog", params, &log)
	return
}

// ReadProcessStdoutLog reads the stdout log for the named process.
func (client Client) ReadProcessStdoutLog(name string, offset int64, length int64) (log string, err error) {
	params := makeParams(name, offset, length)
	err = client.RpcClient.Call("supervisor.readProcessStdoutLog", params, &log)
	return
}

// ReadProcessStderrLog reads the stderr log for the named process.
func (client Client) ReadProcessStderrLog(name string, offset int64, length int64) (log string, err error) {
	params := makeParams(name, offset, length)
	err = client.RpcClient.Call("supervisor.readProcessStderrLog", params, &log)
	return
}

// TailProcessStdoutLog reads the stdout log for the named process.
func (client Client) TailProcessStdoutLog(name string, offset int64, length int64) (tail *ProcessTail, err error) {
	params := makeParams(name, offset, length)
	result := make([]interface{}, 0, 3)
	if err = client.RpcClient.Call("supervisor.tailProcessStdoutLog", params, &result); err == nil {
		tail = newProcessTail(result)
	}
	return
}

// TailProcessStderrLog reads the stderr log for the named process.
func (client Client) TailProcessStderrLog(name string, offset int64, length int64) (tail *ProcessTail, err error) {
	params := makeParams(name, offset, length)
	result := make([]interface{}, 0, 3)
	if err = client.RpcClient.Call("supervisor.tailProcessStderrLog", params, &result); err == nil {
		tail = newProcessTail(result)
	}
	return
}

// ClearProcessLogs clears all logs for the named process.
func (client Client) ClearProcessLogs(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearProcessLogs", name, &result)
	return
}

// ClearAllProcessLogs clears all logs all processes.
func (client Client) ClearAllProcessLogs(name string) (result bool, err error) {
	err = client.RpcClient.Call("supervisor.clearAllProcessLogs", name, &result)
	return
}
<|endoftext|>