<commit_before>package gexec

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"sync"
)

var (
	mu     sync.Mutex
	tmpDir string
)

/*
Build uses go build to compile the package at packagePath.  The resulting binary is saved off in a temporary directory.
A path pointing to this binary is returned.

Build uses the $GOPATH set in your environment.  It passes the variadic args on to `go build`.
*/
func Build(packagePath string, args ...string) (compiledPath string, err error) {
	return doBuild(os.Getenv("GOPATH"), packagePath, nil, args...)
}

/*
BuildWithEnvironment is identical to Build but allows you to specify env vars to be set at build time.
*/
func BuildWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {
	return doBuild(os.Getenv("GOPATH"), packagePath, env, args...)
}

/*
BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).
*/
func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {
	return doBuild(gopath, packagePath, nil, args...)
}

func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) {
	tmpDir, err := temporaryDirectory()
	if err != nil {
		return "", err
	}

	if len(gopath) == 0 {
		return "", errors.New("$GOPATH not provided when building " + packagePath)
	}

	executable := filepath.Join(tmpDir, path.Base(packagePath))
	if runtime.GOOS == "windows" {
		executable = executable + ".exe"
	}

	cmdArgs := append([]string{"build"}, args...)
	cmdArgs = append(cmdArgs, "-o", executable, packagePath)

	build := exec.Command("go", cmdArgs...)
	build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	build.Env = append(build.Env, env...)

	output, err := build.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))
	}

	return executable, nil
}

/*
You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by
gexec. In Ginkgo this is typically done in an AfterSuite callback.
*/
func CleanupBuildArtifacts() {
	mu.Lock()
	defer mu.Unlock()
	if tmpDir != "" {
		os.RemoveAll(tmpDir)
		tmpDir = ""
	}
}

func temporaryDirectory() (string, error) {
	var err error
	mu.Lock()
	defer mu.Unlock()
	if tmpDir == "" {
		tmpDir, err = ioutil.TempDir("", "gexec_artifacts")
		if err != nil {
			return "", err
		}
	}

	return ioutil.TempDir(tmpDir, "g")
}
<commit_msg>Get GOPATH from go internals<commit_after>package gexec

import (
	"errors"
	"fmt"
        "go/build"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"sync"
)

var (
	mu     sync.Mutex
	tmpDir string
)

/*
Build uses go build to compile the package at packagePath.  The resulting binary is saved off in a temporary directory.
A path pointing to this binary is returned.

Build uses the $GOPATH set in your environment.  It passes the variadic args on to `go build`.
*/
func Build(packagePath string, args ...string) (compiledPath string, err error) {
	return doBuild(build.Default.GOPATH, packagePath, nil, args...)
}

/*
BuildWithEnvironment is identical to Build but allows you to specify env vars to be set at build time.
*/
func BuildWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {
	return doBuild(build.Default.GOPATH, packagePath, env, args...)
}

/*
BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).
*/
func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {
	return doBuild(gopath, packagePath, nil, args...)
}

func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) {
	tmpDir, err := temporaryDirectory()
	if err != nil {
		return "", err
	}

	if len(gopath) == 0 {
		return "", errors.New("$GOPATH not provided when building " + packagePath)
	}

	executable := filepath.Join(tmpDir, path.Base(packagePath))
	if runtime.GOOS == "windows" {
		executable = executable + ".exe"
	}

	cmdArgs := append([]string{"build"}, args...)
	cmdArgs = append(cmdArgs, "-o", executable, packagePath)

	build := exec.Command("go", cmdArgs...)
	build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	build.Env = append(build.Env, env...)

	output, err := build.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))
	}

	return executable, nil
}

/*
You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by
gexec. In Ginkgo this is typically done in an AfterSuite callback.
*/
func CleanupBuildArtifacts() {
	mu.Lock()
	defer mu.Unlock()
	if tmpDir != "" {
		os.RemoveAll(tmpDir)
		tmpDir = ""
	}
}

func temporaryDirectory() (string, error) {
	var err error
	mu.Lock()
	defer mu.Unlock()
	if tmpDir == "" {
		tmpDir, err = ioutil.TempDir("", "gexec_artifacts")
		if err != nil {
			return "", err
		}
	}

	return ioutil.TempDir(tmpDir, "g")
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"
	"strings"
	"sync"
	"syscall"
	"time"
    "strconv"
)

const (
	SYNC_PAUSE = 2
	PUSH_PAUSE = 10
)

type GitBackend struct {
	logger  *log.Logger
	gitPath string

	rootDir string

	syncLock      sync.Mutex
	isSyncPending bool

	pushLock      sync.Mutex
	isPushPending bool

	pushHook func()

	isPullActive bool // Is a pull currently running - ignore all events
}

func NewGitBackend(config *Config) *GitBackend {

	rootDir := config.syncDir
	logger := openLog(config, "git.log")

	gitPath, err := exec.LookPath("git")
	if err != nil {
		logger.Fatal("Error looking for 'git' on path. ", err)
	}

	return &GitBackend{
		logger:  logger,
		rootDir: rootDir,
		gitPath: gitPath,
	}
}

// A file or directory has been created
func (self *GitBackend) Changed(filename string) {
	if self.isGit(filename) || self.isPullActive {
		return
	}
	go self.syncLater()
}

// Run: git add --all ; git commit --all
func (self *GitBackend) Sync() error {

	var err *GitError

	// Pull first to ensure a fast-forward when we push
	err = self.pull()
	if err != nil {
		return err
	}

	err = self.git("add", "--all")
	if err != nil {
		return err
	}

    self.displayStatus()

	err = self.git("commit", "--all", "--message=bup")
	if err != nil {
		return err
	}

	go self.pushLater()

	return nil
}

//Display summary of changes
func (self *GitBackend) displayStatus() {

    created, modified, deleted := self.Status()

    var msg string
    if len(created) == 1 {
        msg += "New: " + created[0]
    } else if len(created) > 1 {
        msg += "New: " + strconv.Itoa(len(created))
    }

    if len(modified) == 1 {
        msg += " Edit: " + modified[0]
    } else if len(modified) > 1 {
        msg += " Edit: " + strconv.Itoa(len(modified))
    }

    if len(deleted) == 1 {
        msg += " Del: " + deleted[0]
    } else if len(deleted) > 1 {
        msg += " Del: " + strconv.Itoa(len(deleted))
    }

    if len(msg) != 0 {
        Info(msg)
    }
}

// Register the function to be called after we push to remote
func (self *GitBackend) RegisterPushHook(callback func()) {
	self.pushHook = callback
}

// Should the inotify watch watch the given path
func (self *GitBackend) ShouldWatch(filename string) bool {
	return !self.isGit(filename)
}

// Status of directory. Returns filenames created, modified or deleted.
func (self *GitBackend) Status() (created []string, modified []string, deleted []string) {

	cmd := exec.Command(self.gitPath, "status", "--porcelain")
	cmd.Dir = self.rootDir

	output, err := cmd.CombinedOutput()
    if err != nil {
        self.logger.Println(err)
    }

    for _, line := range strings.Split(string(output), "\n") {
        if len(line) == 0 {
            continue
        }

        lineParts := strings.Split(line, " ")

        status := lineParts[0]
        var filename string
        if len(lineParts) == 2 {
            filename = lineParts[1]
        } else if len(lineParts) == 3 {
            filename = lineParts[2]
        }

        switch status[0] {
            case 'A':
                created = append(created, filename)
            case 'M':
                modified = append(modified, filename)
            case 'R':                         // Renamed, but count as Modified
                modified = append(modified, filename)
            case 'D':
                deleted = append(deleted, filename)
            case '?':
                self.logger.Println("Unknown. Need git add", filename)
            default:
                self.logger.Println("Other", status)
        }
    }

    return created, modified, deleted
}

// Is filename inside a .git directory?
func (self *GitBackend) isGit(filename string) bool {
	return strings.Contains(filename, ".git")
}

// Schedule a synchronise for in a few seconds
func (self *GitBackend) syncLater() {

	// ensure only once per time - might be able to use sync.Once instead (?)
	self.syncLock.Lock()
	if self.isSyncPending {
		self.syncLock.Unlock()
		return
	}
	self.isSyncPending = true
	self.syncLock.Unlock()

	time.Sleep(SYNC_PAUSE * time.Second)
	self.Sync()

	self.isSyncPending = false
}

// Schedule a push for later
func (self *GitBackend) pushLater() {

	// ensure only once per time - might be able to use sync.Once instead (?)
	self.pushLock.Lock()
	if self.isPushPending {
		self.pushLock.Unlock()
		return
	}
	self.isPushPending = true
	self.pushLock.Unlock()

	time.Sleep(PUSH_PAUSE * time.Second)
	err := self.push()
	if err != nil {
		Warn(err.Error())
	}

	self.isPushPending = false
}

// Run: git push
func (self *GitBackend) push() *GitError {
	err := self.git("push", "origin", "master")
	if err == nil && self.pushHook != nil {
		go self.pushHook()
	}
	return err
}

// Run: git pull
func (self *GitBackend) pull() *GitError {
	self.isPullActive = true
	err := self.git("pull", "origin", "master")
	self.isPullActive = false
	return err
}

/* Runs a git command, returns nil if success, error if err
   Errors are not always bad. For example a "commit" that
   didn't have to do anything returns an error.
*/
func (self *GitBackend) git(gitCmd string, args ...string) *GitError {

	cmd := exec.Command(self.gitPath, append([]string{gitCmd}, args...)...)
	cmd.Dir = self.rootDir
	self.logger.Println(cmd)

	output, err := cmd.CombinedOutput()
	self.logger.Println(string(output))

	if err == nil {
        return nil
    }

    exitStatus := err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus()
    gitErr := &GitError{
        cmd: strings.Join(cmd.Args, " "),
        internalError: err,
        output: string(output),
        status: exitStatus}
    if exitStatus != 1 {            // 1 means command had nothing to do
        self.logger.Println(err)
    }
    return gitErr
}

type GitError struct {
	cmd           string
	internalError error
	output        string
    status        int
}

// error implementation which displays git info
func (self *GitError) Error() string {
    msg := "git error running: " + self.cmd + "\n\n"
    msg += self.output + "\n"
	msg += self.internalError.Error()
    return msg
}
<commit_msg>Reverted the 'origin master' thing. I knew there was a reason not to do that.<commit_after>package main

import (
	"log"
	"os/exec"
	"strings"
	"sync"
	"syscall"
	"time"
    "strconv"
)

const (
	SYNC_PAUSE = 2
	PUSH_PAUSE = 10
)

type GitBackend struct {
	logger  *log.Logger
	gitPath string

	rootDir string

	syncLock      sync.Mutex
	isSyncPending bool

	pushLock      sync.Mutex
	isPushPending bool

	pushHook func()

	isPullActive bool // Is a pull currently running - ignore all events
}

func NewGitBackend(config *Config) *GitBackend {

	rootDir := config.syncDir
	logger := openLog(config, "git.log")

	gitPath, err := exec.LookPath("git")
	if err != nil {
		logger.Fatal("Error looking for 'git' on path. ", err)
	}

	return &GitBackend{
		logger:  logger,
		rootDir: rootDir,
		gitPath: gitPath,
	}
}

// A file or directory has been created
func (self *GitBackend) Changed(filename string) {
	if self.isGit(filename) || self.isPullActive {
		return
	}
	go self.syncLater()
}

// Run: git add --all ; git commit --all
func (self *GitBackend) Sync() error {

	var err *GitError

	// Pull first to ensure a fast-forward when we push
	err = self.pull()
	if err != nil {
		return err
	}

	err = self.git("add", "--all")
	if err != nil {
		return err
	}

    self.displayStatus()

	err = self.git("commit", "--all", "--message=bup")
	if err != nil {
		return err
	}

	go self.pushLater()

	return nil
}

//Display summary of changes
func (self *GitBackend) displayStatus() {

    created, modified, deleted := self.Status()

    var msg string
    if len(created) == 1 {
        msg += "New: " + created[0]
    } else if len(created) > 1 {
        msg += "New: " + strconv.Itoa(len(created))
    }

    if len(modified) == 1 {
        msg += " Edit: " + modified[0]
    } else if len(modified) > 1 {
        msg += " Edit: " + strconv.Itoa(len(modified))
    }

    if len(deleted) == 1 {
        msg += " Del: " + deleted[0]
    } else if len(deleted) > 1 {
        msg += " Del: " + strconv.Itoa(len(deleted))
    }

    if len(msg) != 0 {
        Info(msg)
    }
}

// Register the function to be called after we push to remote
func (self *GitBackend) RegisterPushHook(callback func()) {
	self.pushHook = callback
}

// Should the inotify watch watch the given path
func (self *GitBackend) ShouldWatch(filename string) bool {
	return !self.isGit(filename)
}

// Status of directory. Returns filenames created, modified or deleted.
func (self *GitBackend) Status() (created []string, modified []string, deleted []string) {

	cmd := exec.Command(self.gitPath, "status", "--porcelain")
	cmd.Dir = self.rootDir

	output, err := cmd.CombinedOutput()
    if err != nil {
        self.logger.Println(err)
    }

    for _, line := range strings.Split(string(output), "\n") {
        if len(line) == 0 {
            continue
        }

        lineParts := strings.Split(line, " ")

        status := lineParts[0]
        var filename string
        if len(lineParts) == 2 {
            filename = lineParts[1]
        } else if len(lineParts) == 3 {
            filename = lineParts[2]
        }

        switch status[0] {
            case 'A':
                created = append(created, filename)
            case 'M':
                modified = append(modified, filename)
            case 'R':                         // Renamed, but count as Modified
                modified = append(modified, filename)
            case 'D':
                deleted = append(deleted, filename)
            case '?':
                self.logger.Println("Unknown. Need git add", filename)
            default:
                self.logger.Println("Other", status)
        }
    }

    return created, modified, deleted
}

// Is filename inside a .git directory?
func (self *GitBackend) isGit(filename string) bool {
	return strings.Contains(filename, ".git")
}

// Schedule a synchronise for in a few seconds
func (self *GitBackend) syncLater() {

	// ensure only once per time - might be able to use sync.Once instead (?)
	self.syncLock.Lock()
	if self.isSyncPending {
		self.syncLock.Unlock()
		return
	}
	self.isSyncPending = true
	self.syncLock.Unlock()

	time.Sleep(SYNC_PAUSE * time.Second)
	self.Sync()

	self.isSyncPending = false
}

// Schedule a push for later
func (self *GitBackend) pushLater() {

	// ensure only once per time - might be able to use sync.Once instead (?)
	self.pushLock.Lock()
	if self.isPushPending {
		self.pushLock.Unlock()
		return
	}
	self.isPushPending = true
	self.pushLock.Unlock()

	time.Sleep(PUSH_PAUSE * time.Second)
	err := self.push()
	if err != nil {
		Warn(err.Error())
	}

	self.isPushPending = false
}

// Run: git push
func (self *GitBackend) push() *GitError {
	err := self.git("push")
	if err == nil && self.pushHook != nil {
		go self.pushHook()
	}
	return err
}

// Run: git pull
func (self *GitBackend) pull() *GitError {
	self.isPullActive = true
	err := self.git("pull")
	self.isPullActive = false
	return err
}

/* Runs a git command, returns nil if success, error if err
   Errors are not always bad. For example a "commit" that
   didn't have to do anything returns an error.
*/
func (self *GitBackend) git(gitCmd string, args ...string) *GitError {

	cmd := exec.Command(self.gitPath, append([]string{gitCmd}, args...)...)
	cmd.Dir = self.rootDir
	self.logger.Println(cmd)

	output, err := cmd.CombinedOutput()
	self.logger.Println(string(output))

	if err == nil {
        return nil
    }

    exitStatus := err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus()
    gitErr := &GitError{
        cmd: strings.Join(cmd.Args, " "),
        internalError: err,
        output: string(output),
        status: exitStatus}
    if exitStatus != 1 {            // 1 means command had nothing to do
        self.logger.Println(err)
    }
    return gitErr
}

type GitError struct {
	cmd           string
	internalError error
	output        string
    status        int
}

// error implementation which displays git info
func (self *GitError) Error() string {
    msg := "git error running: " + self.cmd + "\n\n"
    msg += self.output + "\n"
	msg += self.internalError.Error()
    return msg
}
<|endoftext|>


<commit_before>package pshdlWavSim

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"

	"github.com/cryptix/wav"
)

type WavSim struct {
	cmd *exec.Cmd

	input  *wav.WavReader
	output *wav.WavWriter

	stdin  io.WriteCloser
	stdout io.ReadCloser
	stderr io.ReadCloser

	samplesTotal uint32

	bytesWritten, bytesRead int64
	writtenSamplesPtr       *int32

	doneWrite chan error
	doneRead  chan error

	iFile, oFile *os.File
}

func NewWavSimFromFile(binPath string, scaler int, coeffs []int, inputFname, outputFname string) (w *WavSim, err error) {
	// open input file
	inputFile, err := os.Open(inputFname)
	if err != nil {
		return nil, err
	}

	// get stat for file Size
	inputStat, err := inputFile.Stat()
	if err != nil {
		return nil, err
	}

	// create wav.Reader
	input, err := wav.NewWavReader(inputFile, inputStat.Size())
	if err != nil {
		return nil, err
	}

	// create output file
	outputFile, err := os.Create(outputFname)
	if err != nil {
		return nil, err
	}

	// get meta information from input
	meta := input.GetWavFile()

	// create output with the same characteristics
	output, err := meta.NewWriter(outputFile)
	if err != nil {
		return nil, err
	}

	// create a WavSim based in these files
	sim, err := NewWavSim(binPath, scaler, coeffs, input, output)
	if err != nil {
		return nil, err
	}

	// store file handles for closing after sim
	sim.iFile = inputFile
	sim.oFile = outputFile

	return sim, nil
}

func NewWavSim(binPath string, scaler int, coeffs []int, input *wav.WavReader, output *wav.WavWriter) (w *WavSim, err error) {
	w = &WavSim{
		input:  input,
		output: output,

		doneWrite: make(chan error),
		doneRead:  make(chan error),
	}

	w.samplesTotal = input.GetSampleCount()

	// construct arguments
	args := make([]string, len(coeffs)+2)
	args[0] = strconv.Itoa(int(w.samplesTotal))
	args[1] = strconv.Itoa(scaler)
	for i, c := range coeffs {
		args[i+2] = strconv.Itoa(c)
	}
	w.cmd = exec.Command(binPath, args...)

	w.stdin, err = w.cmd.StdinPipe()
	if err != nil {
		return nil, err
	}

	w.stdout, err = w.cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	w.stderr, err = w.cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	go w.stderrLog()

	return w, nil
}

// starts executing the Simulation
func (w WavSim) Run() (err error) {
	err = w.cmd.Start()
	if err != nil {
		return err
	}

	go w.readPump()
	go w.writePump()

	err = <-w.doneWrite
	if err != nil {
		return err
	}

	err = <-w.doneRead
	if err != nil {
		return err
	}

	err = w.cmd.Wait()
	if err != nil {
		return err
	}

	if w.bytesRead != w.bytesWritten {
		return fmt.Errorf("i/o missmatch - r[%d] w[%d]", w.bytesRead, w.bytesWritten)
	}

	*w.writtenSamplesPtr = int32(w.samplesTotal)
	err = w.output.CloseFile()
	if err != nil {
		return err
	}

	if w.iFile != nil {
		w.iFile.Close()
	}

	if w.oFile != nil {
		w.oFile.Close()
	}

	return nil
}

// writePump pumps samples to wavWriter from sim's stdout
func (w *WavSim) writePump() {
	var (
		err       error
		wavWriter io.Writer
	)
	wavWriter, w.writtenSamplesPtr, err = w.output.GetDumbWriter()
	if err != nil {
		w.doneRead <- err
	}

	w.bytesRead, err = io.Copy(wavWriter, w.stdout)
	if err != nil {
		w.doneRead <- err
	}

	w.doneRead <- nil
}

// readPump pumps samples to sim's stdin
func (w *WavSim) readPump() {
	in, err := w.input.GetDumbReader()
	if err != nil {
		w.doneWrite <- err
		return
	}

	w.bytesWritten, err = io.Copy(w.stdin, in)
	if err != nil {
		w.doneWrite <- err
		return
	}

	err = w.stdin.Close()
	if err != nil {
		w.doneWrite <- err
		return
	}

	w.doneWrite <- nil
}

func (w WavSim) stderrLog() {
	buffedErr := bufio.NewReader(w.stderr)

errLoop:
	for {
		line, err := buffedErr.ReadString('\n')
		switch {
		case err == nil:
			fmt.Print(line)
		case err == io.EOF:
			break errLoop
		default:
			panic(err)
		}
	}

}
<commit_msg>can't read from stderr before we start the process<commit_after>package pshdlWavSim

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"

	"github.com/cryptix/wav"
)

type WavSim struct {
	cmd *exec.Cmd

	input  *wav.WavReader
	output *wav.WavWriter

	stdin  io.WriteCloser
	stdout io.ReadCloser
	stderr io.ReadCloser

	samplesTotal uint32

	bytesWritten, bytesRead int64
	writtenSamplesPtr       *int32

	doneWrite chan error
	doneRead  chan error

	iFile, oFile *os.File
}

func NewWavSimFromFile(binPath string, scaler int, coeffs []int, inputFname, outputFname string) (w *WavSim, err error) {
	// open input file
	inputFile, err := os.Open(inputFname)
	if err != nil {
		return nil, err
	}

	// get stat for file Size
	inputStat, err := inputFile.Stat()
	if err != nil {
		return nil, err
	}

	// create wav.Reader
	input, err := wav.NewWavReader(inputFile, inputStat.Size())
	if err != nil {
		return nil, err
	}

	// create output file
	outputFile, err := os.Create(outputFname)
	if err != nil {
		return nil, err
	}

	// get meta information from input
	meta := input.GetWavFile()

	// create output with the same characteristics
	output, err := meta.NewWriter(outputFile)
	if err != nil {
		return nil, err
	}

	// create a WavSim based in these files
	sim, err := NewWavSim(binPath, scaler, coeffs, input, output)
	if err != nil {
		return nil, err
	}

	// store file handles for closing after sim
	sim.iFile = inputFile
	sim.oFile = outputFile

	return sim, nil
}

func NewWavSim(binPath string, scaler int, coeffs []int, input *wav.WavReader, output *wav.WavWriter) (w *WavSim, err error) {
	w = &WavSim{
		input:  input,
		output: output,

		doneWrite: make(chan error),
		doneRead:  make(chan error),
	}

	w.samplesTotal = input.GetSampleCount()

	// construct arguments
	args := make([]string, len(coeffs)+2)
	args[0] = strconv.Itoa(int(w.samplesTotal))
	args[1] = strconv.Itoa(scaler)
	for i, c := range coeffs {
		args[i+2] = strconv.Itoa(c)
	}
	w.cmd = exec.Command(binPath, args...)

	w.stdin, err = w.cmd.StdinPipe()
	if err != nil {
		return nil, err
	}

	w.stdout, err = w.cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	w.stderr, err = w.cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	return w, nil
}

// starts executing the Simulation
func (w WavSim) Run() (err error) {
	err = w.cmd.Start()
	if err != nil {
		return err
	}

	go w.stderrLog()

	go w.readPump()
	go w.writePump()

	err = <-w.doneWrite
	if err != nil {
		return err
	}

	err = <-w.doneRead
	if err != nil {
		return err
	}

	err = w.cmd.Wait()
	if err != nil {
		return err
	}

	if w.bytesRead != w.bytesWritten {
		return fmt.Errorf("i/o missmatch - r[%d] w[%d]", w.bytesRead, w.bytesWritten)
	}

	*w.writtenSamplesPtr = int32(w.samplesTotal)
	err = w.output.CloseFile()
	if err != nil {
		return err
	}

	if w.iFile != nil {
		w.iFile.Close()
	}

	if w.oFile != nil {
		w.oFile.Close()
	}

	return nil
}

// writePump pumps samples to wavWriter from sim's stdout
func (w *WavSim) writePump() {
	var (
		err       error
		wavWriter io.Writer
	)
	wavWriter, w.writtenSamplesPtr, err = w.output.GetDumbWriter()
	if err != nil {
		w.doneRead <- err
	}

	w.bytesRead, err = io.Copy(wavWriter, w.stdout)
	if err != nil {
		w.doneRead <- err
	}

	w.doneRead <- nil
}

// readPump pumps samples to sim's stdin
func (w *WavSim) readPump() {
	in, err := w.input.GetDumbReader()
	if err != nil {
		w.doneWrite <- err
		return
	}

	w.bytesWritten, err = io.Copy(w.stdin, in)
	if err != nil {
		w.doneWrite <- err
		return
	}

	err = w.stdin.Close()
	if err != nil {
		w.doneWrite <- err
		return
	}

	w.doneWrite <- nil
}

func (w WavSim) stderrLog() {
	buffedErr := bufio.NewReader(w.stderr)

errLoop:
	for {
		line, err := buffedErr.ReadString('\n')
		switch {
		case err == nil:
			fmt.Print(line)
		case err == io.EOF:
			break errLoop
		default:
			panic(err)
		}
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package orm

import (
	"bytes"
	"database/sql"
	"errors"
	"strings"

	"github.com/issue9/orm/fetch"
)

const (
	and = iota
	or
)

const (
	asc = iota
	desc
)

var (
	ErrEmptyTableName = errors.New("未指定表名")
)

// 以函数链的方式产生SQL语句。
type SQL struct {
	e        engine
	table    string
	cond     *bytes.Buffer
	condArgs []interface{}
	order    *bytes.Buffer
	limit    []int // 元素0为limit，元素1为offset
}

func newSQL(engine engine) *SQL {
	return &SQL{
		e:        engine,
		cond:     new(bytes.Buffer),
		condArgs: []interface{}{},
		order:    new(bytes.Buffer),
		limit:    make([]int, 0, 2), // 最长2个，同时保存limit和offset
	}
}

func (s *SQL) Reset() *SQL {
	s.table = ""
	s.cond.Reset()
	s.condArgs = s.condArgs[:0]
	s.order.Reset()
	s.limit = s.limit[:0]

	return s
}

// 指定Limit相关的值。
func (s *SQL) Limit(limit int, offset ...int) *SQL {
	if len(offset) > 1 {
		panic("offset参数指定了太多的值")
	}

	s.limit = append(s.limit, limit)

	if len(offset) > 0 {
		s.limit = append(s.limit, offset[0])
	}

	return s
}

func (s *SQL) where(op int, cond string, args ...interface{}) *SQL {
	switch {
	case s.cond.Len() == 0:
		s.cond.WriteString(" WHERE(")
	case op == and:
		s.cond.WriteString(" AND(")
	case op == or:
		s.cond.WriteString(" OR(")
	default:
		panic("where:错误的参数op")
	}
	s.cond.WriteString(cond)
	s.cond.WriteByte(')')
	s.condArgs = append(s.condArgs, args...)

	return s
}

// 将之后的语句以and的形式与当前的语句进行连接
func (s *SQL) And(cond string, args ...interface{}) *SQL {
	return s.where(and, cond, args...)
}

// 将之后的语句以or的形式与当前的语句进行连接
func (s *SQL) Or(cond string, args ...interface{}) *SQL {
	return s.where(or, cond, args...)
}

// order by ... asc
// 当cols参数为空时，不产生任何操作。
func (s *SQL) Asc(cols ...string) *SQL {
	if len(cols) == 0 {
		return s
	}

	for _, col := range cols {
		s.order.WriteString(col)
		s.order.WriteByte(',')
	}
	s.order.Truncate(s.order.Len() - 1)
	s.order.WriteString(" ASC,")
	return s
}

// order by ... desc
// 当cols参数为空时，不产生任何操作。
func (s *SQL) Desc(cols ...string) *SQL {
	if len(cols) == 0 {
		return s
	}

	for _, col := range cols {
		s.order.WriteString(col)
		s.order.WriteByte(',')
	}
	s.order.Truncate(s.order.Len() - 1)
	s.order.WriteString(" DESC,")
	return s
}

// 指定表名。
func (s *SQL) Table(tableName string) *SQL {
	s.table = tableName
	return s
}

// 将符合当前条件的所有记录删除。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Delete(replace bool) (sql.Result, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	sql.Reset()
	sql.WriteString("DELETE FROM ")
	s.e.Dialect().Quote(sql, s.table)
	sql.WriteString(s.cond.String())
	return s.e.Exec(replace, sql.String(), s.condArgs...)
}

func (s *SQL) Insert(replace bool, data map[string]interface{}) (sql.Result, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	if len(data) == 0 {
		return nil, errors.New("SQL.Update:未指定需要更新的数据")
	}

	keys := make([]string, len(data))
	vals := make([]interface{}, len(data))
	for k, v := range data {
		keys = append(keys, k)
		vals = append(vals, v)
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	sql.Reset()
	sql.WriteString("INSERT INTO ")
	s.e.Dialect().Quote(sql, s.table)

	sql.WriteByte('(')
	for _, k := range keys {
		sql.WriteString(k)
		sql.WriteByte(',')
	}
	sql.Truncate(sql.Len() - 1)
	sql.WriteString(")(")
	for range vals {
		sql.WriteString("?,")
	}
	sql.Truncate(sql.Len() - 1)
	sql.WriteByte(')')

	return s.e.Exec(true, sql.String(), vals...)
}

// 更新符合当前条件的所有记录。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Update(replace bool, data map[string]interface{}) (sql.Result, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	if len(data) == 0 {
		return nil, errors.New("SQL.Update:未指定需要更新的数据")
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	sql.Reset()
	sql.WriteString("UPDATE ")
	s.e.Dialect().Quote(sql, s.table)
	vals := make([]interface{}, 0, len(data)+len(s.condArgs))
	sql.WriteString(" SET ")
	for k, v := range data {
		s.e.Dialect().Quote(sql, k)
		sql.WriteString("=?,")
		vals = append(vals, v)
	}
	sql.Truncate(sql.Len() - 1) // 去掉最后一个逗号

	sql.WriteString(s.cond.String())
	return s.e.Exec(replace, sql.String(), append(vals, s.condArgs...)...)
}

// 将符合当前条件的所有记录依次写入objs中。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Select(replace bool, objs interface{}) error {
	rows, err := s.query(replace)
	if err != nil {
		return err
	}
	return fetch.Obj(objs, rows)
}

// 返回符合当前条件的所有记录。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) SelectMap(replace bool, cols ...string) ([]map[string]interface{}, error) {
	rows, err := s.query(replace, cols...)
	if err != nil {
		return nil, err
	}
	return fetch.Map(false, rows)
}

func (s *SQL) query(replace bool, cols ...string) (*sql.Rows, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	args := make([]interface{}, 0, len(s.condArgs)) // Query对应的参数
	sql.Reset()
	sql.WriteString("SELECT ")
	if len(cols) == 0 {
		sql.WriteString(" * ")
	} else {
		sql.WriteString(strings.Join(cols, ","))
	}

	// from
	sql.WriteString(" FROM ")
	s.e.Dialect().Quote(sql, s.table)

	// where
	sql.WriteString(s.cond.String())
	args = append(args, s.condArgs...)

	// order
	if s.order.Len() > 0 {
		sql.WriteString(" ORDER BY ")
		s.order.WriteTo(sql)
		sql.Truncate(sql.Len() - 1)
	}

	// limit
	if len(s.limit) > 0 {
		vals, err := s.e.Dialect().LimitSQL(sql, s.limit[0], s.limit[1:]...)
		if err != nil {
			return nil, err
		}

		args = append(args, vals[0])
		if len(vals) > 1 {
			args = append(args, vals[1])
		}
	}

	return s.e.Query(replace, sql.String(), args...)
}
<commit_msg>删除SQL.Insert()，SQL作为DB的一个补充，没必要作得那么全面。<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package orm

import (
	"bytes"
	"database/sql"
	"errors"
	"strings"

	"github.com/issue9/orm/fetch"
)

const (
	and = iota
	or
)

const (
	asc = iota
	desc
)

var (
	ErrEmptyTableName = errors.New("未指定表名")
)

// 以函数链的方式产生SQL语句。
type SQL struct {
	e        engine
	table    string
	cond     *bytes.Buffer
	condArgs []interface{}
	order    *bytes.Buffer
	limit    []int // 元素0为limit，元素1为offset
}

func newSQL(engine engine) *SQL {
	return &SQL{
		e:        engine,
		cond:     new(bytes.Buffer),
		condArgs: []interface{}{},
		order:    new(bytes.Buffer),
		limit:    make([]int, 0, 2), // 最长2个，同时保存limit和offset
	}
}

func (s *SQL) Reset() *SQL {
	s.table = ""
	s.cond.Reset()
	s.condArgs = s.condArgs[:0]
	s.order.Reset()
	s.limit = s.limit[:0]

	return s
}

// 指定Limit相关的值。
func (s *SQL) Limit(limit int, offset ...int) *SQL {
	if len(offset) > 1 {
		panic("offset参数指定了太多的值")
	}

	s.limit = append(s.limit, limit)

	if len(offset) > 0 {
		s.limit = append(s.limit, offset[0])
	}

	return s
}

func (s *SQL) where(op int, cond string, args ...interface{}) *SQL {
	switch {
	case s.cond.Len() == 0:
		s.cond.WriteString(" WHERE(")
	case op == and:
		s.cond.WriteString(" AND(")
	case op == or:
		s.cond.WriteString(" OR(")
	default:
		panic("where:错误的参数op")
	}
	s.cond.WriteString(cond)
	s.cond.WriteByte(')')
	s.condArgs = append(s.condArgs, args...)

	return s
}

// 将之后的语句以and的形式与当前的语句进行连接
func (s *SQL) And(cond string, args ...interface{}) *SQL {
	return s.where(and, cond, args...)
}

// 将之后的语句以or的形式与当前的语句进行连接
func (s *SQL) Or(cond string, args ...interface{}) *SQL {
	return s.where(or, cond, args...)
}

// order by ... asc
// 当cols参数为空时，不产生任何操作。
func (s *SQL) Asc(cols ...string) *SQL {
	if len(cols) == 0 {
		return s
	}

	for _, col := range cols {
		s.order.WriteString(col)
		s.order.WriteByte(',')
	}
	s.order.Truncate(s.order.Len() - 1)
	s.order.WriteString(" ASC,")
	return s
}

// order by ... desc
// 当cols参数为空时，不产生任何操作。
func (s *SQL) Desc(cols ...string) *SQL {
	if len(cols) == 0 {
		return s
	}

	for _, col := range cols {
		s.order.WriteString(col)
		s.order.WriteByte(',')
	}
	s.order.Truncate(s.order.Len() - 1)
	s.order.WriteString(" DESC,")
	return s
}

// 指定表名。
func (s *SQL) Table(tableName string) *SQL {
	s.table = tableName
	return s
}

// 将符合当前条件的所有记录删除。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Delete(replace bool) (sql.Result, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	sql.Reset()
	sql.WriteString("DELETE FROM ")
	s.e.Dialect().Quote(sql, s.table)
	sql.WriteString(s.cond.String())
	return s.e.Exec(replace, sql.String(), s.condArgs...)
}

// 更新符合当前条件的所有记录。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Update(replace bool, data map[string]interface{}) (sql.Result, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	if len(data) == 0 {
		return nil, errors.New("SQL.Update:未指定需要更新的数据")
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	sql.Reset()
	sql.WriteString("UPDATE ")
	s.e.Dialect().Quote(sql, s.table)
	vals := make([]interface{}, 0, len(data)+len(s.condArgs))
	sql.WriteString(" SET ")
	for k, v := range data {
		s.e.Dialect().Quote(sql, k)
		sql.WriteString("=?,")
		vals = append(vals, v)
	}
	sql.Truncate(sql.Len() - 1) // 去掉最后一个逗号

	sql.WriteString(s.cond.String())
	return s.e.Exec(replace, sql.String(), append(vals, s.condArgs...)...)
}

// 将符合当前条件的所有记录依次写入objs中。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) Select(replace bool, objs interface{}) error {
	rows, err := s.query(replace)
	if err != nil {
		return err
	}
	return fetch.Obj(objs, rows)
}

// 返回符合当前条件的所有记录。
// replace，是否需将对语句的占位符进行替换。
func (s *SQL) SelectMap(replace bool, cols ...string) ([]map[string]interface{}, error) {
	rows, err := s.query(replace, cols...)
	if err != nil {
		return nil, err
	}
	return fetch.Map(false, rows)
}

func (s *SQL) query(replace bool, cols ...string) (*sql.Rows, error) {
	if len(s.table) == 0 {
		return nil, ErrEmptyTableName
	}

	sql := pool.Get().(*bytes.Buffer)
	defer pool.Put(sql)

	args := make([]interface{}, 0, len(s.condArgs)) // Query对应的参数
	sql.Reset()
	sql.WriteString("SELECT ")
	if len(cols) == 0 {
		sql.WriteString(" * ")
	} else {
		sql.WriteString(strings.Join(cols, ","))
	}

	// from
	sql.WriteString(" FROM ")
	s.e.Dialect().Quote(sql, s.table)

	// where
	sql.WriteString(s.cond.String())
	args = append(args, s.condArgs...)

	// order
	if s.order.Len() > 0 {
		sql.WriteString(" ORDER BY ")
		s.order.WriteTo(sql)
		sql.Truncate(sql.Len() - 1)
	}

	// limit
	if len(s.limit) > 0 {
		vals, err := s.e.Dialect().LimitSQL(sql, s.limit[0], s.limit[1:]...)
		if err != nil {
			return nil, err
		}

		args = append(args, vals[0])
		if len(vals) > 1 {
			args = append(args, vals[1])
		}
	}

	return s.e.Query(replace, sql.String(), args...)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"io"
	"io/ioutil"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/disintegration/imaging"
	"github.com/huin/goserial"

	"code.google.com/p/freetype-go/freetype"
)

var fontName string
var debug bool

type packet struct {
	header     string
	coord      string
	dataR      []byte
	dataG      []byte
	terminator string
}

type lcdChar struct {
	c      string
	bitmap [16]uint16
	color  int
}

type lcdString struct {
	c     []lcdChar
	coord int
}

type lcdMatrix struct {
	dataR [3][16]uint32
	dataG [3][16]uint32
}

func createTestPacket() *packet {
	if debug {
		fmt.Println("createTestPacket")
	}
	var p packet
	p.header = "pcmat\r"
	p.coord = "000\r5ff\r"
	s1 := ""
	s2 := ""
	for i := 0; i < 192; i++ {
		s1 += "p"
		s2 += "a"
	}
	s1 += "\r"
	s2 += "\r"
	p.dataR = []byte(s1)
	p.dataG = []byte(s2)
	p.terminator = "end\r"

	return &p
}

func createPacket(str lcdString, shift int) *packet {
	if debug {
		fmt.Println("createPacket")
	}

	data := printLCD(str, shift)
	//str.coord += shift

	var packet packet
	packet.header = "pcmat\r"
	packet.coord = "000\r5ff\r"

	var bufr []byte
	var bufg []byte
	for y := 0; y < 16; y++ {

		for x := 0; x < 3; x++ {
			r := data.dataR[x][y]
			rbyte := (r & 0xff000000) >> 24
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x00ff0000) >> 16
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x0000ff00) >> 8
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x000000ff) >> 0
			bufr = append(bufr, byte(rbyte))

			g := data.dataG[x][y]
			//bing := make([]byte, 4)
			//binary.LittleEndian.PutUint32(bing, g)
			gbyte := (g & 0xff000000) >> 24
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x00ff0000) >> 16
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x0000ff00) >> 8
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x000000ff) >> 0
			bufg = append(bufg, byte(gbyte))
		}

	}
	//packet.dataR = []byte(string(bufr) + "\r")
	//packet.dataG = []byte(string(bufg) + "\r")
	packet.dataR = append(packet.dataR, bufr...)
	packet.dataR = append(packet.dataR, []byte("\r")...)
	packet.dataG = append(packet.dataG, bufg...)
	packet.dataG = append(packet.dataG, []byte("\r")...)

	packet.terminator = "end\r"

	return &packet
}

func getUsbttyList() []string {
	if debug {
		fmt.Println("getUsbttyList")
	}
	contents, _ := ioutil.ReadDir("/dev")
	var ret []string

	for _, f := range contents {
		if strings.Contains(f.Name(), "tty.usb") ||
			strings.Contains(f.Name(), "ttyUSB") ||
			strings.Contains(f.Name(), "ttyACM") {
			//return "/dev/" + f.Name()
			ret = append(ret, "/dev/"+f.Name())
		}
	}

	return ret
}

func writeLCDMatrix(p *packet, s io.ReadWriteCloser) {
	if debug {
		fmt.Println("writeLCDMatrix")
	}
	s.Write([]byte(p.header))
	s.Write([]byte(p.coord))
	s.Write([]byte(p.dataR))
	s.Write([]byte(p.dataG))
	s.Write([]byte(p.terminator))
}

func ttySelecter(ttys []string) (string, error) {
	if debug {
		fmt.Println("ttySelecter")
	}

	for i, s := range ttys {
		fmt.Println(strconv.Itoa(i) + ": " + s)
	}
	fmt.Println()
	fmt.Print("Select tty prot: ")

	n := 0
	fmt.Scan(&n)

	if n > len(ttys)-1 {
		return "", errors.New("tty port select error. " + strconv.Itoa(n) + " is not exist.")
	}

	return ttys[n], nil
}

func viewTtySelecterUI() (string, error) {
	if debug {
		fmt.Println("viewTtySelecterUI")
	}
	ttys := getUsbttyList()
	tty, err := ttySelecter(ttys)

	fmt.Println(tty)
	return tty, err
}

func convertString2image(s string) (*image.RGBA, error) {
	if debug {
		fmt.Println("convertString2image")
	}
	dpi := float64(72.0)
	//fontfile := "../font/MS Gothic.ttf"

	//fontfile := "../font/VL.ttf"
	fontfile := fontName
	hinting := "none"
	size := float64(17)
	spacing := float64(0)

	// Read the font data.
	fontBytes, err := ioutil.ReadFile(fontfile)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	font, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// Initialize the context.
	fg, bg := image.Black, image.White
	rgba := image.NewRGBA(image.Rect(0, 0, 16, 16))
	draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
	c := freetype.NewContext()
	c.SetDPI(dpi)
	c.SetFont(font)
	c.SetFontSize(size)
	c.SetClip(rgba.Bounds())
	c.SetDst(rgba)
	c.SetSrc(fg)
	switch hinting {
	default:
		c.SetHinting(freetype.NoHinting)
	case "full":
		c.SetHinting(freetype.FullHinting)
	}

	// Draw the text.
	pt := freetype.Pt(-1, -3+int(c.PointToFix32(size)>>8))

	_, err = c.DrawString(s, pt)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	pt.Y += c.PointToFix32(size * spacing)

	return rgba, nil
}

func cancellationAntiAliasing(img *image.RGBA) *image.NRGBA {
	if debug {
		fmt.Println("cancellationAntiAliasing")
	}
	gray := imaging.Grayscale(img)
	//imaging.Save(gray, "./grayscaled.png")
	w := gray.Rect.Max.X
	h := gray.Rect.Max.Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			r, _, _, _ := gray.At(x, y).RGBA()
			if r > 38000 {
				c := color.RGBA{0xff, 0xff, 0xff, 0xff}
				gray.Set(x, y, c)
			} else {
				c := color.RGBA{0x00, 0x00, 0x00, 0xff}
				gray.Set(x, y, c)
			}
		}
	}
	return gray
}

func convertLCDChar(c string, color int) *lcdChar {
	if debug {
		fmt.Println("convertLCDChar")
	}
	image, _ := convertString2image(c)
	img := cancellationAntiAliasing(image)

	var ret lcdChar
	ret.color = color
	ret.c = c

	for y := 0; y < 16; y++ {
		ret.bitmap[y] = 0
		for x := 0; x < 16; x++ {
			ret.bitmap[y] = ret.bitmap[y] << 1
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0 {
				ret.bitmap[y] |= 1
			} else {
				ret.bitmap[y] |= 0
			}
		}
	}
	return &ret
}

func convertLCDString(str string, color int) *lcdString {
	if debug {
		fmt.Println("convertLCDString")
	}
	var ret lcdString

	for _, c := range str {
		ret.c = append(ret.c, *convertLCDChar(string(c), color))
	}
	ret.coord = 0
	return &ret
}

func connectLCDStr(str0 *lcdString, str1 *lcdString) *lcdString {
	if debug {
		fmt.Println("connectLCDStr")
	}
	var ret lcdString
	ret.c = append(ret.c, str0.c...)
	ret.c = append(ret.c, str1.c...)
	ret.coord = 0
	return &ret
}

func printLCD(str lcdString, shift int) *lcdMatrix {
	if debug {
		fmt.Println("printLCD")
	}
	var ret lcdMatrix

	for y := 0; y < 16; y++ {
		var bufR []uint8
		var bufG []uint8
		for cn := 0; cn < len(str.c); cn++ {
			for x := 0; x < 16; x++ {
				bit := str.c[cn].bitmap[y]
				bit = bit >> (15 - uint(x))
				//mask 0b0000000000000001
				bit = bit & 0x0001
				//赤があるとき
				//buf[coordX] = uint8(bit)
				if str.c[cn].color&0xff0000 == 0xff0000 {
					bufR = append(bufR, uint8(bit))
				} else {
					bufR = append(bufR, uint8(0))
				}
				if str.c[cn].color&0x00ff00 == 0x00ff00 {
					bufG = append(bufG, uint8(bit))
				} else {
					bufG = append(bufG, uint8(0))
				}
			}
		}
		i := 0
		counter := 0

		for x := shift; x < 96+shift; x++ {
			if counter == 32 {
				i++
				if i == 3 {
					break
				}
				counter = 0
			}
			ret.dataR[i][y] = ret.dataR[i][y] << 1
			ret.dataG[i][y] = ret.dataG[i][y] << 1
			if str.coord+x < len(bufR) && x+str.coord >= 0 {
				ret.dataR[i][y] |= uint32(bufR[x+str.coord])
			} else {
				ret.dataR[i][y] |= 0
			}
			if str.coord+x < len(bufG) && str.coord+x >= 0 {
				ret.dataG[i][y] |= uint32(bufG[x+str.coord])
			} else {
				ret.dataG[i][y] |= 0
			}
			counter++
		}
	}

	return &ret

}

func selectFont() (string, error) {
	if debug {
		fmt.Println("selectFont")
	}

	fontDir := "../font/"
	list, err := ioutil.ReadDir(fontDir)
	if err != nil {
		log.Println(err)
		return "", err
	}
	for i, f := range list {
		fmt.Printf("%d: ", i)
		fmt.Println(f.Name())
	}

	n := 0
	fmt.Println()
	fmt.Print("Select font file: ")
	fmt.Scan(&n)
	fmt.Println()
	return "../font/" + list[n].Name(), nil
}

func main() {
	debug = false
	font, err := selectFont()
	if err != nil {
		log.Fatalln(err)
	}
	fontName = font

	str0 := convertLCDString("にゃんぱす。", 0xff0000)
	str1 := convertLCDString("ぴねたんなう。", 0x00ff00)
	str2 := convertLCDString("文蔵いきたい。", 0xffff00)
	str := connectLCDStr(str0, str1)
	str = connectLCDStr(str, str2)

	ttyPort, err := viewTtySelecterUI()
	if err != nil {
		log.Fatalln(err)
	}

	serialConfigure := &goserial.Config{Name: ttyPort, Baud: 9600}
	serialPort, _ := goserial.OpenPort(serialConfigure)

	//packet = createTestPacket()

	fmt.Println("len:", len(str.c))
	shiftCoord := len(str.c) * 16
	fmt.Println("shift coordnate: ", shiftCoord)
	serialPort.Close()

	for k := 0; k < 3; k++ {
		for i := 0; i < shiftCoord+96+1; i++ {
			serialPort, _ = goserial.OpenPort(serialConfigure)
			packet := createPacket(*str, i-96)
			writeLCDMatrix(packet, serialPort)
			time.Sleep(10 * time.Millisecond)
			serialPort.Close()
		}
	}
}
<commit_msg>任意のタイミングで書き換えが可能になった<commit_after>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"io"
	"io/ioutil"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/disintegration/imaging"
	"github.com/huin/goserial"

	"code.google.com/p/freetype-go/freetype"
)

var fontName string
var debug bool

type packet struct {
	header     string
	coord      string
	dataR      []byte
	dataG      []byte
	terminator string
}

type lcdChar struct {
	c      string
	bitmap [16]uint16
	color  int
}

type lcdString struct {
	c     []lcdChar
	coord int
}

type lcdMatrix struct {
	dataR [3][16]uint32
	dataG [3][16]uint32
}

func createTestPacket() *packet {
	if debug {
		fmt.Println("createTestPacket")
	}
	var p packet
	p.header = "pcmat\r"
	p.coord = "000\r5ff\r"
	s1 := ""
	s2 := ""
	for i := 0; i < 192; i++ {
		s1 += "p"
		s2 += "a"
	}
	s1 += "\r"
	s2 += "\r"
	p.dataR = []byte(s1)
	p.dataG = []byte(s2)
	p.terminator = "end\r"

	return &p
}

func createPacket(str lcdString, shift int) *packet {
	if debug {
		fmt.Println("createPacket")
	}

	data := printLCD(str, shift)
	//str.coord += shift

	var packet packet
	packet.header = "pcmat\r"
	packet.coord = "000\r5ff\r"

	var bufr []byte
	var bufg []byte
	for y := 0; y < 16; y++ {

		for x := 0; x < 3; x++ {
			r := data.dataR[x][y]
			rbyte := (r & 0xff000000) >> 24
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x00ff0000) >> 16
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x0000ff00) >> 8
			bufr = append(bufr, byte(rbyte))
			rbyte = (r & 0x000000ff) >> 0
			bufr = append(bufr, byte(rbyte))

			g := data.dataG[x][y]
			//bing := make([]byte, 4)
			//binary.LittleEndian.PutUint32(bing, g)
			gbyte := (g & 0xff000000) >> 24
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x00ff0000) >> 16
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x0000ff00) >> 8
			bufg = append(bufg, byte(gbyte))
			gbyte = (g & 0x000000ff) >> 0
			bufg = append(bufg, byte(gbyte))
		}

	}
	//packet.dataR = []byte(string(bufr) + "\r")
	//packet.dataG = []byte(string(bufg) + "\r")
	packet.dataR = append(packet.dataR, bufr...)
	packet.dataR = append(packet.dataR, []byte("\r")...)
	packet.dataG = append(packet.dataG, bufg...)
	packet.dataG = append(packet.dataG, []byte("\r")...)

	packet.terminator = "end\r"

	return &packet
}

func getUsbttyList() []string {
	if debug {
		fmt.Println("getUsbttyList")
	}
	contents, _ := ioutil.ReadDir("/dev")
	var ret []string

	for _, f := range contents {
		if strings.Contains(f.Name(), "tty.usb") ||
			strings.Contains(f.Name(), "ttyUSB") ||
			strings.Contains(f.Name(), "ttyACM") {
			//return "/dev/" + f.Name()
			ret = append(ret, "/dev/"+f.Name())
		}
	}

	return ret
}

func writeLCDMatrix(p *packet, s io.ReadWriteCloser) {
	if debug {
		fmt.Println("writeLCDMatrix")
	}
	s.Write([]byte(p.header))
	s.Write([]byte(p.coord))
	s.Write([]byte(p.dataR))
	s.Write([]byte(p.dataG))
	s.Write([]byte(p.terminator))
}

func ttySelecter(ttys []string) (string, error) {
	if debug {
		fmt.Println("ttySelecter")
	}

	for i, s := range ttys {
		fmt.Println(strconv.Itoa(i) + ": " + s)
	}
	fmt.Println()
	fmt.Print("Select tty prot: ")

	n := 0
	fmt.Scan(&n)

	if n > len(ttys)-1 {
		return "", errors.New("tty port select error. " + strconv.Itoa(n) + " is not exist.")
	}

	return ttys[n], nil
}

func viewTtySelecterUI() (string, error) {
	if debug {
		fmt.Println("viewTtySelecterUI")
	}
	ttys := getUsbttyList()
	tty, err := ttySelecter(ttys)

	fmt.Println(tty)
	return tty, err
}

func convertString2image(s string) (*image.RGBA, error) {
	if debug {
		fmt.Println("convertString2image")
	}
	dpi := float64(72.0)
	//fontfile := "../font/MS Gothic.ttf"

	//fontfile := "../font/VL.ttf"
	fontfile := fontName
	hinting := "none"
	size := float64(17)
	spacing := float64(0)

	// Read the font data.
	fontBytes, err := ioutil.ReadFile(fontfile)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	font, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	// Initialize the context.
	fg, bg := image.Black, image.White
	rgba := image.NewRGBA(image.Rect(0, 0, 16, 16))
	draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
	c := freetype.NewContext()
	c.SetDPI(dpi)
	c.SetFont(font)
	c.SetFontSize(size)
	c.SetClip(rgba.Bounds())
	c.SetDst(rgba)
	c.SetSrc(fg)
	switch hinting {
	default:
		c.SetHinting(freetype.NoHinting)
	case "full":
		c.SetHinting(freetype.FullHinting)
	}

	// Draw the text.
	pt := freetype.Pt(-1, -3+int(c.PointToFix32(size)>>8))

	_, err = c.DrawString(s, pt)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	pt.Y += c.PointToFix32(size * spacing)

	return rgba, nil
}

func cancellationAntiAliasing(img *image.RGBA) *image.NRGBA {
	if debug {
		fmt.Println("cancellationAntiAliasing")
	}
	gray := imaging.Grayscale(img)
	//imaging.Save(gray, "./grayscaled.png")
	w := gray.Rect.Max.X
	h := gray.Rect.Max.Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			r, _, _, _ := gray.At(x, y).RGBA()
			if r > 38000 {
				c := color.RGBA{0xff, 0xff, 0xff, 0xff}
				gray.Set(x, y, c)
			} else {
				c := color.RGBA{0x00, 0x00, 0x00, 0xff}
				gray.Set(x, y, c)
			}
		}
	}
	return gray
}

func convertLCDChar(c string, color int) *lcdChar {
	if debug {
		fmt.Println("convertLCDChar")
	}
	image, _ := convertString2image(c)
	img := cancellationAntiAliasing(image)

	var ret lcdChar
	ret.color = color
	ret.c = c

	for y := 0; y < 16; y++ {
		ret.bitmap[y] = 0
		for x := 0; x < 16; x++ {
			ret.bitmap[y] = ret.bitmap[y] << 1
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0 {
				ret.bitmap[y] |= 1
			} else {
				ret.bitmap[y] |= 0
			}
		}
	}
	return &ret
}

func convertLCDString(str string, color int) *lcdString {
	if debug {
		fmt.Println("convertLCDString")
	}
	var ret lcdString

	for _, c := range str {
		ret.c = append(ret.c, *convertLCDChar(string(c), color))
	}
	ret.coord = 0
	return &ret
}

func connectLCDStr(str0 *lcdString, str1 *lcdString) *lcdString {
	if debug {
		fmt.Println("connectLCDStr")
	}
	var ret lcdString
	ret.c = append(ret.c, str0.c...)
	ret.c = append(ret.c, str1.c...)
	ret.coord = 0
	return &ret
}

func printLCD(str lcdString, shift int) *lcdMatrix {
	if debug {
		fmt.Println("printLCD")
	}
	var ret lcdMatrix

	for y := 0; y < 16; y++ {
		var bufR []uint8
		var bufG []uint8
		for cn := 0; cn < len(str.c); cn++ {
			for x := 0; x < 16; x++ {
				bit := str.c[cn].bitmap[y]
				bit = bit >> (15 - uint(x))
				//mask 0b0000000000000001
				bit = bit & 0x0001
				//赤があるとき
				//buf[coordX] = uint8(bit)
				if str.c[cn].color&0xff0000 == 0xff0000 {
					bufR = append(bufR, uint8(bit))
				} else {
					bufR = append(bufR, uint8(0))
				}
				if str.c[cn].color&0x00ff00 == 0x00ff00 {
					bufG = append(bufG, uint8(bit))
				} else {
					bufG = append(bufG, uint8(0))
				}
			}
		}
		i := 0
		counter := 0

		for x := shift; x < 96+shift; x++ {
			if counter == 32 {
				i++
				if i == 3 {
					break
				}
				counter = 0
			}
			ret.dataR[i][y] = ret.dataR[i][y] << 1
			ret.dataG[i][y] = ret.dataG[i][y] << 1
			if str.coord+x < len(bufR) && x+str.coord >= 0 {
				ret.dataR[i][y] |= uint32(bufR[x+str.coord])
			} else {
				ret.dataR[i][y] |= 0
			}
			if str.coord+x < len(bufG) && str.coord+x >= 0 {
				ret.dataG[i][y] |= uint32(bufG[x+str.coord])
			} else {
				ret.dataG[i][y] |= 0
			}
			counter++
		}
	}

	return &ret
}

func selectFont() (string, error) {
	if debug {
		fmt.Println("selectFont")
	}

	fontDir := "../font/"
	list, err := ioutil.ReadDir(fontDir)
	if err != nil {
		log.Println(err)
		return "", err
	}
	for i, f := range list {
		fmt.Printf("%d: ", i)
		fmt.Println(f.Name())
	}

	n := 0
	fmt.Println()
	fmt.Print("Select font file: ")
	fmt.Scan(&n)
	fmt.Println()
	return "../font/" + list[n].Name(), nil
}

func main() {
	debug = false
	font, err := selectFont()
	if err != nil {
		log.Fatalln(err)
	}
	fontName = font

	str0 := convertLCDString("【速報】", 0xff0000)
	str1 := convertLCDString("なのは完売", 0xffff00)
	str2 := convertLCDString("", 0xffff00)
	str := connectLCDStr(str0, str1)
	str = connectLCDStr(str, str2)

	ttyPort, err := viewTtySelecterUI()
	if err != nil {
		log.Fatalln(err)
	}

	serialConfigure := &goserial.Config{Name: ttyPort, Baud: 9600}
	serialPort, _ := goserial.OpenPort(serialConfigure)

	shiftCoord := len(str.c) * 16
	//packet = createTestPacket()

	serialPort.Close()

	ch0 := make(chan bool)
	ch1 := make(chan bool)

	go func() {
		for k := 0; k < 100000; k++ {
			for i := 0; i < shiftCoord+96+1; i++ {
				serialPort, _ = goserial.OpenPort(serialConfigure)
				packet := createPacket(*str, i-96)
				writeLCDMatrix(packet, serialPort)
				time.Sleep(10 * time.Millisecond)
				serialPort.Close()
			}
		}
		ch0 <- true
	}()
	go func() {
		for i := 0; i < 1000; i++ {
			var s string
			fmt.Println("input str")
			fmt.Scan(&s)
			str = convertLCDString(s, 0xff0000)
			shiftCoord = len(str.c) * 16
		}
		ch1 <- true
	}()
	<-ch0
	<-ch1
}
<|endoftext|>


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

// references: http://dave.cheney.net/tag/golang

package main

import (
	"bufio"
	"code.google.com/p/go.crypto/ssh"
	"io"
	"log"
	"net"
	"os"
)

// SshCmd bundles a command and its environment together over channels
type SshCmd struct {
	command string
	env map[string]string
}

// SshConn is an ssh connection and channels for communicating with it,
// IO pipes are proxied through the channels, so to write to
// a process's stdin, write to the stdin channel in this struct
type sshConn struct {
	address string
	ssh     *ssh.ClientConn
	command chan SshCmd
	stdin   chan string
	stdout  chan string
	stderr  chan string
	ready   chan string
	done    chan string
}

// SshConnMgr represents a collection of ssh connections
type SshConnMgr struct {
	conns map[string]*sshConn
	auth *[]ssh.ClientAuth
}

// NewSshConn returns a new sshConn with channels pre-made
func NewSshConn(address string, ssh *ssh.ClientConn) (*sshConn) {
	return &sshConn{
		address,             // address
		ssh,                 // ssh
		make(chan SshCmd),   // command
		make(chan string),   // stdin
		make(chan string),   // stdout
		make(chan string),   // stderr
		make(chan string),   // ready
		make(chan string),   // done
	}
}

// NewSshConnMgr initialize a new connection manager with a keyring and ssh-agent
func NewSshConnMgr(key string) (mgr *SshConnMgr) {
	mgr = &SshConnMgr{}
	mgr.conns = map[string]*sshConn{}
	auth := []ssh.ClientAuth{}
	agentSock := os.Getenv("SSH_AUTH_SOCK")

	// only load a private key if requested ~/.ssh/id_rsa is _not_ loaded automatically
	// ssh-agent should be the usual path
	if key != "" {
		kr := new(keyring)
		if err := kr.loadPEM(key); err != nil {
			log.Fatal("Couldn't load specified private key '", key, "': ", err)
		}
		auth = append(auth, ssh.ClientAuthKeyring(kr))
	}

	// ssh-agent support
	if agentSock != "" {
		sock, err := net.Dial("unix", agentSock)
		if err != nil {
			log.Fatal("Could not connect to SSH_AUTH_SOCK. Is ssh-agent running?")
		}

		agent := ssh.NewAgentClient(sock)
		auth = append(auth, ssh.ClientAuthAgent(agent))
	}

	mgr.auth = &auth
	return
}

func (mgr *SshConnMgr) runCmdAll(command SshCmd) {
	for _, conn := range mgr.conns {
		conn.command <-command
	}
	for _, conn := range mgr.conns {
		<-conn.done
	}
}

func (mgr *SshConnMgr) runCmdOne(address string, command SshCmd) {
	log.Printf("[%s] runCmdOne %s\n", address, command)
	mgr.conns[address].command <-command
}

// stopAll sends a 'done' message to each connections' goroutine so
// it will exit cleanly
func (mgr *SshConnMgr) stopAll() {
	for name, conn := range mgr.conns {
		log.Printf("[%s] sending done message ...\n", name)
		conn.done <- "done"
	}

	// wait for confirmation
	for name, conn := range mgr.conns {
		<-conn.done
		log.Printf("[%s] done message acked. Done!\n", name)
	}
}

// connectList tells the connection manager to connect to all nodes in the
// provided list of addresses
// expects a list of ssh addresses in address:port format
func (mgr *SshConnMgr) connectList(list []string, user string, key string) {
	conns := []*sshConn{}

	for _, address := range list {
		conn := NewSshConn(address, nil)

		config := &ssh.ClientConfig{
			User: user,
			Auth: *mgr.auth,
		}

		go conn.handleConnection(config)

		mgr.conns[address] = conn
		conns = append(conns, conn)
	}

	// now wait for them all to become ready, use a local list
	// to allow connectList() to be called multiple times safely
	for _, conn := range conns {
		<-conn.ready
	}
}

func (conn *sshConn) handleConnection(config *ssh.ClientConfig) {
	ssh, err := ssh.Dial("tcp", conn.address, config)
	if err != nil {
		log.Fatal("ssh connection to ", conn.address, " failed: ", err)
	}

	conn.ssh = ssh
	conn.ready <-"ready"

	for {
		log.Printf("going to wait [%s]\n", conn.address)

		select {
		case command, _ := <-conn.command:
			conn.RunCommand(command)
		case <-conn.done:
			conn.done <-"ack"
			break
		}
	}
}

// RunCommand runs a single command on the remote host. A session
// is set up, IO wired to the connection object's channels, environment
// pushed, then execution & wait.
func (conn *sshConn) RunCommand(command SshCmd) {
	sess, err := conn.ssh.NewSession()
	if err != nil {
		// maybe not fatal in the future?
		log.Fatal("[", conn.address, "] session creation failed: ", err)
	}
	defer sess.Close()
	log.Printf("session started\n")

	for k, v := range command.env {
		sess.Setenv(k, v)
	}
	log.Printf("session environment set\n")

	stdin, _ := sess.StdinPipe()
	go forwardToFd(stdin, conn.stdin)
	defer stdin.Close()
	log.Printf("stdin forwarder started\n")

	stdout, _ := sess.StdoutPipe()
	go forwardFromFd(stdout, conn.stdout, "stdout")
	log.Printf("stdout forwarder started\n")

	stderr, _ := sess.StderrPipe()
	go forwardFromFd(stderr, conn.stderr, "stderr")
	log.Printf("stderr forwarder started\n")

	if err := sess.Start(command.command); err != nil {
		log.Fatal("[", conn.address, "] command failed: ", err)
	} else {
		log.Printf("[%s] executed command: %v %v\n", conn.address, command, sess)
	}

	sess.Wait()
	conn.done <-command.command
}

func forwardFromFd(fd io.Reader, to chan string, name string) {
	bfd := bufio.NewReader(fd)
	log.Printf("[%s] forwarding\n", name)

	for {
		line, err := bfd.ReadString('\n')
		if err == io.EOF {
			log.Printf("[%s] EOF\n", name)
			return
		}
		log.Printf("[%s] %s", name, line)
		to <- string(line)
	}
}

func forwardToFd(fd io.Writer, from chan string) {
	for {
		stdin := <-from
		fd.Write([]byte(stdin))
	}
}

/*
	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()
	}()
	if err := session.Run("/usr/bin/scp -qrt ./"); err != nil {
		panic("Failed to run: " + err.Error())
	}
}

*/

// vim: ts=4 sw=4 noet tw=120 softtabstop=4
<commit_msg>[ssh] add comments, make runCmdOne block like runCmdAll<commit_after>// Copyright 2013 Albert P. Tobey. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// references: http://dave.cheney.net/tag/golang

package main

import (
	"bufio"
	"code.google.com/p/go.crypto/ssh"
	"io"
	"log"
	"net"
	"os"
)

// SshCmd bundles a command and its environment together over channels
type SshCmd struct {
	command string
	env map[string]string
}

// SshConn is an ssh connection and channels for communicating with it,
// IO pipes are proxied through the channels, so to write to
// a process's stdin, write to the stdin channel in this struct
type sshConn struct {
	address string
	ssh     *ssh.ClientConn
	command chan SshCmd
	stdin   chan string
	stdout  chan string
	stderr  chan string
	ready   chan string
	done    chan string
}

// SshConnMgr represents a collection of ssh connections
type SshConnMgr struct {
	conns map[string]*sshConn
	auth *[]ssh.ClientAuth
}

// NewSshConn returns a new sshConn with channels pre-made
func NewSshConn(address string, ssh *ssh.ClientConn) (*sshConn) {
	return &sshConn{
		address,             // address
		ssh,                 // ssh
		make(chan SshCmd),   // command
		make(chan string),   // stdin
		make(chan string),   // stdout
		make(chan string),   // stderr
		make(chan string),   // ready
		make(chan string),   // done
	}
}

// NewSshConnMgr initialize a new connection manager with a keyring and ssh-agent
func NewSshConnMgr(key string) (mgr *SshConnMgr) {
	mgr = &SshConnMgr{}
	mgr.conns = map[string]*sshConn{}
	auth := []ssh.ClientAuth{}
	agentSock := os.Getenv("SSH_AUTH_SOCK")

	// only load a private key if requested ~/.ssh/id_rsa is _not_ loaded automatically
	// ssh-agent should be the usual path
	if key != "" {
		kr := new(keyring)
		if err := kr.loadPEM(key); err != nil {
			log.Fatal("Couldn't load specified private key '", key, "': ", err)
		}
		auth = append(auth, ssh.ClientAuthKeyring(kr))
	}

	// ssh-agent support
	if agentSock != "" {
		sock, err := net.Dial("unix", agentSock)
		if err != nil {
			log.Fatal("Could not connect to SSH_AUTH_SOCK. Is ssh-agent running?")
		}

		agent := ssh.NewAgentClient(sock)
		auth = append(auth, ssh.ClientAuthAgent(agent))
	}

	mgr.auth = &auth
	return
}

// runCmdAll runs an SshCmd on all nodes connected by the manager. It waits for
// and ack from all of the connections before returning.
// TODO: timeouts
func (mgr *SshConnMgr) runCmdAll(command SshCmd) {
	for _, conn := range mgr.conns {
		conn.command <-command
	}
	for _, conn := range mgr.conns {
		<-conn.done
	}
}

// runCmdOne runs an SshCmd on one node that must already be connected by the
// connection manager
func (mgr *SshConnMgr) runCmdOne(address string, command SshCmd) {
	log.Printf("[%s] runCmdOne %s\n", address, command)
	conn := mgr.conns[address]
	conn.command <-command
	<-conn.done
}

// stopAll sends a 'done' message to each connections' goroutine so
// it will exit cleanly
func (mgr *SshConnMgr) stopAll() {
	for name, conn := range mgr.conns {
		log.Printf("[%s] sending done message ...\n", name)
		conn.done <- "done"
	}

	// wait for confirmation
	for name, conn := range mgr.conns {
		<-conn.done
		log.Printf("[%s] done message acked. Done!\n", name)
	}
}

// connectList tells the connection manager to connect to all nodes in the
// provided list of addresses
// expects a list of ssh addresses in address:port format
func (mgr *SshConnMgr) connectList(list []string, user string, key string) {
	conns := []*sshConn{}

	for _, address := range list {
		conn := NewSshConn(address, nil)

		config := &ssh.ClientConfig{
			User: user,
			Auth: *mgr.auth,
		}

		go conn.handleConnection(config)

		mgr.conns[address] = conn
		conns = append(conns, conn)
	}

	// now wait for them all to become ready, use a local list
	// to allow connectList() to be called multiple times safely
	for _, conn := range conns {
		<-conn.ready
	}
}

func (conn *sshConn) handleConnection(config *ssh.ClientConfig) {
	ssh, err := ssh.Dial("tcp", conn.address, config)
	if err != nil {
		log.Fatal("ssh connection to ", conn.address, " failed: ", err)
	}

	conn.ssh = ssh
	conn.ready <-"ready"

	for {
		log.Printf("going to wait [%s]\n", conn.address)

		select {
		case command, _ := <-conn.command:
			conn.RunCommand(command)
		case <-conn.done:
			conn.done <-"ack"
			break
		}
	}
}

// RunCommand runs a single command on the remote host. A session
// is set up, IO wired to the connection object's channels, environment
// pushed, then execution & wait.
func (conn *sshConn) RunCommand(command SshCmd) {
	sess, err := conn.ssh.NewSession()
	if err != nil {
		// maybe not fatal in the future?
		log.Fatal("[", conn.address, "] session creation failed: ", err)
	}
	defer sess.Close()
	log.Printf("session started\n")

	for k, v := range command.env {
		sess.Setenv(k, v)
	}
	log.Printf("session environment set\n")

	stdin, _ := sess.StdinPipe()
	go forwardToFd(stdin, conn.stdin)
	defer stdin.Close()
	log.Printf("stdin forwarder started\n")

	stdout, _ := sess.StdoutPipe()
	go forwardFromFd(stdout, conn.stdout, "stdout")
	log.Printf("stdout forwarder started\n")

	stderr, _ := sess.StderrPipe()
	go forwardFromFd(stderr, conn.stderr, "stderr")
	log.Printf("stderr forwarder started\n")

	if err := sess.Start(command.command); err != nil {
		log.Fatal("[", conn.address, "] command failed: ", err)
	} else {
		log.Printf("[%s] executed command: %v %v\n", conn.address, command, sess)
	}

	sess.Wait()
	conn.done <-command.command
}

func forwardFromFd(fd io.Reader, to chan string, name string) {
	bfd := bufio.NewReader(fd)
	log.Printf("[%s] forwarding\n", name)

	for {
		line, err := bfd.ReadString('\n')
		if err == io.EOF {
			log.Printf("[%s] EOF\n", name)
			return
		}
		log.Printf("[%s] %s", name, line)
		to <- string(line)
	}
}

func forwardToFd(fd io.Writer, from chan string) {
	for {
		stdin := <-from
		fd.Write([]byte(stdin))
	}
}

/*
	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()
	}()
	if err := session.Run("/usr/bin/scp -qrt ./"); err != nil {
		panic("Failed to run: " + err.Error())
	}
}

*/

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


<commit_before>// Hap - the simple and effective provisioner
// Copyright (c) 2015 Garrett Woodworth (https://github.com/gwoo)
// The BSD License http://opensource.org/licenses/bsd-license.php.

package hap

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

// SSHConfig holds the config for ssh connections
type SSHConfig struct {
	Addr         string
	Username     string
	Identity     string
	Password     string
	ClientConfig *ssh.ClientConfig
}

// NewClientConfig constructs a new client config
func NewClientConfig(config SSHConfig) (*ssh.ClientConfig, error) {
	sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		return nil, err
	}
	agent := agent.NewClient(sock)
	signers, err := agent.Signers()
	if err != nil {
		return nil, err
	}
	if config.Identity != "" {
		signer, err := NewSigner(config.Identity)
		if err != nil {
			return nil, err
		}
		signers = append(signers, signer)
	}
	auths := []ssh.AuthMethod{
		ssh.PublicKeys(signers...),
		ssh.Password(config.Password),
	}
	cfg := &ssh.ClientConfig{User: config.Username, Auth: auths}
	cfg.SetDefaults()
	return cfg, nil
}

// NewKeyFile takes a key and returns the key file
func NewKeyFile(key string) (string, error) {
	if string(key[0]) == "~" {
		u, err := user.Current()
		if err != nil {
			return "", fmt.Errorf("[identity] %s", err)
		}
		key = strings.Replace(key, "~", u.HomeDir, 1)
	}
	return filepath.EvalSymlinks(key)
}

// NewKey parses and returns the interface for the key type (rsa, dss, etc)
func NewKey(key string) (interface{}, error) {
	file, err := NewKeyFile(key)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}
	return ssh.ParseRawPrivateKey(b)
}

// NewSigner creates a new ssh signer
func NewSigner(key string) (ssh.Signer, error) {
	pk, err := NewKey(key)
	if err != nil {
		return nil, err
	}
	return ssh.NewSignerFromKey(pk)
}
<commit_msg>Update ssh auth.<commit_after>// Hap - the simple and effective provisioner
// Copyright (c) 2015 Garrett Woodworth (https://github.com/gwoo)
// The BSD License http://opensource.org/licenses/bsd-license.php.

package hap

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

// SSHConfig holds the config for ssh connections
type SSHConfig struct {
	Addr         string
	Username     string
	Identity     string
	Password     string
	ClientConfig *ssh.ClientConfig
}

// Construct a new client config
func NewClientConfig(config SshConfig) (*ssh.ClientConfig, error) {
	signers := make([]ssh.Signer, 0)
	if sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
		agent := agent.NewClient(sock)
		agentsigners, _ := agent.Signers()
		signers = append(signers, agentsigners...)
	}
	if config.Identity != "" {
		if signer, err := NewSigner(config.Identity); err == nil {
			signers = append(signers, signer)
		}
	}
	auths := []ssh.AuthMethod{
		ssh.PublicKeys(signers...),
		ssh.Password(config.Password),
	}
	cfg := &ssh.ClientConfig{User: config.Username, Auth: auths}
	cfg.SetDefaults()
	return cfg, nil
}

// NewKeyFile takes a key and returns the key file
func NewKeyFile(key string) (string, error) {
	if string(key[0]) == "~" {
		u, err := user.Current()
		if err != nil {
			return "", fmt.Errorf("[identity] %s", err)
		}
		key = strings.Replace(key, "~", u.HomeDir, 1)
	}
	return filepath.EvalSymlinks(key)
}

// NewKey parses and returns the interface for the key type (rsa, dss, etc)
func NewKey(key string) (interface{}, error) {
	file, err := NewKeyFile(key)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}
	return ssh.ParseRawPrivateKey(b)
}

// NewSigner creates a new ssh signer
func NewSigner(key string) (ssh.Signer, error) {
	pk, err := NewKey(key)
	if err != nil {
		return nil, err
	}
	return ssh.NewSignerFromKey(pk)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"html/template"
	"reflect"
)

// eq reports whether the first argument is equal to
// any of the remaining arguments.
func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func routeUrl(name string, pairs ...string) string {
	u, _ := router.Get(name).URL(pairs...)
	return u.String()
}

func htmlattr(s string) template.HTMLAttr {
	return template.HTMLAttr(s)
}

var funcs = template.FuncMap{
	"eq":  eq,
	"htmlattr": htmlattr,
	"url": routeUrl,
}
<commit_msg>go fmt<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"html/template"
	"reflect"
)

// eq reports whether the first argument is equal to
// any of the remaining arguments.
func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func routeUrl(name string, pairs ...string) string {
	u, _ := router.Get(name).URL(pairs...)
	return u.String()
}

func htmlattr(s string) template.HTMLAttr {
	return template.HTMLAttr(s)
}

var funcs = template.FuncMap{
	"eq":       eq,
	"htmlattr": htmlattr,
	"url":      routeUrl,
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strconv"
)

var (
	sum      float64
	floatSum bool

	scanner *bufio.Scanner
)

func main() {
	flag.BoolVar(&floatSum, "F", false, "compute the sum as a float")
	flag.Parse()

	scanner = bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)

	if floatSum {
		for scanner.Scan() {
			incrFloat(scanner.Text())
		}
	} else {
		for scanner.Scan() {
			incrInt(scanner.Text())
		}
	}

	var format string

	if floatSum {
		format = "%f\n"
	} else {
		format = "%d\n"
	}

	fmt.Printf(format, sum)
}

func incrFloat(s string) {
	f, err := strconv.ParseFloat(s, 64)
	if err == nil {
		sum += f
	}
}

func incrInt(s string) {
	i, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		sum += float64(i)
	}
}
<commit_msg>short sum: float representation<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strconv"
)

var (
	sum      float64
	floatSum bool

	scanner *bufio.Scanner
)

func main() {
	flag.BoolVar(&floatSum, "F", false, "compute the sum as a float")
	flag.Parse()

	scanner = bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)

	if floatSum {
		for scanner.Scan() {
			incrFloat(scanner.Text())
		}
		// we use FormatFloat instead of %f here to print only the smallest
		// number of digits
		fmt.Println(strconv.FormatFloat(sum, 'f', -1, 64))
	} else {
		for scanner.Scan() {
			incrInt(scanner.Text())
		}
		fmt.Printf("%d\n", int64(sum))
	}
}

func incrFloat(s string) {
	f, err := strconv.ParseFloat(s, 64)
	if err == nil {
		sum += f
	}
}

func incrInt(s string) {
	i, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		sum += float64(i)
	}
}
<|endoftext|>


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

package goplay

import (
	"appengine"
	"appengine/datastore"
	"net/http"
	"strings"
	"text/template"
)

const hostname = "play.golang.org"

func init() {
	http.HandleFunc("/", edit)
}

var editTemplate = template.Must(template.ParseFiles("goplay/edit.html"))

type editData struct {
	Snippet *Snippet
}

func edit(w http.ResponseWriter, r *http.Request) {
	// Redirect foo.play.golang.org to play.golang.org.
	if strings.HasSuffix(r.Host, "."+hostname) {
		http.Redirect(w, r, "http://"+hostname, http.StatusFound)
		return
	}

	snip := &Snippet{Body: []byte(hello)}
	if strings.HasPrefix(r.URL.Path, "/p/") {
		c := appengine.NewContext(r)
		id := r.URL.Path[3:]
		key := datastore.NewKey(c, "Snippet", id, 0, nil)
		err := datastore.Get(c, key, snip)
		if err != nil {
			if err != datastore.ErrNoSuchEntity {
				c.Errorf("loading Snippet: %v", err)
			}
			http.Error(w, "Snippet not found", http.StatusNotFound)
			return
		}
	}
	editTemplate.Execute(w, &editData{snip})
}

const hello = `package main

import "fmt"

func main() {
	fmt.Println("Hello, playground")
}
`
<commit_msg>go-playground: serve snippet as plain text when URL ends in .go<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goplay

import (
	"appengine"
	"appengine/datastore"
	"net/http"
	"strings"
	"text/template"
)

const hostname = "play.golang.org"

func init() {
	http.HandleFunc("/", edit)
}

var editTemplate = template.Must(template.ParseFiles("goplay/edit.html"))

type editData struct {
	Snippet *Snippet
}

func edit(w http.ResponseWriter, r *http.Request) {
	// Redirect foo.play.golang.org to play.golang.org.
	if strings.HasSuffix(r.Host, "."+hostname) {
		http.Redirect(w, r, "http://"+hostname, http.StatusFound)
		return
	}

	snip := &Snippet{Body: []byte(hello)}
	if strings.HasPrefix(r.URL.Path, "/p/") {
		c := appengine.NewContext(r)
		id := r.URL.Path[3:]
		serveText := false
		if strings.HasSuffix(id, ".go") {
			id = id[:len(id)-3]
			serveText = true
		}
		key := datastore.NewKey(c, "Snippet", id, 0, nil)
		err := datastore.Get(c, key, snip)
		if err != nil {
			if err != datastore.ErrNoSuchEntity {
				c.Errorf("loading Snippet: %v", err)
			}
			http.Error(w, "Snippet not found", http.StatusNotFound)
			return
		}
		if serveText {
			w.Header().Set("Content-type", "text/plain")
			w.Write(snip.Body)
			return
		}
	}
	editTemplate.Execute(w, &editData{snip})
}

const hello = `package main

import "fmt"

func main() {
	fmt.Println("Hello, playground")
}
`
<|endoftext|>


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

package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/fileutils"
)

func createTarStream(srcPath string) (io.ReadCloser, error) {
	excludes, err := parseDockerignore(srcPath)
	if err != nil {
		return nil, err
	}

	if err := validateContextDirectory(srcPath, excludes); err != nil {
		return nil, err
	}
	tarOpts := &archive.TarOptions{
		Excludes:    excludes,
		Compression: archive.Uncompressed,
		NoLchown:    true,
	}
	return archive.TarWithOptions(srcPath, tarOpts)
}

// validateContextDirectory checks if all the contents of the directory
// can be read and returns an error if some files can't be read.
// Symlinks which point to non-existing files don't trigger an error
func validateContextDirectory(srcPath string, excludes []string) error {
	return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
		// skip this directory/file if it's not in the path, it won't get added to the context
		if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil {
			return err
		} else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
			return err
		} else if skip {
			if f.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		if err != nil {
			if os.IsPermission(err) {
				return fmt.Errorf("can't stat '%s'", filePath)
			}
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}

		// skip checking if symlinks point to non-existing files, such symlinks can be useful
		// also skip named pipes, because they hanging on open
		if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
			return nil
		}

		if !f.IsDir() {
			currentFile, err := os.Open(filePath)
			if err != nil && os.IsPermission(err) {
				return fmt.Errorf("no permission to read from '%s'", filePath)
			}
			currentFile.Close()
		}
		return nil
	})
}

func parseDockerignore(root string) ([]string, error) {
	var excludes []string
	ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore"))
	if err != nil && !os.IsNotExist(err) {
		return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err)
	}
	for _, pattern := range strings.Split(string(ignore), "\n") {
		matches, err := filepath.Match(pattern, "Dockerfile")
		if err != nil {
			return excludes, fmt.Errorf("bad .dockerignore pattern: '%s', error: %s", pattern, err)
		}
		if matches {
			return excludes, fmt.Errorf("dockerfile was excluded by .dockerignore pattern '%s'", pattern)
		}
		excludes = append(excludes, pattern)
	}

	return excludes, nil
}
<commit_msg>Changed field name in upstream struct definition<commit_after>// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/fileutils"
)

func createTarStream(srcPath string) (io.ReadCloser, error) {
	excludes, err := parseDockerignore(srcPath)
	if err != nil {
		return nil, err
	}

	if err := validateContextDirectory(srcPath, excludes); err != nil {
		return nil, err
	}
	tarOpts := &archive.TarOptions{
		ExcludePatterns: excludes,
		Compression:     archive.Uncompressed,
		NoLchown:        true,
	}
	return archive.TarWithOptions(srcPath, tarOpts)
}

// validateContextDirectory checks if all the contents of the directory
// can be read and returns an error if some files can't be read.
// Symlinks which point to non-existing files don't trigger an error
func validateContextDirectory(srcPath string, excludes []string) error {
	return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
		// skip this directory/file if it's not in the path, it won't get added to the context
		if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil {
			return err
		} else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
			return err
		} else if skip {
			if f.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}

		if err != nil {
			if os.IsPermission(err) {
				return fmt.Errorf("can't stat '%s'", filePath)
			}
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}

		// skip checking if symlinks point to non-existing files, such symlinks can be useful
		// also skip named pipes, because they hanging on open
		if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
			return nil
		}

		if !f.IsDir() {
			currentFile, err := os.Open(filePath)
			if err != nil && os.IsPermission(err) {
				return fmt.Errorf("no permission to read from '%s'", filePath)
			}
			currentFile.Close()
		}
		return nil
	})
}

func parseDockerignore(root string) ([]string, error) {
	var excludes []string
	ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore"))
	if err != nil && !os.IsNotExist(err) {
		return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err)
	}
	for _, pattern := range strings.Split(string(ignore), "\n") {
		matches, err := filepath.Match(pattern, "Dockerfile")
		if err != nil {
			return excludes, fmt.Errorf("bad .dockerignore pattern: '%s', error: %s", pattern, err)
		}
		if matches {
			return excludes, fmt.Errorf("dockerfile was excluded by .dockerignore pattern '%s'", pattern)
		}
		excludes = append(excludes, pattern)
	}

	return excludes, nil
}
<|endoftext|>


<commit_before>package plugin

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
)

// GRPCServiceName is the name of the service that the health check should
// return as passing.
const GRPCServiceName = "plugin"

// DefaultGRPCServer can be used with the "GRPCServer" field for Server
// as a default factory method to create a gRPC server with no extra options.
func DefaultGRPCServer(opts []grpc.ServerOption) *grpc.Server {
	return grpc.NewServer(opts...)
}

// GRPCServer is a ServerType implementation that serves plugins over
// gRPC. This allows plugins to easily be written for other languages.
//
// The GRPCServer outputs a custom configuration as a base64-encoded
// JSON structure represented by the GRPCServerConfig config structure.
type GRPCServer struct {
	// Plugins are the list of plugins to serve.
	Plugins map[string]Plugin

	// Server is the actual server that will accept connections. This
	// will be used for plugin registration as well.
	Server func([]grpc.ServerOption) *grpc.Server

	// TLS should be the TLS configuration if available. If this is nil,
	// the connection will not have transport security.
	TLS *tls.Config

	// DoneCh is the channel that is closed when this server has exited.
	DoneCh chan struct{}

	// Stdout/StderrLis are the readers for stdout/stderr that will be copied
	// to the stdout/stderr connection that is output.
	Stdout io.Reader
	Stderr io.Reader

	config GRPCServerConfig
	server *grpc.Server
	broker *GRPCBroker
}

// ServerProtocol impl.
func (s *GRPCServer) Init() error {
	// Create our server
	var opts []grpc.ServerOption
	if s.TLS != nil {
		opts = append(opts, grpc.Creds(credentials.NewTLS(s.TLS)))
	}
	s.server = s.Server(opts)

	// Register the health service
	healthCheck := health.NewServer()
	healthCheck.SetServingStatus(
		GRPCServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
	grpc_health_v1.RegisterHealthServer(s.server, healthCheck)

	// Register the broker service
	brokerServer := newGRPCBrokerServer()
	RegisterGRPCBrokerServer(s.server, brokerServer)
	s.broker = newGRPCBroker(brokerServer, s.TLS)
	go s.broker.Run()

	// Register all our plugins onto the gRPC server.
	for k, raw := range s.Plugins {
		p, ok := raw.(GRPCPlugin)
		if !ok {
			return fmt.Errorf("%q is not a GRPC-compatibile plugin", k)
		}

		if err := p.GRPCServer(s.broker, s.server); err != nil {
			return fmt.Errorf("error registring %q: %s", k, err)
		}
	}

	return nil
}

// Config is the GRPCServerConfig encoded as JSON then base64.
func (s *GRPCServer) Config() string {
	// Create a buffer that will contain our final contents
	var buf bytes.Buffer

	// Wrap the base64 encoding with JSON encoding.
	if err := json.NewEncoder(&buf).Encode(s.config); err != nil {
		// We panic since ths shouldn't happen under any scenario. We
		// carefully control the structure being encoded here and it should
		// always be successful.
		panic(err)
	}

	return buf.String()
}

func (s *GRPCServer) Serve(lis net.Listener) {
	// Start serving in a goroutine
	go s.server.Serve(lis)

	// Wait until graceful completion
	<-s.DoneCh
}

// GRPCServerConfig is the extra configuration passed along for consumers
// to facilitate using GRPC plugins.
type GRPCServerConfig struct {
	StdoutAddr string `json:"stdout_addr"`
	StderrAddr string `json:"stderr_addr"`
}
<commit_msg>Fix small typo in gRPC plugin error message<commit_after>package plugin

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
)

// GRPCServiceName is the name of the service that the health check should
// return as passing.
const GRPCServiceName = "plugin"

// DefaultGRPCServer can be used with the "GRPCServer" field for Server
// as a default factory method to create a gRPC server with no extra options.
func DefaultGRPCServer(opts []grpc.ServerOption) *grpc.Server {
	return grpc.NewServer(opts...)
}

// GRPCServer is a ServerType implementation that serves plugins over
// gRPC. This allows plugins to easily be written for other languages.
//
// The GRPCServer outputs a custom configuration as a base64-encoded
// JSON structure represented by the GRPCServerConfig config structure.
type GRPCServer struct {
	// Plugins are the list of plugins to serve.
	Plugins map[string]Plugin

	// Server is the actual server that will accept connections. This
	// will be used for plugin registration as well.
	Server func([]grpc.ServerOption) *grpc.Server

	// TLS should be the TLS configuration if available. If this is nil,
	// the connection will not have transport security.
	TLS *tls.Config

	// DoneCh is the channel that is closed when this server has exited.
	DoneCh chan struct{}

	// Stdout/StderrLis are the readers for stdout/stderr that will be copied
	// to the stdout/stderr connection that is output.
	Stdout io.Reader
	Stderr io.Reader

	config GRPCServerConfig
	server *grpc.Server
	broker *GRPCBroker
}

// ServerProtocol impl.
func (s *GRPCServer) Init() error {
	// Create our server
	var opts []grpc.ServerOption
	if s.TLS != nil {
		opts = append(opts, grpc.Creds(credentials.NewTLS(s.TLS)))
	}
	s.server = s.Server(opts)

	// Register the health service
	healthCheck := health.NewServer()
	healthCheck.SetServingStatus(
		GRPCServiceName, grpc_health_v1.HealthCheckResponse_SERVING)
	grpc_health_v1.RegisterHealthServer(s.server, healthCheck)

	// Register the broker service
	brokerServer := newGRPCBrokerServer()
	RegisterGRPCBrokerServer(s.server, brokerServer)
	s.broker = newGRPCBroker(brokerServer, s.TLS)
	go s.broker.Run()

	// Register all our plugins onto the gRPC server.
	for k, raw := range s.Plugins {
		p, ok := raw.(GRPCPlugin)
		if !ok {
			return fmt.Errorf("%q is not a GRPC-compatible plugin", k)
		}

		if err := p.GRPCServer(s.broker, s.server); err != nil {
			return fmt.Errorf("error registring %q: %s", k, err)
		}
	}

	return nil
}

// Config is the GRPCServerConfig encoded as JSON then base64.
func (s *GRPCServer) Config() string {
	// Create a buffer that will contain our final contents
	var buf bytes.Buffer

	// Wrap the base64 encoding with JSON encoding.
	if err := json.NewEncoder(&buf).Encode(s.config); err != nil {
		// We panic since ths shouldn't happen under any scenario. We
		// carefully control the structure being encoded here and it should
		// always be successful.
		panic(err)
	}

	return buf.String()
}

func (s *GRPCServer) Serve(lis net.Listener) {
	// Start serving in a goroutine
	go s.server.Serve(lis)

	// Wait until graceful completion
	<-s.DoneCh
}

// GRPCServerConfig is the extra configuration passed along for consumers
// to facilitate using GRPC plugins.
type GRPCServerConfig struct {
	StdoutAddr string `json:"stdout_addr"`
	StderrAddr string `json:"stderr_addr"`
}
<|endoftext|>


<commit_before>package gtk3

/*
#include <gtk/gtk.h>
#include <glib-object.h>

static GtkWidget* to_GtkWidget(void* obj) { return GTK_WIDGET(obj); }

*/
import "C"
import "unsafe"
import "github.com/norisatir/go-gtk3/gobject"
import "github.com/norisatir/go-gtk3/gdk3"

type Allocation struct {
	object *C.GtkAllocation
}

type Requisition struct {
	Width, Height int
}

func (self Requisition) ToNative() unsafe.Pointer {
	var req C.GtkRequisition
	req.width = C.gint(self.Width)
	req.height = C.gint(self.Height)
	return unsafe.Pointer(&req)
}

// Widget-like interface must have method Widget
type WidgetLike interface {
	W() *Widget
	gobject.ObjectLike
}

func NewWidget(o unsafe.Pointer) *Widget {
	return &Widget{C.to_GtkWidget(o)}
}

// Widget Type
type Widget struct {
	object *C.GtkWidget
}

// To be object-like
func (self Widget) ToNative() unsafe.Pointer {
	return unsafe.Pointer(self.object)
}

func (self Widget) Connect(s string, f interface{}, datas ...interface{}) {
	gobject.Connect(self, s, f, datas...)
}

func (self Widget) Set(properties map[string]interface{}) {
	gobject.Set(self, properties)
}

func (self Widget) Get(properties []string) map[string]interface{} {
	return gobject.Get(self, properties)
}

// Widget standard funcs
func (self *Widget) Show() {
	C.gtk_widget_show(self.object)
}

func (self *Widget) ShowNow() {
	C.gtk_widget_show_now(self.object)
}

func (self *Widget) ShowAll() {
	C.gtk_widget_show_all(self.object)
}

func (self *Widget) Destroy() {
	C.gtk_widget_destroy(self.object)
}

func (self *Widget) InDestruction() bool {
	b := C.gtk_widget_in_destruction(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) Hide() {
	C.gtk_widget_hide(self.object)
}

func (self *Widget) Activate() bool {
	b := C.gtk_widget_activate(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) Reparent(new_parent WidgetLike) {
	C.gtk_widget_reparent(self.object, new_parent.W().object)
}

func (self *Widget) IsFocus() bool {
	b := C.gtk_widget_is_focus(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) GrabFocus() {
	C.gtk_widget_grab_focus(self.object)
}

func (self *Widget) GrabDefault() {
	C.gtk_widget_grab_default(self.object)
}

func (self *Widget) SetName(name string) {
	gobject.SetProperty(self, "name", name)
}

func (self *Widget) GetName() string {
	n := gobject.GetProperty(self, "name")
	defer n.Free()
	return gobject.GoString(n.GetPtr())
}

func (self *Widget) SetSensitive(sensitive bool) {
	gobject.SetProperty(self, "sensitive", sensitive)
}

func (self *Widget) SetParent(parent WidgetLike) {
	C.gtk_widget_set_parent(self.object, parent.W().object)
}

func (self *Widget) GetTopLevel() WidgetLike {
	w := C.gtk_widget_get_toplevel(self.object)
	if tl, err := gobject.ConvertToGo(unsafe.Pointer(&w)); err == nil {
		return tl.(WidgetLike)
	}
	return nil
}

func (self *Widget) GetAncestor(widget_type gobject.GType) WidgetLike {
	w := C.gtk_widget_get_ancestor(self.object, C.GType(widget_type))
	if w == nil {
		return nil
	}
	if par, err := gobject.ConvertToGo(unsafe.Pointer(&w)); err == nil {
		return par.(WidgetLike)
	}
	return nil
}

func (self *Widget) GetPreferredSize() (minimumSize, naturalSize Requisition) {
	var min, nat C.GtkRequisition
	C.gtk_widget_get_preferred_size(self.object, &min, &nat)

	minimumSize = Requisition{int(min.width), int(min.height)}
	naturalSize = Requisition{int(nat.width), int(nat.height)}
	return
}

func (self *Widget) SetEvents(events gdk3.GdkEventMask) {
	C.gtk_widget_set_events(self.object, C.gint(events))
}

func (self *Widget) AddEvents(events gdk3.GdkEventMask) {
	C.gtk_widget_add_events(self.object, C.gint(events))
}

func (self *Widget) GetEvents() gdk3.GdkEventMask {
	return gdk3.GdkEventMask(C.gtk_widget_get_events(self.object))
}
<commit_msg>Added Map/Unmap to widget struct<commit_after>package gtk3

/*
#include <gtk/gtk.h>
#include <glib-object.h>

static GtkWidget* to_GtkWidget(void* obj) { return GTK_WIDGET(obj); }

*/
import "C"
import "unsafe"
import "github.com/norisatir/go-gtk3/gobject"
import "github.com/norisatir/go-gtk3/gdk3"

type Allocation struct {
	object *C.GtkAllocation
}

type Requisition struct {
	Width, Height int
}

func (self Requisition) ToNative() unsafe.Pointer {
	var req C.GtkRequisition
	req.width = C.gint(self.Width)
	req.height = C.gint(self.Height)
	return unsafe.Pointer(&req)
}

// Widget-like interface must have method Widget
type WidgetLike interface {
	W() *Widget
	gobject.ObjectLike
}

func NewWidget(o unsafe.Pointer) *Widget {
	return &Widget{C.to_GtkWidget(o)}
}

// Widget Type
type Widget struct {
	object *C.GtkWidget
}

// To be object-like
func (self Widget) ToNative() unsafe.Pointer {
	return unsafe.Pointer(self.object)
}

func (self Widget) Connect(s string, f interface{}, datas ...interface{}) {
	gobject.Connect(self, s, f, datas...)
}

func (self Widget) Set(properties map[string]interface{}) {
	gobject.Set(self, properties)
}

func (self Widget) Get(properties []string) map[string]interface{} {
	return gobject.Get(self, properties)
}

// Widget standard funcs
func (self *Widget) Show() {
	C.gtk_widget_show(self.object)
}

func (self *Widget) ShowNow() {
	C.gtk_widget_show_now(self.object)
}

func (self *Widget) ShowAll() {
	C.gtk_widget_show_all(self.object)
}

func (self *Widget) Destroy() {
	C.gtk_widget_destroy(self.object)
}

func (self *Widget) InDestruction() bool {
	b := C.gtk_widget_in_destruction(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) Hide() {
	C.gtk_widget_hide(self.object)
}

func (self *Widget) Activate() bool {
	b := C.gtk_widget_activate(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) Reparent(new_parent WidgetLike) {
	C.gtk_widget_reparent(self.object, new_parent.W().object)
}

func (self *Widget) IsFocus() bool {
	b := C.gtk_widget_is_focus(self.object)
	return gobject.GoBool(unsafe.Pointer(&b))
}

func (self *Widget) GrabFocus() {
	C.gtk_widget_grab_focus(self.object)
}

func (self *Widget) GrabDefault() {
	C.gtk_widget_grab_default(self.object)
}

func (self *Widget) SetName(name string) {
	gobject.SetProperty(self, "name", name)
}

func (self *Widget) GetName() string {
	n := gobject.GetProperty(self, "name")
	defer n.Free()
	return gobject.GoString(n.GetPtr())
}

func (self *Widget) SetSensitive(sensitive bool) {
	gobject.SetProperty(self, "sensitive", sensitive)
}

func (self *Widget) SetParent(parent WidgetLike) {
	C.gtk_widget_set_parent(self.object, parent.W().object)
}

func (self *Widget) GetTopLevel() WidgetLike {
	w := C.gtk_widget_get_toplevel(self.object)
	if tl, err := gobject.ConvertToGo(unsafe.Pointer(&w)); err == nil {
		return tl.(WidgetLike)
	}
	return nil
}

func (self *Widget) GetAncestor(widget_type gobject.GType) WidgetLike {
	w := C.gtk_widget_get_ancestor(self.object, C.GType(widget_type))
	if w == nil {
		return nil
	}
	if par, err := gobject.ConvertToGo(unsafe.Pointer(&w)); err == nil {
		return par.(WidgetLike)
	}
	return nil
}

func (self *Widget) GetPreferredSize() (minimumSize, naturalSize Requisition) {
	var min, nat C.GtkRequisition
	C.gtk_widget_get_preferred_size(self.object, &min, &nat)

	minimumSize = Requisition{int(min.width), int(min.height)}
	naturalSize = Requisition{int(nat.width), int(nat.height)}
	return
}

func (self *Widget) SetEvents(events gdk3.GdkEventMask) {
	C.gtk_widget_set_events(self.object, C.gint(events))
}

func (self *Widget) AddEvents(events gdk3.GdkEventMask) {
	C.gtk_widget_add_events(self.object, C.gint(events))
}

func (self *Widget) GetEvents() gdk3.GdkEventMask {
	return gdk3.GdkEventMask(C.gtk_widget_get_events(self.object))
}

func (self *Widget) Map() {
	C.gtk_widget_map(self.object)
}

func (self *Widget) Unmap() {
	C.gtk_widget_unmap(self.object)
}
<|endoftext|>