<commit_before>package workflow

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

// executor enables calling TerraForm from Go, across platforms, with any
// additional providers/provisioners that the currently executing binary
// exposes.
//
// The TerraForm binary is expected to be in the executing binary's folder, in
// the current working directory or in the PATH.
type executor struct {
	binaryPath string
}

// Set the binary names for different platforms
const (
	tfBinUnix    = "terraform"
	tfBinWindows = "terraform.exe"
)

// errBinaryNotFound denotes the fact that the TerraForm binary could not be
// found on disk.
var errBinaryNotFound = errors.New(
	"TerraForm not in executable's folder, cwd nor PATH",
)

// newExecutor initializes a new Executor.
func newExecutor() (*executor, error) {
	ex := new(executor)

	// Find the TerraForm binary.
	binPath, err := tfBinaryPath()
	if err != nil {
		return nil, err
	}

	ex.binaryPath = binPath
	return ex, nil
}

// Execute runs the given command and arguments against TerraForm.
//
// An error is returned if the TerraForm binary could not be found, or if the
// TerraForm call itself failed, in which case, details can be found in the
// output.
func (ex *executor) execute(clusterDir string, args ...string) error {
	// Prepare TerraForm command by setting up the command, configuration,
	// and the working directory
	if clusterDir == "" {
		return fmt.Errorf("clusterDir is unset. Quitting")
	}

	cmd := exec.Command(ex.binaryPath, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Dir = clusterDir

	// Start TerraForm.
	return cmd.Run()
}

// tfBinaryPath searches for a TerraForm binary on disk:
// - in the executing binary's folder,
// - in the current working directory,
// - in the PATH.
// The first to be found is the one returned.
func tfBinaryPath() (string, error) {
	// Depending on the platform, the expected binary name is different.
	binaryFileName := tfBinUnix
	if runtime.GOOS == "windows" {
		binaryFileName = tfBinWindows
	}

	// Look into the executable's folder.
	if execFolderPath, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
		path := filepath.Join(execFolderPath, binaryFileName)
		if stat, err := os.Stat(path); err == nil && !stat.IsDir() {
			return path, nil
		}
	}

	// Look into cwd.
	if workingDirectory, err := os.Getwd(); err == nil {
		path := filepath.Join(workingDirectory, binaryFileName)
		if stat, err := os.Stat(path); err == nil && !stat.IsDir() {
			return path, nil
		}
	}

	// If we still haven't found the executable, look for it
	// in the PATH.
	if path, err := exec.LookPath(binaryFileName); err == nil {
		return filepath.Abs(path)
	}

	return "", errBinaryNotFound
}
<commit_msg>pkg/executor: fix executable path lookup<commit_after>package workflow

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

// executor enables calling TerraForm from Go, across platforms, with any
// additional providers/provisioners that the currently executing binary
// exposes.
//
// The TerraForm binary is expected to be in the executing binary's folder, in
// the current working directory or in the PATH.
type executor struct {
	binaryPath string
}

// Set the binary names for different platforms
const (
	tfBinUnix    = "terraform"
	tfBinWindows = "terraform.exe"
)

// errBinaryNotFound denotes the fact that the TerraForm binary could not be
// found on disk.
var errBinaryNotFound = errors.New(
	"TerraForm not in executable's folder, cwd nor PATH",
)

// newExecutor initializes a new Executor.
func newExecutor() (*executor, error) {
	ex := new(executor)

	// Find the TerraForm binary.
	binPath, err := tfBinaryPath()
	if err != nil {
		return nil, err
	}

	ex.binaryPath = binPath
	return ex, nil
}

// Execute runs the given command and arguments against TerraForm.
//
// An error is returned if the TerraForm binary could not be found, or if the
// TerraForm call itself failed, in which case, details can be found in the
// output.
func (ex *executor) execute(clusterDir string, args ...string) error {
	// Prepare TerraForm command by setting up the command, configuration,
	// and the working directory
	if clusterDir == "" {
		return fmt.Errorf("clusterDir is unset. Quitting")
	}

	cmd := exec.Command(ex.binaryPath, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Dir = clusterDir

	// Start TerraForm.
	return cmd.Run()
}

// tfBinaryPath searches for a TerraForm binary on disk:
// - in the executing binary's folder,
// - in the current working directory,
// - in the PATH.
// The first to be found is the one returned.
func tfBinaryPath() (string, error) {
	// Depending on the platform, the expected binary name is different.
	binaryFileName := tfBinUnix
	if runtime.GOOS == "windows" {
		binaryFileName = tfBinWindows
	}

	// Find the current executable's real path
	execPath, err := os.Executable()
	if err != nil {
		return "", err
	}

	// Look into the executable's folder.
	if execFolderPath, err := filepath.Abs(filepath.Dir(execPath)); err == nil {
		path := filepath.Join(execFolderPath, binaryFileName)
		if stat, err := os.Stat(path); err == nil && !stat.IsDir() {
			return path, nil
		}
	}

	// Look into cwd.
	if workingDirectory, err := os.Getwd(); err == nil {
		path := filepath.Join(workingDirectory, binaryFileName)
		if stat, err := os.Stat(path); err == nil && !stat.IsDir() {
			return path, nil
		}
	}

	// If we still haven't found the executable, look for it
	// in the PATH.
	if path, err := exec.LookPath(binaryFileName); err == nil {
		return filepath.Abs(path)
	}

	return "", errBinaryNotFound
}
<|endoftext|>


<commit_before>// Copyright 2017 The Peggy Authors
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

package main

import (
	"sort"
)

// Check does semantic analysis of the rules,
// setting bookkeeping needed to later generate the parser,
// returning any errors encountered in order of their begin location.
func Check(grammar *Grammar) error {
	var errs Errors
	rules := expandTemplates(grammar.Rules, &errs)
	ruleMap := make(map[string]*Rule, len(rules))
	for i, r := range rules {
		r.N = i
		name := r.Name.String()
		if other := ruleMap[name]; other != nil {
			errs.add(r, "rule %s redefined", name)
		}
		ruleMap[name] = r
	}

	var p path
	for _, r := range rules {
		r.checkLeft(ruleMap, p, &errs)
	}

	var labels []map[string]*LabelExpr
	for _, r := range rules {
		ls := check(r, ruleMap, &errs)
		labels = append(labels, ls)
	}
	for i, ls := range labels {
		rule := rules[i]
		for name, expr := range ls {
			l := Label{Name: name, Type: expr.Type(), N: expr.N}
			rule.Labels = append(rule.Labels, l)
		}
	}
	if err := errs.ret(); err != nil {
		return err
	}
	grammar.CheckedRules = rules
	return nil
}

func expandTemplates(ruleDefs []Rule, errs *Errors) []*Rule {
	var expanded, todo []*Rule
	tmplNames := make(map[string]*Rule)
	for i := range ruleDefs {
		r := &ruleDefs[i]
		if len(r.Name.Args) > 0 {
			seenParams := make(map[string]bool)
			for _, param := range r.Name.Args {
				n := param.String()
				if seenParams[n] {
					errs.add(param, "parameter %s redefined", n)
				}
				seenParams[n] = true
			}
			tmplNames[r.Name.Name.String()] = r
		} else {
			expanded = append(expanded, r)
			todo = append(todo, r)
		}
	}

	seen := make(map[string]bool)
	for i := 0; i < len(todo); i++ {
		for _, invok := range invokedTemplates(todo[i]) {
			if seen[invok.Name.String()] {
				continue
			}
			seen[invok.Name.String()] = true
			tmpl := tmplNames[invok.Name.Name.String()]
			if tmpl == nil {
				continue // undefined template, error reported elsewhere
			}
			exp := expand1(tmpl, invok, errs)
			if exp == nil {
				continue // error expanding, error reported elsewhere
			}
			todo = append(todo, exp)
			expanded = append(expanded, exp)
		}
	}
	return expanded
}

func expand1(tmpl *Rule, invok *Ident, errs *Errors) *Rule {
	if len(invok.Args) != len(tmpl.Args) {
		errs.add(invok, "template %s argument count mismatch: got %d, expected %d",
			tmpl.Name, len(invok.Args), len(tmpl.Args))
		return nil
	}
	copy := *tmpl
	sub := make(map[string]string, len(tmpl.Args))
	for i, arg := range invok.Args {
		sub[tmpl.Args[i].String()] = arg.String()
	}
	copy.Args = invok.Args
	copy.Expr = tmpl.Expr.substitute(sub)
	return &copy
}

func invokedTemplates(r *Rule) []*Ident {
	var tmpls []*Ident
	r.Expr.Walk(func(e Expr) bool {
		if id, ok := e.(*Ident); ok {
			if len(id.Args) > 0 {
				tmpls = append(tmpls, id)
			}
		}
		return true
	})
	return tmpls
}

type path struct {
	stack []*Rule
	seen  map[*Rule]bool
}

func (p *path) push(r *Rule) bool {
	if p.seen == nil {
		p.seen = make(map[*Rule]bool)
	}
	if p.seen[r] {
		return false
	}
	p.stack = append(p.stack, r)
	p.seen[r] = true
	return true
}

func (p *path) pop() {
	p.stack = p.stack[:len(p.stack)]
}

func (p *path) cycle(r *Rule) []*Rule {
	for i := len(p.stack) - 1; i >= 0; i-- {
		if p.stack[i] == r {
			return append(p.stack[i:], r)
		}
	}
	panic("no cycle")
}

func cycleString(rules []*Rule) string {
	var s string
	for _, r := range rules {
		if s != "" {
			s += ", "
		}
		s += r.Name.String()
	}
	return s
}

func (r *Rule) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	if r.typ != nil {
		return
	}
	if !p.push(r) {
		cycle := p.cycle(r)
		errs.add(cycle[0], "left-recursion: %s", cycleString(cycle))
		for _, r := range cycle {
			r.typ = new(string)
		}
		return
	}
	r.Expr.checkLeft(rules, p, errs)
	t := r.Expr.Type()
	r.typ = &t
	r.epsilon = r.Expr.epsilon()
	p.pop()
}

func (e *Choice) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.checkLeft(rules, p, errs)
	}
}

func (e *Action) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *Sequence) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.checkLeft(rules, p, errs)
		if !sub.epsilon() {
			break
		}
	}
}

func (e *LabelExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *PredExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *RepExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *OptExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *Ident) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	if e.rule = rules[e.Name.String()]; e.rule != nil {
		e.rule.checkLeft(rules, p, errs)
	}
}

func (e *SubExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *PredCode) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *Literal) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *CharClass) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *Any) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func check(rule *Rule, rules map[string]*Rule, errs *Errors) map[string]*LabelExpr {
	labels := make(map[string]*LabelExpr)
	rule.Expr.check(rules, labels, true, errs)
	return labels
}

func (e *Choice) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.check(rules, labels, valueUsed, errs)
	}

	t := e.Type()
	for _, sub := range e.Exprs {
		// Check types, but if either type is "",
		// it's from a previous error; don't report again.
		if got := sub.Type(); *genActions && valueUsed && got != t && got != "" && t != "" {
			errs.add(sub, "type mismatch: got %s, expected %s", got, t)
		}
	}
}

func (e *Action) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, false, errs)
	for _, l := range labels {
		e.Labels = append(e.Labels, l)
	}
	sort.Slice(e.Labels, func(i, j int) bool {
		return e.Labels[i].Label.String() < e.Labels[j].Label.String()
	})
}

// BUG: figure out what to do about sequence types.
func (e *Sequence) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.check(rules, labels, valueUsed, errs)
	}
	t := e.Exprs[0].Type()
	for _, sub := range e.Exprs {
		if got := sub.Type(); *genActions && valueUsed && got != t && got != "" && t != "" {
			errs.add(sub, "type mismatch: got %s, expected %s", got, t)
		}
	}
}

func (e *LabelExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, true, errs)
	if _, ok := labels[e.Label.String()]; ok {
		errs.add(e.Label, "label %s redefined", e.Label.String())
	}
	e.N = len(labels)
	labels[e.Label.String()] = e
}

func (e *PredExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, false, errs)
}

func (e *RepExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *OptExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *SubExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *Ident) check(rules map[string]*Rule, _ map[string]*LabelExpr, _ bool, errs *Errors) {
	r, ok := rules[e.Name.String()]
	if !ok {
		errs.add(e, "rule %s undefined", e.Name.String())
	} else {
		e.rule = r
	}
}

func (e *PredCode) check(_ map[string]*Rule, labels map[string]*LabelExpr, _ bool, _ *Errors) {
	for _, l := range labels {
		e.Labels = append(e.Labels, l)
	}
	sort.Slice(e.Labels, func(i, j int) bool {
		return e.Labels[i].Label.String() < e.Labels[j].Label.String()
	})
}

func (e *Literal) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}

func (e *CharClass) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}

func (e *Any) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}
<commit_msg>Sort labels by N so that the generated output is deterministic.<commit_after>// Copyright 2017 The Peggy Authors
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd.

package main

import (
	"sort"
)

// Check does semantic analysis of the rules,
// setting bookkeeping needed to later generate the parser,
// returning any errors encountered in order of their begin location.
func Check(grammar *Grammar) error {
	var errs Errors
	rules := expandTemplates(grammar.Rules, &errs)
	ruleMap := make(map[string]*Rule, len(rules))
	for i, r := range rules {
		r.N = i
		name := r.Name.String()
		if other := ruleMap[name]; other != nil {
			errs.add(r, "rule %s redefined", name)
		}
		ruleMap[name] = r
	}

	var p path
	for _, r := range rules {
		r.checkLeft(ruleMap, p, &errs)
	}

	var labels []map[string]*LabelExpr
	for _, r := range rules {
		ls := check(r, ruleMap, &errs)
		labels = append(labels, ls)
	}
	for i, ls := range labels {
		rule := rules[i]
		for name, expr := range ls {
			l := Label{Name: name, Type: expr.Type(), N: expr.N}
			rule.Labels = append(rule.Labels, l)
		}
		sort.Slice(rule.Labels, func(i, j int) bool {
			return rule.Labels[i].N < rule.Labels[j].N
		})
	}
	if err := errs.ret(); err != nil {
		return err
	}
	grammar.CheckedRules = rules
	return nil
}

func expandTemplates(ruleDefs []Rule, errs *Errors) []*Rule {
	var expanded, todo []*Rule
	tmplNames := make(map[string]*Rule)
	for i := range ruleDefs {
		r := &ruleDefs[i]
		if len(r.Name.Args) > 0 {
			seenParams := make(map[string]bool)
			for _, param := range r.Name.Args {
				n := param.String()
				if seenParams[n] {
					errs.add(param, "parameter %s redefined", n)
				}
				seenParams[n] = true
			}
			tmplNames[r.Name.Name.String()] = r
		} else {
			expanded = append(expanded, r)
			todo = append(todo, r)
		}
	}

	seen := make(map[string]bool)
	for i := 0; i < len(todo); i++ {
		for _, invok := range invokedTemplates(todo[i]) {
			if seen[invok.Name.String()] {
				continue
			}
			seen[invok.Name.String()] = true
			tmpl := tmplNames[invok.Name.Name.String()]
			if tmpl == nil {
				continue // undefined template, error reported elsewhere
			}
			exp := expand1(tmpl, invok, errs)
			if exp == nil {
				continue // error expanding, error reported elsewhere
			}
			todo = append(todo, exp)
			expanded = append(expanded, exp)
		}
	}
	return expanded
}

func expand1(tmpl *Rule, invok *Ident, errs *Errors) *Rule {
	if len(invok.Args) != len(tmpl.Args) {
		errs.add(invok, "template %s argument count mismatch: got %d, expected %d",
			tmpl.Name, len(invok.Args), len(tmpl.Args))
		return nil
	}
	copy := *tmpl
	sub := make(map[string]string, len(tmpl.Args))
	for i, arg := range invok.Args {
		sub[tmpl.Args[i].String()] = arg.String()
	}
	copy.Args = invok.Args
	copy.Expr = tmpl.Expr.substitute(sub)
	return &copy
}

func invokedTemplates(r *Rule) []*Ident {
	var tmpls []*Ident
	r.Expr.Walk(func(e Expr) bool {
		if id, ok := e.(*Ident); ok {
			if len(id.Args) > 0 {
				tmpls = append(tmpls, id)
			}
		}
		return true
	})
	return tmpls
}

type path struct {
	stack []*Rule
	seen  map[*Rule]bool
}

func (p *path) push(r *Rule) bool {
	if p.seen == nil {
		p.seen = make(map[*Rule]bool)
	}
	if p.seen[r] {
		return false
	}
	p.stack = append(p.stack, r)
	p.seen[r] = true
	return true
}

func (p *path) pop() {
	p.stack = p.stack[:len(p.stack)]
}

func (p *path) cycle(r *Rule) []*Rule {
	for i := len(p.stack) - 1; i >= 0; i-- {
		if p.stack[i] == r {
			return append(p.stack[i:], r)
		}
	}
	panic("no cycle")
}

func cycleString(rules []*Rule) string {
	var s string
	for _, r := range rules {
		if s != "" {
			s += ", "
		}
		s += r.Name.String()
	}
	return s
}

func (r *Rule) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	if r.typ != nil {
		return
	}
	if !p.push(r) {
		cycle := p.cycle(r)
		errs.add(cycle[0], "left-recursion: %s", cycleString(cycle))
		for _, r := range cycle {
			r.typ = new(string)
		}
		return
	}
	r.Expr.checkLeft(rules, p, errs)
	t := r.Expr.Type()
	r.typ = &t
	r.epsilon = r.Expr.epsilon()
	p.pop()
}

func (e *Choice) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.checkLeft(rules, p, errs)
	}
}

func (e *Action) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *Sequence) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.checkLeft(rules, p, errs)
		if !sub.epsilon() {
			break
		}
	}
}

func (e *LabelExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *PredExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *RepExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *OptExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *Ident) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	if e.rule = rules[e.Name.String()]; e.rule != nil {
		e.rule.checkLeft(rules, p, errs)
	}
}

func (e *SubExpr) checkLeft(rules map[string]*Rule, p path, errs *Errors) {
	e.Expr.checkLeft(rules, p, errs)
}

func (e *PredCode) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *Literal) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *CharClass) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func (e *Any) checkLeft(rules map[string]*Rule, p path, errs *Errors) {}

func check(rule *Rule, rules map[string]*Rule, errs *Errors) map[string]*LabelExpr {
	labels := make(map[string]*LabelExpr)
	rule.Expr.check(rules, labels, true, errs)
	return labels
}

func (e *Choice) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.check(rules, labels, valueUsed, errs)
	}

	t := e.Type()
	for _, sub := range e.Exprs {
		// Check types, but if either type is "",
		// it's from a previous error; don't report again.
		if got := sub.Type(); *genActions && valueUsed && got != t && got != "" && t != "" {
			errs.add(sub, "type mismatch: got %s, expected %s", got, t)
		}
	}
}

func (e *Action) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, false, errs)
	for _, l := range labels {
		e.Labels = append(e.Labels, l)
	}
	sort.Slice(e.Labels, func(i, j int) bool {
		return e.Labels[i].Label.String() < e.Labels[j].Label.String()
	})
}

// BUG: figure out what to do about sequence types.
func (e *Sequence) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	for _, sub := range e.Exprs {
		sub.check(rules, labels, valueUsed, errs)
	}
	t := e.Exprs[0].Type()
	for _, sub := range e.Exprs {
		if got := sub.Type(); *genActions && valueUsed && got != t && got != "" && t != "" {
			errs.add(sub, "type mismatch: got %s, expected %s", got, t)
		}
	}
}

func (e *LabelExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, true, errs)
	if _, ok := labels[e.Label.String()]; ok {
		errs.add(e.Label, "label %s redefined", e.Label.String())
	}
	e.N = len(labels)
	labels[e.Label.String()] = e
}

func (e *PredExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, false, errs)
}

func (e *RepExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *OptExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *SubExpr) check(rules map[string]*Rule, labels map[string]*LabelExpr, valueUsed bool, errs *Errors) {
	e.Expr.check(rules, labels, valueUsed, errs)
}

func (e *Ident) check(rules map[string]*Rule, _ map[string]*LabelExpr, _ bool, errs *Errors) {
	r, ok := rules[e.Name.String()]
	if !ok {
		errs.add(e, "rule %s undefined", e.Name.String())
	} else {
		e.rule = r
	}
}

func (e *PredCode) check(_ map[string]*Rule, labels map[string]*LabelExpr, _ bool, _ *Errors) {
	for _, l := range labels {
		e.Labels = append(e.Labels, l)
	}
	sort.Slice(e.Labels, func(i, j int) bool {
		return e.Labels[i].Label.String() < e.Labels[j].Label.String()
	})
}

func (e *Literal) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}

func (e *CharClass) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}

func (e *Any) check(map[string]*Rule, map[string]*LabelExpr, bool, *Errors) {}
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Collins
//
// 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 main

import (
	"encoding/binary"
	"sort"

	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/type/nibble"
	"github.com/thinkofdeath/steven/world/biome"
)

var chunkMap world = map[chunkPosition]*chunk{}

type world map[chunkPosition]*chunk

func (w world) Block(x, y, z int) Block {
	cx := x >> 4
	cz := z >> 4
	chunk := w[chunkPosition{cx, cz}]
	if chunk == nil {
		return BlockBedrock.Base
	}
	return chunk.block(x&0xF, y, z&0xF)
}

func (w world) SetBlock(b Block, x, y, z int) {
	cx := x >> 4
	cz := z >> 4
	chunk := w[chunkPosition{cx, cz}]
	if chunk == nil {
		return
	}
	chunk.setBlock(b, x&0xF, y, z&0xF)
}

func (w world) UpdateBlock(x, y, z int) {
	for yy := -1; yy <= 1; yy++ {
		for zz := -1; zz <= 1; zz++ {
			for xx := -1; xx <= 1; xx++ {
				bx, by, bz := x+xx, y+yy, z+zz
				w.SetBlock(w.Block(bx, by, bz).UpdateState(bx, by, bz), bx, by, bz)
			}
		}
	}
}

type chunkPosition struct {
	X, Z int
}

type chunk struct {
	chunkPosition

	Sections [16]*chunkSection
	Biomes   [16 * 16]byte
}

func (c *chunk) block(x, y, z int) Block {
	s := y >> 4
	if s < 0 || s > 15 {
		return BlockAir.Base
	}
	sec := c.Sections[s]
	if sec == nil {
		return BlockAir.Base
	}
	return sec.block(x, y&0xF, z)
}
func (c *chunk) setBlock(b Block, x, y, z int) {
	s := y >> 4
	if s < 0 || s > 15 {
		return
	}
	sec := c.Sections[s]
	if sec == nil {
		return
	}
	sec.setBlock(b, x, y&0xF, z)
}

func (c *chunk) biome(x, z int) *biome.Type {
	return biome.ById(c.Biomes[z<<4|x])
}

func (c *chunk) free() {
	for _, s := range c.Sections {
		if s != nil {
			s.Buffer.Free()
		}
	}
}

type chunkSection struct {
	chunk *chunk
	Y     int

	Blocks     [16 * 16 * 16]Block
	BlockLight nibble.Array
	SkyLight   nibble.Array

	Buffer *render.ChunkBuffer

	dirty    bool
	building bool
}

func (cs *chunkSection) block(x, y, z int) Block {
	return cs.Blocks[(y<<8)|(z<<4)|x]
}

func (cs *chunkSection) setBlock(b Block, x, y, z int) {
	cs.Blocks[(y<<8)|(z<<4)|x] = b
	cs.dirty = true
}

func (cs *chunkSection) blockLight(x, y, z int) byte {
	return cs.BlockLight.Get((y << 8) | (z << 4) | x)
}

func (cs *chunkSection) skyLight(x, y, z int) byte {
	return cs.SkyLight.Get((y << 8) | (z << 4) | x)
}

func newChunkSection(c *chunk, y int) *chunkSection {
	cs := &chunkSection{
		chunk:      c,
		Y:          y,
		BlockLight: nibble.New(16 * 16 * 16),
		SkyLight:   nibble.New(16 * 16 * 16),
	}
	for i := range cs.Blocks {
		cs.Blocks[i] = BlockAir.Blocks[0]
	}
	return cs
}

func loadChunk(x, z int, data []byte, mask uint16, sky, isNew bool) int {
	var c *chunk
	if isNew {
		c = &chunk{
			chunkPosition: chunkPosition{
				X: x, Z: z,
			},
		}
	} else {
		c = chunkMap[chunkPosition{
			X: x, Z: z,
		}]
		if c == nil {
			return 0
		}
	}

	for i := 0; i < 16; i++ {
		if mask&(1<<uint(i)) == 0 {
			continue
		}
		if c.Sections[i] == nil {
			c.Sections[i] = newChunkSection(c, i)
		}
	}
	offset := 0
	for i, section := range c.Sections {
		if section == nil || mask&(1<<uint(i)) == 0 {
			continue
		}

		for i := 0; i < 16*16*16; i++ {
			section.Blocks[i] = GetBlockByCombinedID(binary.LittleEndian.Uint16(data[offset:]))
			offset += 2
		}
	}
	for i, section := range c.Sections {
		if section == nil || mask&(1<<uint(i)) == 0 {
			continue
		}
		copy(section.BlockLight, data[offset:])
		offset += len(section.BlockLight)
	}
	if sky {
		for i, section := range c.Sections {
			if section == nil || mask&(1<<uint(i)) == 0 {
				continue
			}
			copy(section.SkyLight, data[offset:])
			offset += len(section.BlockLight)
		}
	}

	if isNew {
		copy(c.Biomes[:], data[offset:])
		offset += len(c.Biomes)
	}

	syncChan <- func() {
		// Allocate the render buffers sync
		for y, section := range c.Sections {
			if section != nil {
				section.Buffer = render.AllocateChunkBuffer(c.X, y, c.Z)
			}
		}

		chunkMap[c.chunkPosition] = c
		for _, section := range c.Sections {
			if section == nil {
				continue
			}
			cx := c.X << 4
			cy := section.Y << 4
			cz := c.Z << 4
			for y := 0; y < 16; y++ {
				for z := 0; z < 16; z++ {
					for x := 0; x < 16; x++ {
						section.setBlock(
							section.block(x, y, z).UpdateState(cx+x, cy+y, cz+z),
							x, y, z,
						)
					}
				}
			}
		}

		for xx := -1; xx <= 1; xx++ {
			for zz := -1; zz <= 1; zz++ {
				c := chunkMap[chunkPosition{x + xx, z + zz}]
				if c != nil {
					for _, section := range c.Sections {
						if section == nil {
							continue
						}
						cx, cy, cz := c.X<<4, section.Y<<4, c.Z<<4
						for y := 0; y < 16; y++ {
							if !(xx != 0 && zz != 0) {
								// Row/Col
								for i := 0; i < 16; i++ {
									var bx, bz int
									if xx != 0 {
										bz = i
										if xx == -1 {
											bx = 15
										}
									} else {
										bx = i
										if zz == -1 {
											bz = 15
										}
									}
									section.setBlock(
										section.block(bx, y, bz).UpdateState(cx+bx, cy+y, cz+bz),
										bx, y, bz,
									)
								}
							} else {
								// Just the corner
								var bx, bz int
								if xx == -1 {
									bx = 15
								}
								if zz == -1 {
									bz = 15
								}
								section.setBlock(
									section.block(bx, y, bz).UpdateState(cx+bx, cy+y, cz+bz),
									bx, y, bz,
								)
							}
						}
						section.dirty = true
					}
				}
			}
		}
	}

	return offset
}

func sortedChunks() []*chunk {
	out := make([]*chunk, len(chunkMap))
	i := 0
	for _, c := range chunkMap {
		out[i] = c
		i++
	}
	sort.Sort(chunkSorter(out))
	return out
}

type chunkSorter []*chunk

func (cs chunkSorter) Len() int {
	return len(cs)
}

func (cs chunkSorter) Less(a, b int) bool {
	ac := cs[a]
	bc := cs[b]
	xx := float64(ac.X<<4+8) - render.Camera.X
	zz := float64(ac.Z<<4+8) - render.Camera.Z
	adist := xx*xx + zz*zz
	xx = float64(bc.X<<4+8) - render.Camera.X
	zz = float64(bc.Z<<4+8) - render.Camera.Z
	bdist := xx*xx + zz*zz
	return adist < bdist
}

func (cs chunkSorter) Swap(a, b int) {
	cs[a], cs[b] = cs[b], cs[a]
}
<commit_msg>/: only allocate a new chunk buffer if one doesn't exist<commit_after>// Copyright 2015 Matthew Collins
//
// 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 main

import (
	"encoding/binary"
	"sort"

	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/type/nibble"
	"github.com/thinkofdeath/steven/world/biome"
)

var chunkMap world = map[chunkPosition]*chunk{}

type world map[chunkPosition]*chunk

func (w world) Block(x, y, z int) Block {
	cx := x >> 4
	cz := z >> 4
	chunk := w[chunkPosition{cx, cz}]
	if chunk == nil {
		return BlockBedrock.Base
	}
	return chunk.block(x&0xF, y, z&0xF)
}

func (w world) SetBlock(b Block, x, y, z int) {
	cx := x >> 4
	cz := z >> 4
	chunk := w[chunkPosition{cx, cz}]
	if chunk == nil {
		return
	}
	chunk.setBlock(b, x&0xF, y, z&0xF)
}

func (w world) UpdateBlock(x, y, z int) {
	for yy := -1; yy <= 1; yy++ {
		for zz := -1; zz <= 1; zz++ {
			for xx := -1; xx <= 1; xx++ {
				bx, by, bz := x+xx, y+yy, z+zz
				w.SetBlock(w.Block(bx, by, bz).UpdateState(bx, by, bz), bx, by, bz)
			}
		}
	}
}

type chunkPosition struct {
	X, Z int
}

type chunk struct {
	chunkPosition

	Sections [16]*chunkSection
	Biomes   [16 * 16]byte
}

func (c *chunk) block(x, y, z int) Block {
	s := y >> 4
	if s < 0 || s > 15 {
		return BlockAir.Base
	}
	sec := c.Sections[s]
	if sec == nil {
		return BlockAir.Base
	}
	return sec.block(x, y&0xF, z)
}
func (c *chunk) setBlock(b Block, x, y, z int) {
	s := y >> 4
	if s < 0 || s > 15 {
		return
	}
	sec := c.Sections[s]
	if sec == nil {
		return
	}
	sec.setBlock(b, x, y&0xF, z)
}

func (c *chunk) biome(x, z int) *biome.Type {
	return biome.ById(c.Biomes[z<<4|x])
}

func (c *chunk) free() {
	for _, s := range c.Sections {
		if s != nil {
			s.Buffer.Free()
		}
	}
}

type chunkSection struct {
	chunk *chunk
	Y     int

	Blocks     [16 * 16 * 16]Block
	BlockLight nibble.Array
	SkyLight   nibble.Array

	Buffer *render.ChunkBuffer

	dirty    bool
	building bool
}

func (cs *chunkSection) block(x, y, z int) Block {
	return cs.Blocks[(y<<8)|(z<<4)|x]
}

func (cs *chunkSection) setBlock(b Block, x, y, z int) {
	cs.Blocks[(y<<8)|(z<<4)|x] = b
	cs.dirty = true
}

func (cs *chunkSection) blockLight(x, y, z int) byte {
	return cs.BlockLight.Get((y << 8) | (z << 4) | x)
}

func (cs *chunkSection) skyLight(x, y, z int) byte {
	return cs.SkyLight.Get((y << 8) | (z << 4) | x)
}

func newChunkSection(c *chunk, y int) *chunkSection {
	cs := &chunkSection{
		chunk:      c,
		Y:          y,
		BlockLight: nibble.New(16 * 16 * 16),
		SkyLight:   nibble.New(16 * 16 * 16),
	}
	for i := range cs.Blocks {
		cs.Blocks[i] = BlockAir.Blocks[0]
	}
	return cs
}

func loadChunk(x, z int, data []byte, mask uint16, sky, isNew bool) int {
	var c *chunk
	if isNew {
		c = &chunk{
			chunkPosition: chunkPosition{
				X: x, Z: z,
			},
		}
	} else {
		c = chunkMap[chunkPosition{
			X: x, Z: z,
		}]
		if c == nil {
			return 0
		}
	}

	for i := 0; i < 16; i++ {
		if mask&(1<<uint(i)) == 0 {
			continue
		}
		if c.Sections[i] == nil {
			c.Sections[i] = newChunkSection(c, i)
		}
	}
	offset := 0
	for i, section := range c.Sections {
		if section == nil || mask&(1<<uint(i)) == 0 {
			continue
		}

		for i := 0; i < 16*16*16; i++ {
			section.Blocks[i] = GetBlockByCombinedID(binary.LittleEndian.Uint16(data[offset:]))
			offset += 2
		}
	}
	for i, section := range c.Sections {
		if section == nil || mask&(1<<uint(i)) == 0 {
			continue
		}
		copy(section.BlockLight, data[offset:])
		offset += len(section.BlockLight)
	}
	if sky {
		for i, section := range c.Sections {
			if section == nil || mask&(1<<uint(i)) == 0 {
				continue
			}
			copy(section.SkyLight, data[offset:])
			offset += len(section.BlockLight)
		}
	}

	if isNew {
		copy(c.Biomes[:], data[offset:])
		offset += len(c.Biomes)
	}

	syncChan <- func() {
		// Allocate the render buffers sync
		for y, section := range c.Sections {
			if section != nil && section.Buffer == nil {
				section.Buffer = render.AllocateChunkBuffer(c.X, y, c.Z)
			}
		}

		chunkMap[c.chunkPosition] = c
		for _, section := range c.Sections {
			if section == nil {
				continue
			}
			cx := c.X << 4
			cy := section.Y << 4
			cz := c.Z << 4
			for y := 0; y < 16; y++ {
				for z := 0; z < 16; z++ {
					for x := 0; x < 16; x++ {
						section.setBlock(
							section.block(x, y, z).UpdateState(cx+x, cy+y, cz+z),
							x, y, z,
						)
					}
				}
			}
		}

		for xx := -1; xx <= 1; xx++ {
			for zz := -1; zz <= 1; zz++ {
				c := chunkMap[chunkPosition{x + xx, z + zz}]
				if c != nil {
					for _, section := range c.Sections {
						if section == nil {
							continue
						}
						cx, cy, cz := c.X<<4, section.Y<<4, c.Z<<4
						for y := 0; y < 16; y++ {
							if !(xx != 0 && zz != 0) {
								// Row/Col
								for i := 0; i < 16; i++ {
									var bx, bz int
									if xx != 0 {
										bz = i
										if xx == -1 {
											bx = 15
										}
									} else {
										bx = i
										if zz == -1 {
											bz = 15
										}
									}
									section.setBlock(
										section.block(bx, y, bz).UpdateState(cx+bx, cy+y, cz+bz),
										bx, y, bz,
									)
								}
							} else {
								// Just the corner
								var bx, bz int
								if xx == -1 {
									bx = 15
								}
								if zz == -1 {
									bz = 15
								}
								section.setBlock(
									section.block(bx, y, bz).UpdateState(cx+bx, cy+y, cz+bz),
									bx, y, bz,
								)
							}
						}
						section.dirty = true
					}
				}
			}
		}
	}

	return offset
}

func sortedChunks() []*chunk {
	out := make([]*chunk, len(chunkMap))
	i := 0
	for _, c := range chunkMap {
		out[i] = c
		i++
	}
	sort.Sort(chunkSorter(out))
	return out
}

type chunkSorter []*chunk

func (cs chunkSorter) Len() int {
	return len(cs)
}

func (cs chunkSorter) Less(a, b int) bool {
	ac := cs[a]
	bc := cs[b]
	xx := float64(ac.X<<4+8) - render.Camera.X
	zz := float64(ac.Z<<4+8) - render.Camera.Z
	adist := xx*xx + zz*zz
	xx = float64(bc.X<<4+8) - render.Camera.X
	zz = float64(bc.Z<<4+8) - render.Camera.Z
	bdist := xx*xx + zz*zz
	return adist < bdist
}

func (cs chunkSorter) Swap(a, b int) {
	cs[a], cs[b] = cs[b], cs[a]
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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 kverify verifies a running kubernetes cluster is healthy
package kverify

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/docker/machine/libmachine/state"
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/version"
	"k8s.io/client-go/kubernetes"
	kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/minikube/pkg/minikube/bootstrapper"
	"k8s.io/minikube/pkg/minikube/command"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/cruntime"
)

// WaitForAPIServerProcess waits for api server to be healthy returns error if it doesn't
func WaitForAPIServerProcess(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg config.ClusterConfig, cr command.Runner, start time.Time, timeout time.Duration) error {
	glog.Infof("waiting for apiserver process to appear ...")
	err := wait.PollImmediate(time.Millisecond*500, timeout, func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during process check")
		}

		if time.Since(start) > minLogCheckTime {
			announceProblems(r, bs, cfg, cr)
			time.Sleep(kconst.APICallRetryInterval * 5)
		}

		if _, ierr := apiServerPID(cr); ierr != nil {
			return false, nil
		}

		return true, nil
	})
	if err != nil {
		return fmt.Errorf("apiserver process never appeared")
	}
	glog.Infof("duration metric: took %s to wait for apiserver process to appear ...", time.Since(start))
	return nil
}

// apiServerPID returns our best guess to the apiserver pid
func apiServerPID(cr command.Runner) (int, error) {
	rr, err := cr.RunCmd(exec.Command("sudo", "pgrep", "-xnf", "kube-apiserver.*minikube.*"))
	if err != nil {
		return 0, err
	}
	s := strings.TrimSpace(rr.Stdout.String())
	return strconv.Atoi(s)
}

// WaitForHealthyAPIServer waits for api server status to be running
func WaitForHealthyAPIServer(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg config.ClusterConfig, cr command.Runner, client *kubernetes.Clientset, start time.Time, hostname string, port int, timeout time.Duration) error {
	glog.Infof("waiting for apiserver healthz status ...")
	hStart := time.Now()

	healthz := func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during healthz check")
		}

		if time.Since(start) > minLogCheckTime {
			announceProblems(r, bs, cfg, cr)
			time.Sleep(kconst.APICallRetryInterval * 5)
		}

		status, err := apiServerHealthz(hostname, port)
		if err != nil {
			glog.Warningf("status: %v", err)
			return false, nil
		}
		if status != state.Running {
			return false, nil
		}
		return true, nil
	}

	if err := wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, healthz); err != nil {
		return fmt.Errorf("apiserver healthz never reported healthy")
	}

	vcheck := func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during version check")
		}
		if err := APIServerVersionMatch(client, cfg.KubernetesConfig.KubernetesVersion); err != nil {
			glog.Warningf("api server version match failed: %v", err)
			return false, nil
		}
		return true, nil
	}

	if err := wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, vcheck); err != nil {
		return fmt.Errorf("controlPlane never updated to %s", cfg.KubernetesConfig.KubernetesVersion)
	}

	glog.Infof("duration metric: took %s to wait for apiserver health ...", time.Since(hStart))
	return nil
}

// APIServerVersionMatch checks if the server version matches the expected
func APIServerVersionMatch(client *kubernetes.Clientset, expected string) error {
	vi, err := client.ServerVersion()
	if err != nil {
		return errors.Wrap(err, "server version")
	}
	glog.Infof("control plane version: %s", vi)
	if version.CompareKubeAwareVersionStrings(vi.String(), expected) != 0 {
		return fmt.Errorf("controlPane = %q, expected: %q", vi.String(), expected)
	}
	return nil
}

// APIServerStatus returns apiserver status in libmachine style state.State
func APIServerStatus(cr command.Runner, hostname string, port int) (state.State, error) {
	glog.Infof("Checking apiserver status ...")

	pid, err := apiServerPID(cr)
	if err != nil {
		glog.Warningf("stopped: unable to get apiserver pid: %v", err)
		return state.Stopped, nil
	}

	// Get the freezer cgroup entry for this pid
	rr, err := cr.RunCmd(exec.Command("sudo", "egrep", "^[0-9]+:freezer:", fmt.Sprintf("/proc/%d/cgroup", pid)))
	if err != nil {
		glog.Warningf("unable to find freezer cgroup: %v", err)
		return apiServerHealthz(hostname, port)

	}
	freezer := strings.TrimSpace(rr.Stdout.String())
	glog.Infof("apiserver freezer: %q", freezer)
	fparts := strings.Split(freezer, ":")
	if len(fparts) != 3 {
		glog.Warningf("unable to parse freezer - found %d parts: %s", len(fparts), freezer)
		return apiServerHealthz(hostname, port)
	}

	rr, err = cr.RunCmd(exec.Command("sudo", "cat", path.Join("/sys/fs/cgroup/freezer", fparts[2], "freezer.state")))
	if err != nil {
		// example error from github action:
		// cat: /sys/fs/cgroup/freezer/actions_job/e62ef4349cc5a70f4b49f8a150ace391da6ad6df27073c83ecc03dbf81fde1ce/kubepods/burstable/poda1de58db0ce81d19df7999f6808def1b/5df53230fe3483fd65f341923f18a477fda92ae9cd71061168130ef164fe479c/freezer.state: No such file or directory\n"*
		// TODO: #7770 investigate how to handle this error better.
		if strings.Contains(rr.Stderr.String(), "freezer.state: No such file or directory\n") {
			glog.Infof("unable to get freezer state (might be okay and be related to #770): %s", rr.Stderr.String())
		} else {
			glog.Warningf("unable to get freezer state: %s", rr.Stderr.String())
		}

		return apiServerHealthz(hostname, port)
	}

	fs := strings.TrimSpace(rr.Stdout.String())
	glog.Infof("freezer state: %q", fs)
	if fs == "FREEZING" || fs == "FROZEN" {
		return state.Paused, nil
	}
	return apiServerHealthz(hostname, port)
}

// apiServerHealthz hits the /healthz endpoint and returns libmachine style state.State
func apiServerHealthz(hostname string, port int) (state.State, error) {
	url := fmt.Sprintf("https://%s/healthz", net.JoinHostPort(hostname, fmt.Sprint(port)))
	glog.Infof("Checking apiserver healthz at %s ...", url)
	// To avoid: x509: certificate signed by unknown authority
	tr := &http.Transport{
		Proxy:           nil, // To avoid connectiv issue if http(s)_proxy is set.
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get(url)
	// Connection refused, usually.
	if err != nil {
		glog.Infof("stopped: %s: %v", url, err)
		return state.Stopped, nil
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	glog.Infof("%s returned %d:\n%s", url, resp.StatusCode, body)
	if resp.StatusCode == http.StatusUnauthorized {
		return state.Error, fmt.Errorf("%s returned code %d (unauthorized). Check your apiserver authorization settings:\n%s", url, resp.StatusCode, body)
	}
	if resp.StatusCode != http.StatusOK {
		return state.Error, fmt.Errorf("%s returned error %d:\n%s", url, resp.StatusCode, body)
	}
	return state.Running, nil
}
<commit_msg>Log an error if we can't read the response body<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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 kverify verifies a running kubernetes cluster is healthy
package kverify

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/docker/machine/libmachine/state"
	"github.com/golang/glog"
	"github.com/pkg/errors"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/version"
	"k8s.io/client-go/kubernetes"
	kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/minikube/pkg/minikube/bootstrapper"
	"k8s.io/minikube/pkg/minikube/command"
	"k8s.io/minikube/pkg/minikube/config"
	"k8s.io/minikube/pkg/minikube/cruntime"
)

// WaitForAPIServerProcess waits for api server to be healthy returns error if it doesn't
func WaitForAPIServerProcess(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg config.ClusterConfig, cr command.Runner, start time.Time, timeout time.Duration) error {
	glog.Infof("waiting for apiserver process to appear ...")
	err := wait.PollImmediate(time.Millisecond*500, timeout, func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during process check")
		}

		if time.Since(start) > minLogCheckTime {
			announceProblems(r, bs, cfg, cr)
			time.Sleep(kconst.APICallRetryInterval * 5)
		}

		if _, ierr := apiServerPID(cr); ierr != nil {
			return false, nil
		}

		return true, nil
	})
	if err != nil {
		return fmt.Errorf("apiserver process never appeared")
	}
	glog.Infof("duration metric: took %s to wait for apiserver process to appear ...", time.Since(start))
	return nil
}

// apiServerPID returns our best guess to the apiserver pid
func apiServerPID(cr command.Runner) (int, error) {
	rr, err := cr.RunCmd(exec.Command("sudo", "pgrep", "-xnf", "kube-apiserver.*minikube.*"))
	if err != nil {
		return 0, err
	}
	s := strings.TrimSpace(rr.Stdout.String())
	return strconv.Atoi(s)
}

// WaitForHealthyAPIServer waits for api server status to be running
func WaitForHealthyAPIServer(r cruntime.Manager, bs bootstrapper.Bootstrapper, cfg config.ClusterConfig, cr command.Runner, client *kubernetes.Clientset, start time.Time, hostname string, port int, timeout time.Duration) error {
	glog.Infof("waiting for apiserver healthz status ...")
	hStart := time.Now()

	healthz := func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during healthz check")
		}

		if time.Since(start) > minLogCheckTime {
			announceProblems(r, bs, cfg, cr)
			time.Sleep(kconst.APICallRetryInterval * 5)
		}

		status, err := apiServerHealthz(hostname, port)
		if err != nil {
			glog.Warningf("status: %v", err)
			return false, nil
		}
		if status != state.Running {
			return false, nil
		}
		return true, nil
	}

	if err := wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, healthz); err != nil {
		return fmt.Errorf("apiserver healthz never reported healthy")
	}

	vcheck := func() (bool, error) {
		if time.Since(start) > timeout {
			return false, fmt.Errorf("cluster wait timed out during version check")
		}
		if err := APIServerVersionMatch(client, cfg.KubernetesConfig.KubernetesVersion); err != nil {
			glog.Warningf("api server version match failed: %v", err)
			return false, nil
		}
		return true, nil
	}

	if err := wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, vcheck); err != nil {
		return fmt.Errorf("controlPlane never updated to %s", cfg.KubernetesConfig.KubernetesVersion)
	}

	glog.Infof("duration metric: took %s to wait for apiserver health ...", time.Since(hStart))
	return nil
}

// APIServerVersionMatch checks if the server version matches the expected
func APIServerVersionMatch(client *kubernetes.Clientset, expected string) error {
	vi, err := client.ServerVersion()
	if err != nil {
		return errors.Wrap(err, "server version")
	}
	glog.Infof("control plane version: %s", vi)
	if version.CompareKubeAwareVersionStrings(vi.String(), expected) != 0 {
		return fmt.Errorf("controlPane = %q, expected: %q", vi.String(), expected)
	}
	return nil
}

// APIServerStatus returns apiserver status in libmachine style state.State
func APIServerStatus(cr command.Runner, hostname string, port int) (state.State, error) {
	glog.Infof("Checking apiserver status ...")

	pid, err := apiServerPID(cr)
	if err != nil {
		glog.Warningf("stopped: unable to get apiserver pid: %v", err)
		return state.Stopped, nil
	}

	// Get the freezer cgroup entry for this pid
	rr, err := cr.RunCmd(exec.Command("sudo", "egrep", "^[0-9]+:freezer:", fmt.Sprintf("/proc/%d/cgroup", pid)))
	if err != nil {
		glog.Warningf("unable to find freezer cgroup: %v", err)
		return apiServerHealthz(hostname, port)

	}
	freezer := strings.TrimSpace(rr.Stdout.String())
	glog.Infof("apiserver freezer: %q", freezer)
	fparts := strings.Split(freezer, ":")
	if len(fparts) != 3 {
		glog.Warningf("unable to parse freezer - found %d parts: %s", len(fparts), freezer)
		return apiServerHealthz(hostname, port)
	}

	rr, err = cr.RunCmd(exec.Command("sudo", "cat", path.Join("/sys/fs/cgroup/freezer", fparts[2], "freezer.state")))
	if err != nil {
		// example error from github action:
		// cat: /sys/fs/cgroup/freezer/actions_job/e62ef4349cc5a70f4b49f8a150ace391da6ad6df27073c83ecc03dbf81fde1ce/kubepods/burstable/poda1de58db0ce81d19df7999f6808def1b/5df53230fe3483fd65f341923f18a477fda92ae9cd71061168130ef164fe479c/freezer.state: No such file or directory\n"*
		// TODO: #7770 investigate how to handle this error better.
		if strings.Contains(rr.Stderr.String(), "freezer.state: No such file or directory\n") {
			glog.Infof("unable to get freezer state (might be okay and be related to #770): %s", rr.Stderr.String())
		} else {
			glog.Warningf("unable to get freezer state: %s", rr.Stderr.String())
		}

		return apiServerHealthz(hostname, port)
	}

	fs := strings.TrimSpace(rr.Stdout.String())
	glog.Infof("freezer state: %q", fs)
	if fs == "FREEZING" || fs == "FROZEN" {
		return state.Paused, nil
	}
	return apiServerHealthz(hostname, port)
}

// apiServerHealthz hits the /healthz endpoint and returns libmachine style state.State
func apiServerHealthz(hostname string, port int) (state.State, error) {
	url := fmt.Sprintf("https://%s/healthz", net.JoinHostPort(hostname, fmt.Sprint(port)))
	glog.Infof("Checking apiserver healthz at %s ...", url)
	// To avoid: x509: certificate signed by unknown authority
	tr := &http.Transport{
		Proxy:           nil, // To avoid connectiv issue if http(s)_proxy is set.
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get(url)
	// Connection refused, usually.
	if err != nil {
		glog.Infof("stopped: %s: %v", url, err)
		return state.Stopped, nil
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Warningf("unable to read response body: %s", err)
	}

	glog.Infof("%s returned %d:\n%s", url, resp.StatusCode, body)
	if resp.StatusCode == http.StatusUnauthorized {
		return state.Error, fmt.Errorf("%s returned code %d (unauthorized). Check your apiserver authorization settings:\n%s", url, resp.StatusCode, body)
	}
	if resp.StatusCode != http.StatusOK {
		return state.Error, fmt.Errorf("%s returned error %d:\n%s", url, resp.StatusCode, body)
	}
	return state.Running, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"go/format"
	"os"
	"path/filepath"
	"regexp"
)

func (self *Generator) GenClassTypes(ns *Namespace) {
	output := new(bytes.Buffer)
	w(output, "package %s\n\n", self.PackageName)
	w(output, "/*\n")
	for _, include := range self.Includes {
		w(output, "#include <%s>\n", include)
	}
	w(output, "*/\n")
	w(output, "import \"C\"\n")
	w(output, "import \"unsafe\"\n")

	// generate class map
	classes := make(map[string]*Class)
	for _, c := range ns.Classes {
		classes[c.Name] = c
	}

	for _, c := range ns.Classes {
		goType := cTypeToGoType(c.CType)
		typeName := c.Name

		// skip
		skip := false
		for _, t := range self.TypesIgnorePatterns {
			matched, err := regexp.MatchString(t, typeName)
			checkError(err)
			if matched {
				skip = true
				break
			}
		}
		if skip {
			continue
		}

		w(output, "type %s struct {\n", c.Name)
		currentClass := c
		for currentClass != nil {
			w(output, "*_Trait%s\n", currentClass.Name)
			parent := currentClass.Parent
			currentClass = classes[parent]
			if parent != "" && currentClass == nil {
				p("==fixme== external class %s\n", parent)
			}
		}
		w(output, "CPointer unsafe.Pointer\n")
		w(output, "}\n\n")

		// type mapping
		TypeMapping["*"+goType] = "*" + typeName
		InParamMapping[fs("*%s -> *%s", typeName, goType)] = func(param *Param) {
			param.CgoParam = fs("(*%s)(%s.CPointer)", goType, param.GoName)
		}
		OutParamMapping[fs("*%s -> *%s", goType, typeName)] = func(param *Param) {
			param.CgoAfterStmt += fs("_ = __cgo__%s", param.GoName) //FIXME
		}
	}

	f, err := os.Create(filepath.Join(self.outputDir, self.PackageName+"_class_types.go"))
	checkError(err)
	formatted, err := format.Source(output.Bytes())
	if err != nil {
		f.Write(output.Bytes())
		f.Close()
		checkError(err)
	}
	f.Write(formatted)
	f.Close()
}

func (self *Generator) GenClasses(ns *Namespace) {
	/*
		for _, c := range ns.Classes {
			p("%s\n", c.Name)
			p("%s\n", c.CSymbolPrefix)
			p("%s\n", c.CType)
			p("%s\n", c.Parent)
			p("%s\n", c.Abstract)
			p("%v\n", c.Prerequisite)
			p("%v\n", c.Implements)
			p("%v\n", c.Constructors)
			p("%v\n", c.VirtualMethods)
			p("%v\n", c.Methods)
			p("%v\n", c.Functions)
			p("%v\n", c.Properties)
			p("%v\n", c.Fields)
			p("%v\n", c.Signals)
			p("<<<\n")
		}
	*/
}
<commit_msg>generator: class pointer constructor and out param mapping<commit_after>package main

import (
	"bytes"
	"go/format"
	"os"
	"path/filepath"
	"regexp"
)

func (self *Generator) GenClassTypes(ns *Namespace) {
	output := new(bytes.Buffer)
	w(output, "package %s\n\n", self.PackageName)
	w(output, "/*\n")
	for _, include := range self.Includes {
		w(output, "#include <%s>\n", include)
	}
	w(output, "*/\n")
	w(output, "import \"C\"\n")
	w(output, "import \"unsafe\"\n")

	// generate class map
	classes := make(map[string]*Class)
	for _, c := range ns.Classes {
		classes[c.Name] = c
	}

	for _, c := range ns.Classes {
		goType := cTypeToGoType(c.CType)
		typeName := c.Name

		// skip
		skip := false
		for _, t := range self.TypesIgnorePatterns {
			matched, err := regexp.MatchString(t, typeName)
			checkError(err)
			if matched {
				skip = true
				break
			}
		}
		if skip {
			continue
		}

		w(output, "type %s struct {\n", typeName)
		currentClass := c
		constructExpr := ""
		for currentClass != nil {
			w(output, "*_Trait%s\n", currentClass.Name)
			constructExpr += fs("&_Trait%s{(*%s)(p)},\n",
				currentClass.Name, cTypeToGoType(currentClass.CType))
			parent := currentClass.Parent
			currentClass = classes[parent]
			if parent != "" && currentClass == nil {
				p("==fixme== external class %s\n", parent)
			}
		}
		w(output, "CPointer unsafe.Pointer\n")
		w(output, "}\n")
		w(output, `func New%sFromCPointer(p unsafe.Pointer) *%s {
			return &%s{
				%sp,
			}
		}
		`, typeName, typeName, typeName, constructExpr)

		// type mapping
		TypeMapping["*"+goType] = "*" + typeName
		InParamMapping[fs("*%s -> *%s", typeName, goType)] = func(param *Param) {
			param.CgoParam = fs("(*%s)(%s.CPointer)", goType, param.GoName)
		}
		OutParamMapping[fs("*%s -> *%s", goType, typeName)] = func(param *Param) {
			param.CgoAfterStmt += fs("%s = New%sFromCPointer(unsafe.Pointer(__cgo__%s))",
				param.GoName, typeName, param.GoName)
		}
	}

	f, err := os.Create(filepath.Join(self.outputDir, self.PackageName+"_class_types.go"))
	checkError(err)
	formatted, err := format.Source(output.Bytes())
	if err != nil {
		f.Write(output.Bytes())
		f.Close()
		checkError(err)
	}
	f.Write(formatted)
	f.Close()
}

func (self *Generator) GenClasses(ns *Namespace) {
	/*
		for _, c := range ns.Classes {
			p("%s\n", c.Name)
			p("%s\n", c.CSymbolPrefix)
			p("%s\n", c.CType)
			p("%s\n", c.Parent)
			p("%s\n", c.Abstract)
			p("%v\n", c.Prerequisite)
			p("%v\n", c.Implements)
			p("%v\n", c.Constructors)
			p("%v\n", c.VirtualMethods)
			p("%v\n", c.Methods)
			p("%v\n", c.Functions)
			p("%v\n", c.Properties)
			p("%v\n", c.Fields)
			p("%v\n", c.Signals)
			p("<<<\n")
		}
	*/
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 5, 9, 0, 0, 0, 0, time.UTC)
	printTargetTime(target)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent          = "\t"
	highlight_start = "\x1b[1;35m"
	highlight_end   = "\x1b[0m"
)

func printTargetTime(target time.Time) {
	fmt.Print(indent, highlight_start, "Just Go", highlight_end, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<commit_msg>local time<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 5, 9, 0, 0, 0, 0, time.Local)
	printTargetTime(target)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent          = "\t"
	highlight_start = "\x1b[1;35m"
	highlight_end   = "\x1b[0m"
)

func printTargetTime(target time.Time) {
	fmt.Print(indent, highlight_start, "Just Go", highlight_end, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<|endoftext|>


<commit_before>package opentracing

// TraceContext encpasulates the smallest amount of state needed to describe a
// Span's identity within a larger [potentially distributed] trace. The
// TraceContext is not intended to encode the span's operation name, timing,
// or log data, but merely any unique identifiers (etc) needed to contextualize
// it within a larger trace tree.
//
// TraceContexts are sufficient to propagate the, well, *context* of a
// particular trace between processes.
//
// TraceContext also support a simple string map of "trace tags". These trace
// tags are special in that they are propagated *in-band*, presumably alongside
// application data. See the documentation for SetTraceTag() for more details
// and some important caveats.
type TraceContext interface {
	// NewChild creates a child context for this TraceContext, and returns both
	// that child's own TraceContext as well as any Tags that should be added
	// to the child's Span.
	//
	// The returned TraceContext type must be the same as the type of the
	// TraceContext implementation itself.
	NewChild() (childCtx TraceContext, childSpanTags Tags)

	// SetTraceTag sets a tag on this TraceContext that also propagates to
	// future TraceContext children per TraceContext.NewChild.
	//
	// SetTraceTag() enables powerful functionality given a full-stack
	// opentracing integration (e.g., arbitrary application data from a mobile
	// app can make it, transparently, all the way into the depths of a storage
	// system), and with it some powerful costs: use this feature with care.
	//
	// IMPORTANT NOTE #1: SetTraceTag() will only propagate trace tags to
	// *future* children of the TraceContext (see NewChild()) and/or the
	// Span that references it.
	//
	// IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
	// value is copied into every local *and remote* child of this
	// TraceContext, and that can add up to a lot of network and cpu
	// overhead.
	//
	// IMPORTANT NOTE #3: Trace tags are case-insensitive: implementations may
	// wish to use them as HTTP header keys (or key suffixes), and of course
	// HTTP headers are case insensitive.
	//
	// Returns a reference to this TraceContext for chaining, etc.
	SetTraceTag(caseInsensitiveKey, value string) TraceContext

	// Gets the value for a trace tag given its key. Returns the empty string
	// if the value isn't found in this TraceContext.
	TraceTag(caseInsensitiveKey string) string
}

// TraceContextMarshaler is a simple interface to marshal a TraceContext to a
// binary byte array or a string-to-string map.
type TraceContextMarshaler interface {
	// Converts the TraceContext into marshaled binary data (see
	// TraceContextUnmarshaler.UnmarshalTraceContextBinary()).
	//
	// The first return value must represent the marshaler's serialization of
	// the core identifying information in `tcid`.
	//
	// The second return value must represent the marshaler's serialization of
	// the trace tags, per `SetTraceTag` and `TraceTag`.
	MarshalTraceContextBinary(
		tcid TraceContext,
	) (
		traceContextID []byte,
		traceTags []byte,
	)

	// Converts the TraceContext into a marshaled string:string map (see
	// TraceContextUnmarshaler.UnmarshalTraceContextStringMap()).
	//
	// The first return value must represent the marshaler's serialization of
	// the core identifying information in `tcid`.
	//
	// The second return value must represent the marshaler's serialization of
	// the trace tags, per `SetTraceTag` and `TraceTag`.
	MarshalTraceContextStringMap(
		tcid TraceContext,
	) (
		traceContextID map[string]string,
		traceTags map[string]string,
	)
}

// TraceContextUnmarshaler is a simple interface to unmarshal a binary byte
// array or a string-to-string map into a TraceContext.
type TraceContextUnmarshaler interface {
	// Converts the marshaled binary data (see
	// TraceContextMarshaler.MarshalTraceContextBinary()) into a TraceContext.
	//
	// The first parameter contains the marshaler's serialization of the core
	// identifying information in a TraceContext instance.
	//
	// The first parameter contains the marshaler's serialization of the trace
	// tags (per `SetTraceTag` and `TraceTag`) attached to a TraceContext
	// instance.
	UnmarshalTraceContextBinary(
		traceContextID []byte,
		traceTags []byte,
	) (TraceContext, error)

	// Converts the marshaled string:string map (see
	// TraceContextMarshaler.MarshalTraceContextStringMap()) into a TraceContext.
	//
	// The first parameter contains the marshaler's serialization of the core
	// identifying information in a TraceContext instance.
	//
	// The first parameter contains the marshaler's serialization of the trace
	// tags (per `SetTraceTag` and `TraceTag`) attached to a TraceContext
	// instance.
	UnmarshalTraceContextStringMap(
		traceContextID map[string]string,
		traceTags map[string]string,
	) (TraceContext, error)
}

// TraceContextSource is a long-lived interface that knows how to create a root
// TraceContext and marshal/unmarshal any other.
type TraceContextSource interface {
	TraceContextMarshaler
	TraceContextUnmarshaler

	// Create a TraceContext which has no parent (and thus begins its own trace).
	// A TraceContextSource must always return the same type in successive calls
	// to NewRootTraceContext().
	NewRootTraceContext() TraceContext
}
<commit_msg>review responses<commit_after>package opentracing

// TraceContext encpasulates the smallest amount of state needed to describe a
// Span's identity within a larger [potentially distributed] trace. The
// TraceContext is not intended to encode the span's operation name, timing,
// or log data, but merely any unique identifiers (etc) needed to contextualize
// it within a larger trace tree.
//
// TraceContexts are sufficient to propagate the, well, *context* of a
// particular trace between processes.
//
// TraceContext also support a simple string map of "trace tags". These trace
// tags are special in that they are propagated *in-band*, presumably alongside
// application data. See the documentation for SetTraceTag() for more details
// and some important caveats.
type TraceContext interface {
	// NewChild creates a child context for this TraceContext, and returns both
	// that child's own TraceContext as well as any Tags that should be added
	// to the child's Span.
	//
	// The returned TraceContext type must be the same as the type of the
	// TraceContext implementation itself.
	NewChild() (childCtx TraceContext, childSpanTags Tags)

	// SetTraceTag sets a tag on this TraceContext that also propagates to
	// future TraceContext children per TraceContext.NewChild.
	//
	// SetTraceTag() enables powerful functionality given a full-stack
	// opentracing integration (e.g., arbitrary application data from a mobile
	// app can make it, transparently, all the way into the depths of a storage
	// system), and with it some powerful costs: use this feature with care.
	//
	// IMPORTANT NOTE #1: SetTraceTag() will only propagate trace tags to
	// *future* children of the TraceContext (see NewChild()) and/or the
	// Span that references it.
	//
	// IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
	// value is copied into every local *and remote* child of this
	// TraceContext, and that can add up to a lot of network and cpu
	// overhead.
	//
	// IMPORTANT NOTE #3: Trace tags are case-insensitive: implementations may
	// wish to use them as HTTP header keys (or key suffixes), and of course
	// HTTP headers are case insensitive.
	//
	// Returns a reference to this TraceContext for chaining, etc.
	SetTraceTag(caseInsensitiveKey, value string) TraceContext

	// Gets the value for a trace tag given its key. Returns the empty string
	// if the value isn't found in this TraceContext.
	TraceTag(caseInsensitiveKey string) string
}

// TraceContextMarshaler is a simple interface to marshal a TraceContext to a
// binary byte array or a string-to-string map.
type TraceContextMarshaler interface {
	// Converts the TraceContext into marshaled binary data (see
	// TraceContextUnmarshaler.UnmarshalTraceContextBinary()).
	//
	// The first return value must represent the marshaler's serialization of
	// the core identifying information in `tcid`.
	//
	// The second return value must represent the marshaler's serialization of
	// the trace tags, per `SetTraceTag` and `TraceTag`.
	MarshalTraceContextBinary(
		tcid TraceContext,
	) (
		traceContextID []byte,
		traceTags []byte,
	)

	// Converts the TraceContext into a marshaled string:string map (see
	// TraceContextUnmarshaler.UnmarshalTraceContextStringMap()).
	//
	// The first return value must represent the marshaler's serialization of
	// the core identifying information in `tcid`.
	//
	// The second return value must represent the marshaler's serialization of
	// the trace tags, per `SetTraceTag` and `TraceTag`.
	MarshalTraceContextStringMap(
		tcid TraceContext,
	) (
		traceContextID map[string]string,
		traceTags map[string]string,
	)
}

// TraceContextUnmarshaler is a simple interface to unmarshal a binary byte
// array or a string-to-string map into a TraceContext.
type TraceContextUnmarshaler interface {
	// Converts the marshaled binary data (see
	// TraceContextMarshaler.MarshalTraceContextBinary()) into a TraceContext.
	//
	// The first parameter contains the marshaler's serialization of the core
	// identifying information in a TraceContext instance.
	//
	// The second parameter contains the marshaler's serialization of the trace
	// tags (per `SetTraceTag` and `TraceTag`) attached to a TraceContext
	// instance.
	UnmarshalTraceContextBinary(
		traceContextID []byte,
		traceTags []byte,
	) (TraceContext, error)

	// Converts the marshaled string:string map (see
	// TraceContextMarshaler.MarshalTraceContextStringMap()) into a TraceContext.
	//
	// The first parameter contains the marshaler's serialization of the core
	// identifying information in a TraceContext instance.
	//
	// The second parameter contains the marshaler's serialization of the trace
	// tags (per `SetTraceTag` and `TraceTag`) attached to a TraceContext
	// instance.
	//
	// It's permissable to pass the same map to both parameters (e.g., an HTTP
	// request headers map): the implementation should only unmarshal the
	// subset its interested in.
	UnmarshalTraceContextStringMap(
		traceContextID map[string]string,
		traceTags map[string]string,
	) (TraceContext, error)
}

// TraceContextSource is a long-lived interface that knows how to create a root
// TraceContext and marshal/unmarshal any other.
type TraceContextSource interface {
	TraceContextMarshaler
	TraceContextUnmarshaler

	// Create a TraceContext which has no parent (and thus begins its own trace).
	// A TraceContextSource must always return the same type in successive calls
	// to NewRootTraceContext().
	NewRootTraceContext() TraceContext
}
<|endoftext|>


<commit_before>package logging

import (
	"net"
	"time"
)

const (
	DefaultReconnectDuration = 10
)

type NetHandler struct {
	*BaseHandler
	Network string
	Address string
	Timeout time.Duration
}

func NewNetHandler(network, address string, timeout time.Duration) (*NetHandler, error) {
	h := &NetHandler{
		Network: network,
		Address: address,
		Timeout: timeout,
	}
	conn, err := h.DialTimeout()
	if err != nil {
		return nil, err
	}
	bh, err := NewBaseHandler(conn, INFO, DefaultTimeLayout, DefaultFormat)
	if err != nil {
		return nil, err
	}
	h.BaseHandler = bh
	h.GotError = h.GotNetError
	return h, nil
}

func (h *NetHandler) DialTimeout() (net.Conn, error) {
	return net.DialTimeout(h.Network, h.Address, h.Timeout)
}

func (h *NetHandler) GotNetError(err error) {
	if _, ok := err.(net.Error); !ok {
		h.PanicError(err)
	}
	for {
		conn, err := h.DialTimeout()
		if err == nil {
			h.Writer = conn
			break
		}
		time.Sleep(DefaultReconnectDuration * time.Second)
	}
}
<commit_msg>use base handler's GotError<commit_after>package logging

import (
	"net"
	"time"
)

const (
	DefaultReconnectDuration = 10
)

type NetHandler struct {
	*BaseHandler
	Network string
	Address string
	Timeout time.Duration
}

func NewNetHandler(network, address string, timeout time.Duration) (*NetHandler, error) {
	h := &NetHandler{
		Network: network,
		Address: address,
		Timeout: timeout,
	}
	conn, err := h.DialTimeout()
	if err != nil {
		return nil, err
	}
	bh, err := NewBaseHandler(conn, INFO, DefaultTimeLayout, DefaultFormat)
	if err != nil {
		return nil, err
	}
	h.BaseHandler = bh
	h.GotError = h.GotNetError
	return h, nil
}

func (h *NetHandler) DialTimeout() (net.Conn, error) {
	return net.DialTimeout(h.Network, h.Address, h.Timeout)
}

func (h *NetHandler) GotNetError(err error) {
	if _, ok := err.(net.Error); !ok {
		h.BaseHandler.GotError(err)
		return
	}
	for {
		conn, err := h.DialTimeout()
		if err == nil {
			h.Writer = conn
			break
		}
		time.Sleep(DefaultReconnectDuration * time.Second)
	}
}
<|endoftext|>


<commit_before>package integration_test

import (
	"archive/tar"
	"compress/gzip"
	"encoding/json"
	"github.com/cloudfoundry/libbuildpack/cutlass"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

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

var _ = Describe("CF NodeJS Buildpack", func() {
	var (
		app              *cutlass.App
		serviceBrokerApp *cutlass.App
		serviceNameOne   string
		expected         = strings.ReplaceAll("./node_modules/.bin/slnodejs run  --useinitialcolor true --token token1 --buildsessionid bs1  ./dist/server.js", " ", "")
	)

	BeforeEach(func() {
		serviceNameOne = "sealights-" + cutlass.RandStringRunes(20)
	})

	AfterEach(func() {
		app = DestroyApp(app)

		_ = RunCF("delete-service", "-f", serviceNameOne)

		serviceBrokerApp = DestroyApp(serviceBrokerApp)
	})

	It("deploying a NodeJS app with sealights", func() {
		app = cutlass.New(Fixtures("with_sealights"))
		app.Name = "nodejs-sealights-" + cutlass.RandStringRunes(10)
		app.Memory = "256M"
		app.Disk = "512M"

		app.SetEnv("SL_BUILD_SESSION_ID", "bs1")

		By("Pushing an app with a user provided service", func() {
			Expect(RunCF("create-user-provided-service", serviceNameOne, "-p", `{
				"token": "token1"
			}`)).To(Succeed())

			Expect(RunCF("bind-service", app.Name, serviceNameOne)).To(Succeed())
			Expect(app.PushNoStart()).To(Succeed())
			Expect(app.DownloadDroplet(filepath.Join(app.Path, "droplet.tgz"))).To(Succeed())
			file, err := os.Open(filepath.Join(app.Path, "droplet.tgz"))
			Expect(err).ToNot(HaveOccurred())
			defer file.Close()
			gz, err := gzip.NewReader(file)
			Expect(err).ToNot(HaveOccurred())
			defer gz.Close()
			tr := tar.NewReader(gz)

			for {
				hdr, err := tr.Next()
				if err == io.EOF {
					break
				}
				if hdr.Name != "./app/package.json" {
					continue
				}
				b, err := ioutil.ReadAll(tr)
				p := map[string]interface{}{}
				json.Unmarshal(b, &p)

				Expect(p["scripts"].(map[string]interface{})["start"].(string)).To(Equal(expected))
			}
		})

		By("Unbinding and deleting the CUPS seeker service", func() {
			Expect(RunCF("unbind-service", app.Name, serviceNameOne)).To(Succeed())
			Expect(RunCF("delete-service", "-f", serviceNameOne)).To(Succeed())
		})
	})
})
<commit_msg>Fixing integration tests failing for Sealights integration (#434)<commit_after>package integration_test

import (
	"archive/tar"
	"compress/gzip"
	"encoding/json"
	"github.com/cloudfoundry/libbuildpack/cutlass"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

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

var _ = Describe("CF NodeJS Buildpack", func() {
	var (
		app              *cutlass.App
		serviceBrokerApp *cutlass.App
		serviceNameOne   string
		expected         = strings.ReplaceAll("./node_modules/.bin/slnodejs run  --useinitialcolor true --token token1 --buildsessionid bs1  ./dist/server.js", " ", "")
	)

	BeforeEach(func() {
		serviceNameOne = "sealights-" + cutlass.RandStringRunes(20)
	})

	AfterEach(func() {
		app = DestroyApp(app)

		_ = RunCF("delete-service", "-f", serviceNameOne)

		serviceBrokerApp = DestroyApp(serviceBrokerApp)
	})

	It("deploying a NodeJS app with sealights", func() {
		app = cutlass.New(Fixtures("with_sealights"))
		app.Name = "nodejs-sealights-" + cutlass.RandStringRunes(10)
		app.Memory = "256M"
		app.Disk = "512M"

		app.SetEnv("SL_BUILD_SESSION_ID", "bs1")

		By("Pushing an app with a user provided service", func() {
			Expect(RunCF("create-user-provided-service", serviceNameOne, "-p", `{
				"token": "token1"
			}`)).To(Succeed())

			Expect(app.PushNoStart()).To(Succeed())
			Expect(RunCF("bind-service", app.Name, serviceNameOne)).To(Succeed())
			Expect(app.PushNoStart()).To(Succeed())
			Expect(app.DownloadDroplet(filepath.Join(app.Path, "droplet.tgz"))).To(Succeed())
			file, err := os.Open(filepath.Join(app.Path, "droplet.tgz"))
			Expect(err).ToNot(HaveOccurred())
			defer file.Close()
			gz, err := gzip.NewReader(file)
			Expect(err).ToNot(HaveOccurred())
			defer gz.Close()
			tr := tar.NewReader(gz)

			for {
				hdr, err := tr.Next()
				if err == io.EOF {
					break
				}
				if hdr.Name != "./app/package.json" {
					continue
				}
				b, err := ioutil.ReadAll(tr)
				p := map[string]interface{}{}
				json.Unmarshal(b, &p)

				Expect(p["scripts"].(map[string]interface{})["start"].(string)).To(Equal(expected))
			}
		})

		By("Unbinding and deleting the CUPS seeker service", func() {
			Expect(RunCF("unbind-service", app.Name, serviceNameOne)).To(Succeed())
			Expect(RunCF("delete-service", "-f", serviceNameOne)).To(Succeed())
		})
	})
})
<|endoftext|>


<commit_before>package isumm

import (
	"fmt"
	"net/http"
	"text/template"
	"time"

	"appengine"
	"appengine/user"
)

var appTemplate = template.Must(template.ParseFiles("static/app.template.html"))

type appParams struct {
	User         string
	Currency     string
	LogoutURL    string
	Investments  []*Investment
	SummaryGraph []timeSeriesPoint
}

func App(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	u := user.Current(c) // Login is mandatory on this page. No need to check nil value here.
	if !IsUserAllowed(u) {
		InvalidUserPage(c, w, r, u)
		return
	}
	logoutUrl, err := LogoutURL(c, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	investments, err := GetInvestments(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	params := appParams{
		User:         u.String(),
		Currency:     Currency,
		LogoutURL:    logoutUrl,
		Investments:  investments,
		SummaryGraph: AmountSummaryChart(investments)}
	if err := appTemplate.Execute(w, params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// timeSeriesPoint represents a chart point where x-axis is a timeseries.
// All fields are private because interesting result is the String().
type timeSeriesPoint struct {
	date    time.Time
	balance float32
}

func (g timeSeriesPoint) String() string {
	return fmt.Sprintf("[%d, %.2f]", g.date.UnixNano()/1000000, g.balance)
}

func AmountSummaryChart(invs []*Investment) []timeSeriesPoint {
	auxChart := make(map[time.Time]float32)
	for _, i := range invs {
		for _, s := range i.Ops.Summarize() {
			auxChart[s.Date] += s.Balance
		}
	}
	var chart []timeSeriesPoint
	for t, b := range auxChart {
		chart = append(chart, timeSeriesPoint{t, b})
	}
	return chart
}
<commit_msg>Fixing import of handler_app.go: instead of text/template it should be html/template<commit_after>package isumm

import (
	"fmt"
	"html/template"
	"net/http"
	"time"

	"appengine"
	"appengine/user"
)

var appTemplate = template.Must(template.ParseFiles("static/app.template.html"))

type appParams struct {
	User         string
	Currency     string
	LogoutURL    string
	Investments  []*Investment
	SummaryGraph []timeSeriesPoint
}

func App(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	u := user.Current(c) // Login is mandatory on this page. No need to check nil value here.
	if !IsUserAllowed(u) {
		InvalidUserPage(c, w, r, u)
		return
	}
	logoutUrl, err := LogoutURL(c, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	investments, err := GetInvestments(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	params := appParams{
		User:         u.String(),
		Currency:     Currency,
		LogoutURL:    logoutUrl,
		Investments:  investments,
		SummaryGraph: AmountSummaryChart(investments)}
	if err := appTemplate.Execute(w, params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// timeSeriesPoint represents a chart point where x-axis is a timeseries.
// All fields are private because interesting result is the String().
type timeSeriesPoint struct {
	date    time.Time
	balance float32
}

func (g timeSeriesPoint) String() string {
	return fmt.Sprintf("[%d, %.2f]", g.date.UnixNano()/1000000, g.balance)
}

func AmountSummaryChart(invs []*Investment) []timeSeriesPoint {
	auxChart := make(map[time.Time]float32)
	for _, i := range invs {
		for _, s := range i.Ops.Summarize() {
			auxChart[s.Date] += s.Balance
		}
	}
	var chart []timeSeriesPoint
	for t, b := range auxChart {
		chart = append(chart, timeSeriesPoint{t, b})
	}
	return chart
}
<|endoftext|>


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

// Hello is a trivial example of a main package.
package main

import (
	"fmt"

	"code.google.com/p/go.example/newmath"
)

func main() {
	fmt.Printf("Hello, world.  Sqrt(2) = %g\n", newmath.Sqrt(2))
}

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

// Hello is a trivial example of a main package.
package main

import (
	"fmt"

	"code.google.com/p/go.example/newmath"
)

func main() {
	fmt.Printf("Hello, world.  Sqrt(2) = %d\n", newmath.Sqrt(2))
}
<|endoftext|>


<commit_before>package color

import (
	"sync"
	"unicode"
)

const (
	errInvalid = "%!h(INVALID)"
	errMissing = "%!h(MISSING)"
	errBadAttr = "%!h(BADATTR)"
	errNoVerb  = "%!(NOVERB)"
)

// stateFn represents the state of the highlighter as a function that returns the next state.
type stateFn func(*highlighter) stateFn

// highlighter holds the state of the scanner.
type highlighter struct {
	s     string // string being scanned
	buf   []byte // buffer for result
	pos   int    // position in buf
	attrs []byte // attributes of current highlight verb
}

var hlPool = sync.Pool{
	New: func() interface{} { return new(highlighter) },
}

// Highlight replaces the highlight verbs in s with their appropriate
// control sequences and then returns the resulting string.
func Highlight(s string) string {
	hl := getHighlighter(s)
	hl.run()
	return hl.free()
}

func getHighlighter(s string) (hl *highlighter) {
	hl = hlPool.Get().(*highlighter)
	hl.s = s
	return
}

func (hl *highlighter) free() (s string) {
	s = string(hl.buf)
	hl.buf = hl.buf[:0]
	hl.pos = 0
	hlPool.Put(hl)
	return
}

// run runs the state machine for the highlighter.
func (hl *highlighter) run() {
	for state := scanText; state != nil; {
		state = state(hl)
	}
}

const eof = -1

// get returns the current rune.
func (hl *highlighter) get() rune {
	if hl.pos >= len(hl.s) {
		return eof
	}
	return rune(hl.s[hl.pos])
}

// appends a control sequence derived from h.attrs[1:] to h.buf.
func (hl *highlighter) appendAttrs() {
	hl.buf = append(hl.buf, csi...)
	hl.buf = append(hl.buf, hl.attrs[1:]...)
	hl.buf = append(hl.buf, 'm')
}

// scanText scans until the next highlight or reset verb.
func scanText(hl *highlighter) stateFn {
	last := hl.pos
	for {
		if r := hl.get(); r == eof {
			hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
			return nil
		} else if r == '%' {
			break
		}
		hl.pos++
	}
	if last < hl.pos {
		hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
		last = hl.pos
	}
	hl.pos++
	switch hl.get() {
	case 'r':
		hl.pos++
		return verbReset
	case 'h':
		hl.pos += 2
		return scanHighlight
	case eof:
		hl.buf = append(hl.buf, errNoVerb...)
		return nil
	}
	hl.pos++
	hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
	return scanText
}

// verbReset appends the reset verb with the reset control sequence.
func verbReset(hl *highlighter) stateFn {
	hl.attrs = append(hl.attrs, attrs["reset"]...)
	hl.appendAttrs()
	hl.attrs = hl.attrs[:0]
	return scanText
}

// scanHighlight scans the highlight verb for attributes,
// then replaces it with a control sequence derived from said attributes.
func scanHighlight(hl *highlighter) stateFn {
	r := hl.get()
	switch {
	case r == 'f':
		return scanColor256(hl, preFg256)
	case r == 'b':
		return scanColor256(hl, preBg256)
	case unicode.IsLetter(r):
		return scanAttribute(hl, 0)
	case r == '+':
		hl.pos++
		return scanHighlight
	case r == ']':
		if len(hl.attrs) != 0 {
			hl.appendAttrs()
		} else {
			hl.buf = append(hl.buf, errMissing...)
		}
		hl.attrs = hl.attrs[:0]
		hl.pos++
		return scanText
	default:
		hl.buf = append(hl.buf, errInvalid...)
		return abortHighlight
	}
}

// scanAttribute scans a named attribute
func scanAttribute(hl *highlighter, off int) stateFn {
	start := hl.pos - off
	for unicode.IsLetter(hl.get()) {
		hl.pos++
	}
	if a, ok := attrs[hl.s[start:hl.pos]]; ok {
		hl.attrs = append(hl.attrs, a...)
	} else {
		hl.buf = append(hl.buf, errBadAttr...)
		return abortHighlight
	}
	return scanHighlight
}

func abortHighlight(hl *highlighter) stateFn {
	hl.attrs = hl.attrs[:0]
	for {
		switch hl.get() {
		case ']':
			hl.pos++
			return scanText
		case eof:
			return nil
		}
		hl.pos++
	}
}

// scanColor256 scans a 256 color attribute
func scanColor256(hl *highlighter, pre string) stateFn {
	hl.pos++
	if hl.get() != 'g' {
		return scanAttribute(hl, 1)
	}
	hl.pos++
	if !unicode.IsNumber(hl.get()) {
		return scanAttribute(hl, 2)
	}
	start := hl.pos
	hl.pos++
	for unicode.IsNumber(hl.get()) {
		hl.pos++
	}
	hl.attrs = append(hl.attrs, pre...)
	hl.attrs = append(hl.attrs, hl.s[start:hl.pos]...)
	return scanHighlight
}
<commit_msg>abortHighlight takes a msg arg<commit_after>package color

import (
	"sync"
	"unicode"
)

const (
	errInvalid = "%!h(INVALID)"
	errMissing = "%!h(MISSING)"
	errBadAttr = "%!h(BADATTR)"
	errNoVerb  = "%!(NOVERB)"
)

// stateFn represents the state of the highlighter as a function that returns the next state.
type stateFn func(*highlighter) stateFn

// highlighter holds the state of the scanner.
type highlighter struct {
	s     string // string being scanned
	buf   []byte // buffer for result
	pos   int    // position in buf
	attrs []byte // attributes of current highlight verb
}

var hlPool = sync.Pool{
	New: func() interface{} { return new(highlighter) },
}

// Highlight replaces the highlight verbs in s with their appropriate
// control sequences and then returns the resulting string.
func Highlight(s string) string {
	hl := getHighlighter(s)
	hl.run()
	return hl.free()
}

func getHighlighter(s string) (hl *highlighter) {
	hl = hlPool.Get().(*highlighter)
	hl.s = s
	return
}

func (hl *highlighter) free() (s string) {
	s = string(hl.buf)
	hl.buf = hl.buf[:0]
	hl.pos = 0
	hlPool.Put(hl)
	return
}

// run runs the state machine for the highlighter.
func (hl *highlighter) run() {
	for state := scanText; state != nil; {
		state = state(hl)
	}
}

const eof = -1

// get returns the current rune.
func (hl *highlighter) get() rune {
	if hl.pos >= len(hl.s) {
		return eof
	}
	return rune(hl.s[hl.pos])
}

// appends a control sequence derived from h.attrs[1:] to h.buf.
func (hl *highlighter) appendAttrs() {
	hl.buf = append(hl.buf, csi...)
	hl.buf = append(hl.buf, hl.attrs[1:]...)
	hl.buf = append(hl.buf, 'm')
}

// scanText scans until the next highlight or reset verb.
func scanText(hl *highlighter) stateFn {
	last := hl.pos
	for {
		if r := hl.get(); r == eof {
			hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
			return nil
		} else if r == '%' {
			break
		}
		hl.pos++
	}
	if last < hl.pos {
		hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
		last = hl.pos
	}
	hl.pos++
	switch hl.get() {
	case 'r':
		hl.pos++
		return verbReset
	case 'h':
		hl.pos += 2
		return scanHighlight
	case eof:
		hl.buf = append(hl.buf, errNoVerb...)
		return nil
	}
	hl.pos++
	hl.buf = append(hl.buf, hl.s[last:hl.pos]...)
	return scanText
}

// verbReset appends the reset verb with the reset control sequence.
func verbReset(hl *highlighter) stateFn {
	hl.attrs = append(hl.attrs, attrs["reset"]...)
	hl.appendAttrs()
	hl.attrs = hl.attrs[:0]
	return scanText
}

// scanHighlight scans the highlight verb for attributes,
// then replaces it with a control sequence derived from said attributes.
func scanHighlight(hl *highlighter) stateFn {
	r := hl.get()
	switch {
	case r == 'f':
		return scanColor256(hl, preFg256)
	case r == 'b':
		return scanColor256(hl, preBg256)
	case unicode.IsLetter(r):
		return scanAttribute(hl, 0)
	case r == '+':
		hl.pos++
		return scanHighlight
	case r == ']':
		if len(hl.attrs) != 0 {
			hl.appendAttrs()
		} else {
			hl.buf = append(hl.buf, errMissing...)
		}
		hl.attrs = hl.attrs[:0]
		hl.pos++
		return scanText
	default:
		return abortHighlight(hl, errInvalid)
	}
}

// scanAttribute scans a named attribute
func scanAttribute(hl *highlighter, off int) stateFn {
	start := hl.pos - off
	for unicode.IsLetter(hl.get()) {
		hl.pos++
	}
	if a, ok := attrs[hl.s[start:hl.pos]]; ok {
		hl.attrs = append(hl.attrs, a...)
	} else {
		return abortHighlight(hl, errBadAttr)
	}
	return scanHighlight
}

func abortHighlight(hl *highlighter, msg string) stateFn {
	hl.buf = append(hl.buf, msg...)
	hl.attrs = hl.attrs[:0]
	for {
		switch hl.get() {
		case ']':
			hl.pos++
			return scanText
		case eof:
			return nil
		}
		hl.pos++
	}
}

// scanColor256 scans a 256 color attribute
func scanColor256(hl *highlighter, pre string) stateFn {
	hl.pos++
	if hl.get() != 'g' {
		return scanAttribute(hl, 1)
	}
	hl.pos++
	if !unicode.IsNumber(hl.get()) {
		return scanAttribute(hl, 2)
	}
	start := hl.pos
	hl.pos++
	for unicode.IsNumber(hl.get()) {
		hl.pos++
	}
	hl.attrs = append(hl.attrs, pre...)
	hl.attrs = append(hl.attrs, hl.s[start:hl.pos]...)
	return scanHighlight
}
<|endoftext|>


<commit_before>package hooks

import (
	"regexp"
	"sync"
	"time"

	"github.com/danielkrainas/csense/api/v1"
	"github.com/danielkrainas/csense/context"
	"github.com/danielkrainas/csense/storage"
	"github.com/danielkrainas/csense/uuid"
)

type Filter interface {
	Match(hook *v1.Hook, c *v1.ContainerInfo) bool
}

type CriteriaFilter struct{}

func (f *CriteriaFilter) Match(hook *v1.Hook, c *v1.ContainerInfo) bool {
	crit := hook.Criteria

	if c.Name != "" && IsValid(crit.Name, c.Name) {
		return true
	}

	if c.ImageName != "" && IsValid(crit.ImageName, c.ImageName) {
		return true
	}

	for k, v := range c.Labels {
		if x, ok := c.Labels[k]; ok && x == v {
			return true
		}
	}

	return false
}

func IsValid(c *v1.Condition, v string) bool {
	if c == nil {
		return false
	}

	switch c.Op {
	case v1.OperandEqual:
		return c.Value == v
	case v1.OperandNotEqual:
		return c.Value != v
	case v1.OperandMatch:
		ok, err := regexp.MatchString(c.Value, v)
		return err == nil && ok
	}

	return false
}

func DefaultHook() *v1.Hook {
	return &v1.Hook{
		ID:      uuid.Generate(),
		Events:  make([]v1.EventType, 0),
		TTL:     -1,
		Created: time.Now().Unix(),
		Format:  v1.FormatJSON,
	}
}

func FilterAll(hooks []*v1.Hook, c *v1.ContainerInfo, f Filter) []*v1.Hook {
	results := make([]*v1.Hook, 0)
	for _, hook := range hooks {
		if f.Match(hook, c) {
			results = append(results, hook)
		}
	}

	return results
}

type Cache struct {
	ticker *time.Ticker
	update sync.Mutex
	hooks  []*v1.Hook
}

func (c *Cache) Hooks() []*v1.Hook {
	c.update.Lock()
	defer c.update.Unlock()
	return c.hooks
}

func NewCache(ctx context.Context, d time.Duration, store storage.HookStore) *Cache {
	c := &Cache{
		ticker: time.NewTicker(d),
		hooks:  []*v1.Hook{},
	}

	go func() {
		for {
			<-c.ticker.C
			hooks, err := store.GetAll(ctx)
			if err != nil {
				context.GetLogger(ctx).Warnf("error caching hooks: %v", err)
				continue
			}

			c.update.Lock()
			c.hooks = hooks
			c.update.Unlock()
		}
	}()

	return c
}
<commit_msg>handle name and image name field match<commit_after>package hooks

import (
	"regexp"
	"sync"
	"time"

	"github.com/danielkrainas/csense/api/v1"
	"github.com/danielkrainas/csense/context"
	"github.com/danielkrainas/csense/storage"
	"github.com/danielkrainas/csense/uuid"
)

type Filter interface {
	Match(hook *v1.Hook, c *v1.ContainerInfo) bool
}

type CriteriaFilter struct{}

func (f *CriteriaFilter) Match(hook *v1.Hook, c *v1.ContainerInfo) bool {
	crit := hook.Criteria

	for fieldName, condition := range crit.Fields {
		valid := false
		switch fieldName {
		case v1.FieldName:
			valid = IsValid(condition, c.Name)
		case v1.FieldImageName:
			valid = IsValid(condition, c.ImageName)
		}

		if valid {
			return valid
		}
	}

	for k, v := range c.Labels {
		if x, ok := c.Labels[k]; ok && x == v {
			return true
		}
	}

	return false
}

func IsValid(c *v1.Condition, v string) bool {
	if c == nil {
		return false
	}

	switch c.Op {
	case v1.OperandEqual:
		return c.Value == v
	case v1.OperandNotEqual:
		return c.Value != v
	case v1.OperandMatch:
		ok, err := regexp.MatchString(c.Value, v)
		return err == nil && ok
	}

	return false
}

func DefaultHook() *v1.Hook {
	return &v1.Hook{
		ID:      uuid.Generate(),
		Events:  make([]v1.EventType, 0),
		TTL:     -1,
		Created: time.Now().Unix(),
		Format:  v1.FormatJSON,
	}
}

func FilterAll(hooks []*v1.Hook, c *v1.ContainerInfo, f Filter) []*v1.Hook {
	results := make([]*v1.Hook, 0)
	for _, hook := range hooks {
		if f.Match(hook, c) {
			results = append(results, hook)
		}
	}

	return results
}

type Cache struct {
	ticker *time.Ticker
	update sync.Mutex
	hooks  []*v1.Hook
}

func (c *Cache) Hooks() []*v1.Hook {
	c.update.Lock()
	defer c.update.Unlock()
	return c.hooks
}

func NewCache(ctx context.Context, d time.Duration, store storage.HookStore) *Cache {
	c := &Cache{
		ticker: time.NewTicker(d),
		hooks:  []*v1.Hook{},
	}

	go func() {
		for {
			<-c.ticker.C
			hooks, err := store.GetAll(ctx)
			if err != nil {
				context.GetLogger(ctx).Warnf("error caching hooks: %v", err)
				continue
			}

			c.update.Lock()
			c.hooks = hooks
			c.update.Unlock()
		}
	}()

	return c
}
<|endoftext|>