<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas

import (
	"fmt"
	"net/http"

	"github.com/juju/errors"
	"github.com/juju/gomaasapi"
	"github.com/juju/loggo"

	"github.com/juju/juju/cloud"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
)

// Logger for the MAAS provider.
var logger = loggo.GetLogger("juju.provider.maas")

type maasEnvironProvider struct {
	environProviderCredentials
}

var _ environs.EnvironProvider = (*maasEnvironProvider)(nil)

var providerInstance maasEnvironProvider

func (maasEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Debugf("opening model %q.", cfg.Name())
	env, err := NewEnviron(cfg)
	if err != nil {
		return nil, err
	}
	return env, nil
}

var errAgentNameAlreadySet = errors.New(
	"maas-agent-name is already set; this should not be set by hand")

// RestrictedConfigAttributes is specified in the EnvironProvider interface.
func (p maasEnvironProvider) RestrictedConfigAttributes() []string {
	return []string{"maas-server"}
}

// PrepareForCreateEnvironment is specified in the EnvironProvider interface.
func (p maasEnvironProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
	attrs := cfg.UnknownAttrs()
	oldName, found := attrs["maas-agent-name"]
	if found && oldName != "" {
		return nil, errAgentNameAlreadySet
	}
	attrs["maas-agent-name"] = cfg.UUID()
	return cfg.Apply(attrs)
}

// BootstrapConfig is specified in the EnvironProvider interface.
func (p maasEnvironProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) {
	// For MAAS, either:
	// 1. the endpoint from the cloud definition defines the MAAS server URL
	//    (if a full cloud definition had been set up)
	// 2. the region defines the MAAS server ip/host
	//    (if the bootstrap shortcut is used)
	server := args.CloudEndpoint
	if server == "" && args.CloudRegion != "" {
		server = fmt.Sprintf("http://%s/MAAS", args.CloudRegion)
	}
	if server == "" {
		return nil, errors.New("MAAS server not specified")
	}
	attrs := map[string]interface{}{
		"maas-server": server,
	}
	// Add the credentials.
	switch authType := args.Credentials.AuthType(); authType {
	case cloud.OAuth1AuthType:
		credentialAttrs := args.Credentials.Attributes()
		for k, v := range credentialAttrs {
			attrs[k] = v
		}
	default:
		return nil, errors.NotSupportedf("%q auth-type", authType)
	}
	cfg, err := args.Config.Apply(attrs)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p.PrepareForCreateEnvironment(cfg)
}

// PrepareForBootstrap is specified in the EnvironProvider interface.
func (p maasEnvironProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	env, err := p.Open(cfg)
	if err != nil {
		return nil, err
	}
	if ctx.ShouldVerifyCredentials() {
		if err := verifyCredentials(env.(*maasEnviron)); err != nil {
			return nil, err
		}
	}
	return env, nil
}

func verifyCredentials(env *maasEnviron) error {
	var err error
	// Verify we can connect to the server and authenticate.
	// TODO (mfoord): horrible hardcoded version check.
	if env.apiVersion == "2.0" {
		// TODO (mfoord): use a lighterweight endpoint than machines.
		// Could implement /api/2.0/maas/ op=get_config in new API
		// layer.
		_, err = env.maasController.Machines(gomaasapi.MachinesParams{})
	} else {
		_, err = env.getMAASClient().GetSubObject("maas").CallGet("get_config", nil)
	}
	if err, ok := errors.Cause(err).(gomaasapi.ServerError); ok && err.StatusCode == http.StatusUnauthorized {
		logger.Debugf("authentication failed: %v", err)
		return errors.New(`authentication failed.

Please ensure the credentials are correct.`)
	}
	return nil
}

// SecretAttrs is specified in the EnvironProvider interface.
func (prov maasEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	secretAttrs := make(map[string]string)
	maasCfg, err := prov.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	secretAttrs["maas-oauth"] = maasCfg.maasOAuth()
	return secretAttrs, nil
}

// DetectRegions is specified in the environs.CloudRegionDetector interface.
func (p maasEnvironProvider) DetectRegions() ([]cloud.Region, error) {
	return nil, errors.NotFoundf("regions")
}
<commit_msg>Change type<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas

import (
	"fmt"
	"net/http"

	"github.com/juju/errors"
	"github.com/juju/gomaasapi"
	"github.com/juju/loggo"

	"github.com/juju/juju/cloud"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
)

// Logger for the MAAS provider.
var logger = loggo.GetLogger("juju.provider.maas")

type maasEnvironProvider struct {
	environProviderCredentials
}

var _ environs.EnvironProvider = (*maasEnvironProvider)(nil)

var providerInstance maasEnvironProvider

func (maasEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Debugf("opening model %q.", cfg.Name())
	env, err := NewEnviron(cfg)
	if err != nil {
		return nil, err
	}
	return env, nil
}

var errAgentNameAlreadySet = errors.New(
	"maas-agent-name is already set; this should not be set by hand")

// RestrictedConfigAttributes is specified in the EnvironProvider interface.
func (p maasEnvironProvider) RestrictedConfigAttributes() []string {
	return []string{"maas-server"}
}

// PrepareForCreateEnvironment is specified in the EnvironProvider interface.
func (p maasEnvironProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
	attrs := cfg.UnknownAttrs()
	oldName, found := attrs["maas-agent-name"]
	if found && oldName != "" {
		return nil, errAgentNameAlreadySet
	}
	attrs["maas-agent-name"] = cfg.UUID()
	return cfg.Apply(attrs)
}

// BootstrapConfig is specified in the EnvironProvider interface.
func (p maasEnvironProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) {
	// For MAAS, either:
	// 1. the endpoint from the cloud definition defines the MAAS server URL
	//    (if a full cloud definition had been set up)
	// 2. the region defines the MAAS server ip/host
	//    (if the bootstrap shortcut is used)
	server := args.CloudEndpoint
	if server == "" && args.CloudRegion != "" {
		server = fmt.Sprintf("http://%s/MAAS", args.CloudRegion)
	}
	if server == "" {
		return nil, errors.New("MAAS server not specified")
	}
	attrs := map[string]interface{}{
		"maas-server": server,
	}
	// Add the credentials.
	switch authType := args.Credentials.AuthType(); authType {
	case cloud.OAuth1AuthType:
		credentialAttrs := args.Credentials.Attributes()
		for k, v := range credentialAttrs {
			attrs[k] = v
		}
	default:
		return nil, errors.NotSupportedf("%q auth-type", authType)
	}
	cfg, err := args.Config.Apply(attrs)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p.PrepareForCreateEnvironment(cfg)
}

// PrepareForBootstrap is specified in the EnvironProvider interface.
func (p maasEnvironProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	env, err := p.Open(cfg)
	if err != nil {
		return nil, err
	}
	if ctx.ShouldVerifyCredentials() {
		if err := verifyCredentials(env.(*maasEnviron)); err != nil {
			return nil, err
		}
	}
	return env, nil
}

func verifyCredentials(env *maasEnviron) error {
	var err error
	// Verify we can connect to the server and authenticate.
	// TODO (mfoord): horrible hardcoded version check.
	if env.apiVersion == "2.0" {
		// TODO (mfoord): use a lighterweight endpoint than machines.
		// Could implement /api/2.0/maas/ op=get_config in new API
		// layer.
		_, err = env.maasController.Machines(gomaasapi.MachinesArgs{})
	} else {
		_, err = env.getMAASClient().GetSubObject("maas").CallGet("get_config", nil)
	}
	if err, ok := errors.Cause(err).(gomaasapi.ServerError); ok && err.StatusCode == http.StatusUnauthorized {
		logger.Debugf("authentication failed: %v", err)
		return errors.New(`authentication failed.

Please ensure the credentials are correct.`)
	}
	return nil
}

// SecretAttrs is specified in the EnvironProvider interface.
func (prov maasEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	secretAttrs := make(map[string]string)
	maasCfg, err := prov.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	secretAttrs["maas-oauth"] = maasCfg.maasOAuth()
	return secretAttrs, nil
}

// DetectRegions is specified in the environs.CloudRegionDetector interface.
func (p maasEnvironProvider) DetectRegions() ([]cloud.Region, error) {
	return nil, errors.NotFoundf("regions")
}
<|endoftext|>


<commit_before>//  Copyright (c) 2015 ikawaha.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package dic

import (
	"bytes"
	"sync"

	"github.com/ikawaha/kagome/internal/dic/data"
)

const (
	IPADicPath = "dic/ipa"
)

var (
	sysDicIPA     *Dic
	initSysDicIPA sync.Once
)

// SysDic returns the kagome system dictionary.
func SysDic() *Dic {
	return SysDicIPA()
}

// SysDicIPA returns the IPA system dictionary.
func SysDicIPA() *Dic {
	initSysDicIPA.Do(func() {
		sysDicIPA = loadInternalSysDic(IPADicPath)
	})
	return sysDicIPA
}

func loadInternalSysDic(path string) (d *Dic) {
	d = new(Dic)
	var (
		buf []byte
		err error
	)
	// morph.dic
	if buf, err = data.Asset(path + "/morph.dic"); err != nil {
		panic(err)
	}
	if err = d.loadMorphDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// index.dic
	if buf, err = data.Asset(path + "/index.dic"); err != nil {
		panic(err)
	}
	if err = d.loadIndexDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// connection.dic
	if buf, err = data.Asset(path + "/connection.dic"); err != nil {
		panic(err)
	}
	if err = d.loadConnectionDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// chardef.dic
	if buf, err = data.Asset(path + "/chardef.dic"); err != nil {
		panic(err)
	}
	if err = d.loadCharDefDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// unk.dic
	if buf, err = data.Asset(path + "/unk.dic"); err != nil {
		panic(err)
	}
	if err = d.loadUnkDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	return
}

/*
func loadInternalSysDic(path string) (d *Dic) {
	d = new(Dic)
	if err := func() error {
		buf, e := data.Asset(path + "/morph.dic")
		if e != nil {
			return e
		}
		dec := gob.NewDecoder(bytes.NewBuffer(buf))
		if e = dec.Decode(&d.Morphs); e != nil {
			return fmt.Errorf("dic initializer, Morphs: %v", e)
		}
		if e = dec.Decode(&d.Contents); e != nil {
			return fmt.Errorf("dic initializer, Contents: %v", e)
		}
		return nil
	}(); err != nil {
		panic(err)
	}

	if err := func() error {
		buf, e := data.Asset(path + "/index.dic")
		if e != nil {
			return e
		}
		t, e := fst.Read(bytes.NewReader(buf))
		if e != nil {
			return fmt.Errorf("dic initializer, Index: %v", e)
		}
		d.Index = t
		return nil
	}(); err != nil {
		panic(err)
	}

	if err := func() error {
		buf, e := data.Asset(path + "/connection.dic")
		if e != nil {
			return e
		}
		dec := gob.NewDecoder(bytes.NewBuffer(buf))
		if e = dec.Decode(&d.Connection); e != nil {
			return fmt.Errorf("dic initializer, Connection: %v", e)
		}
		return nil
	}(); err != nil {
		panic(err)
	}

	if err := func() error {
		buf, e := data.Asset(path + "/chardef.dic")
		if e != nil {
			return e
		}
		dec := gob.NewDecoder(bytes.NewBuffer(buf))
		if e = dec.Decode(&d.CharClass); e != nil {
			return fmt.Errorf("dic initializer, CharClass: %v", e)
		}
		if e = dec.Decode(&d.CharCategory); e != nil {
			return fmt.Errorf("dic initializer, CharCategory: %v", e)
		}
		if e = dec.Decode(&d.InvokeList); e != nil {
			return fmt.Errorf("dic initializer, InvokeList: %v", e)
		}
		if e = dec.Decode(&d.GroupList); e != nil {
			return fmt.Errorf("dic initializer, GroupList: %v", e)
		}
		return nil
	}(); err != nil {
		panic(err)
	}

	if err := func() error {
		buf, e := data.Asset(path + "/unk.dic")
		if e != nil {
			return e
		}
		dec := gob.NewDecoder(bytes.NewBuffer(buf))
		if e = dec.Decode(&d.UnkMorphs); e != nil {
			return fmt.Errorf("dic initializer, UnkMorphs: %v", e)
		}
		if e = dec.Decode(&d.UnkIndex); e != nil {
			return fmt.Errorf("dic initializer, UnkIndex: %v", e)
		}
		if e = dec.Decode(&d.UnkIndexDup); e != nil {
			return fmt.Errorf("dic initializer, UnkIndexDup: %v", e)
		}
		if e = dec.Decode(&d.UnkContents); e != nil {
			return fmt.Errorf("dic initializer, UnkContents: %v", e)
		}
		return nil
	}(); err != nil {
		panic(err)
	}
	return
}
*/
<commit_msg>Remove useless comments<commit_after>//  Copyright (c) 2015 ikawaha.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package dic

import (
	"bytes"
	"sync"

	"github.com/ikawaha/kagome/internal/dic/data"
)

const (
	IPADicPath = "dic/ipa"
)

var (
	sysDicIPA     *Dic
	initSysDicIPA sync.Once
)

// SysDic returns the kagome system dictionary.
func SysDic() *Dic {
	return SysDicIPA()
}

// SysDicIPA returns the IPA system dictionary.
func SysDicIPA() *Dic {
	initSysDicIPA.Do(func() {
		sysDicIPA = loadInternalSysDic(IPADicPath)
	})
	return sysDicIPA
}

func loadInternalSysDic(path string) (d *Dic) {
	d = new(Dic)
	var (
		buf []byte
		err error
	)
	// morph.dic
	if buf, err = data.Asset(path + "/morph.dic"); err != nil {
		panic(err)
	}
	if err = d.loadMorphDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// index.dic
	if buf, err = data.Asset(path + "/index.dic"); err != nil {
		panic(err)
	}
	if err = d.loadIndexDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// connection.dic
	if buf, err = data.Asset(path + "/connection.dic"); err != nil {
		panic(err)
	}
	if err = d.loadConnectionDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// chardef.dic
	if buf, err = data.Asset(path + "/chardef.dic"); err != nil {
		panic(err)
	}
	if err = d.loadCharDefDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	// unk.dic
	if buf, err = data.Asset(path + "/unk.dic"); err != nil {
		panic(err)
	}
	if err = d.loadUnkDicPart(bytes.NewBuffer(buf)); err != nil {
		panic(err)
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build darwin freebsd linux windows
// +build !js
// +build !android
// +build !ios

package ui

import (
	"errors"
	"runtime"
	"sync"
	"time"

	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

type userInterface struct {
	window      *glfw.Window
	width       int
	height      int
	scale       float64
	deviceScale float64
	glfwScale   float64
	fullscreen  bool
	funcs       chan func()
	running     bool
	sizeChanged bool
	origPosX    int
	origPosY    int
	m           sync.Mutex
}

var currentUI *userInterface

func init() {
	if err := initialize(); err != nil {
		panic(err)
	}
}

func initialize() error {
	runtime.LockOSThread()

	if err := glfw.Init(); err != nil {
		return err
	}
	glfw.WindowHint(glfw.Visible, glfw.False)
	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 2)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)

	// As start, create an window with temporary size to create OpenGL context thread.
	window, err := glfw.CreateWindow(16, 16, "", nil, nil)
	if err != nil {
		return err
	}
	hideConsoleWindowOnWindows()
	u := &userInterface{
		window:      window,
		funcs:       make(chan func()),
		sizeChanged: true,
		origPosX:    -1,
		origPosY:    -1,
	}
	u.window.MakeContextCurrent()
	glfw.SwapInterval(1)
	currentUI = u
	return nil
}

func RunMainThreadLoop(ch <-chan error) error {
	// TODO: Check this is done on the main thread.
	currentUI.setRunning(true)
	defer func() {
		currentUI.setRunning(false)
	}()
	for {
		select {
		case f := <-currentUI.funcs:
			f()
		case err := <-ch:
			// ch returns a value not only when an error occur but also it is closed.
			return err
		}
	}
}

func (u *userInterface) isRunning() bool {
	u.m.Lock()
	defer u.m.Unlock()
	return u.running
}

func (u *userInterface) setRunning(running bool) {
	u.m.Lock()
	defer u.m.Unlock()
	u.running = running
}

func (u *userInterface) runOnMainThread(f func() error) error {
	if u.funcs == nil {
		// already closed
		return nil
	}
	ch := make(chan struct{})
	var err error
	u.funcs <- func() {
		err = f()
		close(ch)
	}
	<-ch
	return err
}

func SetScreenSize(width, height int) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(width, height, u.scale, u.fullscreen)
		return nil
	})
	return r
}

func SetScreenScale(scale float64) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(u.width, u.height, scale, u.fullscreen)
		return nil
	})
	return r
}

func SetFullscreen(fullscreen bool) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(u.width, u.height, u.scale, fullscreen)
		return nil
	})
	return r
}

func ScreenScale() float64 {
	u := currentUI
	if !u.isRunning() {
		return 0
	}
	s := 0.0
	_ = u.runOnMainThread(func() error {
		s = u.scale
		return nil
	})
	return s
}

func IsFullscreen() bool {
	u := currentUI
	if !u.isRunning() {
		return false
	}
	f := false
	_ = u.runOnMainThread(func() error {
		f = u.fullscreen
		return nil
	})
	return f
}

func SetCursorVisibility(visible bool) {
	// This can be called before Run: change the state asyncly.
	go func() {
		_ = currentUI.runOnMainThread(func() error {
			c := glfw.CursorNormal
			if !visible {
				c = glfw.CursorHidden
			}
			currentUI.window.SetInputMode(glfw.CursorMode, c)
			return nil
		})
	}()
}

func Run(width, height int, scale float64, title string, g GraphicsContext) error {
	u := currentUI
	// GLContext must be created before setting the screen size, which requires
	// swapping buffers.
	opengl.Init(currentUI.runOnMainThread)
	if err := u.runOnMainThread(func() error {
		m := glfw.GetPrimaryMonitor()
		v := m.GetVideoMode()
		if !u.setScreenSize(width, height, scale, false) {
			return errors.New("ui: Fail to set the screen size")
		}
		u.window.SetTitle(title)
		u.window.Show()

		w, h := u.glfwSize()
		x := (v.Width - w) / 2
		y := (v.Height - h) / 3
		x, y = adjustWindowPosition(x, y)
		u.window.SetPos(x, y)
		return nil
	}); err != nil {
		return err
	}
	return u.loop(g)
}

func (u *userInterface) glfwSize() (int, int) {
	if u.glfwScale == 0 {
		u.glfwScale = glfwScale()
	}
	return int(float64(u.width) * u.scale * u.glfwScale), int(float64(u.height) * u.scale * u.glfwScale)
}

func (u *userInterface) actualScreenScale() float64 {
	if u.deviceScale == 0 {
		u.deviceScale = deviceScale()
	}
	return u.scale * u.deviceScale
}

func (u *userInterface) pollEvents() {
	glfw.PollEvents()
	if u.glfwScale == 0 {
		u.glfwScale = glfwScale()
	}
	currentInput.update(u.window, u.scale*u.glfwScale)
}

func (u *userInterface) update(g GraphicsContext) error {
	shouldClose := false
	_ = u.runOnMainThread(func() error {
		shouldClose = u.window.ShouldClose()
		return nil
	})
	if shouldClose {
		return &RegularTermination{}
	}

	actualScale := 0.0
	_ = u.runOnMainThread(func() error {
		if !u.sizeChanged {
			return nil
		}
		u.sizeChanged = false
		actualScale = u.actualScreenScale()
		return nil
	})
	if 0 < actualScale {
		g.SetSize(u.width, u.height, actualScale)
	}

	_ = u.runOnMainThread(func() error {
		u.pollEvents()
		for u.window.GetAttrib(glfw.Focused) == 0 {
			// Wait for an arbitrary period to avoid busy loop.
			time.Sleep(time.Second / 60)
			u.pollEvents()
			if u.window.ShouldClose() {
				return nil
			}
		}
		return nil
	})
	if err := g.Update(); err != nil {
		return err
	}
	return nil
}

func (u *userInterface) loop(g GraphicsContext) error {
	defer func() {
		_ = u.runOnMainThread(func() error {
			glfw.Terminate()
			return nil
		})
	}()
	for {
		if err := u.update(g); err != nil {
			return err
		}
		// The bound framebuffer must be the default one (0) before swapping buffers.
		if err := opengl.GetContext().BindScreenFramebuffer(); err != nil {
			return err
		}
		_ = u.runOnMainThread(func() error {
			u.swapBuffers()
			return nil
		})
	}
}

func (u *userInterface) swapBuffers() {
	u.window.SwapBuffers()
}

func (u *userInterface) setScreenSize(width, height int, scale float64, fullscreen bool) bool {
	if u.width == width && u.height == height && u.scale == scale && u.fullscreen == fullscreen {
		return false
	}

	origScale := u.scale
	u.scale = scale

	// On Windows, giving a too small width doesn't call a callback (#165).
	// To prevent hanging up, return asap if the width is too small.
	// 252 is an arbitrary number and I guess this is small enough.
	// TODO: The same check should be in ui_js.go
	const minWindowWidth = 252
	if int(float64(width)*u.actualScreenScale()) < minWindowWidth {
		u.scale = origScale
		return false
	}
	u.width = width
	u.height = height

	// To make sure the current existing framebuffers are rendered,
	// swap buffers here before SetSize is called.
	u.swapBuffers()

	u.fullscreen = fullscreen

	window := u.window
	m := glfw.GetPrimaryMonitor()
	v := m.GetVideoMode()
	if u.fullscreen {
		u.origPosX, u.origPosY = window.GetPos()
		window.SetMonitor(m, 0, 0, v.Width, v.Height, v.RefreshRate)
	} else {
		window.SetMonitor(nil, 0, 0, 16, 16, v.RefreshRate)
		ch := make(chan struct{})
		window.SetFramebufferSizeCallback(func(_ *glfw.Window, width, height int) {
			window.SetFramebufferSizeCallback(nil)
			close(ch)
		})
		w, h := u.glfwSize()
		window.SetSize(w, h)
	event:
		for {
			glfw.PollEvents()
			select {
			case <-ch:
				break event
			default:
			}
		}
		// Reverted from fullscreen
		if u.origPosX >= 0 && u.origPosY >= 0 {
			window.SetPos(u.origPosX, u.origPosY)
		}
	}
	// TODO: Rename this variable?
	u.sizeChanged = true
	return true
}
<commit_msg>ui: Adjust fullscreen scale (#267)<commit_after>// Copyright 2015 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build darwin freebsd linux windows
// +build !js
// +build !android
// +build !ios

package ui

import (
	"errors"
	"runtime"
	"sync"
	"time"

	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

type userInterface struct {
	window          *glfw.Window
	width           int
	height          int
	scale           float64
	deviceScale     float64
	glfwScale       float64
	fullscreen      bool
	fullscreenScale float64
	funcs           chan func()
	running         bool
	sizeChanged     bool
	origPosX        int
	origPosY        int
	m               sync.Mutex
}

var currentUI *userInterface

func init() {
	if err := initialize(); err != nil {
		panic(err)
	}
}

func initialize() error {
	runtime.LockOSThread()

	if err := glfw.Init(); err != nil {
		return err
	}
	glfw.WindowHint(glfw.Visible, glfw.False)
	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 2)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)

	// As start, create an window with temporary size to create OpenGL context thread.
	window, err := glfw.CreateWindow(16, 16, "", nil, nil)
	if err != nil {
		return err
	}
	hideConsoleWindowOnWindows()
	u := &userInterface{
		window:      window,
		funcs:       make(chan func()),
		sizeChanged: true,
		origPosX:    -1,
		origPosY:    -1,
	}
	u.window.MakeContextCurrent()
	glfw.SwapInterval(1)
	currentUI = u
	return nil
}

func RunMainThreadLoop(ch <-chan error) error {
	// TODO: Check this is done on the main thread.
	currentUI.setRunning(true)
	defer func() {
		currentUI.setRunning(false)
	}()
	for {
		select {
		case f := <-currentUI.funcs:
			f()
		case err := <-ch:
			// ch returns a value not only when an error occur but also it is closed.
			return err
		}
	}
}

func (u *userInterface) isRunning() bool {
	u.m.Lock()
	defer u.m.Unlock()
	return u.running
}

func (u *userInterface) setRunning(running bool) {
	u.m.Lock()
	defer u.m.Unlock()
	u.running = running
}

func (u *userInterface) runOnMainThread(f func() error) error {
	if u.funcs == nil {
		// already closed
		return nil
	}
	ch := make(chan struct{})
	var err error
	u.funcs <- func() {
		err = f()
		close(ch)
	}
	<-ch
	return err
}

func SetScreenSize(width, height int) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(width, height, u.scale, u.fullscreen)
		return nil
	})
	return r
}

func SetScreenScale(scale float64) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(u.width, u.height, scale, u.fullscreen)
		return nil
	})
	return r
}

func SetFullscreen(fullscreen bool) bool {
	u := currentUI
	if !u.isRunning() {
		panic("ui: Run is not called yet")
	}
	r := false
	_ = u.runOnMainThread(func() error {
		r = u.setScreenSize(u.width, u.height, u.scale, fullscreen)
		return nil
	})
	return r
}

func ScreenScale() float64 {
	u := currentUI
	if !u.isRunning() {
		return 0
	}
	s := 0.0
	_ = u.runOnMainThread(func() error {
		s = u.scale
		return nil
	})
	return s
}

func IsFullscreen() bool {
	u := currentUI
	if !u.isRunning() {
		return false
	}
	f := false
	_ = u.runOnMainThread(func() error {
		f = u.fullscreen
		return nil
	})
	return f
}

func SetCursorVisibility(visible bool) {
	// This can be called before Run: change the state asyncly.
	go func() {
		_ = currentUI.runOnMainThread(func() error {
			c := glfw.CursorNormal
			if !visible {
				c = glfw.CursorHidden
			}
			currentUI.window.SetInputMode(glfw.CursorMode, c)
			return nil
		})
	}()
}

func Run(width, height int, scale float64, title string, g GraphicsContext) error {
	u := currentUI
	// GLContext must be created before setting the screen size, which requires
	// swapping buffers.
	opengl.Init(currentUI.runOnMainThread)
	if err := u.runOnMainThread(func() error {
		m := glfw.GetPrimaryMonitor()
		v := m.GetVideoMode()
		if !u.setScreenSize(width, height, scale, false) {
			return errors.New("ui: Fail to set the screen size")
		}
		u.window.SetTitle(title)
		u.window.Show()

		w, h := u.glfwSize()
		x := (v.Width - w) / 2
		y := (v.Height - h) / 3
		x, y = adjustWindowPosition(x, y)
		u.window.SetPos(x, y)
		return nil
	}); err != nil {
		return err
	}
	return u.loop(g)
}

func (u *userInterface) glfwSize() (int, int) {
	if u.glfwScale == 0 {
		u.glfwScale = glfwScale()
	}
	return int(float64(u.width) * u.scale * u.glfwScale), int(float64(u.height) * u.scale * u.glfwScale)
}

func (u *userInterface) actualScreenScale() float64 {
	if u.deviceScale == 0 {
		u.deviceScale = deviceScale()
	}
	if u.fullscreen {
		if u.fullscreenScale == 0 {
			m := glfw.GetPrimaryMonitor()
			v := m.GetVideoMode()
			sw := float64(v.Width) / float64(u.width)
			sh := float64(v.Height) / float64(u.height)
			s := sw
			if s > sh {
				s = sh
			}
			u.fullscreenScale = s
		}
		return u.fullscreenScale * u.deviceScale
	}
	return u.scale * u.deviceScale
}

func (u *userInterface) pollEvents() {
	glfw.PollEvents()
	if u.glfwScale == 0 {
		u.glfwScale = glfwScale()
	}
	currentInput.update(u.window, u.scale*u.glfwScale)
}

func (u *userInterface) update(g GraphicsContext) error {
	shouldClose := false
	_ = u.runOnMainThread(func() error {
		shouldClose = u.window.ShouldClose()
		return nil
	})
	if shouldClose {
		return &RegularTermination{}
	}

	actualScale := 0.0
	_ = u.runOnMainThread(func() error {
		if !u.sizeChanged {
			return nil
		}
		u.sizeChanged = false
		actualScale = u.actualScreenScale()
		return nil
	})
	if 0 < actualScale {
		g.SetSize(u.width, u.height, actualScale)
	}

	_ = u.runOnMainThread(func() error {
		u.pollEvents()
		for u.window.GetAttrib(glfw.Focused) == 0 {
			// Wait for an arbitrary period to avoid busy loop.
			time.Sleep(time.Second / 60)
			u.pollEvents()
			if u.window.ShouldClose() {
				return nil
			}
		}
		return nil
	})
	if err := g.Update(); err != nil {
		return err
	}
	return nil
}

func (u *userInterface) loop(g GraphicsContext) error {
	defer func() {
		_ = u.runOnMainThread(func() error {
			glfw.Terminate()
			return nil
		})
	}()
	for {
		if err := u.update(g); err != nil {
			return err
		}
		// The bound framebuffer must be the default one (0) before swapping buffers.
		if err := opengl.GetContext().BindScreenFramebuffer(); err != nil {
			return err
		}
		_ = u.runOnMainThread(func() error {
			u.swapBuffers()
			return nil
		})
	}
}

func (u *userInterface) swapBuffers() {
	u.window.SwapBuffers()
}

func (u *userInterface) setScreenSize(width, height int, scale float64, fullscreen bool) bool {
	if u.width == width && u.height == height && u.scale == scale && u.fullscreen == fullscreen {
		return false
	}

	origScale := u.scale
	u.scale = scale

	// On Windows, giving a too small width doesn't call a callback (#165).
	// To prevent hanging up, return asap if the width is too small.
	// 252 is an arbitrary number and I guess this is small enough.
	// TODO: The same check should be in ui_js.go
	const minWindowWidth = 252
	if int(float64(width)*u.actualScreenScale()) < minWindowWidth {
		u.scale = origScale
		return false
	}
	u.width = width
	u.height = height

	// To make sure the current existing framebuffers are rendered,
	// swap buffers here before SetSize is called.
	u.swapBuffers()

	u.fullscreen = fullscreen

	window := u.window
	m := glfw.GetPrimaryMonitor()
	v := m.GetVideoMode()
	if u.fullscreen {
		u.origPosX, u.origPosY = window.GetPos()
		window.SetMonitor(m, 0, 0, v.Width, v.Height, v.RefreshRate)
	} else {
		window.SetMonitor(nil, 0, 0, 16, 16, v.RefreshRate)
		ch := make(chan struct{})
		window.SetFramebufferSizeCallback(func(_ *glfw.Window, width, height int) {
			window.SetFramebufferSizeCallback(nil)
			close(ch)
		})
		w, h := u.glfwSize()
		window.SetSize(w, h)
	event:
		for {
			glfw.PollEvents()
			select {
			case <-ch:
				break event
			default:
			}
		}
		// Reverted from fullscreen
		if u.origPosX >= 0 && u.origPosY >= 0 {
			window.SetPos(u.origPosX, u.origPosY)
		}
	}
	// TODO: Rename this variable?
	u.sizeChanged = true
	return true
}
<|endoftext|>


<commit_before>/*
 * gomacro - A Go intepreter with Lisp-like macros
 *
 * Copyright (C) 2017 Massimiliano Ghilardi
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * literal.go
 *
 *  Created on: Feb 13, 2017
 *      Author: Massimiliano Ghilardi
 */

package interpreter

import (
	"go/ast"
	"go/constant"
	"go/token"
	r "reflect"
	"strconv"
	"strings"
)

var Unknown = constant.MakeUnknown()

func (env *Env) evalLiteral0(node *ast.BasicLit) interface{} {
	kind := node.Kind
	str := node.Value
	var ret interface{}

	switch kind {

	case token.INT:
		if strings.HasPrefix(str, "-") {
			i64, err := strconv.ParseInt(str, 0, 0)
			if err != nil {
				return Error(err)
			}
			// prefer int to int64. reason: in compiled Go,
			// type inference deduces int for all constants representable by an int
			i := int(i64)
			if int64(i) == i64 {
				return i
			}
			return i64
		} else {
			u64, err := strconv.ParseUint(str, 0, 0)
			if err != nil {
				return Error(err)
			}
			// prefer, in order: int, int64, uint, uint64. reason: in compiled Go,
			// type inference deduces int for all constants representable by an int
			i := int(u64)
			if i >= 0 && uint64(i) == u64 {
				return i
			}
			i64 := int64(u64)
			if i64 >= 0 && uint64(i64) == u64 {
				return i64
			}
			u := uint(u64)
			if uint64(u) == u64 {
				return u
			}
			return u64
		}

	case token.FLOAT:
		f, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return Error(err)
		}
		ret = f

	case token.IMAG:
		if strings.HasSuffix(str, "i") {
			str = str[:len(str)-1]
		}
		im, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return Error(err)
		}
		ret = complex(0.0, im)
		// env.Debugf("evalLiteral(): parsed IMAG %s -> %T %#v -> %T %#v", str, im, im, ret, ret)

	case token.CHAR:
		return unescapeChar(str)

	case token.STRING:
		return unescapeString(str)

	default:
		env.Errorf("unimplemented basic literal: %v", node)
		ret = nil
	}
	return ret
}

func (env *Env) evalCompositeLiteral(node *ast.CompositeLit) (r.Value, []r.Value) {
	//	prefix := node.Type
	// t := env.evalType(prefix)
	return env.Errorf("unimplemented composite literal: %v", node)
}

// lambda()
func (env *Env) evalFunctionLiteral(node *ast.FuncLit) (r.Value, []r.Value) {
	// env.Debugf("func() at position %v", node.Type.Func)

	ret, _ := env.evalDeclFunction(nil, node.Type, node.Body)
	return ret, nil
}
<commit_msg>implemented composite literals<commit_after>/*
 * gomacro - A Go intepreter with Lisp-like macros
 *
 * Copyright (C) 2017 Massimiliano Ghilardi
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * literal.go
 *
 *  Created on: Feb 13, 2017
 *      Author: Massimiliano Ghilardi
 */

package interpreter

import (
	"go/ast"
	"go/constant"
	"go/token"
	r "reflect"
	"strconv"
	"strings"
)

var Unknown = constant.MakeUnknown()

func (env *Env) evalLiteral0(node *ast.BasicLit) interface{} {
	kind := node.Kind
	str := node.Value
	var ret interface{}

	switch kind {

	case token.INT:
		if strings.HasPrefix(str, "-") {
			i64, err := strconv.ParseInt(str, 0, 0)
			if err != nil {
				return Error(err)
			}
			// prefer int to int64. reason: in compiled Go,
			// type inference deduces int for all constants representable by an int
			i := int(i64)
			if int64(i) == i64 {
				return i
			}
			return i64
		} else {
			u64, err := strconv.ParseUint(str, 0, 0)
			if err != nil {
				return Error(err)
			}
			// prefer, in order: int, int64, uint, uint64. reason: in compiled Go,
			// type inference deduces int for all constants representable by an int
			i := int(u64)
			if i >= 0 && uint64(i) == u64 {
				return i
			}
			i64 := int64(u64)
			if i64 >= 0 && uint64(i64) == u64 {
				return i64
			}
			u := uint(u64)
			if uint64(u) == u64 {
				return u
			}
			return u64
		}

	case token.FLOAT:
		f, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return Error(err)
		}
		ret = f

	case token.IMAG:
		if strings.HasSuffix(str, "i") {
			str = str[:len(str)-1]
		}
		im, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return Error(err)
		}
		ret = complex(0.0, im)
		// env.Debugf("evalLiteral(): parsed IMAG %s -> %T %#v -> %T %#v", str, im, im, ret, ret)

	case token.CHAR:
		return unescapeChar(str)

	case token.STRING:
		return unescapeString(str)

	default:
		env.Errorf("unimplemented basic literal: %v", node)
		ret = nil
	}
	return ret
}

func (env *Env) evalCompositeLiteral(node *ast.CompositeLit) (r.Value, []r.Value) {
	t := env.evalType(node.Type)
	obj := Nil
	switch t.Kind() {
	case r.Map:
		obj = r.MakeMap(t)
		kt := t.Key()
		vt := t.Elem()
		for _, elt := range node.Elts {
			switch elt := elt.(type) {
			case *ast.KeyValueExpr:
				key := env.valueToType(env.evalExpr1(elt.Key), kt)
				val := env.valueToType(env.evalExpr1(elt.Value), vt)
				obj.SetMapIndex(key, val)
			default:
				env.Errorf("map literal: invalid element, expecting <*ast.KeyValueExpr>, found: %v <%v>", elt, r.TypeOf(elt))
			}
		}
	case r.Array, r.Slice:
		kt := r.TypeOf(int(0))
		vt := t.Elem()
		idx := -1
		val := Nil
		zero := Nil
		if t.Kind() == r.Array {
			obj = r.New(t).Elem()
		} else {
			zero = r.Zero(vt)
			obj = r.MakeSlice(t, 0, len(node.Elts))
		}
		for _, elt := range node.Elts {
			switch elt := elt.(type) {
			case *ast.KeyValueExpr:
				idx = int(env.valueToType(env.evalExpr1(elt.Key), kt).Int())
				val = env.valueToType(env.evalExpr1(elt.Value), vt)
			default:
				// golang specs:
				// "An element without a key uses the previous element's index plus one.
				// If the first element has no key, its index is zero."
				idx++
				val = env.valueToType(env.evalExpr1(elt), vt)
			}
			if zero != Nil { // is slice
				for obj.Len() <= idx {
					obj = r.Append(obj, zero)
				}
			}
			obj.Index(idx).Set(val)
		}
	case r.Struct:
		obj = r.New(t).Elem()
		var pairs, elts bool
		var field r.Value
		var expr ast.Expr
		for idx, elt := range node.Elts {
			switch elt := elt.(type) {
			case *ast.KeyValueExpr:
				if elts {
					return env.Errorf("cannot mix keyed and non-keyed initializers in struct composite literal: %v", node)
				}
				pairs = true
				name := elt.Key.(*ast.Ident).Name
				field = obj.FieldByName(name)
				expr = elt.Value
			default:
				if pairs {
					return env.Errorf("cannot mix keyed and non-keyed initializers in struct composite literal: %v", node)
				}
				elts = true
				field = obj.Field(idx)
				expr = elt
			}
			val := env.valueToType(env.evalExpr1(expr), field.Type())
			field.Set(val)
		}
	default:
		env.Errorf("unexpected composite literal: %v", node)
	}
	return obj, nil
}

// lambda()
func (env *Env) evalFunctionLiteral(node *ast.FuncLit) (r.Value, []r.Value) {
	// env.Debugf("func() at position %v", node.Type.Func)

	ret, _ := env.evalDeclFunction(nil, node.Type, node.Body)
	return ret, nil
}
<|endoftext|>


<commit_before>package utils

import (
    "bytes"
    "os"
    "os/exec"
    "strconv"
    "strings"
    "syscall"
)

// GetEnv returns the value of the environment variable or provided fallback
// value if the environment variable is not defined.
func GetEnv(key string, fallback string) string {
    if value, ok := os.LookupEnv(key); ok {
        return value
    }

    return fallback
}

// GetEnvBool is the same like GetEnv but for boolean values.
func GetEnvBool(key string, fallback bool) bool {
    if value, ok := os.LookupEnv(key); ok {
        trueValues := [7]string{
            "true",
            "True",
            "TRUE",
            "yes",
            "Yes",
            "YES",
            "1",
        }

        for _, v := range trueValues {
            if value == v {
                return true
            }
        }

        return false
    }

    return fallback
}

// GetEnvInt is the same like GetEnv but for integer values.
func GetEnvInt(key string, fallback int) int {
    if value, ok := os.LookupEnv(key); ok {
        val, err := strconv.Atoi(value)

        if err != nil {
            return fallback
        }

        return val
    }

    return fallback
}

// GetEnvFloat is the same like GetEnv but for float values.
func GetEnvFloat(key string, fallback float64) float64 {
    if value, ok := os.LookupEnv(key); ok {
        val, err := strconv.ParseFloat(value, 64)

        if err != nil {
            return fallback
        }

        return val
    }

    return fallback
}

const defaultFailedCode = 1

// Run runs a command and returns the exit code, stdour and stderr output.
func Run(args []string) (exitCode int, stdout string, stderr string) {
    var outbuf, errbuf bytes.Buffer
    cmd := exec.Command(args[0], args[1:]...)
    cmd.Stdout = &outbuf
    cmd.Stderr = &errbuf

    err := cmd.Run()
    stdout = outbuf.String()
    stderr = errbuf.String()

    if err != nil {
        if exitError, ok := err.(*exec.ExitError); ok {
            ws := exitError.Sys().(syscall.WaitStatus)
            exitCode = ws.ExitStatus()
        } else {
            exitCode = defaultFailedCode

            if stderr == "" {
                stderr = err.Error()
            }
        }
    } else {
        ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
        exitCode = ws.ExitStatus()
    }

    stdout = strings.TrimSpace(stdout)
    stderr = strings.TrimSpace(stderr)

    return
}
<commit_msg>Renaming variable<commit_after>package utils

import (
    "bytes"
    "os"
    "os/exec"
    "strconv"
    "strings"
    "syscall"
)

// GetEnv returns the value of the environment variable or provided fallback
// value if the environment variable is not defined.
func GetEnv(key string, fallback string) string {
    if value, ok := os.LookupEnv(key); ok {
        return value
    }

    return fallback
}

// GetEnvBool is the same like GetEnv but for boolean values.
func GetEnvBool(key string, fallback bool) bool {
    if value, ok := os.LookupEnv(key); ok {
        trueValues := [7]string{
            "true",
            "True",
            "TRUE",
            "yes",
            "Yes",
            "YES",
            "1",
        }

        for _, v := range trueValues {
            if value == v {
                return true
            }
        }

        return false
    }

    return fallback
}

// GetEnvInt is the same like GetEnv but for integer values.
func GetEnvInt(key string, fallback int) int {
    if value, ok := os.LookupEnv(key); ok {
        val, err := strconv.Atoi(value)

        if err != nil {
            return fallback
        }

        return val
    }

    return fallback
}

// GetEnvFloat is the same like GetEnv but for float values.
func GetEnvFloat(key string, fallback float64) float64 {
    if value, ok := os.LookupEnv(key); ok {
        val, err := strconv.ParseFloat(value, 64)

        if err != nil {
            return fallback
        }

        return val
    }

    return fallback
}

const defaultFailedCode = 1

// Run runs a command and returns the exit code, stdour and stderr output.
func Run(args []string) (rc int, stdout string, stderr string) {
    var outbuf, errbuf bytes.Buffer
    cmd := exec.Command(args[0], args[1:]...)
    cmd.Stdout = &outbuf
    cmd.Stderr = &errbuf

    err := cmd.Run()
    stdout = outbuf.String()
    stderr = errbuf.String()

    if err != nil {
        if exitError, ok := err.(*exec.ExitError); ok {
            ws := exitError.Sys().(syscall.WaitStatus)
            rc = ws.ExitStatus()
        } else {
            rc = defaultFailedCode

            if stderr == "" {
                stderr = err.Error()
            }
        }
    } else {
        ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
        rc = ws.ExitStatus()
    }

    stdout = strings.TrimSpace(stdout)
    stderr = strings.TrimSpace(stderr)

    return
}
<|endoftext|>


<commit_before>package generator

import (
	"bytes"
	"fmt"
	"io"

	tl "github.com/xlab/cgogen/translator"
)

func (gen *Generator) writeDefinesGroup(wr io.Writer, defines []*tl.CDecl) (n int) {
	writeStartConst(wr)
	for _, decl := range defines {
		if !decl.IsDefine {
			continue
		}
		name := gen.tr.TransformName(tl.TargetConst, decl.Name)
		fmt.Fprintf(wr, "// %s as defined in %s\n", name,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))

		if decl.Value != nil {
			fmt.Fprintf(wr, "%s = %v", name, decl.Value)
		} else {
			fmt.Fprintf(wr, "%s = %s", name, decl.Expression)
		}
		writeSpace(wr, 1)
		n++
	}
	writeEndConst(wr)
	return
}

func (gen *Generator) writeConstDeclaration(wr io.Writer, decl *tl.CDecl) {
	declName := gen.tr.TransformName(tl.TargetConst, decl.Name)
	fmt.Fprintf(wr, "// %s as declared in %s\n", declName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	goSpec := gen.tr.TranslateSpec(decl.Spec)

	if decl.Value != nil {
		fmt.Fprintf(wr, "const %s %s = %v", declName, goSpec, decl.Value)
		return
	}
	fmt.Fprintf(wr, "const %s %s = %s", declName, goSpec, decl.Expression)
}

func (gen *Generator) expandEnumAnonymous(wr io.Writer, decl *tl.CDecl, namesSeen map[string]bool) {
	var typeName []byte
	var hasType bool
	if decl.IsTypedef {
		if typeName = gen.tr.TransformName(tl.TargetType, decl.Name); len(typeName) > 0 {
			hasType = true
		}
	}

	spec := decl.Spec.(*tl.CEnumSpec)
	if hasType {
		enumType := gen.tr.TranslateSpec(&spec.Type)
		fmt.Fprintf(wr, "// %s as declared in %s\n", typeName,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
		fmt.Fprintf(wr, "type %s %s\n", typeName, enumType)
		writeSpace(wr, 1)
		fmt.Fprintf(wr, "// %s enumeration from %s\n", typeName,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	}
	writeStartConst(wr)
	for i, m := range spec.Members {
		if !gen.tr.IsAcceptableName(tl.TargetConst, m.Name) {
			continue
		}
		mName := gen.tr.TransformName(tl.TargetConst, m.Name)
		if len(mName) == 0 {
			continue
		} else if namesSeen[string(mName)] {
			continue
		} else {
			namesSeen[string(mName)] = true
		}
		if !hasType {
			fmt.Fprintf(wr, "// %s as declared in %s\n", mName,
				gen.tr.SrcLocation(tl.TargetConst, m.Name, m.Pos))
		}
		switch {
		case m.Value != nil:
			if hasType {
				fmt.Fprintf(wr, "%s %s = %s\n", mName, typeName, iotaOnZero(i, m.Value))
				continue
			}
			fmt.Fprintf(wr, "%s = %s\n", mName, iotaOnZero(i, m.Value))
		case len(m.Expression) != 0:
			if hasType {
				fmt.Fprintf(wr, "%s %s = %s\n", mName, typeName, iotaOnZero(i, m.Expression))
				continue
			}
			fmt.Fprintf(wr, "%s = %s\n", mName, iotaOnZero(i, m.Expression))
		default:
			if i == 0 && hasType {
				fmt.Fprintf(wr, "%s %s = iota\n", mName, typeName)
				continue
			} else if i == 0 {
				fmt.Fprintf(wr, "%s = iota\n", mName)
			}
			fmt.Fprintf(wr, "%s\n", mName)
		}
	}
	writeEndConst(wr)
	writeSpace(wr, 1)
}

func (gen *Generator) expandEnum(wr io.Writer, decl *tl.CDecl) {
	var declName []byte
	var isTypedef bool
	if decl.IsTypedef {
		if declName = gen.tr.TransformName(tl.TargetType, decl.Name); len(declName) > 0 {
			isTypedef = true
		}
	}

	spec := decl.Spec.(*tl.CEnumSpec)
	tagName := gen.tr.TransformName(tl.TargetType, decl.Spec.GetBase())
	enumType := gen.tr.TranslateSpec(&spec.Type)
	fmt.Fprintf(wr, "// %s as declared in %s\n", tagName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	fmt.Fprintf(wr, "type %s %s\n", tagName, enumType)
	writeSpace(wr, 1)
	if isTypedef {
		if !bytes.Equal(tagName, declName) && len(declName) > 0 {
			// alias type decl name to the tag
			fmt.Fprintf(wr, "// %s as declared in %s\n", declName,
				gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
			fmt.Fprintf(wr, "type %s %s", declName, tagName)
			writeSpace(wr, 1)
		}
	}

	fmt.Fprintf(wr, "// %s enumeration from %s\n", tagName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	writeStartConst(wr)
	for i, m := range spec.Members {
		if !gen.tr.IsAcceptableName(tl.TargetConst, m.Name) {
			continue
		}
		mName := gen.tr.TransformName(tl.TargetConst, m.Name)
		if len(mName) == 0 {
			continue
		}
		switch {
		case m.Value != nil:
			fmt.Fprintf(wr, "%s %s = %v\n", mName, declName, iotaOnZero(i, m.Value))
		case len(m.Expression) != 0:
			fmt.Fprintf(wr, "%s %s = %v\n", mName, declName, iotaOnZero(i, m.Expression))
		default:
			if i == 0 {
				fmt.Fprintf(wr, "%s %s = iota\n", mName, declName)
				continue
			}
			fmt.Fprintf(wr, "%s\n", mName)
		}
	}
	writeEndConst(wr)
	writeSpace(wr, 1)
}

func iotaOnZero(i int, v interface{}) string {
	result := fmt.Sprintf("%v", v)
	if i == 0 {
		if result == "0" {
			return "iota"
		}
	}
	return result
}

func writeStartConst(wr io.Writer) {
	fmt.Fprintln(wr, "const (")
}

func writeEndConst(wr io.Writer) {
	fmt.Fprintln(wr, ")")
}
<commit_msg>Const decl fix.<commit_after>package generator

import (
	"bytes"
	"fmt"
	"io"

	tl "github.com/xlab/cgogen/translator"
)

func (gen *Generator) writeDefinesGroup(wr io.Writer, defines []*tl.CDecl) (n int) {
	writeStartConst(wr)
	for _, decl := range defines {
		if !decl.IsDefine {
			continue
		}
		name := gen.tr.TransformName(tl.TargetConst, decl.Name)
		fmt.Fprintf(wr, "// %s as defined in %s\n", name,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))

		if decl.Value != nil {
			fmt.Fprintf(wr, "%s = %v", name, decl.Value)
		} else if len(decl.Expression) > 0 {
			fmt.Fprintf(wr, "%s = %s", name, decl.Expression)
		} else {
			fmt.Printf(wr, name)
		}
		writeSpace(wr, 1)
		n++
	}
	writeEndConst(wr)
	return
}

func (gen *Generator) writeConstDeclaration(wr io.Writer, decl *tl.CDecl) {
	declName := gen.tr.TransformName(tl.TargetConst, decl.Name)
	fmt.Fprintf(wr, "// %s as declared in %s\n", declName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	goSpec := gen.tr.TranslateSpec(decl.Spec)

	if decl.Value != nil {
		fmt.Fprintf(wr, "const %s %s = %v", declName, goSpec, decl.Value)
		return
	} else if len(decl.Expression) > 0 {
		fmt.Fprintf(wr, "const %s %s = %s", declName, goSpec, decl.Expression)
		return
	}
	fmt.Fprintf(wr, "const %s %s", declName, goSpec)
}

func (gen *Generator) expandEnumAnonymous(wr io.Writer, decl *tl.CDecl, namesSeen map[string]bool) {
	var typeName []byte
	var hasType bool
	if decl.IsTypedef {
		if typeName = gen.tr.TransformName(tl.TargetType, decl.Name); len(typeName) > 0 {
			hasType = true
		}
	}

	spec := decl.Spec.(*tl.CEnumSpec)
	if hasType {
		enumType := gen.tr.TranslateSpec(&spec.Type)
		fmt.Fprintf(wr, "// %s as declared in %s\n", typeName,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
		fmt.Fprintf(wr, "type %s %s\n", typeName, enumType)
		writeSpace(wr, 1)
		fmt.Fprintf(wr, "// %s enumeration from %s\n", typeName,
			gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	}
	writeStartConst(wr)
	for i, m := range spec.Members {
		if !gen.tr.IsAcceptableName(tl.TargetConst, m.Name) {
			continue
		}
		mName := gen.tr.TransformName(tl.TargetConst, m.Name)
		if len(mName) == 0 {
			continue
		} else if namesSeen[string(mName)] {
			continue
		} else {
			namesSeen[string(mName)] = true
		}
		if !hasType {
			fmt.Fprintf(wr, "// %s as declared in %s\n", mName,
				gen.tr.SrcLocation(tl.TargetConst, m.Name, m.Pos))
		}
		switch {
		case m.Value != nil:
			if hasType {
				fmt.Fprintf(wr, "%s %s = %s\n", mName, typeName, iotaOnZero(i, m.Value))
				continue
			}
			fmt.Fprintf(wr, "%s = %s\n", mName, iotaOnZero(i, m.Value))
		case len(m.Expression) > 0:
			if hasType {
				fmt.Fprintf(wr, "%s %s = %s\n", mName, typeName, iotaOnZero(i, m.Expression))
				continue
			}
			fmt.Fprintf(wr, "%s = %s\n", mName, iotaOnZero(i, m.Expression))
		default:
			if i == 0 && hasType {
				fmt.Fprintf(wr, "%s %s = iota\n", mName, typeName)
				continue
			} else if i == 0 {
				fmt.Fprintf(wr, "%s = iota\n", mName)
			}
			fmt.Fprintf(wr, "%s\n", mName)
		}
	}
	writeEndConst(wr)
	writeSpace(wr, 1)
}

func (gen *Generator) expandEnum(wr io.Writer, decl *tl.CDecl) {
	var declName []byte
	var isTypedef bool
	if decl.IsTypedef {
		if declName = gen.tr.TransformName(tl.TargetType, decl.Name); len(declName) > 0 {
			isTypedef = true
		}
	}

	spec := decl.Spec.(*tl.CEnumSpec)
	tagName := gen.tr.TransformName(tl.TargetType, decl.Spec.GetBase())
	enumType := gen.tr.TranslateSpec(&spec.Type)
	fmt.Fprintf(wr, "// %s as declared in %s\n", tagName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	fmt.Fprintf(wr, "type %s %s\n", tagName, enumType)
	writeSpace(wr, 1)
	if isTypedef {
		if !bytes.Equal(tagName, declName) && len(declName) > 0 {
			// alias type decl name to the tag
			fmt.Fprintf(wr, "// %s as declared in %s\n", declName,
				gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
			fmt.Fprintf(wr, "type %s %s", declName, tagName)
			writeSpace(wr, 1)
		}
	}

	fmt.Fprintf(wr, "// %s enumeration from %s\n", tagName,
		gen.tr.SrcLocation(tl.TargetConst, decl.Name, decl.Pos))
	writeStartConst(wr)
	for i, m := range spec.Members {
		if !gen.tr.IsAcceptableName(tl.TargetConst, m.Name) {
			continue
		}
		mName := gen.tr.TransformName(tl.TargetConst, m.Name)
		if len(mName) == 0 {
			continue
		}
		switch {
		case m.Value != nil:
			fmt.Fprintf(wr, "%s %s = %v\n", mName, declName, iotaOnZero(i, m.Value))
		case len(m.Expression) > 0:
			fmt.Fprintf(wr, "%s %s = %v\n", mName, declName, iotaOnZero(i, m.Expression))
		default:
			if i == 0 {
				fmt.Fprintf(wr, "%s %s = iota\n", mName, declName)
				continue
			}
			fmt.Fprintf(wr, "%s\n", mName)
		}
	}
	writeEndConst(wr)
	writeSpace(wr, 1)
}

func iotaOnZero(i int, v interface{}) string {
	result := fmt.Sprintf("%v", v)
	if i == 0 {
		if result == "0" {
			return "iota"
		}
	}
	return result
}

func writeStartConst(wr io.Writer) {
	fmt.Fprintln(wr, "const (")
}

func writeEndConst(wr io.Writer) {
	fmt.Fprintln(wr, ")")
}
<|endoftext|>


<commit_before>package xslt

import (
	"fmt"
	"github.com/moovweb/gokogiri/xml"
	"github.com/moovweb/gokogiri/xpath"
	"unsafe"
)

func (style *Stylesheet) RegisterXsltFunctions() {
	style.Functions["key"] = XsltKey
	style.Functions["system-property"] = XsltSystemProperty
	//element-available
	//function-available
	//document
	//id
	//current
	//lang
	//generate-id
	//unparsed-entity-uri
	//format-number
}

type Nodeset []xml.Node

type Key struct {
	nodes map[string]Nodeset
	use   string
	match string
}

/*
func (key *Key) Evaluate() {
    c := CompileMatch()
    for n in doc.Nodes {
        if c.Matches(n) {
            Nodes = append(Nodes, n)
        }
    }
}
*/

func (n Nodeset) ToPointers() (pointers []unsafe.Pointer) {
	for _, node := range n {
		pointers = append(pointers, node.NodePtr())
	}
	return
}

// Implementation of key() from XSLT spec
func XsltKey(context xpath.VariableScope, args []interface{}) interface{} {
	if len(args) < 2 {
		return nil
	}
	// always convert to string
	name := args[0].(string)
	// convert to string (TODO: unless nodeset)
	val := args[1].(string)
	//get the execution context
	c := context.(*ExecutionContext)
	//look up the key
	k, ok := c.Style.Keys[name]
	if !ok {
		return nil
	}
	result, _ := k.nodes[val]
	//return the nodeset
	return result.ToPointers()
}

// Implementation of system-property() from XSLT spec
func XsltSystemProperty(context xpath.VariableScope, args []interface{}) interface{} {
	if len(args) < 1 {
		return nil
	}
	switch args[0].(string) {
	case "xsl:version":
		return 1.0
	case "xsl:vendor":
		return "John C Barstow"
	case "xsl:vendor-url":
		return "http://github.com/jbowtie"
	default:
		fmt.Println("EXEC system-property", args[0])
	}
	return nil
}
<commit_msg>Add a skeletal implementation of the document() function<commit_after>package xslt

import (
	"fmt"
	"github.com/moovweb/gokogiri/xml"
	"github.com/moovweb/gokogiri/xpath"
	"unsafe"
)

func (style *Stylesheet) RegisterXsltFunctions() {
	style.Functions["key"] = XsltKey
	style.Functions["system-property"] = XsltSystemProperty
	style.Functions["document"] = XsltDocumentFn
	//element-available
	//function-available
	//document
	//id
	//current
	//lang
	//generate-id
	//unparsed-entity-uri
	//format-number
}

type Nodeset []xml.Node

type Key struct {
	nodes map[string]Nodeset
	use   string
	match string
}

/*
func (key *Key) Evaluate() {
    c := CompileMatch()
    for n in doc.Nodes {
        if c.Matches(n) {
            Nodes = append(Nodes, n)
        }
    }
}
*/

func (n Nodeset) ToPointers() (pointers []unsafe.Pointer) {
	for _, node := range n {
		pointers = append(pointers, node.NodePtr())
	}
	return
}

// Implementation of key() from XSLT spec
func XsltKey(context xpath.VariableScope, args []interface{}) interface{} {
	if len(args) < 2 {
		return nil
	}
	// always convert to string
	name := args[0].(string)
	// convert to string (TODO: unless nodeset)
	val := args[1].(string)
	//get the execution context
	c := context.(*ExecutionContext)
	//look up the key
	k, ok := c.Style.Keys[name]
	if !ok {
		return nil
	}
	result, _ := k.nodes[val]
	//return the nodeset
	return result.ToPointers()
}

// Implementation of system-property() from XSLT spec
func XsltSystemProperty(context xpath.VariableScope, args []interface{}) interface{} {
	if len(args) < 1 {
		return nil
	}
	switch args[0].(string) {
	case "xsl:version":
		return 1.0
	case "xsl:vendor":
		return "John C Barstow"
	case "xsl:vendor-url":
		return "http://github.com/jbowtie/ratago"
	default:
		fmt.Println("EXEC system-property", args[0])
	}
	return nil
}

//Implementation of document() from XSLT spec
func XsltDocumentFn(context xpath.VariableScope, args []interface{}) interface{} {
	if len(args) < 1 {
		return nil
	}
	c := context.(*ExecutionContext)

	switch doc := args[0].(type) {
	case string:
		if doc == "" {
			return []xml.Node{c.Style.Doc}
		}
		return nil
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Rana Ian. All rights reserved.
// Use of this source code is governed by The MIT License
// found in the accompanying LICENSE file.

package ora

import (
	"fmt"
	"testing"
)

func TestSession_PrepCloseStmt(t *testing.T) {

	// setup
	env, err := GetDrv().OpenEnv()
	defer env.Close()
	testErr(err, t)
	srv, err := env.OpenSrv(testServerName)
	defer srv.Close()
	testErr(err, t)
	ses, err := srv.OpenSes(testUsername, testPassword)
	defer ses.Close()
	testErr(err, t)

	stmt, err := ses.Prep("select 'go' from dual")
	testErr(err, t)

	err = stmt.Close()
	testErr(err, t)
}

func TestSession_Tx_StartCommit(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	tx, err := testSes.StartTx()
	testErr(err, t)

	stmt, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("insert into %v (c1) values (11)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	err = tx.Commit()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)

	rset, err := stmt.Query()
	testErr(err, t)

	for rset.Next() {

	}
	if 2 != rset.Len() {
		t.Fatalf("row count: expected(%v), actual(%v)", 2, rset.Len())
	}
}

func TestSession_Tx_StartRollback(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	tx, err := testSes.StartTx()
	testErr(err, t)

	stmt, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("insert into %v (c1) values (11)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	err = tx.Rollback()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)

	rset, err := stmt.Query()
	testErr(err, t)

	for rset.Next() {
	}
	if 0 != rset.Len() {
		t.Fatalf("row count: expected(%v), actual(%v)", 0, rset.Len())
	}
}

func TestSession_PrepAndExec(t *testing.T) {
	rowsAffected, err := testSes.PrepAndExec(fmt.Sprintf("create table %v (c1 number)", tableName()))
	testErr(err, t)

	if rowsAffected != 0 {
		t.Fatalf("expected(%v), actual(%v)", 0, rowsAffected)
	}
}

func TestSession_PrepAndQuery(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	// insert one row
	stmtIns, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmtIns.Exec()
	testErr(err, t)

	stmt, rset, err := testSes.PrepAndQuery(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)
	if stmt == nil {
		t.Fatalf("expected non-nil stmt")
	}
	defer stmt.Close()
	if rset == nil {
		t.Fatalf("expected non-nil rset")
	}

	row := rset.NextRow()
	if row[0] == 9 {
		t.Fatalf("expected(%v), actual(%v)", 9, row[0])
	}
}
<commit_msg>added PrepAndExec test<commit_after>// Copyright 2014 Rana Ian. All rights reserved.
// Use of this source code is governed by The MIT License
// found in the accompanying LICENSE file.

package ora

import (
	"fmt"
	"testing"
)

func TestSession_PrepCloseStmt(t *testing.T) {

	// setup
	env, err := GetDrv().OpenEnv()
	defer env.Close()
	testErr(err, t)
	srv, err := env.OpenSrv(testServerName)
	defer srv.Close()
	testErr(err, t)
	ses, err := srv.OpenSes(testUsername, testPassword)
	defer ses.Close()
	testErr(err, t)

	stmt, err := ses.Prep("select 'go' from dual")
	testErr(err, t)

	err = stmt.Close()
	testErr(err, t)
}

func TestSession_Tx_StartCommit(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	tx, err := testSes.StartTx()
	testErr(err, t)

	stmt, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("insert into %v (c1) values (11)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	err = tx.Commit()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)

	rset, err := stmt.Query()
	testErr(err, t)

	for rset.Next() {

	}
	if 2 != rset.Len() {
		t.Fatalf("row count: expected(%v), actual(%v)", 2, rset.Len())
	}
}

func TestSession_Tx_StartRollback(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	tx, err := testSes.StartTx()
	testErr(err, t)

	stmt, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("insert into %v (c1) values (11)", tableName))
	testErr(err, t)
	_, err = stmt.Exec()
	testErr(err, t)

	err = tx.Rollback()
	testErr(err, t)

	stmt, err = testSes.Prep(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)

	rset, err := stmt.Query()
	testErr(err, t)

	for rset.Next() {
	}
	if 0 != rset.Len() {
		t.Fatalf("row count: expected(%v), actual(%v)", 0, rset.Len())
	}
}

func TestSession_PrepAndExec(t *testing.T) {
	rowsAffected, err := testSes.PrepAndExec(fmt.Sprintf("create table %v (c1 number)", tableName()))
	testErr(err, t)

	if rowsAffected != 0 {
		t.Fatalf("expected(%v), actual(%v)", 0, rowsAffected)
	}
}

func TestSession_PrepAndExec_Insert(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	values := make([]int64, 1000000)
	for n, _ := range values {
		values[n] = int64(n)
	}
	rowsAffected, err := testSes.PrepAndExec(fmt.Sprintf("INSERT INTO %v (C1) VALUES (:C1)", tableName), values)
	testErr(err, t)

	if rowsAffected != 1000000 {
		t.Fatalf("expected(%v), actual(%v)", 1000000, rowsAffected)
	}
}

func TestSession_PrepAndQuery(t *testing.T) {
	tableName, err := createTable(1, numberP38S0, testSes)
	testErr(err, t)
	defer dropTable(tableName, testSes, t)

	// insert one row
	stmtIns, err := testSes.Prep(fmt.Sprintf("insert into %v (c1) values (9)", tableName))
	testErr(err, t)
	_, err = stmtIns.Exec()
	testErr(err, t)

	stmt, rset, err := testSes.PrepAndQuery(fmt.Sprintf("select c1 from %v", tableName))
	testErr(err, t)
	if stmt == nil {
		t.Fatalf("expected non-nil stmt")
	}
	defer stmt.Close()
	if rset == nil {
		t.Fatalf("expected non-nil rset")
	}

	row := rset.NextRow()
	if row[0] == 9 {
		t.Fatalf("expected(%v), actual(%v)", 9, row[0])
	}
}
<|endoftext|>


<commit_before>// Package hclhil adapts Hashicorp Configuration Language and Hashicorp
// Interpolation Language (HCL and HIL, respectively) to work within the
// ZCL API.
//
// This is intended to help applications that previously used HCL/HIL to
// gradually adopt hcl while remaining generally compatible with their
// previous configuration formats.
package hclhil
<commit_msg>hclhil: documentation typo<commit_after>// Package hclhil adapts Hashicorp Configuration Language and Hashicorp
// Interpolation Language (HCL and HIL, respectively) to work within the
// ZCL API.
//
// This is intended to help applications that previously used HCL/HIL to
// gradually adopt zcl while remaining generally compatible with their
// previous configuration formats.
package hclhil
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package mtail_test

import (
	"os"
	"path"
	"sync"
	"testing"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestGlobBeforeStart(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log2"),
			true,
		},
		{
			path.Join(workdir, "1log"),
			false,
		},
	}
	count := 0
	for _, tt := range globTests {
		log := testutil.TestOpenFile(t, tt.name)
		defer log.Close()
		if tt.expected {
			count++
		}
		testutil.WriteString(t, log, "\n")
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Expecting log count of %d, received %g", count, r)
	}
}

func TestGlobAfterStart(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log2"),
			true,
		},
		{
			path.Join(workdir, "1log"),
			false,
		},
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")))
	defer stopM()

	count := 0
	for _, tt := range globTests {
		if tt.expected {
			count++
		}
	}
	logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", float64(count))
	linesCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", float64(count))
	for _, tt := range globTests {
		log := testutil.TestOpenFile(t, tt.name)
		defer log.Close()
		testutil.WriteString(t, log, "\n")
	}
	m.PollWatched()
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		linesCountCheck()
	}()
	go func() {
		defer wg.Done()
		logCountCheck()
	}()
	wg.Wait()
}

func TestGlobIgnoreFolder(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		isFolder bool
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			false,
			true,
		},
		{
			path.Join(workdir, "logarchive"),
			true,
			false,
		},
		{
			path.Join(workdir, "log2.gz"),
			false,
			false,
		},
	}
	count := 0
	for _, tt := range globTests {
		var err error
		var log *os.File

		if tt.isFolder {
			err = os.Mkdir(tt.name, 0700)
			testutil.FatalIfErr(t, err)
			continue
		} else {
			log, err = os.Create(tt.name)
		}

		if !tt.isFolder && tt.expected {
			count++
		}
		defer log.Close()
		testutil.FatalIfErr(t, err)
		testutil.WriteString(t, log, "\n")
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")), mtail.IgnoreRegexPattern("\\.gz"))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Expecting log Count for %d, received %g", count, r)
	}
}

func TestFilenameRegexIgnore(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log1.gz"),
			false,
		},
		{
			path.Join(workdir, "log2gz"),
			true,
		},
	}
	count := 0
	for _, tt := range globTests {
		log, err := os.Create(tt.name)
		testutil.FatalIfErr(t, err)
		defer log.Close()
		if tt.expected {
			count++
		}
		testutil.WriteString(t, log, "\n")
	}

	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")), mtail.IgnoreRegexPattern("\\.gz"))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Log count not matching\n\texpected: %d\n\t: received: %g", count, r)
	}
}

func TestGlobRelativeAfterStart(t *testing.T) {
	testutil.SkipIfShort(t)
	tmpDir, rmTmpDir := testutil.TestTempDir(t)
	defer rmTmpDir()

	logDir := path.Join(tmpDir, "logs")
	progDir := path.Join(tmpDir, "progs")
	err := os.Mkdir(logDir, 0700)
	testutil.FatalIfErr(t, err)
	err = os.Mkdir(progDir, 0700)
	testutil.FatalIfErr(t, err)

	// Move to logdir to make relative paths
	defer testutil.TestChdir(t, logDir)()

	m, stopM := mtail.TestStartServer(t, 0, mtail.ProgramPath(progDir), mtail.LogPathPatterns("log.*"))
	defer stopM()

	{
		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 1)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.1.txt")
		f := testutil.TestOpenFile(t, logFile)

		n, err := f.WriteString("line 1\n")
		testutil.FatalIfErr(t, err)
		glog.Infof("Wrote %d bytes", n)
		testutil.FatalIfErr(t, f.Sync())
		m.PollWatched() // TODO: refactor above

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}

	{

		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 1)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.2.txt")
		f := testutil.TestOpenFile(t, logFile)
		n, err := f.WriteString("line 1\n")
		testutil.FatalIfErr(t, err)
		glog.Infof("Wrote %d bytes", n)
		m.PollWatched() // TODO: refactor above

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}
	{
		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 0)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.2.txt")
		f := testutil.TestOpenFile(t, logFile)
		n, err := f.WriteString("line 1\n")
		testutil.FatalIfErr(t, err)
		glog.Infof("Wrote %d bytes", n)
		m.PollWatched() // TODO: refactor above

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}

	glog.Infof("end")
}
<commit_msg>Refactor the log_glob test per the TODOs.<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package mtail_test

import (
	"os"
	"path"
	"sync"
	"testing"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestGlobBeforeStart(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log2"),
			true,
		},
		{
			path.Join(workdir, "1log"),
			false,
		},
	}
	count := 0
	for _, tt := range globTests {
		log := testutil.TestOpenFile(t, tt.name)
		defer log.Close()
		if tt.expected {
			count++
		}
		testutil.WriteString(t, log, "\n")
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Expecting log count of %d, received %g", count, r)
	}
}

func TestGlobAfterStart(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log2"),
			true,
		},
		{
			path.Join(workdir, "1log"),
			false,
		},
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")))
	defer stopM()

	count := 0
	for _, tt := range globTests {
		if tt.expected {
			count++
		}
	}
	logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", float64(count))
	linesCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", float64(count))
	for _, tt := range globTests {
		log := testutil.TestOpenFile(t, tt.name)
		defer log.Close()
		testutil.WriteString(t, log, "\n")
	}
	m.PollWatched()
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		linesCountCheck()
	}()
	go func() {
		defer wg.Done()
		logCountCheck()
	}()
	wg.Wait()
}

func TestGlobIgnoreFolder(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		isFolder bool
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			false,
			true,
		},
		{
			path.Join(workdir, "logarchive"),
			true,
			false,
		},
		{
			path.Join(workdir, "log2.gz"),
			false,
			false,
		},
	}
	count := 0
	for _, tt := range globTests {
		var err error
		var log *os.File

		if tt.isFolder {
			err = os.Mkdir(tt.name, 0700)
			testutil.FatalIfErr(t, err)
			continue
		} else {
			log, err = os.Create(tt.name)
		}

		if !tt.isFolder && tt.expected {
			count++
		}
		defer log.Close()
		testutil.FatalIfErr(t, err)
		testutil.WriteString(t, log, "\n")
	}
	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")), mtail.IgnoreRegexPattern("\\.gz"))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Expecting log Count for %d, received %g", count, r)
	}
}

func TestFilenameRegexIgnore(t *testing.T) {
	testutil.SkipIfShort(t)

	workdir, rmWorkdir := testutil.TestTempDir(t)
	defer rmWorkdir()

	globTests := []struct {
		name     string
		expected bool
	}{
		{
			path.Join(workdir, "log1"),
			true,
		},
		{
			path.Join(workdir, "log1.gz"),
			false,
		},
		{
			path.Join(workdir, "log2gz"),
			true,
		},
	}
	count := 0
	for _, tt := range globTests {
		log, err := os.Create(tt.name)
		testutil.FatalIfErr(t, err)
		defer log.Close()
		if tt.expected {
			count++
		}
		testutil.WriteString(t, log, "\n")
	}

	m, stopM := mtail.TestStartServer(t, 0, mtail.LogPathPatterns(path.Join(workdir, "log*")), mtail.IgnoreRegexPattern("\\.gz"))
	defer stopM()

	if r := m.GetMetric("log_count"); r != float64(count) {
		t.Errorf("Log count not matching\n\texpected: %d\n\t: received: %g", count, r)
	}
}

func TestGlobRelativeAfterStart(t *testing.T) {
	testutil.SkipIfShort(t)
	tmpDir, rmTmpDir := testutil.TestTempDir(t)
	defer rmTmpDir()

	logDir := path.Join(tmpDir, "logs")
	progDir := path.Join(tmpDir, "progs")
	err := os.Mkdir(logDir, 0700)
	testutil.FatalIfErr(t, err)
	err = os.Mkdir(progDir, 0700)
	testutil.FatalIfErr(t, err)

	// Move to logdir to make relative paths
	defer testutil.TestChdir(t, logDir)()

	m, stopM := mtail.TestStartServer(t, 0, mtail.ProgramPath(progDir), mtail.LogPathPatterns("log.*"))
	defer stopM()

	{
		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 1)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.1.txt")
		f := testutil.TestOpenFile(t, logFile)

		testutil.WriteString(t, f, "line 1\n")
		m.PollWatched()

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}

	{

		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 1)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.2.txt")
		f := testutil.TestOpenFile(t, logFile)
		testutil.WriteString(t, f, "line 1\n")
		m.PollWatched()

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}
	{
		logCountCheck := m.ExpectMetricDeltaWithDeadline("log_count", 0)
		lineCountCheck := m.ExpectMetricDeltaWithDeadline("lines_total", 1)

		logFile := path.Join(logDir, "log.2.txt")
		f := testutil.TestOpenFile(t, logFile)
		testutil.WriteString(t, f, "line 1\n")
		m.PollWatched()

		var wg sync.WaitGroup
		wg.Add(2)
		go func() {
			defer wg.Done()
			logCountCheck()
		}()
		go func() {
			defer wg.Done()
			lineCountCheck()
		}()
		wg.Wait()
	}

	glog.Infof("end")
}
<|endoftext|>


<commit_before>/*
Ginkgomon provides ginkgo test helpers.
*/
package ginkgomon

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

// Config defines a ginkgomon Runner.
type Config struct {
	Command           *exec.Cmd     // process to be executed
	Name              string        // prefixes all output lines
	AnsiColorCode     string        // colors the output
	StartCheck        string        // text to match to indicate sucessful start.
	StartCheckTimeout time.Duration // how long to wait to see StartCheck
	Cleanup           func()        // invoked once the process exits
}

/*
The ginkgomon Runner invokes a new process using gomega's gexec package.

If a start check is defined, the runner will wait until it sees the start check
before declaring ready.

Runner implements gexec.Exiter and gbytes.BufferProvider, so you can test exit
codes and process output using the appropriate gomega matchers:
http://onsi.github.io/gomega/#gexec-testing-external-processes
*/
type Runner struct {
	Command           *exec.Cmd
	Name              string
	AnsiColorCode     string
	StartCheck        string
	StartCheckTimeout time.Duration
	Cleanup           func()
	session           *gexec.Session
	sessionReady      chan struct{}
}

// New creates a ginkgomon Runner from a config object. Runners must be created
// with New to properly initialize their internal state.
func New(config Config) *Runner {
	return &Runner{
		Name:              config.Name,
		Command:           config.Command,
		AnsiColorCode:     config.AnsiColorCode,
		StartCheck:        config.StartCheck,
		StartCheckTimeout: config.StartCheckTimeout,
		Cleanup:           config.Cleanup,
		sessionReady:      make(chan struct{}),
	}
}

// ExitCode returns the exit code of the process, or -1 if the process has not
// exited.  It can be used with the gexec.Exit matcher.
func (r *Runner) ExitCode() int {
	if r.sessionReady == nil {
		ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name))
	}
	<-r.sessionReady
	return r.session.ExitCode()
}

// Buffer returns a gbytes.Buffer, for use with the gbytes.Say matcher.
func (r *Runner) Buffer() *gbytes.Buffer {
	if r.sessionReady == nil {
		ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name))
	}
	<-r.sessionReady
	return r.session.Buffer()
}

func (r *Runner) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error {
	defer ginkgo.GinkgoRecover()

	allOutput := gbytes.NewBuffer()

	debugWriter := gexec.NewPrefixedWriter(
		fmt.Sprintf("\x1b[32m[d]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
		ginkgo.GinkgoWriter,
	)

	session, err := gexec.Start(
		r.Command,
		gexec.NewPrefixedWriter(
			fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
			io.MultiWriter(allOutput, ginkgo.GinkgoWriter),
		),
		gexec.NewPrefixedWriter(
			fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
			io.MultiWriter(allOutput, ginkgo.GinkgoWriter),
		),
	)

	Ω(err).ShouldNot(HaveOccurred())

	fmt.Fprintf(debugWriter, "spawned %s (pid: %d)\n", r.Command.Path, r.Command.Process.Pid)

	r.session = session
	if r.sessionReady != nil {
		close(r.sessionReady)
	}

	startCheckDuration := r.StartCheckTimeout
	if startCheckDuration == 0 {
		startCheckDuration = 5 * time.Second
	}

	var startCheckTimeout <-chan time.Time
	if r.StartCheck != "" {
		startCheckTimeout = time.After(startCheckDuration)
	}

	detectStartCheck := allOutput.Detect(r.StartCheck)

	for {
		select {
		case <-detectStartCheck: // works even with empty string
			allOutput.CancelDetects()
			startCheckTimeout = nil
			detectStartCheck = nil
			close(ready)

		case <-startCheckTimeout:
			// clean up hanging process
			session.Kill().Wait()

			// fail to start
			return fmt.Errorf(
				"did not see %s in command's output within %s. full output:\n\n%s",
				r.StartCheck,
				startCheckDuration,
				string(allOutput.Contents()),
			)

		case signal := <-sigChan:
			session.Signal(signal)

		case <-session.Exited:
			if r.Cleanup != nil {
				r.Cleanup()
			}

			if session.ExitCode() == 0 {
				return nil
			}

			return fmt.Errorf("exit status %d", session.ExitCode())
		}
	}
}
<commit_msg>Expose session.Err on ginkgomon.Runner<commit_after>/*
Ginkgomon provides ginkgo test helpers.
*/
package ginkgomon

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

// Config defines a ginkgomon Runner.
type Config struct {
	Command           *exec.Cmd     // process to be executed
	Name              string        // prefixes all output lines
	AnsiColorCode     string        // colors the output
	StartCheck        string        // text to match to indicate sucessful start.
	StartCheckTimeout time.Duration // how long to wait to see StartCheck
	Cleanup           func()        // invoked once the process exits
}

/*
The ginkgomon Runner invokes a new process using gomega's gexec package.

If a start check is defined, the runner will wait until it sees the start check
before declaring ready.

Runner implements gexec.Exiter and gbytes.BufferProvider, so you can test exit
codes and process output using the appropriate gomega matchers:
http://onsi.github.io/gomega/#gexec-testing-external-processes
*/
type Runner struct {
	Command           *exec.Cmd
	Name              string
	AnsiColorCode     string
	StartCheck        string
	StartCheckTimeout time.Duration
	Cleanup           func()
	session           *gexec.Session
	sessionReady      chan struct{}
}

// New creates a ginkgomon Runner from a config object. Runners must be created
// with New to properly initialize their internal state.
func New(config Config) *Runner {
	return &Runner{
		Name:              config.Name,
		Command:           config.Command,
		AnsiColorCode:     config.AnsiColorCode,
		StartCheck:        config.StartCheck,
		StartCheckTimeout: config.StartCheckTimeout,
		Cleanup:           config.Cleanup,
		sessionReady:      make(chan struct{}),
	}
}

// ExitCode returns the exit code of the process, or -1 if the process has not
// exited.  It can be used with the gexec.Exit matcher.
func (r *Runner) ExitCode() int {
	if r.sessionReady == nil {
		ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name))
	}
	<-r.sessionReady
	return r.session.ExitCode()
}

// Buffer returns a gbytes.Buffer, for use with the gbytes.Say matcher.
func (r *Runner) Buffer() *gbytes.Buffer {
	if r.sessionReady == nil {
		ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name))
	}
	<-r.sessionReady
	return r.session.Buffer()
}

// Err returns the gbytes.Buffer associated with the stderr stream.
// For use with the gbytes.Say matcher.
func (r *Runner) Err() *gbytes.Buffer {
	if r.sessionReady == nil {
		ginkgo.Fail(fmt.Sprintf("ginkgomon.Runner '%s' improperly created without using New", r.Name))
	}
	<-r.sessionReady
	return r.session.Err
}

func (r *Runner) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error {
	defer ginkgo.GinkgoRecover()

	allOutput := gbytes.NewBuffer()

	debugWriter := gexec.NewPrefixedWriter(
		fmt.Sprintf("\x1b[32m[d]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
		ginkgo.GinkgoWriter,
	)

	session, err := gexec.Start(
		r.Command,
		gexec.NewPrefixedWriter(
			fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
			io.MultiWriter(allOutput, ginkgo.GinkgoWriter),
		),
		gexec.NewPrefixedWriter(
			fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", r.AnsiColorCode, r.Name),
			io.MultiWriter(allOutput, ginkgo.GinkgoWriter),
		),
	)

	Ω(err).ShouldNot(HaveOccurred())

	fmt.Fprintf(debugWriter, "spawned %s (pid: %d)\n", r.Command.Path, r.Command.Process.Pid)

	r.session = session
	if r.sessionReady != nil {
		close(r.sessionReady)
	}

	startCheckDuration := r.StartCheckTimeout
	if startCheckDuration == 0 {
		startCheckDuration = 5 * time.Second
	}

	var startCheckTimeout <-chan time.Time
	if r.StartCheck != "" {
		startCheckTimeout = time.After(startCheckDuration)
	}

	detectStartCheck := allOutput.Detect(r.StartCheck)

	for {
		select {
		case <-detectStartCheck: // works even with empty string
			allOutput.CancelDetects()
			startCheckTimeout = nil
			detectStartCheck = nil
			close(ready)

		case <-startCheckTimeout:
			// clean up hanging process
			session.Kill().Wait()

			// fail to start
			return fmt.Errorf(
				"did not see %s in command's output within %s. full output:\n\n%s",
				r.StartCheck,
				startCheckDuration,
				string(allOutput.Contents()),
			)

		case signal := <-sigChan:
			session.Signal(signal)

		case <-session.Exited:
			if r.Cleanup != nil {
				r.Cleanup()
			}

			if session.ExitCode() == 0 {
				return nil
			}

			return fmt.Errorf("exit status %d", session.ExitCode())
		}
	}
}
<|endoftext|>


<commit_before>package file

import (
	"bytes"
	"io"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/registry/upload"
	"github.com/admpub/nging/application/registry/upload/convert"
	"github.com/admpub/nging/application/registry/upload/driver/local"
	"github.com/admpub/nging/application/registry/upload/helper"
)

var fileGeneratorLock = sync.RWMutex{}

func File(ctx echo.Context) error {
	uploadType := ctx.Param(`type`)
	typ, _, _ := upload.GetTableInfo(uploadType)
	file := ctx.Param(`*`)
	file = filepath.Join(helper.UploadDir, typ, file)
	var (
		convertFunc  convert.Convert
		ok           bool
		originalFile string
	)
	extension := ctx.Query(`ex`)
	if len(extension) > 0 {
		extension = `.` + extension
		convertFunc, ok = convert.GetConverter(extension)
		if !ok {
			return ctx.File(file)
		}
		originalFile = file
	} else {
		originalExtension := filepath.Ext(file)
		extension = strings.ToLower(originalExtension)
		convertFunc, ok = convert.GetConverter(extension)
		if !ok {
			return ctx.File(file)
		}
		originalFile = strings.TrimSuffix(file, originalExtension)
		index := strings.LastIndex(originalFile, `.`)
		// 单扩展名或相同扩展名的情况下不转换格式
		if index < 0 || strings.ToLower(originalFile[index:]) == extension {
			return ctx.File(originalFile)
		}
	}
	supported := strings.Contains(ctx.Header(echo.HeaderAccept), "image/"+strings.TrimPrefix(extension, `.`))
	if !supported {
		return ctx.File(originalFile)
	}

	fileGeneratorLock.RLock()
	if err := ctx.File(file); err != echo.ErrNotFound {
		return err
	}
	fileGeneratorLock.RUnlock()

	fileGeneratorLock.Lock()
	defer fileGeneratorLock.Unlock()

	return ctx.ServeCallbackContent(func(_ echo.Context) (io.Reader, error) {
		newStore := upload.StorerGet(local.Name)
		if newStore == nil {
			return nil, ctx.E(`存储引擎“%s”未被登记`, storerName)
		}
		storer, err := newStore(ctx, typ)
		if err != nil {
			return nil, err
		}
		f, err := storer.Get(`/` + originalFile)
		if err != nil {
			return nil, echo.ErrNotFound
		}
		defer f.Close()
		buf, err := convertFunc(f, 70)
		if err != nil {
			return nil, err
		}
		b := buf.Bytes()
		saveFile := storer.URLToFile(`/` + file)
		_, _, err = storer.Put(saveFile, buf, int64(len(b)))
		return bytes.NewBuffer(b), err
	}, path.Base(file), time.Now())
}
<commit_msg>update<commit_after>package file

import (
	"bytes"
	"io"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/registry/upload"
	"github.com/admpub/nging/application/registry/upload/convert"
	"github.com/admpub/nging/application/registry/upload/driver/local"
	"github.com/admpub/nging/application/registry/upload/helper"
)

var fileGeneratorLock = sync.RWMutex{}

func File(ctx echo.Context) error {
	uploadType := ctx.Param(`type`)
	typ, _, _ := upload.GetTableInfo(uploadType)
	file := ctx.Param(`*`)
	file = filepath.Join(helper.UploadDir, typ, file)
	var (
		convertFunc  convert.Convert
		ok           bool
		originalFile string
	)
	extension := ctx.Query(`ex`)
	if len(extension) > 0 {
		extension = `.` + extension
		convertFunc, ok = convert.GetConverter(extension)
		if !ok {
			return ctx.File(file)
		}
		originalFile = file
	} else {
		originalExtension := filepath.Ext(file)
		extension = strings.ToLower(originalExtension)
		convertFunc, ok = convert.GetConverter(extension)
		if !ok {
			return ctx.File(file)
		}
		originalFile = strings.TrimSuffix(file, originalExtension)
		index := strings.LastIndex(originalFile, `.`)
		// 单扩展名或相同扩展名的情况下不转换格式
		if index < 0 || strings.ToLower(originalFile[index:]) == extension {
			return ctx.File(originalFile)
		}
	}
	supported := strings.Contains(ctx.Header(echo.HeaderAccept), "image/"+strings.TrimPrefix(extension, `.`))
	if !supported {
		return ctx.File(originalFile)
	}

	fileGeneratorLock.RLock()
	if err := ctx.File(file); err != echo.ErrNotFound {
		return err
	}
	fileGeneratorLock.RUnlock()

	fileGeneratorLock.Lock()
	defer fileGeneratorLock.Unlock()

	return ctx.ServeCallbackContent(func(_ echo.Context) (io.Reader, error) {
		storerName := local.Name
		newStore := upload.StorerGet(storerName)
		if newStore == nil {
			return nil, ctx.E(`存储引擎“%s”未被登记`, storerName)
		}
		storer, err := newStore(ctx, typ)
		if err != nil {
			return nil, err
		}
		f, err := storer.Get(`/` + originalFile)
		if err != nil {
			return nil, echo.ErrNotFound
		}
		defer f.Close()
		buf, err := convertFunc(f, 70)
		if err != nil {
			return nil, err
		}
		b := buf.Bytes()
		saveFile := storer.URLToFile(`/` + file)
		_, _, err = storer.Put(saveFile, buf, int64(len(b)))
		return bytes.NewBuffer(b), err
	}, path.Base(file), time.Now())
}
<|endoftext|>