<commit_before>package sbom

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

	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/gio"
	"github.com/goreleaser/goreleaser/internal/ids"
	"github.com/goreleaser/goreleaser/internal/logext"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
)

// Environment variables to pass through to exec
var passthroughEnvVars = []string{"HOME", "USER", "USERPROFILE", "TMPDIR", "TMP", "TEMP", "PATH"}

// Pipe that catalogs common artifacts as an SBOM.
type Pipe struct{}

func (Pipe) String() string { return "cataloging artifacts" }
func (Pipe) Skip(ctx *context.Context) bool {
	return ctx.SkipSBOMCataloging || len(ctx.Config.SBOMs) == 0
}

// Default sets the Pipes defaults.
func (Pipe) Default(ctx *context.Context) error {
	ids := ids.New("sboms")
	for i := range ctx.Config.SBOMs {
		cfg := &ctx.Config.SBOMs[i]
		if cfg.Cmd == "" {
			cfg.Cmd = "syft"
		}
		if cfg.Artifacts == "" {
			cfg.Artifacts = "archive"
		}
		if len(cfg.Documents) == 0 {
			switch cfg.Artifacts {
			case "binary":
				cfg.Documents = []string{"{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom"}
			case "any":
				cfg.Documents = []string{}
			default:
				cfg.Documents = []string{"{{ .ArtifactName }}.sbom"}
			}
		}
		if cfg.Cmd == "syft" {
			if len(cfg.Args) == 0 {
				cfg.Args = []string{"$artifact", "--file", "$document", "--output", "spdx-json"}
			}
			if len(cfg.Env) == 0 && cfg.Artifacts == "source" || cfg.Artifacts == "archive" {
				cfg.Env = []string{
					"SYFT_FILE_METADATA_CATALOGER_ENABLED=true",
				}
			}
		}
		if cfg.ID == "" {
			cfg.ID = "default"
		}

		if cfg.Artifacts != "any" && len(cfg.Documents) > 1 {
			return fmt.Errorf("multiple SBOM outputs when artifacts=%q is unsupported", cfg.Artifacts)
		}

		ids.Inc(cfg.ID)
	}
	return ids.Validate()
}

// Run executes the Pipe.
func (Pipe) Run(ctx *context.Context) error {
	g := semerrgroup.New(ctx.Parallelism)
	for _, cfg := range ctx.Config.SBOMs {
		g.Go(catalogTask(ctx, cfg))
	}
	return g.Wait()
}

func catalogTask(ctx *context.Context, cfg config.SBOM) func() error {
	return func() error {
		var filters []artifact.Filter
		switch cfg.Artifacts {
		case "source":
			filters = append(filters, artifact.ByType(artifact.UploadableSourceArchive))
			if len(cfg.IDs) > 0 {
				log.Warn("when artifacts is `source`, `ids` has no effect. ignoring")
			}
		case "archive":
			filters = append(filters, artifact.ByType(artifact.UploadableArchive))
		case "binary":
			filters = append(filters, artifact.Or(
				artifact.ByType(artifact.Binary),
				artifact.ByType(artifact.UploadableBinary),
				artifact.ByType(artifact.UniversalBinary),
			))
		case "package":
			filters = append(filters, artifact.ByType(artifact.LinuxPackage))
		case "any":
			newArtifacts, err := catalogArtifact(ctx, cfg, nil)
			if err != nil {
				return err
			}
			for _, newArtifact := range newArtifacts {
				ctx.Artifacts.Add(newArtifact)
			}
			return nil
		default:
			return fmt.Errorf("invalid list of artifacts to catalog: %s", cfg.Artifacts)
		}

		if len(cfg.IDs) > 0 {
			filters = append(filters, artifact.ByIDs(cfg.IDs...))
		}
		artifacts := ctx.Artifacts.Filter(artifact.And(filters...)).List()
		return catalog(ctx, cfg, artifacts)
	}
}

func catalog(ctx *context.Context, cfg config.SBOM, artifacts []*artifact.Artifact) error {
	for _, a := range artifacts {
		newArtifacts, err := catalogArtifact(ctx, cfg, a)
		if err != nil {
			return err
		}
		for _, newArtifact := range newArtifacts {
			ctx.Artifacts.Add(newArtifact)
		}
	}
	return nil
}

func subprocessDistPath(distDir string, pathRelativeToCwd string) (string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	if !filepath.IsAbs(distDir) {
		distDir, err = filepath.Abs(distDir)
		if err != nil {
			return "", err
		}
	}
	relativePath, err := filepath.Rel(cwd, distDir)
	if err != nil {
		return "", err
	}
	return strings.TrimPrefix(pathRelativeToCwd, relativePath+string(filepath.Separator)), nil
}

func catalogArtifact(ctx *context.Context, cfg config.SBOM, a *artifact.Artifact) ([]*artifact.Artifact, error) {
	env := ctx.Env.Copy()
	artifactDisplayName := "(any)"
	templater := tmpl.New(ctx).WithEnv(env)

	if a != nil {
		procPath, err := subprocessDistPath(ctx.Config.Dist, a.Path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: cannot determine artifact path for %q: %w", a.Path, err)
		}
		env["artifact"] = procPath
		env["artifactID"] = a.ID()

		templater = templater.WithArtifact(a, nil)
		artifactDisplayName = a.Path
	}

	var paths []string
	for idx, sbom := range cfg.Documents {
		input := filepath.Join(ctx.Config.Dist, expand(sbom, env))

		path, err := templater.Apply(input)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", input, err)
		}

		path, err = filepath.Abs(path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: unable to create artifact path %q: %w", sbom, err)
		}

		procPath, err := subprocessDistPath(ctx.Config.Dist, path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: cannot determine document path for %q: %w", path, err)
		}

		env[fmt.Sprintf("document%d", idx)] = procPath
		if idx == 0 {
			env["document"] = procPath
		}

		paths = append(paths, procPath)
	}

	var names []string
	for _, p := range paths {
		names = append(names, filepath.Base(p))
	}

	fields := log.Fields{"cmd": cfg.Cmd, "artifact": artifactDisplayName, "sboms": strings.Join(names, ", ")}

	// nolint:prealloc
	var args []string
	for _, arg := range cfg.Args {
		renderedArg, err := templater.Apply(expand(arg, env))
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", arg, err)
		}
		args = append(args, renderedArg)
	}

	// The GoASTScanner flags this as a security risk.
	// However, this works as intended. The nosec annotation
	// tells the scanner to ignore this.
	// #nosec
	cmd := exec.CommandContext(ctx, cfg.Cmd, args...)
	cmd.Env = []string{}
	for _, key := range passthroughEnvVars {
		if value := os.Getenv(key); value != "" {
			cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
		}
	}
	cmd.Env = append(cmd.Env, cfg.Env...)
	cmd.Dir = ctx.Config.Dist

	var b bytes.Buffer
	w := gio.Safe(&b)
	cmd.Stderr = io.MultiWriter(logext.NewWriter(fields, logext.Error), w)
	cmd.Stdout = io.MultiWriter(logext.NewWriter(fields, logext.Info), w)

	log.WithFields(fields).Info("cataloging")
	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("cataloging artifacts: %s failed: %w: %s", cfg.Cmd, err, b.String())
	}

	var artifacts []*artifact.Artifact

	for _, sbom := range cfg.Documents {
		templater = tmpl.New(ctx).WithEnv(env)
		if a != nil {
			env["artifact"] = a.Name
			templater = templater.WithArtifact(a, nil)
		}

		name, err := templater.Apply(expand(sbom, env))
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", a, err)
		}

		search := filepath.Join(ctx.Config.Dist, name)
		matches, err := filepath.Glob(search)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts: failed to find SBOM artifact %q: %w", search, err)
		}
		for _, match := range matches {
			artifacts = append(artifacts, &artifact.Artifact{
				Type: artifact.SBOM,
				Name: name,
				Path: match,
				Extra: map[string]interface{}{
					artifact.ExtraID: cfg.ID,
				},
			})
		}

	}

	return artifacts, nil
}

func expand(s string, env map[string]string) string {
	return os.Expand(s, func(key string) string {
		return env[key]
	})
}
<commit_msg>fix: sbom binary filter (#2798)<commit_after>package sbom

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

	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/gio"
	"github.com/goreleaser/goreleaser/internal/ids"
	"github.com/goreleaser/goreleaser/internal/logext"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
)

// Environment variables to pass through to exec
var passthroughEnvVars = []string{"HOME", "USER", "USERPROFILE", "TMPDIR", "TMP", "TEMP", "PATH"}

// Pipe that catalogs common artifacts as an SBOM.
type Pipe struct{}

func (Pipe) String() string { return "cataloging artifacts" }
func (Pipe) Skip(ctx *context.Context) bool {
	return ctx.SkipSBOMCataloging || len(ctx.Config.SBOMs) == 0
}

// Default sets the Pipes defaults.
func (Pipe) Default(ctx *context.Context) error {
	ids := ids.New("sboms")
	for i := range ctx.Config.SBOMs {
		cfg := &ctx.Config.SBOMs[i]
		if cfg.Cmd == "" {
			cfg.Cmd = "syft"
		}
		if cfg.Artifacts == "" {
			cfg.Artifacts = "archive"
		}
		if len(cfg.Documents) == 0 {
			switch cfg.Artifacts {
			case "binary":
				cfg.Documents = []string{"{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom"}
			case "any":
				cfg.Documents = []string{}
			default:
				cfg.Documents = []string{"{{ .ArtifactName }}.sbom"}
			}
		}
		if cfg.Cmd == "syft" {
			if len(cfg.Args) == 0 {
				cfg.Args = []string{"$artifact", "--file", "$document", "--output", "spdx-json"}
			}
			if len(cfg.Env) == 0 && cfg.Artifacts == "source" || cfg.Artifacts == "archive" {
				cfg.Env = []string{
					"SYFT_FILE_METADATA_CATALOGER_ENABLED=true",
				}
			}
		}
		if cfg.ID == "" {
			cfg.ID = "default"
		}

		if cfg.Artifacts != "any" && len(cfg.Documents) > 1 {
			return fmt.Errorf("multiple SBOM outputs when artifacts=%q is unsupported", cfg.Artifacts)
		}

		ids.Inc(cfg.ID)
	}
	return ids.Validate()
}

// Run executes the Pipe.
func (Pipe) Run(ctx *context.Context) error {
	g := semerrgroup.New(ctx.Parallelism)
	for _, cfg := range ctx.Config.SBOMs {
		g.Go(catalogTask(ctx, cfg))
	}
	return g.Wait()
}

func catalogTask(ctx *context.Context, cfg config.SBOM) func() error {
	return func() error {
		var filters []artifact.Filter
		switch cfg.Artifacts {
		case "source":
			filters = append(filters, artifact.ByType(artifact.UploadableSourceArchive))
			if len(cfg.IDs) > 0 {
				log.Warn("when artifacts is `source`, `ids` has no effect. ignoring")
			}
		case "archive":
			filters = append(filters, artifact.ByType(artifact.UploadableArchive))
		case "binary":
			filters = append(filters, artifact.ByType(artifact.UploadableBinary))
		case "package":
			filters = append(filters, artifact.ByType(artifact.LinuxPackage))
		case "any":
			newArtifacts, err := catalogArtifact(ctx, cfg, nil)
			if err != nil {
				return err
			}
			for _, newArtifact := range newArtifacts {
				ctx.Artifacts.Add(newArtifact)
			}
			return nil
		default:
			return fmt.Errorf("invalid list of artifacts to catalog: %s", cfg.Artifacts)
		}

		if len(cfg.IDs) > 0 {
			filters = append(filters, artifact.ByIDs(cfg.IDs...))
		}
		artifacts := ctx.Artifacts.Filter(artifact.And(filters...)).List()
		return catalog(ctx, cfg, artifacts)
	}
}

func catalog(ctx *context.Context, cfg config.SBOM, artifacts []*artifact.Artifact) error {
	for _, a := range artifacts {
		newArtifacts, err := catalogArtifact(ctx, cfg, a)
		if err != nil {
			return err
		}
		for _, newArtifact := range newArtifacts {
			ctx.Artifacts.Add(newArtifact)
		}
	}
	return nil
}

func subprocessDistPath(distDir string, pathRelativeToCwd string) (string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	if !filepath.IsAbs(distDir) {
		distDir, err = filepath.Abs(distDir)
		if err != nil {
			return "", err
		}
	}
	relativePath, err := filepath.Rel(cwd, distDir)
	if err != nil {
		return "", err
	}
	return strings.TrimPrefix(pathRelativeToCwd, relativePath+string(filepath.Separator)), nil
}

func catalogArtifact(ctx *context.Context, cfg config.SBOM, a *artifact.Artifact) ([]*artifact.Artifact, error) {
	env := ctx.Env.Copy()
	artifactDisplayName := "(any)"
	templater := tmpl.New(ctx).WithEnv(env)

	if a != nil {
		procPath, err := subprocessDistPath(ctx.Config.Dist, a.Path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: cannot determine artifact path for %q: %w", a.Path, err)
		}
		env["artifact"] = procPath
		env["artifactID"] = a.ID()

		templater = templater.WithArtifact(a, nil)
		artifactDisplayName = a.Path
	}

	var paths []string
	for idx, sbom := range cfg.Documents {
		input := filepath.Join(ctx.Config.Dist, expand(sbom, env))

		path, err := templater.Apply(input)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", input, err)
		}

		path, err = filepath.Abs(path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: unable to create artifact path %q: %w", sbom, err)
		}

		procPath, err := subprocessDistPath(ctx.Config.Dist, path)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: cannot determine document path for %q: %w", path, err)
		}

		env[fmt.Sprintf("document%d", idx)] = procPath
		if idx == 0 {
			env["document"] = procPath
		}

		paths = append(paths, procPath)
	}

	var names []string
	for _, p := range paths {
		names = append(names, filepath.Base(p))
	}

	fields := log.Fields{"cmd": cfg.Cmd, "artifact": artifactDisplayName, "sboms": strings.Join(names, ", ")}

	// nolint:prealloc
	var args []string
	for _, arg := range cfg.Args {
		renderedArg, err := templater.Apply(expand(arg, env))
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", arg, err)
		}
		args = append(args, renderedArg)
	}

	// The GoASTScanner flags this as a security risk.
	// However, this works as intended. The nosec annotation
	// tells the scanner to ignore this.
	// #nosec
	cmd := exec.CommandContext(ctx, cfg.Cmd, args...)
	cmd.Env = []string{}
	for _, key := range passthroughEnvVars {
		if value := os.Getenv(key); value != "" {
			cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
		}
	}
	cmd.Env = append(cmd.Env, cfg.Env...)
	cmd.Dir = ctx.Config.Dist

	var b bytes.Buffer
	w := gio.Safe(&b)
	cmd.Stderr = io.MultiWriter(logext.NewWriter(fields, logext.Error), w)
	cmd.Stdout = io.MultiWriter(logext.NewWriter(fields, logext.Info), w)

	log.WithFields(fields).Info("cataloging")
	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("cataloging artifacts: %s failed: %w: %s", cfg.Cmd, err, b.String())
	}

	var artifacts []*artifact.Artifact

	for _, sbom := range cfg.Documents {
		templater = tmpl.New(ctx).WithEnv(env)
		if a != nil {
			env["artifact"] = a.Name
			templater = templater.WithArtifact(a, nil)
		}

		name, err := templater.Apply(expand(sbom, env))
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts failed: %s: invalid template: %w", a, err)
		}

		search := filepath.Join(ctx.Config.Dist, name)
		matches, err := filepath.Glob(search)
		if err != nil {
			return nil, fmt.Errorf("cataloging artifacts: failed to find SBOM artifact %q: %w", search, err)
		}
		for _, match := range matches {
			artifacts = append(artifacts, &artifact.Artifact{
				Type: artifact.SBOM,
				Name: name,
				Path: match,
				Extra: map[string]interface{}{
					artifact.ExtraID: cfg.ID,
				},
			})
		}

	}

	return artifacts, nil
}

func expand(s string, env map[string]string) string {
	return os.Expand(s, func(key string) string {
		return env[key]
	})
}
<|endoftext|>


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

package test

import (
	"github.com/mediaFORGE/gol"
	"github.com/mediaFORGE/gol/internal/mock"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type BaseLoggerTestSuite struct {
	suite.Suite
}

type setupBaseLoggerTest struct {
	setUp   func(
		msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
	) *gol.BaseLogger
	message gol.LogMessage
	output  string
}

func (s *BaseLoggerTestSuite) TestGetSetFilter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Filter())
	l.SetFilter(&mock.MockLogFilter{})
	assert.NotNil(s.T(), l.Filter())
}

func (s *BaseLoggerTestSuite) TestGetSetFormatter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Formatter())
	l.SetFormatter(&mock.MockLogFormatter{})
	assert.NotNil(s.T(), l.Formatter())
}

func (s *BaseLoggerTestSuite) TestGetSetWriter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Writer())
	l.SetWriter(&mock.MockWriter{})
	assert.NotNil(s.T(), l.Writer())
}

func (s *BaseLoggerTestSuite) TestSend() {

	in := map[string]setupBaseLoggerTest{
		"error": setupBaseLoggerTest{
			setUp: func(
				msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
			) (logger *gol.BaseLogger) {
				mf.Mock.On("Filter", msg).Return(false, nil)
				mfmt.Mock.On("Format", msg).Return("ERROR", nil)
				mw.Mock.On("Write", []byte("ERROR")).Return(5, nil)

				logger = &gol.BaseLogger{}
				logger.SetFilter(mf)
				logger.SetFormatter(mfmt)
				logger.SetWriter(mw)

				return
			},
			message: map[string]interface{}{
				"severity": gol.Error,
			},
			output: "ERROR",
		},
		"info": setupBaseLoggerTest{
			setUp: func(
				msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
			) (logger *gol.BaseLogger) {
				mf.Mock.On("Filter", msg).Return(true, nil)

				logger = &gol.BaseLogger{}
				logger.SetFilter(mf)
				logger.SetFormatter(mfmt)
				logger.SetWriter(mw)

				return
			},
			message: map[string]interface{}{
				"severity": gol.Info,
			},
			output: "",
		},
	}

	for _, t := range in {
		mf := &mock.MockLogFilter{}
		mfmt := &mock.MockLogFormatter{}
		mw := &mock.MockWriter{}
		logger := t.setUp(&t.message, mf, mfmt, mw)

		logger.Send(&t.message)

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

package test

import (
	"github.com/mediaFORGE/gol"
	"github.com/mediaFORGE/gol/fields"
	"github.com/mediaFORGE/gol/fields/severity"
	"github.com/mediaFORGE/gol/internal/mock"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type BaseLoggerTestSuite struct {
	suite.Suite
}

type setupBaseLoggerTest struct {
	setUp   func(
		msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
	) *gol.BaseLogger
	message gol.LogMessage
	output  string
}

func (s *BaseLoggerTestSuite) TestGetSetFilter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Filter())
	l.SetFilter(&mock.MockLogFilter{})
	assert.NotNil(s.T(), l.Filter())
}

func (s *BaseLoggerTestSuite) TestGetSetFormatter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Formatter())
	l.SetFormatter(&mock.MockLogFormatter{})
	assert.NotNil(s.T(), l.Formatter())
}

func (s *BaseLoggerTestSuite) TestGetSetWriter() {

	l := gol.BaseLogger{}

	assert.Nil(s.T(), l.Writer())
	l.SetWriter(&mock.MockWriter{})
	assert.NotNil(s.T(), l.Writer())
}

func (s *BaseLoggerTestSuite) TestSend() {

	in := map[string]setupBaseLoggerTest{
		"error": setupBaseLoggerTest{
			setUp: func(
				msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
			) (logger *gol.BaseLogger) {
				mf.Mock.On("Filter", msg).Return(false, nil)
				mfmt.Mock.On("Format", msg).Return("ERROR", nil)
				mw.Mock.On("Write", []byte("ERROR")).Return(5, nil)

				logger = &gol.BaseLogger{}
				logger.SetFilter(mf)
				logger.SetFormatter(mfmt)
				logger.SetWriter(mw)

				return
			},
			message: map[string]interface{}{
				fields.Severity: severity.Error,
			},
			output: "ERROR",
		},
		"info": setupBaseLoggerTest{
			setUp: func(
				msg *gol.LogMessage, mf *mock.MockLogFilter, mfmt *mock.MockLogFormatter, mw *mock.MockWriter,
			) (logger *gol.BaseLogger) {
				mf.Mock.On("Filter", msg).Return(true, nil)

				logger = &gol.BaseLogger{}
				logger.SetFilter(mf)
				logger.SetFormatter(mfmt)
				logger.SetWriter(mw)

				return
			},
			message: map[string]interface{}{
				fields.Severity: severity.Info,
			},
			output: "",
		},
	}

	for _, t := range in {
		mf := &mock.MockLogFilter{}
		mfmt := &mock.MockLogFormatter{}
		mw := &mock.MockWriter{}
		logger := t.setUp(&t.message, mf, mfmt, mw)

		logger.Send(&t.message)

		mf.AssertExpectations(s.T())
		mfmt.AssertExpectations(s.T())
		mw.AssertExpectations(s.T())
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package glam

import "github.com/drakmaniso/glam/math"

//------------------------------------------------------------------------------

// `Mat4` is a single-precision matrix with 4 columns and 4 rows.
//
// Note: matrices are stored in column-major order, so when writing literals
// remember to use the transpose.
type Mat4 [4][4]float32

//------------------------------------------------------------------------------

// `NewMat4` allocates and returns a new matrix. The elements are stored in
// alphabetical order (column-major order).
func NewMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) *Mat4 {
	return &Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `MakeMat4` returns (by value) a matrix. The elements are stored in
// alphabetical order (column-major order).
func MakeMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) Mat4 {
	return Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `SetTo` initializes `matrix`. The elements are stored in
// alphabetical order (column-major order).
func (matrix *Mat4) SetTo(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) {
	matrix[0][0] = a
	matrix[0][1] = b
	matrix[0][2] = c
	matrix[0][3] = d

	matrix[1][0] = e
	matrix[1][1] = f
	matrix[1][2] = g
	matrix[1][3] = h

	matrix[2][0] = i
	matrix[2][1] = j
	matrix[2][2] = k
	matrix[2][3] = l

	matrix[3][0] = m
	matrix[3][1] = n
	matrix[3][2] = o
	matrix[3][3] = p
}

//------------------------------------------------------------------------------

// `At` returns the element at '(column, row)`.
func (m Mat4) At(column, row int) float32 {
	return m[column][row]
}

// `Set` sets the element at `(column, row)` to `value`.
func (m *Mat4) Set(column, row int, value float32) {
	m[column][row] = value
}

//------------------------------------------------------------------------------

// `Perspective` returns (by value) a perspective projection matrix.
func Perspective(fieldOfView float32, aspectRatio float32, near float32, far float32) Mat4 {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	return Mat4{
		{f / aspectRatio, 0, 0, 0},
		{0, f, 0, 0},
		{0, 0, (far + near) / (near - far), -1},
		{0, 0, (2 * far * near) / (near - far), 0},
	}
}

// `SetToPerspective` sets `m` to a perspective projection matrix.
func (m *Mat4) SetToPerspective(fieldOfView float32, aspectRatio float32, near float32, far float32) {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	m[0][0] = f / aspectRatio
	m[0][1] = 0
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = f
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (far + near) / (near - far)
	m[0][3] = -1

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (2 * far * near) / (near - far)
	m[0][3] = 0
}

//------------------------------------------------------------------------------
<commit_msg>Switched argument order for `At` and `SetTo` (conform to math).<commit_after>// Copyright (c) 2013 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package glam

import "github.com/drakmaniso/glam/math"

//------------------------------------------------------------------------------

// `Mat4` is a single-precision matrix with 4 columns and 4 rows.
//
// Note: matrices are stored in column-major order, so when writing literals
// remember to use the transpose.
type Mat4 [4][4]float32

//------------------------------------------------------------------------------

// `NewMat4` allocates and returns a new matrix. The elements are stored in
// alphabetical order (column-major order).
func NewMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) *Mat4 {
	return &Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `MakeMat4` returns (by value) a matrix. The elements are stored in
// alphabetical order (column-major order).
func MakeMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) Mat4 {
	return Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `SetTo` initializes `matrix`. The elements are stored in
// alphabetical order (column-major order).
func (matrix *Mat4) SetTo(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) {
	matrix[0][0] = a
	matrix[0][1] = b
	matrix[0][2] = c
	matrix[0][3] = d

	matrix[1][0] = e
	matrix[1][1] = f
	matrix[1][2] = g
	matrix[1][3] = h

	matrix[2][0] = i
	matrix[2][1] = j
	matrix[2][2] = k
	matrix[2][3] = l

	matrix[3][0] = m
	matrix[3][1] = n
	matrix[3][2] = o
	matrix[3][3] = p
}

//------------------------------------------------------------------------------

// `At` returns the element at '(row, column)`.
func (m Mat4) At(row, column int) float32 {
	return m[column][row]
}

// `Set` sets the element at `(row, column)` to `value`.
func (m *Mat4) Set(row, column int, value float32) {
	m[column][row] = value
}

//------------------------------------------------------------------------------

// `Perspective` returns (by value) a perspective projection matrix.
func Perspective(fieldOfView float32, aspectRatio float32, near float32, far float32) Mat4 {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	return Mat4{
		{f / aspectRatio, 0, 0, 0},
		{0, f, 0, 0},
		{0, 0, (far + near) / (near - far), -1},
		{0, 0, (2 * far * near) / (near - far), 0},
	}
}

// `SetToPerspective` sets `m` to a perspective projection matrix.
func (m *Mat4) SetToPerspective(fieldOfView float32, aspectRatio float32, near float32, far float32) {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	m[0][0] = f / aspectRatio
	m[0][1] = 0
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = f
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (far + near) / (near - far)
	m[0][3] = -1

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (2 * far * near) / (near - far)
	m[0][3] = 0
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package util

func checkError(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Export function<commit_after>package util

func CheckError(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package integration_test

import (
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
	"time"
)

var tmpDir string
var pathToGinkgo string

func TestIntegration(t *testing.T) {
	SetDefaultEventuallyTimeout(10 * time.Second)
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

var _ = BeforeSuite(func() {
	var err error
	pathToGinkgo, err = gexec.Build("github.com/onsi/ginkgo/ginkgo")
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	var err error
	tmpDir, err = ioutil.TempDir("", "ginkgo-run")
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = AfterEach(func() {
	err := os.RemoveAll(tmpDir)
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = AfterSuite(func() {
	gexec.CleanupBuildArtifacts()
})

func tmpPath(destination string) string {
	return filepath.Join(tmpDir, destination)
}

func copyIn(fixture string, destination string) {
	err := os.MkdirAll(destination, 0777)
	Ω(err).ShouldNot(HaveOccurred())

	filepath.Walk(filepath.Join("_fixtures", fixture), func(path string, info os.FileInfo, err error) error {
		base := filepath.Base(path)
		if base == fixture {
			return nil
		}

		src, err := os.Open(path)
		Ω(err).ShouldNot(HaveOccurred())

		dst, err := os.Create(filepath.Join(destination, base))
		Ω(err).ShouldNot(HaveOccurred())

		_, err = io.Copy(dst, src)
		Ω(err).ShouldNot(HaveOccurred())
		return nil
	})
}

func ginkgoCommand(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(pathToGinkgo, args...)
	cmd.Dir = dir
	cmd.Env = []string{}
	for _, env := range os.Environ() {
		if !strings.Contains(env, "GINKGO_REMOTE_REPORTING_SERVER") {
			cmd.Env = append(cmd.Env, env)
		}
	}

	return cmd
}

func startGinkgo(dir string, args ...string) *gexec.Session {
	cmd := ginkgoCommand(dir, args...)
	session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	return session
}
<commit_msg>bump integration test timeout for travis<commit_after>package integration_test

import (
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
	"time"
)

var tmpDir string
var pathToGinkgo string

func TestIntegration(t *testing.T) {
	SetDefaultEventuallyTimeout(15 * time.Second)
	RegisterFailHandler(Fail)
	RunSpecs(t, "Integration Suite")
}

var _ = BeforeSuite(func() {
	var err error
	pathToGinkgo, err = gexec.Build("github.com/onsi/ginkgo/ginkgo")
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	var err error
	tmpDir, err = ioutil.TempDir("", "ginkgo-run")
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = AfterEach(func() {
	err := os.RemoveAll(tmpDir)
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = AfterSuite(func() {
	gexec.CleanupBuildArtifacts()
})

func tmpPath(destination string) string {
	return filepath.Join(tmpDir, destination)
}

func copyIn(fixture string, destination string) {
	err := os.MkdirAll(destination, 0777)
	Ω(err).ShouldNot(HaveOccurred())

	filepath.Walk(filepath.Join("_fixtures", fixture), func(path string, info os.FileInfo, err error) error {
		base := filepath.Base(path)
		if base == fixture {
			return nil
		}

		src, err := os.Open(path)
		Ω(err).ShouldNot(HaveOccurred())

		dst, err := os.Create(filepath.Join(destination, base))
		Ω(err).ShouldNot(HaveOccurred())

		_, err = io.Copy(dst, src)
		Ω(err).ShouldNot(HaveOccurred())
		return nil
	})
}

func ginkgoCommand(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(pathToGinkgo, args...)
	cmd.Dir = dir
	cmd.Env = []string{}
	for _, env := range os.Environ() {
		if !strings.Contains(env, "GINKGO_REMOTE_REPORTING_SERVER") {
			cmd.Env = append(cmd.Env, env)
		}
	}

	return cmd
}

func startGinkgo(dir string, args ...string) *gexec.Session {
	cmd := ginkgoCommand(dir, args...)
	session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	return session
}
<|endoftext|>


<commit_before>package lifecycle_test

import (
	"runtime/debug"
	"time"

	"github.com/cloudfoundry-incubator/garden"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Process", func() {

	var container garden.Container

	BeforeEach(func() {
		client = startGarden()
		var err error
		container, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("signalling", func() {
		It("a process can be sent SIGTERM immediately after having been started", func() {
			stdout := gbytes.NewBuffer()

			process, err := container.Run(garden.ProcessSpec{
				User: "vcap",
				Path: "sh",
				Args: []string{
					"-c",
					`
                sleep 10
                exit 12
                `,
				},
			}, garden.ProcessIO{
				Stdout: stdout,
			})
			Expect(err).ToNot(HaveOccurred())

			err = process.Signal(garden.SignalTerminate)
			Expect(err).ToNot(HaveOccurred())
			Expect(process.Wait()).NotTo(Equal(12))
		})
	})

	startAndWait := func() (garden.Process, <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		process, err := container.Run(garden.ProcessSpec{
			User: "vcap",
			Path: "sh",
			Args: []string{"-c", `
				  trap 'echo termed; exit 42' SIGTERM

					while true; do
					  echo waiting
					  sleep 1
					done
				`},
		}, procIo)
		Expect(err).NotTo(HaveOccurred())

		attachedProcess, err := container.Attach(process.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		exitChan := make(chan int)
		go func(p garden.Process, exited chan<- int) {
			GinkgoRecover()
			status, waitErr := p.Wait()
			Expect(waitErr).NotTo(HaveOccurred())
			exited <- status
		}(attachedProcess, exitChan)

		return attachedProcess, exitChan
	}

	waitForExit := func(p garden.Process, e <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		attachedProcess, err := container.Attach(p.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		Expect(attachedProcess.Signal(garden.SignalTerminate)).To(Succeed())
		select {
		case status := <-e:
			Expect(status).To(Equal(42))
			Eventually(buf).Should(gbytes.Say("termed"))
		case <-time.After(time.Second * 10):
			debug.PrintStack()
			Fail("timed out!")
		}
	}

	It("should not allow process outcomes to interfere with eachother", func() {
		p1, e1 := startAndWait()
		p2, e2 := startAndWait()
		p3, e3 := startAndWait()
		p4, e4 := startAndWait()

		waitForExit(p1, e1)
		waitForExit(p2, e2)
		waitForExit(p4, e4)
		waitForExit(p3, e3)
	})
})
<commit_msg>Fix typo in test name<commit_after>package lifecycle_test

import (
	"runtime/debug"
	"time"

	"github.com/cloudfoundry-incubator/garden"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Process", func() {

	var container garden.Container

	BeforeEach(func() {
		client = startGarden()
		var err error
		container, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("signalling", func() {
		It("a process can be sent SIGTERM immediately after having been started", func() {
			stdout := gbytes.NewBuffer()

			process, err := container.Run(garden.ProcessSpec{
				User: "vcap",
				Path: "sh",
				Args: []string{
					"-c",
					`
                sleep 10
                exit 12
                `,
				},
			}, garden.ProcessIO{
				Stdout: stdout,
			})
			Expect(err).ToNot(HaveOccurred())

			err = process.Signal(garden.SignalTerminate)
			Expect(err).ToNot(HaveOccurred())
			Expect(process.Wait()).NotTo(Equal(12))
		})
	})

	startAndWait := func() (garden.Process, <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		process, err := container.Run(garden.ProcessSpec{
			User: "vcap",
			Path: "sh",
			Args: []string{"-c", `
				  trap 'echo termed; exit 42' SIGTERM

					while true; do
					  echo waiting
					  sleep 1
					done
				`},
		}, procIo)
		Expect(err).NotTo(HaveOccurred())

		attachedProcess, err := container.Attach(process.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		exitChan := make(chan int)
		go func(p garden.Process, exited chan<- int) {
			GinkgoRecover()
			status, waitErr := p.Wait()
			Expect(waitErr).NotTo(HaveOccurred())
			exited <- status
		}(attachedProcess, exitChan)

		return attachedProcess, exitChan
	}

	waitForExit := func(p garden.Process, e <-chan int) {
		buf := gbytes.NewBuffer()
		procIo := garden.ProcessIO{
			Stdout: buf,
			Stderr: buf,
		}
		attachedProcess, err := container.Attach(p.ID(), procIo)
		Expect(err).NotTo(HaveOccurred())
		Eventually(buf).Should(gbytes.Say("waiting"))

		Expect(attachedProcess.Signal(garden.SignalTerminate)).To(Succeed())
		select {
		case status := <-e:
			Expect(status).To(Equal(42))
			Eventually(buf).Should(gbytes.Say("termed"))
		case <-time.After(time.Second * 10):
			debug.PrintStack()
			Fail("timed out!")
		}
	}

	It("should not allow process outcomes to interfere with each other", func() {
		p1, e1 := startAndWait()
		p2, e2 := startAndWait()
		p3, e3 := startAndWait()
		p4, e4 := startAndWait()

		waitForExit(p1, e1)
		waitForExit(p2, e2)
		waitForExit(p4, e4)
		waitForExit(p3, e3)
	})
})
<|endoftext|>


<commit_before>package main

import (
	"log"
	"regexp"

	"github.com/hashicorp/consul/api"
)

// get a client handle for a specified address (or the local agent if "")
func getClient(address string) (*api.Client, error) {
	config := api.DefaultConfig()
	if address != "" {
		config.Address = address
	}
	return api.NewClient(config)
}

// get a list of all services, limit to those matching the search criteria
func getList(serviceString string, tag string) []*api.ServiceEntry {
	client, err := getClient("")
	if err != nil {
		log.Fatalf("Unable to get a consul client connection: %s\n", err)
	}

	serviceList, _, err := client.Catalog().Services(nil)
	if err != nil {
		log.Fatalf("Unable to get list of services from catalog: %s", err)
	}

	nodeServiceMap := make(map[string]map[string]*api.CatalogService)

	for svc := range serviceList {
		catsvcs, _, err := client.Catalog().Service(svc, tag, nil)
		if err != nil {
			log.Fatalf("Unable to query for service \"%s\" from catalog: %s", svc, err)
		}
		for _, catsvc := range catsvcs {
			if _, ok := nodeServiceMap[catsvc.Node]; !ok {
				nodeServiceMap[catsvc.Node] = make(map[string]*api.CatalogService)
			}
			nodeServiceMap[catsvc.Node][catsvc.ServiceID] = catsvc
		}
	}

	// get a handle to the health endpoint and pre-calculate the regexp
	health := client.Health()
	var re *regexp.Regexp
	if serviceString != "" {
		re = regexp.MustCompile(serviceString)
	}

	// prepare a slice to hold the result list
	seOut := make([]*api.ServiceEntry, 0)

	for _, services := range nodeServiceMap {
		for serviceID, service := range services {
			match := true
			if re != nil {
				idStr := re.FindString(serviceID)
				nameStr := re.FindString(service.ServiceName)
				match = idStr != "" || nameStr != ""
			}
			if match {
				seList, _, err := health.Service(service.ServiceName, tag, false, nil)
				if err != nil {
					log.Fatalf("Unable to query health status of: %s\n", err)
				}
				for _, se := range seList {
					if se.Service.ID == serviceID {
						seOut = append(seOut, se)
						break
					}
				}
			}
		}
	}

	return seOut
}

// A service entry is considered healty if all the eligible checks are passing.
// serfChecks are not eligible
func isHealthy(se *api.ServiceEntry) bool {
	if se == nil || se.Checks == nil || len(se.Checks) == 0 {
		// No checks = failing
		return false
	}

	var healthy bool = true
	var eligible int = 0
	for _, c := range se.Checks {
		if c.Name == "serfHealth" {
			continue
		}
		// All found checks have to be passing
		healthy = healthy && (c.Status == "passing")
		eligible++
	}

	// No eligible checks were found
	if eligible == 0 {
		return false
	}

	return healthy
}
<commit_msg>performance.<commit_after>package main

import (
	"log"
	"regexp"

	"github.com/hashicorp/consul/api"
)

// get a client handle for a specified address (or the local agent if "")
func getClient(address string) (*api.Client, error) {
	config := api.DefaultConfig()
	if address != "" {
		config.Address = address
	}
	return api.NewClient(config)
}

// get a list of all services, limit to those matching the search criteria
func getList(serviceString string, tag string) []*api.ServiceEntry {
	client, err := getClient("")
	if err != nil {
		log.Fatalf("Unable to get a consul client connection: %s\n", err)
	}

	serviceList, _, err := client.Catalog().Services(nil)
	if err != nil {
		log.Fatalf("Unable to get list of services from catalog: %s", err)
	}

	nodeServiceMap := make(map[string]map[string]*api.ServiceEntry)

	for svc := range serviceList {
		entries, _, err := client.Health().Service(svc, tag, false, nil)
		if err != nil {
			log.Fatalf("Unable to query for service \"%s\" from catalog: %s", svc, err)
		}
		for _, entry := range entries {
			if _, ok := nodeServiceMap[entry.Node.Node]; !ok {
				nodeServiceMap[entry.Node.Node] = make(map[string]*api.ServiceEntry)
			}
			nodeServiceMap[entry.Node.Node][entry.Service.ID] = entry
		}
	}

	// get a handle to the health endpoint and pre-calculate the regexp
	var re *regexp.Regexp
	if serviceString != "" {
		re = regexp.MustCompile(serviceString)
	}

	// prepare a slice to hold the result list
	seOut := make([]*api.ServiceEntry, 0)

	for _, services := range nodeServiceMap {
		for serviceID, service := range services {
			match := true
			if re != nil {
				idStr := re.FindString(serviceID)
				nameStr := re.FindString(service.Service.ID)
				match = idStr != "" || nameStr != ""
			}
			if match {
				seOut = append(seOut, service)
			}
		}
	}

	return seOut
}

// A service entry is considered healty if all the eligible checks are passing.
// serfChecks are not eligible
func isHealthy(se *api.ServiceEntry) bool {
	if se == nil || se.Checks == nil || len(se.Checks) == 0 {
		// No checks = failing
		return false
	}

	var healthy bool = true
	var eligible int = 0
	for _, c := range se.Checks {
		if c.Name == "serfHealth" {
			continue
		}
		// All found checks have to be passing
		healthy = healthy && (c.Status == "passing")
		eligible++
	}

	// No eligible checks were found
	if eligible == 0 {
		return false
	}

	return healthy
}
<|endoftext|>


<commit_before>package colonycore

import (
	"github.com/eaciit/orm/v1"
)

type Server struct {
	orm.ModelBase
	ID         string `json:"_id", bson:"_id"`
	OS         string `json:"os", bson:"os"`
	AppPath    string `json:"appPath",bson:"appPath"`
	DataPath   string `json:"dataPath",bson:"dataPath"`
	Host       string `json:"host", bson:"host"`
	ServerType string `json:"serverType", bson:"serverType"`
	SSHType    string `json:"sshtype", bson:"sshtype"`
	SSHFile    string `json:"sshfile", bson:"sshfile"`
	SSHUser    string `json:"sshuser", bson:"sshuser"`
	SSHPass    string `json:"sshpass", bson:"sshpass"`
}

func (s *Server) TableName() string {
	return "servers"
}

func (s *Server) RecordID() interface{} {
	return s.ID
}
<commit_msg>no message<commit_after>package colonycore

import (
	"github.com/eaciit/orm/v1"
)

type Server struct {
	orm.ModelBase
	ID         string `json:"_id", bson:"_id"`
	OS         string `json:"os", bson:"os"`
	AppPath    string `json:"appPath",bson:"appPath"`
	DataPath   string `json:"dataPath",bson:"dataPath"`
	Host       string `json:"host", bson:"host"`
	ServerType string `json:"serverType", bson:"serverType"`
	SSHType    string `json:"sshtype", bson:"sshtype"`
	SSHFile    string `json:"sshfile", bson:"sshfile"`
	SSHUser    string `json:"sshuser", bson:"sshuser"`
	SSHPass    string `json:"sshpass", bson:"sshpass"`
	CmdExtract string `json:"cmdextract", bson:"cmdextract"`
	CmdNewFile string `json:"cmdnewfile", bson:"cmdnewfile"`
	CmdCopy    string `json:"cmdcopy", bson:"cmdcopy"`
	CmdMkDir   string `json:"cmdmkdir", bson:"cmdmkdir"`
}

func (s *Server) TableName() string {
	return "servers"
}

func (s *Server) RecordID() interface{} {
	return s.ID
}
<|endoftext|>


<commit_before>package brightbox

import (
	"time"
)

// Image represents a Machine Image
// https://api.gb1.brightbox.com/1.0/#image
type Image struct {
	ID                string
	Name              string
	Username          string
	Status            string
	Locked            bool
	Description       string
	Source            string
	Arch              string
	CreatedAt         time.Time `json:"created_at"`
	Official          bool
	Public            bool
	Owner             string
	SourceType        string `json:"source_type"`
	VirtualSize       int    `json:"virtual_size"`
	DiskSize          int    `json:"disk_size"`
	CompatibilityMode bool   `json:"compatibility_mode"`
	AncestorID        string `json:"ancestor_id"`
	LicenceName       string `json:"licence_name"`
}

// ImageOptions is used to create and update machine images
type ImageOptions struct {
	ID                string  `json:"-"`
	Name              *string `json:"name,omitempty"`
	Username          *string `json:"username,omitempty"`
	Status            *string `json:"status,omitempty"`
	Description       *string `json:"description,omitempty"`
	Source            *string `json:"source,omitempty"`
	Arch              *string `json:"arch,omitempty"`
	Public            *bool   `json:"public,omitempty"`
	CompatibilityMode *bool   `json:"compatibility_mode,omitempty"`
}

// APIPath returns the relative URL path to the collection endpoint
func (c Image) APIPath() string {
	return "images"
}

// FetchID returns the ID field from the object
func (c Image) FetchID() string {
	return c.ID
}

// PostPath returns the relative URL path to POST an object
func (c Image) PostPath(from *ImageOptions) string {
	return c.APIPath()
}

// PutPath returns the relative URL path to PUT an object
func (c Image) PutPath(from *ImageOptions) string {
	return c.APIPath() + "/" + from.OptionID()
}

// DestroyPath returns the relative URL path to DESTROY an object
func (c Image) DestroyPath(from string) string {
	return c.APIPath() + "/" + from
}

// OptionID returns the ID field from and options object
// ID will be blank for create, and set for update
func (c ImageOptions) OptionID() string {
	return c.ID
}

// LockID returns the path to a lockable object
func (c Image) LockID() string {
	return c.APIPath() + "/" + c.FetchID()
}
<commit_msg>Fix Ancestor reference in Images<commit_after>package brightbox

import (
	"time"
)

// Image represents a Machine Image
// https://api.gb1.brightbox.com/1.0/#image
type Image struct {
	ID                string
	Name              string
	Username          string
	Status            string
	Locked            bool
	Description       string
	Source            string
	Arch              string
	CreatedAt         time.Time `json:"created_at"`
	Official          bool
	Public            bool
	Owner             string
	SourceType        string `json:"source_type"`
	VirtualSize       int    `json:"virtual_size"`
	DiskSize          int    `json:"disk_size"`
	CompatibilityMode bool   `json:"compatibility_mode"`
	LicenceName       string `json:"licence_name"`
	Ancestor          *Image
}

// ImageOptions is used to create and update machine images
type ImageOptions struct {
	ID                string  `json:"-"`
	Name              *string `json:"name,omitempty"`
	Username          *string `json:"username,omitempty"`
	Status            *string `json:"status,omitempty"`
	Description       *string `json:"description,omitempty"`
	Source            *string `json:"source,omitempty"`
	Arch              *string `json:"arch,omitempty"`
	Public            *bool   `json:"public,omitempty"`
	CompatibilityMode *bool   `json:"compatibility_mode,omitempty"`
}

// APIPath returns the relative URL path to the collection endpoint
func (c Image) APIPath() string {
	return "images"
}

// FetchID returns the ID field from the object
func (c Image) FetchID() string {
	return c.ID
}

// PostPath returns the relative URL path to POST an object
func (c Image) PostPath(from *ImageOptions) string {
	return c.APIPath()
}

// PutPath returns the relative URL path to PUT an object
func (c Image) PutPath(from *ImageOptions) string {
	return c.APIPath() + "/" + from.OptionID()
}

// DestroyPath returns the relative URL path to DESTROY an object
func (c Image) DestroyPath(from string) string {
	return c.APIPath() + "/" + from
}

// OptionID returns the ID field from and options object
// ID will be blank for create, and set for update
func (c ImageOptions) OptionID() string {
	return c.ID
}

// LockID returns the path to a lockable object
func (c Image) LockID() string {
	return c.APIPath() + "/" + c.FetchID()
}
<|endoftext|>


<commit_before>// Package yiigo makes Golang development easier !
//
// Basic usage
//
// MySQL
//
//    // default db
//    yiigo.RegisterDB("default", yiigo.MySQL, "root:root@tcp(localhost:3306)/test")
//
//    yiigo.DB.Get(&User{}, "SELECT * FROM `user` WHERE `id` = ?", 1)
//
//    // other db
//    yiigo.RegisterDB("foo", yiigo.MySQL, "root:root@tcp(localhost:3306)/foo")
//
//    yiigo.UseDB("foo").Get(&User{}, "SELECT * FROM `user` WHERE `id` = ?", 1)
//
// MongoDB
//
//    // default mongodb
//    yiigo.RegisterMongoDB("default", "mongodb://localhost:27017")
//
//    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
//    yiigo.Mongo.Database("test").Collection("numbers").InsertOne(ctx, bson.M{"name": "pi", "value": 3.14159})
//
//    // other mongodb
//    yiigo.RegisterMongoDB("foo", "mongodb://localhost:27017")
//
//    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
//    yiigo.UseMongo("foo").Database("test").Collection("numbers").InsertOne(ctx, bson.M{"name": "pi", "value": 3.14159})
//
// Redis
//
//    // default redis
//    yiigo.RegisterRedis("default", "localhost:6379")
//
//    conn, err := yiigo.Redis.Get()
//
//    if err != nil {
// 	     log.Fatal(err)
//    }
//
//    defer yiigo.Redis.Put(conn)
//
//    conn.Do("SET", "test_key", "hello world")
//
//    // other redis
//    yiigo.RegisterRedis("foo", "localhost:6379")
//
//    foo := yiigo.UseRedis("foo")
//    conn, err := foo.Get()
//
//    if err != nil {
// 	     log.Fatal(err)
//    }
//
//    defer foo.Put(conn)
//
//    conn.Do("SET", "test_key", "hello world")
//
// Config:
//
//    // env.toml
//    //
//    // [app]
//    // env = "dev"
//    // debug = true
//    // port = 50001
//
//    yiigo.UseEnv("env.toml")
//
//    yiigo.Env.GetBool("app.debug", true)
//    yiigo.Env.GetInt("app.port", 12345)
//    yiigo.Env.GetString("app.env", "dev")
//
// Logger:
//
//    // default logger
//    yiigo.RegisterLogger("default", "app.log")
//    yiigo.Logger.Info("hello world")
//
//    // other logger
//    yiigo.RegisterLogger("foo", "foo.log")
//    yiigo.UseLogger("foo").Info("hello world")
//
// For more details, see the documentation for the types and methods.
//
package yiigo
<commit_msg>Udpate doc.go<commit_after>// Package yiigo makes Golang development easier !
//
// Basic usage
//
// MySQL
//
//    // default db
//    yiigo.RegisterDB("default", yiigo.MySQL, "root:root@tcp(localhost:3306)/test")
//
//    yiigo.DB.Get(&User{}, "SELECT * FROM `user` WHERE `id` = ?", 1)
//
//    // other db
//    yiigo.RegisterDB("foo", yiigo.MySQL, "root:root@tcp(localhost:3306)/foo")
//
//    yiigo.UseDB("foo").Get(&User{}, "SELECT * FROM `user` WHERE `id` = ?", 1)
//
// MongoDB
//
//    // default mongodb
//    yiigo.RegisterMongoDB("default", "mongodb://localhost:27017")
//
//    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
//    yiigo.Mongo.Database("test").Collection("numbers").InsertOne(ctx, bson.M{"name": "pi", "value": 3.14159})
//
//    // other mongodb
//    yiigo.RegisterMongoDB("foo", "mongodb://localhost:27017")
//
//    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
//    yiigo.UseMongo("foo").Database("test").Collection("numbers").InsertOne(ctx, bson.M{"name": "pi", "value": 3.14159})
//
// Redis
//
//    // default redis
//    yiigo.RegisterRedis("default", "localhost:6379")
//
//    conn, err := yiigo.Redis.Get()
//
//    if err != nil {
// 	     log.Fatal(err)
//    }
//
//    defer yiigo.Redis.Put(conn)
//
//    conn.Do("SET", "test_key", "hello world")
//
//    // other redis
//    yiigo.RegisterRedis("foo", "localhost:6379")
//
//    foo := yiigo.UseRedis("foo")
//    conn, err := foo.Get()
//
//    if err != nil {
// 	     log.Fatal(err)
//    }
//
//    defer foo.Put(conn)
//
//    conn.Do("SET", "test_key", "hello world")
//
// Config
//
//    // env.toml
//    //
//    // [app]
//    // env = "dev"
//    // debug = true
//    // port = 50001
//
//    yiigo.UseEnv("env.toml")
//
//    yiigo.Env.GetBool("app.debug", true)
//    yiigo.Env.GetInt("app.port", 12345)
//    yiigo.Env.GetString("app.env", "dev")
//
// Logger
//
//    // default logger
//    yiigo.RegisterLogger("default", "app.log")
//    yiigo.Logger.Info("hello world")
//
//    // other logger
//    yiigo.RegisterLogger("foo", "foo.log")
//    yiigo.UseLogger("foo").Info("hello world")
//
// For more details, see the documentation for the types and methods.
//
package yiigo
<|endoftext|>


<commit_before>// Package hraftd is a simple distributed key-value store, acting
// as a reference use of the Raft implemenation from Hashicorp.
package hraftd
<commit_msg>Fix godoc typos<commit_after>// Package hraftd is a simple distributed key-value store, acting
// as a reference use of the Raft implementation from Hashicorp.
package hraftd
<|endoftext|>


<commit_before>/*
Package vlc provides golang bindings for libVLC version 2.X/3.X/4.X.

Usage

Initialization
	// Initialize libVLC. Additional command line arguments can be passed in
	// to libVLC by specifying them in the Init function.
	if err := vlc.Init("--no-video", "--quiet"); err != nil {
		log.Fatal(err)
	}
	defer vlc.Release()

Player example
	// Create a new player.
	player, err := vlc.NewPlayer()
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		player.Stop()
		player.Release()
	}()

	// Add a media file from path or from URL.
	// Set player media from path:
	// media, err := player.LoadMediaFromPath("localpath/test.mp4")
	// Set player media from URL:
	media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
	if err != nil {
		log.Fatal(err)
	}
	defer media.Release()

	// Start playing the media.
	err = player.Play()
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve player event manager.
	manager, err := player.EventManager()
	if err != nil {
		log.Fatal(err)
	}

	// Register the media end reached event with the event manager.
	quit := make(chan struct{})
	eventCallback := func(event vlc.Event, userData interface{}) {
		close(quit)
	}

	eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer manager.Detach(eventID)

	<-quit

List player example
    // Create a new list player.
    player, err := vlc.NewListPlayer()
    if err != nil {
        log.Fatal(err)
    }
    defer func() {
        player.Stop()
        player.Release()
    }()

    // Create a new media list.
    list, err := vlc.NewMediaList()
    if err != nil {
        log.Fatal(err)
    }
    defer list.Release()

    err = list.AddMediaFromPath("localpath/example1.mp3")
    if err != nil {
        log.Fatal(err)
    }

    err = list.AddMediaFromURL("http://example.com")
    if err != nil {
        log.Fatal(err)
    }

    // Set player media list.
    err = player.SetMediaList(list)
    if err != nil {
        log.Fatal(err)
    }

    // Media files can be added to the list after the list has been added
    // to the player. The player will play these files as well.
    err = list.AddMediaFromPath("localpath/example2.mp3")
    if err != nil {
        log.Fatal(err)
    }

    // Retrieve player event manager.
    manager, err := player.EventManager()
    if err != nil {
        log.Fatal(err)
    }

    // Register the media end reached event with the event manager.
    quit := make(chan struct{})
    eventCallback := func(event vlc.Event, userData interface{}) {
        close(quit)
    }

    eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer manager.Detach(eventID)

    <-quit
*/
package vlc
<commit_msg>Add event handling GoDoc example<commit_after>/*
Package vlc provides golang bindings for libVLC version 2.X/3.X/4.X.

Usage

Initialization
	// Initialize libVLC. Additional command line arguments can be passed in
	// to libVLC by specifying them in the Init function.
	if err := vlc.Init("--no-video", "--quiet"); err != nil {
		log.Fatal(err)
	}
	defer vlc.Release()

Player example
	// Create a new player.
	player, err := vlc.NewPlayer()
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		player.Stop()
		player.Release()
	}()

	// Add a media file from path or from URL.
	// Set player media from path:
	// media, err := player.LoadMediaFromPath("localpath/test.mp4")
	// Set player media from URL:
	media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
	if err != nil {
		log.Fatal(err)
	}
	defer media.Release()

	// Start playing the media.
	err = player.Play()
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve player event manager.
	manager, err := player.EventManager()
	if err != nil {
		log.Fatal(err)
	}

	// Register the media end reached event with the event manager.
	quit := make(chan struct{})
	eventCallback := func(event vlc.Event, userData interface{}) {
		close(quit)
	}

	eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer manager.Detach(eventID)

	<-quit

List player example
    // Create a new list player.
    player, err := vlc.NewListPlayer()
    if err != nil {
        log.Fatal(err)
    }
    defer func() {
        player.Stop()
        player.Release()
    }()

    // Create a new media list.
    list, err := vlc.NewMediaList()
    if err != nil {
        log.Fatal(err)
    }
    defer list.Release()

    err = list.AddMediaFromPath("localpath/example1.mp3")
    if err != nil {
        log.Fatal(err)
    }

    err = list.AddMediaFromURL("http://example.com")
    if err != nil {
        log.Fatal(err)
    }

    // Set player media list.
    err = player.SetMediaList(list)
    if err != nil {
        log.Fatal(err)
    }

    // Media files can be added to the list after the list has been added
    // to the player. The player will play these files as well.
    err = list.AddMediaFromPath("localpath/example2.mp3")
    if err != nil {
        log.Fatal(err)
    }

    // Retrieve player event manager.
    manager, err := player.EventManager()
    if err != nil {
        log.Fatal(err)
    }

    // Register the media end reached event with the event manager.
    quit := make(chan struct{})
    eventCallback := func(event vlc.Event, userData interface{}) {
        close(quit)
    }

    eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer manager.Detach(eventID)

    <-quit

Handling multiple events example
	// Initialize libVLC. Additional command line arguments can be passed in
	// to libVLC by specifying them in the Init function.
	if err := vlc.Init("--quiet"); err != nil {
		log.Fatal(err)
	}
	defer vlc.Release()

	// Create a new player.
	player, err := vlc.NewPlayer()
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		player.Stop()
		player.Release()
	}()

	// Add a media file from path or from URL.
	// Set player media from URL:
	// media, err := player.LoadMediaFromURL("http://stream-uk1.radioparadise.com/mp3-32")
	// Set player media from path:
	media, err := player.LoadMediaFromPath("test.mp3")
	if err != nil {
		log.Fatal(err)
	}
	defer media.Release()

	// Start playing the media.
	err = player.Play()
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve player event manager.
	manager, err := player.EventManager()
	if err != nil {
		log.Fatal(err)
	}

	// Create event handler.
	quit := make(chan struct{})
	eventCallback := func(event vlc.Event, userData interface{}) {
		switch event {
		case vlc.MediaPlayerEndReached:
			log.Println("Player end reached")
			close(quit)
		case vlc.MediaPlayerTimeChanged:
			media, err := player.Media()
			if err != nil {
				log.Println(err)
				break
			}

			stats, err := media.Stats()
			if err != nil {
				log.Println(err)
				break
			}
			log.Printf("%+v\n", stats)
		}
	}

	// Register events with the event manager of the player.
	events := []vlc.Event{
		vlc.MediaPlayerTimeChanged,
		vlc.MediaPlayerEndReached,
	}

	var eventIDs []vlc.EventID
	for _, event := range events {
		eventID, err := manager.Attach(event, eventCallback, nil)
		if err != nil {
			log.Fatal(err)
		}

		eventIDs = append(eventIDs, eventID)
	}

	// De-register attached events.
	defer func() {
		for _, eventID := range eventIDs {
			manager.Detach(eventID)
		}
	}()

	<-quit
*/
package vlc
<|endoftext|>


<commit_before>// Copyright 2015, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

package main

import "os"
import "fmt"
import "strings"
import "io/ioutil"
import "path"
import "path/filepath"
import "unicode"
import "unicode/utf8"
import "go/doc"
import "go/build"
import "go/token"
import "go/parser"

var args []string
var matchCase = false
var unexported = false
var showCmd = false

func handleDoc(t *tokenizer) {
	if tok, old := t.Next(); old {
		switch tok {
		case "-c", "--c":
			matchCase = true
		case "-u", "--u":
			unexported = true
		case "-cmd", "--cmd":
			showCmd = true
		default:
			args = append(args, tok)
		}
	} else {
		if strings.Index(tok, "-") == 0 {
			// go doc [-u] [-c] [-cmd]
			for _, s := range []string{"-u", "-c", "-cmd"} {
				if strings.Index(s, tok) == 0 {
					fmt.Println(s + " ")
				}
			}
		} else {
			switch len(args) {
			case 0:
				// go doc
				// go doc <sym>[.<method>]
				relPkg := false
				if cwd, err := os.Getwd(); err == nil {
					relPkg = suggestPackageContents(cwd, "", tok)
				}

				// go doc <pkg>
				if len(tok) > 0 || !relPkg {
					suggestPackages(tok)
				}

				// go doc [<pkg>].<sym>[.<method>]
				root, base := path.Split(tok)
				if i := strings.Index(base, "."); len(tok) > 0 && i > 0 {
					i += len(root)
					for _, pkgPath := range makePaths(tok[:i]) {
						tokRoot, tok := tok[:i+1], tok[i+1:]
						if suggestPackageContents(pkgPath, tokRoot, tok) {
							break
						}
					}
				}
			case 1:
				// go doc <pkg> <sym>[.<method>]
				for _, pkgPath := range makePaths(args[0]) {
					if suggestPackageContents(pkgPath, "", tok) {
						break
					}
				}
			}
		}
		return
	}
	handleDoc(t)
}

// Parse a package and suggest all symbols found in it.
func suggestPackageContents(pkgPath, tokRoot, tok string) bool {
	name, pkg := parsePackage(pkgPath)
	if pkg == nil || (name == "main" && !showCmd) {
		return false
	}

	for _, c := range pkg.Consts {
		for _, n := range c.Names {
			suggestSymbol(tokRoot, tok, n)
		}
	}
	for _, v := range pkg.Vars {
		for _, n := range v.Names {
			suggestSymbol(tokRoot, tok, n)
		}
	}
	for _, f := range pkg.Funcs {
		suggestSymbol(tokRoot, tok, f.Name)
	}
	for _, t := range pkg.Types {
		suggestSymbol(tokRoot, tok, t.Name)
		for _, m := range t.Methods {
			suggestSymbol(tokRoot, tok, t.Name+"."+m.Name)
		}
	}
	return true
}

// Print the symbol as a suggestion.
func suggestSymbol(tokRoot, tok, name string) {
	// Check if name is exported
	if !unexported {
		i := strings.LastIndex(name, ".")
		r1, _ := utf8.DecodeRuneInString(name)
		r2, _ := utf8.DecodeRuneInString(name[i+1:])
		if !unicode.IsUpper(r1) || !unicode.IsUpper(r2) {
			return
		}
	}

	if strings.Index(name, tok) == 0 {
		fmt.Println(tokRoot + name + " ")
	} else if !matchCase {
		// Copied from cmd/doc/pkg.go.
		simpleFold := func(r rune) rune {
			for {
				r1 := unicode.SimpleFold(r)
				if r1 <= r {
					return r1
				}
				r = r1
			}
		}

		// Copied from cmd/doc/pkg.go.
		for _, u := range tok {
			p, w := utf8.DecodeRuneInString(name)
			name = name[w:]
			if u == p {
				continue
			}
			if unicode.IsLower(u) && simpleFold(u) == simpleFold(p) {
				continue
			}
			return
		}
		fmt.Println(tokRoot + tok + name + " ")
	}
}

// Suggest packages that tok could possibly be pointing toward.
func suggestPackages(tok string) {
	root, base := path.Split(tok)
	if isDir(tok) {
		root, base = tok, ""
	}

	for _, dirPath := range makePaths(root) {
		for _, dir := range getDirs(dirPath) {
			if strings.Index(dir, base) != 0 {
				// Skip paths don't match the partial token
				continue
			}
			if strings.Index(dir, ".") == 0 && len(base) == 0 {
				// Skip hidden folders unless there is a partial match
				continue
			}
			path := path.Join(dirPath, dir)
			if isPackage(path) {
				fmt.Println(root + dir + " ")
			}
			if hasPackages(path) {
				fmt.Println(root + dir + string(os.PathSeparator))
			}
		}
	}
}

// Expand GOROOT and GOPATH with respect to some dirPath.
func makePaths(dirPath string) (paths []string) {
	// TODO(jtsai): Can dirPath be an absolute path?
	for _, dir := range filepath.SplitList(build.Default.GOPATH) {
		if dir != "" {
			paths = append(paths, path.Join(dir, "src", dirPath))
		}
	}
	if dir := build.Default.GOROOT; dir != "" {
		paths = append(paths, path.Join(dir, "src", dirPath))
	}
	return
}

// Check if dirPath points to a directory.
func isDir(dirPath string) bool {
	return len(dirPath) > 0 && dirPath[len(dirPath)-1] == os.PathSeparator
}

// Get all directories within the directory at dirPath.
func getDirs(dirPath string) (dirs []string) {
	fis, _ := ioutil.ReadDir(dirPath)
	for _, fi := range fis {
		if fi.Mode()&os.ModeSymlink > 0 {
			_fi, err := os.Stat(path.Join(dirPath, fi.Name()))
			if err == nil {
				fi = _fi
			}
		}
		if fi.IsDir() {
			dirs = append(dirs, fi.Name())
		}
	}
	return
}

// Check if the path is a Go package. This function simply checks if at least
// one Go file exists in the directory and could be wrong.
func isPackage(path string) bool {
	fis, _ := ioutil.ReadDir(path)
	for _, fi := range fis {
		if strings.HasSuffix(fi.Name(), ".go") {
			return true
		}
	}
	return false
}

// Check if this directory contains other Go packages. This function simply
// checks if other directories exist within this directory and could be wrong.
func hasPackages(path string) bool {
	return len(getDirs(path)) > 0
}

// Parse a package at a given dir.
// This logic is a stripped down version of cmd/doc/pkg.go.
func parsePackage(dir string) (_ string, _ *doc.Package) {
	if dir == "" {
		return
	}

	pkg, err := build.ImportDir(dir, build.ImportComment)
	if err != nil {
		return
	}

	fs := token.NewFileSet()
	include := func(info os.FileInfo) bool {
		for _, name := range pkg.GoFiles {
			if name == info.Name() {
				return true
			}
		}
		for _, name := range pkg.CgoFiles {
			if name == info.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
	if err != nil {
		return
	}
	if len(pkgs) != 1 {
		return
	}
	astPkg := pkgs[pkg.Name]

	docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
	for _, typ := range docPkg.Types {
		docPkg.Consts = append(docPkg.Consts, typ.Consts...)
		docPkg.Vars = append(docPkg.Vars, typ.Vars...)
		docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
	}

	return pkg.Name, docPkg
}
<commit_msg>Make suggest functions return the number of suggestions made<commit_after>// Copyright 2015, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

package main

import "os"
import "fmt"
import "strings"
import "io/ioutil"
import "path"
import "path/filepath"
import "unicode"
import "unicode/utf8"
import "go/doc"
import "go/build"
import "go/token"
import "go/parser"

var args []string
var matchCase = false
var unexported = false
var showCmd = false

func handleDoc(t *tokenizer) {
	if tok, old := t.Next(); old {
		switch tok {
		case "-c", "--c":
			matchCase = true
		case "-u", "--u":
			unexported = true
		case "-cmd", "--cmd":
			showCmd = true
		default:
			args = append(args, tok)
		}
	} else {
		if strings.Index(tok, "-") == 0 {
			// go doc [-u] [-c] [-cmd]
			for _, s := range []string{"-u", "-c", "-cmd"} {
				if strings.Index(s, tok) == 0 {
					fmt.Println(s + " ")
				}
			}
		} else {
			switch len(args) {
			case 0:
				// go doc
				// go doc <sym>[.<method>]
				relPkg := false
				if cwd, err := os.Getwd(); err == nil {
					relPkg = suggestPackageContents(cwd, "", tok) > 0
				}

				// go doc <pkg>
				if len(tok) > 0 || !relPkg {
					suggestPackages(tok)
				}

				// go doc [<pkg>].<sym>[.<method>]
				root, base := path.Split(tok)
				if i := strings.Index(base, "."); len(tok) > 0 && i > 0 {
					i += len(root)
					for _, pkgPath := range makePaths(tok[:i]) {
						tokRoot, tok := tok[:i+1], tok[i+1:]
						if suggestPackageContents(pkgPath, tokRoot, tok) > 0 {
							break
						}
					}
				}
			case 1:
				// go doc <pkg> <sym>[.<method>]
				for _, pkgPath := range makePaths(args[0]) {
					if suggestPackageContents(pkgPath, "", tok) > 0 {
						break
					}
				}
			}
		}
		return
	}
	handleDoc(t)
}

// Parse a package and suggest all symbols found in it.
func suggestPackageContents(pkgPath, tokRoot, tok string) (cnt int) {
	name, pkg := parsePackage(pkgPath)
	if pkg == nil || (name == "main" && !showCmd) {
		return cnt
	}

	for _, c := range pkg.Consts {
		for _, n := range c.Names {
			cnt += suggestSymbol(tokRoot, tok, n)
		}
	}
	for _, v := range pkg.Vars {
		for _, n := range v.Names {
			cnt += suggestSymbol(tokRoot, tok, n)
		}
	}
	for _, f := range pkg.Funcs {
		cnt += suggestSymbol(tokRoot, tok, f.Name)
	}
	for _, t := range pkg.Types {
		cnt += suggestSymbol(tokRoot, tok, t.Name)
		for _, m := range t.Methods {
			cnt += suggestSymbol(tokRoot, tok, t.Name+"."+m.Name)
		}
	}
	return cnt
}

// Print the symbol as a suggestion.
func suggestSymbol(tokRoot, tok, name string) (cnt int) {
	// Check if name is exported
	if !unexported {
		i := strings.LastIndex(name, ".")
		r1, _ := utf8.DecodeRuneInString(name)
		r2, _ := utf8.DecodeRuneInString(name[i+1:])
		if !unicode.IsUpper(r1) || !unicode.IsUpper(r2) {
			return 0
		}
	}

	if strings.Index(name, tok) == 0 {
		fmt.Println(tokRoot + name + " ")
	} else if !matchCase {
		// Copied from cmd/doc/pkg.go.
		simpleFold := func(r rune) rune {
			for {
				r1 := unicode.SimpleFold(r)
				if r1 <= r {
					return r1
				}
				r = r1
			}
		}

		// Copied from cmd/doc/pkg.go.
		for _, u := range tok {
			p, w := utf8.DecodeRuneInString(name)
			name = name[w:]
			if u == p {
				continue
			}
			if unicode.IsLower(u) && simpleFold(u) == simpleFold(p) {
				continue
			}
			return 0
		}
		fmt.Println(tokRoot + tok + name + " ")
	}
	return 1
}

// Suggest packages that tok could possibly be pointing toward.
func suggestPackages(tok string) (cnt int) {
	root, base := path.Split(tok)
	if isDir(tok) {
		root, base = tok, ""
	}

	for _, dirPath := range makePaths(root) {
		for _, dir := range getDirs(dirPath) {
			if strings.Index(dir, base) != 0 {
				// Skip paths don't match the partial token
				continue
			}
			if strings.Index(dir, ".") == 0 && len(base) == 0 {
				// Skip hidden folders unless there is a partial match
				continue
			}
			path := path.Join(dirPath, dir)
			if isPackage(path) {
				fmt.Println(root + dir + " ")
				cnt++
			}
			if hasPackages(path) {
				fmt.Println(root + dir + string(os.PathSeparator))
				cnt++
			}
		}
	}
	return cnt
}

// Expand GOROOT and GOPATH with respect to some dirPath.
func makePaths(dirPath string) (paths []string) {
	// TODO(jtsai): Can dirPath be an absolute path?
	for _, dir := range filepath.SplitList(build.Default.GOPATH) {
		if dir != "" {
			paths = append(paths, path.Join(dir, "src", dirPath))
		}
	}
	if dir := build.Default.GOROOT; dir != "" {
		paths = append(paths, path.Join(dir, "src", dirPath))
	}
	return
}

// Check if dirPath points to a directory.
func isDir(dirPath string) bool {
	return len(dirPath) > 0 && dirPath[len(dirPath)-1] == os.PathSeparator
}

// Get all directories within the directory at dirPath.
func getDirs(dirPath string) (dirs []string) {
	fis, _ := ioutil.ReadDir(dirPath)
	for _, fi := range fis {
		if fi.Mode()&os.ModeSymlink > 0 {
			_fi, err := os.Stat(path.Join(dirPath, fi.Name()))
			if err == nil {
				fi = _fi
			}
		}
		if fi.IsDir() {
			dirs = append(dirs, fi.Name())
		}
	}
	return
}

// Check if the path is a Go package. This function simply checks if at least
// one Go file exists in the directory and could be wrong.
func isPackage(path string) bool {
	fis, _ := ioutil.ReadDir(path)
	for _, fi := range fis {
		if strings.HasSuffix(fi.Name(), ".go") {
			return true
		}
	}
	return false
}

// Check if this directory contains other Go packages. This function simply
// checks if other directories exist within this directory and could be wrong.
func hasPackages(path string) bool {
	return len(getDirs(path)) > 0
}

// Parse a package at a given dir.
// This logic is a stripped down version of cmd/doc/pkg.go.
func parsePackage(dir string) (_ string, _ *doc.Package) {
	if dir == "" {
		return
	}

	pkg, err := build.ImportDir(dir, build.ImportComment)
	if err != nil {
		return
	}

	fs := token.NewFileSet()
	include := func(info os.FileInfo) bool {
		for _, name := range pkg.GoFiles {
			if name == info.Name() {
				return true
			}
		}
		for _, name := range pkg.CgoFiles {
			if name == info.Name() {
				return true
			}
		}
		return false
	}
	pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
	if err != nil {
		return
	}
	if len(pkgs) != 1 {
		return
	}
	astPkg := pkgs[pkg.Name]

	docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
	for _, typ := range docPkg.Types {
		docPkg.Consts = append(docPkg.Consts, typ.Consts...)
		docPkg.Vars = append(docPkg.Vars, typ.Vars...)
		docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
	}

	return pkg.Name, docPkg
}
<|endoftext|>


<commit_before>// Package luar provides custom type reflection to gopher-lua.
//
// Notice
//
// This package is currently in development, and its behavior may change. This
// message will be removed once the package is considered stable.
//
// Basic types
//
// Go bool, number, and string types are converted to the equivalent basic
// Lua type.
//
// Example:
//  New(L, "Hello World") -> lua.LString("Hello World")
//  New(L, uint(834))     -> lua.LNumber(uint(834))
//
// Channel types
//
// Channel types have the following methods defined:
//  receive():    Receives data from the channel. Returns nil plus false if the
//                channel is closed.
//  send(data):   Sends data to the channel.
//  close():      Closes the channel.
//
// Example:
//  ch := make(chan string)
//  L.SetGlobal("ch", New(L, ch))
//  ---
//  ch:receive()      -- equivalent to v, ok := ch
//  ch:send("hello")  -- equivalent to ch <- "hello"
//  ch:close()        -- equivalent to close(ch)
//
// Function types
//
// Function types can be called from Lua. Its arguments and returned values
// will be automatically converted from and to Lua types, respectively (see
// exception below). However, a function that uses luar.LState can bypass the
// automatic argument and return value conversion (see luar.LState
// documentation for example).
//
// Example:
//  fn := func(name string, age uint) string {
//    return fmt.Sprintf("Hello %s, age %d", name, age)
//  }
//  L.SetGlobal("fn", New(L, fn))
//  ---
//  print(fn("Tim", 5)) -- prints "Hello Tim, age 5"
//
// A special conversion case happens when function returns a lua.LValue slice.
// In that case, luar will automatically unpack the slice.
//
// Example
//  fn := func() []lua.LValue {
//    return []lua.LValue{lua.LString("Hello"), lua.LNumber(2.5)}
//  }
//  L.SetGlobal("fn", New(L, fn))
//  ---
//  x, y = fn()
//  print(x) -- prints "Hello"
//  print(y) -- prints "2.5"
//
// Map types
//
// Map types can be accessed and modified like a normal Lua table a meta table.
// Its length can also be queried using the # operator.
//
// Rather than using pairs to create an map iterator, calling the value (e.g.
// map_variable()) will return an iterator for the map.
//
// Example:
//  places := map[string]string{
//    "NA": "North America",
//    "EU": "European Union",
//  }
//  L.SetGlobal("places", New(L, places))
//  ---
//  print(#places)       -- prints "2"
//  print(places.NA)     -- prints "North America"
//  print(places["EU"])  -- prints "European Union"
//  for k, v = places() do
//    print(k .. ": " .. v)
//  end
//
// Slice types
//
// Like map types, slices be accessed, be modified, and have their length
// queried. Additionally, the following methods are defined for slices:
//  append(items...):   Appends the items to the slice. Returns a slice with
//                      the items appended.
//  capacity():         Returns the slice capacity.
//
// For consistency with other Lua code, slices use one-based indexing.
//
// Example:
//  letters := []string{"a", "e", "i"}
//  L.SetGlobal("letters", New(L, letters))
//  ---
//  letters = letters:append("o", "u")
//
// Struct types
//
// Struct types can have their fields accessed and modified and their methods
// called. First letters of field/method names are automatically converted to
// uppercase.
//
// Example:
//  type Person {
//    Name string
//  }
//  func (p Person) SayHello() {
//    fmt.Printf("Hello, %s\n", p.Name)
//  }
//
//  tim := Person{"Tim"}
//  L.SetGlobal("tim", New(L, tim))
//  ---
//  tim:SayHello() -- same as tim:sayHello()
//
// Type types
//
// Type constructors can be created using NewType. When called, it returns a
// new variable which is the same type of variable that was passed to NewType.
//
// Example:
//  type Person struct {
//    Name string
//  }
//  L.SetGlobal("Person", NewType(L, Person{}))
//  ---
//  p = Person()
//  p.Name = "John"
//  print("Hello, " .. p.Name)  // prints "Hello, John"
package luar
<commit_msg>add missing colon to docs<commit_after>// Package luar provides custom type reflection to gopher-lua.
//
// Notice
//
// This package is currently in development, and its behavior may change. This
// message will be removed once the package is considered stable.
//
// Basic types
//
// Go bool, number, and string types are converted to the equivalent basic
// Lua type.
//
// Example:
//  New(L, "Hello World") -> lua.LString("Hello World")
//  New(L, uint(834))     -> lua.LNumber(uint(834))
//
// Channel types
//
// Channel types have the following methods defined:
//  receive():    Receives data from the channel. Returns nil plus false if the
//                channel is closed.
//  send(data):   Sends data to the channel.
//  close():      Closes the channel.
//
// Example:
//  ch := make(chan string)
//  L.SetGlobal("ch", New(L, ch))
//  ---
//  ch:receive()      -- equivalent to v, ok := ch
//  ch:send("hello")  -- equivalent to ch <- "hello"
//  ch:close()        -- equivalent to close(ch)
//
// Function types
//
// Function types can be called from Lua. Its arguments and returned values
// will be automatically converted from and to Lua types, respectively (see
// exception below). However, a function that uses luar.LState can bypass the
// automatic argument and return value conversion (see luar.LState
// documentation for example).
//
// Example:
//  fn := func(name string, age uint) string {
//    return fmt.Sprintf("Hello %s, age %d", name, age)
//  }
//  L.SetGlobal("fn", New(L, fn))
//  ---
//  print(fn("Tim", 5)) -- prints "Hello Tim, age 5"
//
// A special conversion case happens when function returns a lua.LValue slice.
// In that case, luar will automatically unpack the slice.
//
// Example:
//  fn := func() []lua.LValue {
//    return []lua.LValue{lua.LString("Hello"), lua.LNumber(2.5)}
//  }
//  L.SetGlobal("fn", New(L, fn))
//  ---
//  x, y = fn()
//  print(x) -- prints "Hello"
//  print(y) -- prints "2.5"
//
// Map types
//
// Map types can be accessed and modified like a normal Lua table a meta table.
// Its length can also be queried using the # operator.
//
// Rather than using pairs to create an map iterator, calling the value (e.g.
// map_variable()) will return an iterator for the map.
//
// Example:
//  places := map[string]string{
//    "NA": "North America",
//    "EU": "European Union",
//  }
//  L.SetGlobal("places", New(L, places))
//  ---
//  print(#places)       -- prints "2"
//  print(places.NA)     -- prints "North America"
//  print(places["EU"])  -- prints "European Union"
//  for k, v = places() do
//    print(k .. ": " .. v)
//  end
//
// Slice types
//
// Like map types, slices be accessed, be modified, and have their length
// queried. Additionally, the following methods are defined for slices:
//  append(items...):   Appends the items to the slice. Returns a slice with
//                      the items appended.
//  capacity():         Returns the slice capacity.
//
// For consistency with other Lua code, slices use one-based indexing.
//
// Example:
//  letters := []string{"a", "e", "i"}
//  L.SetGlobal("letters", New(L, letters))
//  ---
//  letters = letters:append("o", "u")
//
// Struct types
//
// Struct types can have their fields accessed and modified and their methods
// called. First letters of field/method names are automatically converted to
// uppercase.
//
// Example:
//  type Person {
//    Name string
//  }
//  func (p Person) SayHello() {
//    fmt.Printf("Hello, %s\n", p.Name)
//  }
//
//  tim := Person{"Tim"}
//  L.SetGlobal("tim", New(L, tim))
//  ---
//  tim:SayHello() -- same as tim:sayHello()
//
// Type types
//
// Type constructors can be created using NewType. When called, it returns a
// new variable which is the same type of variable that was passed to NewType.
//
// Example:
//  type Person struct {
//    Name string
//  }
//  L.SetGlobal("Person", NewType(L, Person{}))
//  ---
//  p = Person()
//  p.Name = "John"
//  print("Hello, " .. p.Name)  // prints "Hello, John"
package luar
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package hbasekv

import (
	"fmt"
	"math/rand"
	"net/url"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/go-hbase"
	"github.com/pingcap/go-themis"
	"github.com/pingcap/go-themis/oracle"
	"github.com/pingcap/go-themis/oracle/oracles"
	"github.com/pingcap/tidb/kv"
)

const (
	// hbaseColFamily is the hbase column family name.
	hbaseColFamily = "f"
	// hbaseQualifier is the hbase column name.
	hbaseQualifier = "q"
	// hbaseFmlAndQual is a shortcut.
	hbaseFmlAndQual = hbaseColFamily + ":" + hbaseQualifier
	// fix length conn pool
	hbaseConnPoolSize = 10
)

var (
	hbaseColFamilyBytes = []byte(hbaseColFamily)
	hbaseQualifierBytes = []byte(hbaseQualifier)
)

var (
	_ kv.Storage = (*hbaseStore)(nil)
)

var (
	// ErrInvalidDSN is returned when store dsn is invalid.
	ErrInvalidDSN = errors.New("invalid dsn")
)

type storeCache struct {
	mu    sync.Mutex
	cache map[string]*hbaseStore
}

var mc storeCache

func init() {
	mc.cache = make(map[string]*hbaseStore)
	rand.Seed(time.Now().UnixNano())
}

type hbaseStore struct {
	mu         sync.Mutex
	uuid       string
	storeName  string
	oracleAddr string
	oracle     oracle.Oracle
	conns      []hbase.HBaseClient
}

func (s *hbaseStore) getHBaseClient() hbase.HBaseClient {
	// return hbase connection randomly
	return s.conns[rand.Intn(hbaseConnPoolSize)]
}

func (s *hbaseStore) Begin() (kv.Transaction, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return nil, errors.Trace(err)
	}
	txn := newHbaseTxn(t, s.storeName)
	return txn, nil
}

func (s *hbaseStore) GetSnapshot(ver kv.Version) (kv.Snapshot, error) {
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return newHbaseSnapshot(t, s.storeName), nil
}

func (s *hbaseStore) Close() error {
	mc.mu.Lock()
	defer mc.mu.Unlock()

	delete(mc.cache, s.uuid)

	var err error
	for _, conn := range s.conns {
		err = conn.Close()
		if err != nil {
			log.Error(err)
		}
	}
	// return last error
	return err
}

func (s *hbaseStore) UUID() string {
	return s.uuid
}

func (s *hbaseStore) CurrentVersion() (kv.Version, error) {
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return kv.Version{Ver: 0}, errors.Trace(err)
	}
	defer t.Release()

	return kv.Version{Ver: t.GetStartTS()}, nil
}

// Driver implements engine Driver.
type Driver struct {
}

// Open opens or creates an HBase storage with given path.
//
// The format of path should be 'hbase://zk1,zk2,zk3/table[?tso=host:port]'.
// If tso is not provided, it will use a local oracle instead. (for test only)
func (d Driver) Open(path string) (kv.Storage, error) {
	mc.mu.Lock()
	defer mc.mu.Unlock()

	zks, oracleAddr, tableName, err := parsePath(path)
	if err != nil {
		return nil, errors.Trace(err)
	}

	uuid := fmt.Sprintf("hbase-%v-%v", zks, tableName)
	if store, ok := mc.cache[uuid]; ok {
		if oracleAddr != store.oracleAddr {
			err = errors.Errorf("hbase: store(%s) is opened with a different tso(%v)", uuid, store.oracleAddr)
			log.Warn(err)
			return nil, err
		}
		return store, nil
	}

	// create buffered HBase connections, HBaseClient is goroutine-safe, so
	// it's OK to redistribute to transactions.
	conns := make([]hbase.HBaseClient, 0, hbaseConnPoolSize)
	for i := 0; i < hbaseConnPoolSize; i++ {
		var c hbase.HBaseClient
		c, err = hbase.NewClient(zks, "/hbase")
		if err != nil {
			return nil, errors.Trace(err)
		}
		conns = append(conns, c)
	}

	c := conns[0]
	var b bool
	b, err = c.TableExists(tableName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if !b {
		// Create new hbase table for store.
		t := hbase.NewTableDesciptor(hbase.NewTableNameWithDefaultNS(tableName))
		cf := hbase.NewColumnFamilyDescriptor(hbaseColFamily)
		cf.AddAttr("THEMIS_ENABLE", "true")
		t.AddColumnDesc(cf)
		//TODO: specify split?
		if err := c.CreateTable(t, nil); err != nil {
			return nil, errors.Trace(err)
		}
	}

	var ora oracle.Oracle
	if len(oracleAddr) == 0 {
		log.Warnf("hbase: store(%s) is using local oracle(for test only)", uuid)
		ora = oracles.NewLocalOracle()
	} else {
		ora = oracles.NewRemoteOracle(oracleAddr)
	}

	s := &hbaseStore{
		uuid:       uuid,
		storeName:  tableName,
		oracleAddr: oracleAddr,
		oracle:     ora,
		conns:      conns,
	}
	mc.cache[uuid] = s
	return s, nil
}

func parsePath(path string) (zks []string, oracleAddr, tableName string, err error) {
	u, err := url.Parse(path)
	if err != nil {
		return nil, "", "", errors.Trace(err)
	}
	if strings.ToLower(u.Scheme) != "hbase" {
		return nil, "", "", errors.Trace(ErrInvalidDSN)
	}
	p, tableName := filepath.Split(u.Path)
	if p != "/" {
		return nil, "", "", errors.Trace(ErrInvalidDSN)
	}
	zks = strings.Split(u.Host, ",")
	oracleAddr = u.Query().Get("tso")
	return zks, oracleAddr, tableName, nil
}
<commit_msg>*: update log<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package hbasekv

import (
	"fmt"
	"math/rand"
	"net/url"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/go-hbase"
	"github.com/pingcap/go-themis"
	"github.com/pingcap/go-themis/oracle"
	"github.com/pingcap/go-themis/oracle/oracles"
	"github.com/pingcap/tidb/kv"
)

const (
	// hbaseColFamily is the hbase column family name.
	hbaseColFamily = "f"
	// hbaseQualifier is the hbase column name.
	hbaseQualifier = "q"
	// hbaseFmlAndQual is a shortcut.
	hbaseFmlAndQual = hbaseColFamily + ":" + hbaseQualifier
	// fix length conn pool
	hbaseConnPoolSize = 10
)

var (
	hbaseColFamilyBytes = []byte(hbaseColFamily)
	hbaseQualifierBytes = []byte(hbaseQualifier)
)

var (
	_ kv.Storage = (*hbaseStore)(nil)
)

var (
	// ErrInvalidDSN is returned when store dsn is invalid.
	ErrInvalidDSN = errors.New("invalid dsn")
)

type storeCache struct {
	mu    sync.Mutex
	cache map[string]*hbaseStore
}

var mc storeCache

func init() {
	mc.cache = make(map[string]*hbaseStore)
	rand.Seed(time.Now().UnixNano())
}

type hbaseStore struct {
	mu         sync.Mutex
	uuid       string
	storeName  string
	oracleAddr string
	oracle     oracle.Oracle
	conns      []hbase.HBaseClient
}

func (s *hbaseStore) getHBaseClient() hbase.HBaseClient {
	// return hbase connection randomly
	return s.conns[rand.Intn(hbaseConnPoolSize)]
}

func (s *hbaseStore) Begin() (kv.Transaction, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return nil, errors.Trace(err)
	}
	txn := newHbaseTxn(t, s.storeName)
	return txn, nil
}

func (s *hbaseStore) GetSnapshot(ver kv.Version) (kv.Snapshot, error) {
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return newHbaseSnapshot(t, s.storeName), nil
}

func (s *hbaseStore) Close() error {
	mc.mu.Lock()
	defer mc.mu.Unlock()

	delete(mc.cache, s.uuid)

	var err error
	for _, conn := range s.conns {
		err = conn.Close()
		if err != nil {
			log.Error(err)
		}
	}
	// return last error
	return err
}

func (s *hbaseStore) UUID() string {
	return s.uuid
}

func (s *hbaseStore) CurrentVersion() (kv.Version, error) {
	hbaseCli := s.getHBaseClient()
	t, err := themis.NewTxn(hbaseCli, s.oracle)
	if err != nil {
		return kv.Version{Ver: 0}, errors.Trace(err)
	}
	defer t.Release()

	return kv.Version{Ver: t.GetStartTS()}, nil
}

// Driver implements engine Driver.
type Driver struct {
}

// Open opens or creates an HBase storage with given path.
//
// The format of path should be 'hbase://zk1,zk2,zk3/table[?tso=host:port]'.
// If tso is not provided, it will use a local oracle instead. (for test only)
func (d Driver) Open(path string) (kv.Storage, error) {
	mc.mu.Lock()
	defer mc.mu.Unlock()

	zks, oracleAddr, tableName, err := parsePath(path)
	if err != nil {
		return nil, errors.Trace(err)
	}

	uuid := fmt.Sprintf("hbase-%v-%v", zks, tableName)
	if store, ok := mc.cache[uuid]; ok {
		if oracleAddr != store.oracleAddr {
			err = errors.Errorf("hbase: store(%s) is opened with a different tso, old: %v, new: %v", uuid, store.oracleAddr, oracleAddr)
			log.Warn(errors.ErrorStack(err))
			return nil, err
		}
		return store, nil
	}

	// create buffered HBase connections, HBaseClient is goroutine-safe, so
	// it's OK to redistribute to transactions.
	conns := make([]hbase.HBaseClient, 0, hbaseConnPoolSize)
	for i := 0; i < hbaseConnPoolSize; i++ {
		var c hbase.HBaseClient
		c, err = hbase.NewClient(zks, "/hbase")
		if err != nil {
			return nil, errors.Trace(err)
		}
		conns = append(conns, c)
	}

	c := conns[0]
	var b bool
	b, err = c.TableExists(tableName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if !b {
		// Create new hbase table for store.
		t := hbase.NewTableDesciptor(hbase.NewTableNameWithDefaultNS(tableName))
		cf := hbase.NewColumnFamilyDescriptor(hbaseColFamily)
		cf.AddAttr("THEMIS_ENABLE", "true")
		t.AddColumnDesc(cf)
		//TODO: specify split?
		if err := c.CreateTable(t, nil); err != nil {
			return nil, errors.Trace(err)
		}
	}

	var ora oracle.Oracle
	if len(oracleAddr) == 0 {
		log.Warnf("hbase: store(%s) is using local oracle(for test only)", uuid)
		ora = oracles.NewLocalOracle()
	} else {
		ora = oracles.NewRemoteOracle(oracleAddr)
	}

	s := &hbaseStore{
		uuid:       uuid,
		storeName:  tableName,
		oracleAddr: oracleAddr,
		oracle:     ora,
		conns:      conns,
	}
	mc.cache[uuid] = s
	return s, nil
}

func parsePath(path string) (zks []string, oracleAddr, tableName string, err error) {
	u, err := url.Parse(path)
	if err != nil {
		return nil, "", "", errors.Trace(err)
	}
	if strings.ToLower(u.Scheme) != "hbase" {
		return nil, "", "", errors.Trace(ErrInvalidDSN)
	}
	p, tableName := filepath.Split(u.Path)
	if p != "/" {
		return nil, "", "", errors.Trace(ErrInvalidDSN)
	}
	zks = strings.Split(u.Host, ",")
	oracleAddr = u.Query().Get("tso")
	return zks, oracleAddr, tableName, nil
}
<|endoftext|>


<commit_before><commit_msg>Do FetchAll async.<commit_after><|endoftext|>


<commit_before>//  Copyright (c) 2016 Couchbase, Inc.
//  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 moss

import (
	"fmt"
)

func (s *Store) snapshotPrevious(ss Snapshot) (Snapshot, error) {
	footer, ok := ss.(*Footer)
	if !ok {
		return nil, fmt.Errorf("snapshot not a footer")
	}

	slocs, _ := footer.segmentLocs()
	defer footer.DecRef()

	if len(slocs) <= 0 {
		return nil, nil
	}

	mref := slocs[0].mref
	if mref == nil || mref.refs <= 0 {
		return nil, fmt.Errorf("footer mref nil")
	}

	fref := mref.fref
	if fref == nil || fref.refs <= 0 || fref.file == nil {
		return nil, fmt.Errorf("footer fref nil")
	}

	finfo, err := fref.file.Stat()
	if err != nil {
		return nil, err
	}

	ssPrev, err := ScanFooter(s.options, fref, finfo.Name(), footer.PrevFooterOffset)
	if err == ErrNoValidFooter {
		return nil, nil
	}

	return ssPrev, err
}
<commit_msg>Fix data race in snapshotPrevious()<commit_after>//  Copyright (c) 2016 Couchbase, Inc.
//  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 moss

import (
	"fmt"
)

func (s *Store) snapshotPrevious(ss Snapshot) (Snapshot, error) {
	footer, ok := ss.(*Footer)
	if !ok {
		return nil, fmt.Errorf("snapshot not a footer")
	}

	slocs, _ := footer.segmentLocs()
	defer footer.DecRef()

	if len(slocs) <= 0 {
		return nil, nil
	}

	mref := slocs[0].mref
	if mref == nil {
		return nil, fmt.Errorf("footer mref nil")
	}

	mref.m.Lock()
	if mref.refs <= 0 {
		mref.m.Unlock()
		return nil, fmt.Errorf("footer mmap has 0 refs")
	}
	fref := mref.fref
	mref.m.Unlock() // Safe since the file beneath the mmap cannot change.

	if fref == nil {
		return nil, fmt.Errorf("footer fref nil")
	}

	fref.m.Lock()
	if fref.refs <= 0 || fref.file == nil {
		fref.m.Unlock()
		return nil, fmt.Errorf("footer has 0 refs")
	}
	fref.m.Unlock() // Safe since the file ref count is positive.

	finfo, err := fref.file.Stat()
	if err != nil {
		return nil, err
	}

	ssPrev, err := ScanFooter(s.options, fref, finfo.Name(), footer.PrevFooterOffset)
	if err == ErrNoValidFooter {
		return nil, nil
	}

	return ssPrev, err
}
<|endoftext|>