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

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"reflect"
	"strings"
	"unicode"
	"utf8"
)

func initRewrite() {
	if *rewriteRule == "" {
		return
	}
	f := strings.Split(*rewriteRule, "->", -1)
	if len(f) != 2 {
		fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
		os.Exit(2)
	}
	pattern := parseExpr(f[0], "pattern")
	replace := parseExpr(f[1], "replacement")
	rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
}

// parseExpr parses s as an expression.
// It might make sense to expand this to allow statement patterns,
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr {
	x, err := parser.ParseExpr(fset, "input", s)
	if err != nil {
		fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
		os.Exit(2)
	}
	return x
}

// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
	m := make(map[string]reflect.Value)
	pat := reflect.NewValue(pattern)
	repl := reflect.NewValue(replace)
	var f func(val reflect.Value) reflect.Value // f is recursive
	f = func(val reflect.Value) reflect.Value {
		for k := range m {
			m[k] = reflect.Value{}, false
		}
		val = apply(f, val)
		if match(m, pat, val) {
			val = subst(m, repl, reflect.NewValue(val.Interface().(ast.Node).Pos()))
		}
		return val
	}
	return apply(f, reflect.NewValue(p)).Interface().(*ast.File)
}

// setValue is a wrapper for x.SetValue(y); it protects
// the caller from panics if x cannot be changed to y.
func setValue(x, y reflect.Value) {
	defer func() {
		if x := recover(); x != nil {
			if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
				// x cannot be set to y - ignore this rewrite
				return
			}
			panic(x)
		}
	}()
	x.Set(y)
}

// apply replaces each AST field x in val with f(x), returning val.
// To avoid extra conversions, f operates on the reflect.Value form.
func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
	if !val.IsValid() {
		return reflect.Value{}
	}
	switch v := reflect.Indirect(val); v.Kind() {
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			e := v.Index(i)
			setValue(e, f(e))
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			e := v.Field(i)
			setValue(e, f(e))
		}
	case reflect.Interface:
		e := v.Elem()
		setValue(v, f(e))
	}
	return val
}

var positionType = reflect.Typeof(token.NoPos)
var identType = reflect.Typeof((*ast.Ident)(nil))

func isWildcard(s string) bool {
	rune, size := utf8.DecodeRuneInString(s)
	return size == len(s) && unicode.IsLower(rune)
}

// match returns true if pattern matches val,
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
	// Wildcard matches any expression.  If it appears multiple
	// times in the pattern, it must match the same expression
	// each time.
	if m != nil && pattern.IsValid() && pattern.Type() == identType {
		name := pattern.Interface().(*ast.Ident).Name
		if isWildcard(name) && val.IsValid() {
			// wildcards only match expressions
			if _, ok := val.Interface().(ast.Expr); ok {
				if old, ok := m[name]; ok {
					return match(nil, old, val)
				}
				m[name] = val
				return true
			}
		}
	}

	// Otherwise, pattern and val must match recursively.
	if !pattern.IsValid() || !val.IsValid() {
		return !pattern.IsValid() && !val.IsValid()
	}
	if pattern.Type() != val.Type() {
		return false
	}

	// Special cases.
	switch pattern.Type() {
	case positionType:
		// token positions don't need to match
		return true
	case identType:
		// For identifiers, only the names need to match
		// (and none of the other *ast.Object information).
		// This is a common case, handle it all here instead
		// of recursing down any further via reflection.
		p := pattern.Interface().(*ast.Ident)
		v := val.Interface().(*ast.Ident)
		return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
	}

	p := reflect.Indirect(pattern)
	v := reflect.Indirect(val)
	if !p.IsValid() || !v.IsValid() {
		return !p.IsValid() && !v.IsValid()
	}

	switch p.Kind() {
	case reflect.Slice:
		v := v
		if p.Len() != v.Len() {
			return false
		}
		for i := 0; i < p.Len(); i++ {
			if !match(m, p.Index(i), v.Index(i)) {
				return false
			}
		}
		return true

	case reflect.Struct:
		v := v
		if p.NumField() != v.NumField() {
			return false
		}
		for i := 0; i < p.NumField(); i++ {
			if !match(m, p.Field(i), v.Field(i)) {
				return false
			}
		}
		return true

	case reflect.Interface:
		v := v
		return match(m, p.Elem(), v.Elem())
	}

	// Handle token integers, etc.
	return p.Interface() == v.Interface()
}

// subst returns a copy of pattern with values from m substituted in place
// of wildcards and pos used as the position of tokens from the pattern.
// if m == nil, subst returns a copy of pattern and doesn't change the line
// number information.
func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
	if !pattern.IsValid() {
		return reflect.Value{}
	}

	// Wildcard gets replaced with map value.
	if m != nil && pattern.Type() == identType {
		name := pattern.Interface().(*ast.Ident).Name
		if isWildcard(name) {
			if old, ok := m[name]; ok {
				return subst(nil, old, reflect.Value{})
			}
		}
	}

	if pos.IsValid() && pattern.Type() == positionType {
		// use new position only if old position was valid in the first place
		if old := pattern.Interface().(token.Pos); !old.IsValid() {
			return pattern
		}
		return pos
	}

	// Otherwise copy.
	switch p := pattern; p.Kind() {
	case reflect.Slice:
		v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
		for i := 0; i < p.Len(); i++ {
			v.Index(i).Set(subst(m, p.Index(i), pos))
		}
		return v

	case reflect.Struct:
		v := reflect.Zero(p.Type())
		for i := 0; i < p.NumField(); i++ {
			v.Field(i).Set(subst(m, p.Field(i), pos))
		}
		return v

	case reflect.Ptr:
		v := reflect.Zero(p.Type())
		v.Set(subst(m, p.Elem(), pos).Addr())
		return v

	case reflect.Interface:
		v := reflect.Zero(p.Type())
		v.Set(subst(m, p.Elem(), pos))
		return v
	}

	return pattern
}
<commit_msg>gofmt: avoid endless loops<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"reflect"
	"strings"
	"unicode"
	"utf8"
)

func initRewrite() {
	if *rewriteRule == "" {
		return
	}
	f := strings.Split(*rewriteRule, "->", -1)
	if len(f) != 2 {
		fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
		os.Exit(2)
	}
	pattern := parseExpr(f[0], "pattern")
	replace := parseExpr(f[1], "replacement")
	rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
}

// parseExpr parses s as an expression.
// It might make sense to expand this to allow statement patterns,
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr {
	x, err := parser.ParseExpr(fset, "input", s)
	if err != nil {
		fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
		os.Exit(2)
	}
	return x
}

// Keep this function for debugging.
/*
func dump(msg string, val reflect.Value) {
	fmt.Printf("%s:\n", msg)
	ast.Print(fset, val.Interface())
	fmt.Println()
}
*/

// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
	m := make(map[string]reflect.Value)
	pat := reflect.NewValue(pattern)
	repl := reflect.NewValue(replace)
	var f func(val reflect.Value) reflect.Value // f is recursive
	f = func(val reflect.Value) reflect.Value {
		for k := range m {
			m[k] = reflect.Value{}, false
		}
		val = apply(f, val)
		if match(m, pat, val) {
			val = subst(m, repl, reflect.NewValue(val.Interface().(ast.Node).Pos()))
		}
		return val
	}
	return apply(f, reflect.NewValue(p)).Interface().(*ast.File)
}

// setValue is a wrapper for x.SetValue(y); it protects
// the caller from panics if x cannot be changed to y.
func setValue(x, y reflect.Value) {
	defer func() {
		if x := recover(); x != nil {
			if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
				// x cannot be set to y - ignore this rewrite
				return
			}
			panic(x)
		}
	}()
	x.Set(y)
}

// Values/types for special cases.
var (
	objectPtrNil = reflect.NewValue((*ast.Object)(nil))

	identType     = reflect.Typeof((*ast.Ident)(nil))
	objectPtrType = reflect.Typeof((*ast.Object)(nil))
	positionType  = reflect.Typeof(token.NoPos)
)

// apply replaces each AST field x in val with f(x), returning val.
// To avoid extra conversions, f operates on the reflect.Value form.
func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
	if !val.IsValid() {
		return reflect.Value{}
	}

	// *ast.Objects introduce cycles and are likely incorrect after
	// rewrite; don't follow them but replace with nil instead
	if val.Type() == objectPtrType {
		return objectPtrNil
	}

	switch v := reflect.Indirect(val); v.Kind() {
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			e := v.Index(i)
			setValue(e, f(e))
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			e := v.Field(i)
			setValue(e, f(e))
		}
	case reflect.Interface:
		e := v.Elem()
		setValue(v, f(e))
	}
	return val
}

func isWildcard(s string) bool {
	rune, size := utf8.DecodeRuneInString(s)
	return size == len(s) && unicode.IsLower(rune)
}

// match returns true if pattern matches val,
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
	// Wildcard matches any expression.  If it appears multiple
	// times in the pattern, it must match the same expression
	// each time.
	if m != nil && pattern.IsValid() && pattern.Type() == identType {
		name := pattern.Interface().(*ast.Ident).Name
		if isWildcard(name) && val.IsValid() {
			// wildcards only match expressions
			if _, ok := val.Interface().(ast.Expr); ok {
				if old, ok := m[name]; ok {
					return match(nil, old, val)
				}
				m[name] = val
				return true
			}
		}
	}

	// Otherwise, pattern and val must match recursively.
	if !pattern.IsValid() || !val.IsValid() {
		return !pattern.IsValid() && !val.IsValid()
	}
	if pattern.Type() != val.Type() {
		return false
	}

	// Special cases.
	switch pattern.Type() {
	case identType:
		// For identifiers, only the names need to match
		// (and none of the other *ast.Object information).
		// This is a common case, handle it all here instead
		// of recursing down any further via reflection.
		p := pattern.Interface().(*ast.Ident)
		v := val.Interface().(*ast.Ident)
		return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
	case objectPtrType, positionType:
		// object pointers and token positions don't need to match
		return true
	}

	p := reflect.Indirect(pattern)
	v := reflect.Indirect(val)
	if !p.IsValid() || !v.IsValid() {
		return !p.IsValid() && !v.IsValid()
	}

	switch p.Kind() {
	case reflect.Slice:
		if p.Len() != v.Len() {
			return false
		}
		for i := 0; i < p.Len(); i++ {
			if !match(m, p.Index(i), v.Index(i)) {
				return false
			}
		}
		return true

	case reflect.Struct:
		if p.NumField() != v.NumField() {
			return false
		}
		for i := 0; i < p.NumField(); i++ {
			if !match(m, p.Field(i), v.Field(i)) {
				return false
			}
		}
		return true

	case reflect.Interface:
		return match(m, p.Elem(), v.Elem())
	}

	// Handle token integers, etc.
	return p.Interface() == v.Interface()
}

// subst returns a copy of pattern with values from m substituted in place
// of wildcards and pos used as the position of tokens from the pattern.
// if m == nil, subst returns a copy of pattern and doesn't change the line
// number information.
func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
	if !pattern.IsValid() {
		return reflect.Value{}
	}

	// Wildcard gets replaced with map value.
	if m != nil && pattern.Type() == identType {
		name := pattern.Interface().(*ast.Ident).Name
		if isWildcard(name) {
			if old, ok := m[name]; ok {
				return subst(nil, old, reflect.Value{})
			}
		}
	}

	if pos.IsValid() && pattern.Type() == positionType {
		// use new position only if old position was valid in the first place
		if old := pattern.Interface().(token.Pos); !old.IsValid() {
			return pattern
		}
		return pos
	}

	// Otherwise copy.
	switch p := pattern; p.Kind() {
	case reflect.Slice:
		v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
		for i := 0; i < p.Len(); i++ {
			v.Index(i).Set(subst(m, p.Index(i), pos))
		}
		return v

	case reflect.Struct:
		v := reflect.Zero(p.Type())
		for i := 0; i < p.NumField(); i++ {
			v.Field(i).Set(subst(m, p.Field(i), pos))
		}
		return v

	case reflect.Ptr:
		v := reflect.Zero(p.Type())
		if elem := p.Elem(); elem.IsValid() {
			v.Set(subst(m, elem, pos).Addr())
		}
		return v

	case reflect.Interface:
		v := reflect.Zero(p.Type())
		if elem := p.Elem(); elem.IsValid() {
			v.Set(subst(m, elem, pos))
		}
		return v
	}

	return pattern
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 retry

import (
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/wait"
)

// DefaultRetry is the recommended retry for a conflict where multiple clients
// are making changes to the same resource.
var DefaultRetry = wait.Backoff{
	Steps:    5,
	Duration: 10 * time.Millisecond,
	Factor:   1.0,
	Jitter:   0.1,
}

// DefaultBackoff is the recommended backoff for a conflict where a client
// may be attempting to make an unrelated modification to a resource under
// active management by one or more controllers.
var DefaultBackoff = wait.Backoff{
	Steps:    4,
	Duration: 10 * time.Millisecond,
	Factor:   5.0,
	Jitter:   0.1,
}

// RetryConflict executes the provided function repeatedly, retrying if the server returns a conflicting
// write. Callers should preserve previous executions if they wish to retry changes. It performs an
// exponential backoff.
//
//     var pod *api.Pod
//     err := RetryOnConflict(DefaultBackoff, func() (err error) {
//       pod, err = c.Pods("mynamespace").UpdateStatus(podStatus)
//       return
//     })
//     if err != nil {
//       // may be conflict if max retries were hit
//       return err
//     }
//     ...
//
// TODO: Make Backoff an interface?
func RetryOnConflict(backoff wait.Backoff, fn func() error) error {
	var lastConflictErr error
	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
		err := fn()
		switch {
		case err == nil:
			return true, nil
		case errors.IsConflict(err):
			lastConflictErr = err
			return false, nil
		default:
			return false, err
		}
	})
	if err == wait.ErrWaitTimeout {
		err = lastConflictErr
	}
	return err
}
<commit_msg>make util/retry more generic<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 retry

import (
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/wait"
)

// DefaultRetry is the recommended retry for a conflict where multiple clients
// are making changes to the same resource.
var DefaultRetry = wait.Backoff{
	Steps:    5,
	Duration: 10 * time.Millisecond,
	Factor:   1.0,
	Jitter:   0.1,
}

// DefaultBackoff is the recommended backoff for a conflict where a client
// may be attempting to make an unrelated modification to a resource under
// active management by one or more controllers.
var DefaultBackoff = wait.Backoff{
	Steps:    4,
	Duration: 10 * time.Millisecond,
	Factor:   5.0,
	Jitter:   0.1,
}

// OnError executes the provided function repeatedly, retrying if the server returns a specified
// error. Callers should preserve previous executions if they wish to retry changes. It performs an
// exponential backoff.
//
//     var pod *api.Pod
//     err := retry.OnError(DefaultBackoff, errors.IsConflict, func() (err error) {
//       pod, err = c.Pods("mynamespace").UpdateStatus(podStatus)
//       return
//     })
//     if err != nil {
//       // may be conflict if max retries were hit
//       return err
//     }
//     ...
//
// TODO: Make Backoff an interface?
func OnError(backoff wait.Backoff, errorFunc func(error) bool, fn func() error) error {
	var lastConflictErr error
	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
		err := fn()
		switch {
		case err == nil:
			return true, nil
		case errorFunc(err):
			lastConflictErr = err
			return false, nil
		default:
			return false, err
		}
	})
	if err == wait.ErrWaitTimeout {
		err = lastConflictErr
	}
	return err
}

// RetryOnConflict executes the function function repeatedly, retrying if the server returns a conflicting
func RetryOnConflict(backoff wait.Backoff, fn func() error) error {
	return OnError(backoff, errors.IsConflict, fn)
}
<|endoftext|>


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

package util

import (
	"testing"

	"github.com/square/metrics/api"
	"github.com/square/metrics/testing_support/assert"
)

func checkRuleErrorCode(a assert.Assert, err error, expected RuleErrorCode) {
	a = a.Stack(1)
	if err == nil {
		a.Errorf("No error provided.")
		return
	}
	casted, ok := err.(RuleError)
	if !ok {
		a.Errorf("Invalid Error type: %s", err.Error())
		return
	}
	a.EqInt(int(casted.Code()), int(expected))
}

func checkConversionErrorCode(t *testing.T, err error, expected ConversionErrorCode) {
	casted, ok := err.(ConversionError)
	if !ok {
		t.Errorf("Invalid Error type")
		return
	}
	a := assert.New(t)
	a.EqInt(int(casted.Code()), int(expected))
}

func TestCompile_Good(t *testing.T) {
	a := assert.New(t)
	_, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
}

func TestCompile_Error(t *testing.T) {
	for _, test := range []struct {
		rawRule      RawRule
		expectedCode RuleErrorCode
	}{
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: ""}, InvalidMetricKey},
		{RawRule{Pattern: "prefix.%foo%abc%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.%foo%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.abc.%%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: "test-metric", Regex: map[string]string{"foo": "(bar)"}}, InvalidCustomRegex},
	} {
		_, err := Compile(test.rawRule)
		a := assert.New(t).Contextf("%s", test.rawRule.Pattern)
		checkRuleErrorCode(a, err, test.expectedCode)
	}
}

func TestMatchRule_Simple(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("prefix.abc")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-metric")
	a.EqString(matcher.TagSet["foo"], "abc")

	_, matches = rule.MatchRule("prefix.abc.def")
	if matches {
		t.Errorf("Unexpected matching")
	}
}

func TestMatchRule_FilterTag(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%.%bar%",
		MetricKeyPattern: "test-metric.%bar%",
	})
	a.CheckError(err)
	originalName := "prefix.fooValue.barValue"
	matcher, matched := rule.MatchRule(originalName)
	if !matched {
		t.Errorf("Expected matching but didn't occur")
		return
	}
	a.EqString(string(matcher.MetricKey), "test-metric.barValue")
	a.Eq(matcher.TagSet, api.TagSet(map[string]string{"foo": "fooValue"}))
	// perform the reverse.
	reversed, err := rule.ToGraphiteName(matcher)
	a.CheckError(err)
	a.EqString(string(reversed), originalName)
}

func TestMatchRule_CustomRegex(t *testing.T) {
	a := assert.New(t)
	regex := make(map[string]string)
	regex["name"] = "[a-z]+"
	regex["shard"] = "[0-9]+"
	rule, err := Compile(RawRule{
		Pattern:          "feed.%name%-shard-%shard%",
		MetricKeyPattern: "test-feed-metric",
		Regex:            regex,
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("feed.feedname-shard-12")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-feed-metric")
	a.EqString(matcher.TagSet["name"], "feedname")
	a.EqString(matcher.TagSet["shard"], "12")
}

func TestLoadYAML(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules:
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	a.CheckError(err)
	a.EqInt(len(ruleSet.rules), 1)
	a.EqString(string(ruleSet.rules[0].raw.MetricKeyPattern), "abc")
	a.Eq(ruleSet.rules[0].graphitePatternTags, []string{"tag"})
}

func TestLoadYAML_Invalid(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	checkRuleErrorCode(a, err, InvalidYaml)
	a.EqInt(len(ruleSet.rules), 0)
}

func TestToGraphiteName(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	tm := api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	}
	reversed, err := rule.ToGraphiteName(tm)
	a.CheckError(err)
	a.EqString(string(reversed), "prefix.fooValue")
}

func TestToGraphiteName_Error(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	reversed, err := rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet(""),
	})
	checkConversionErrorCode(t, err, MissingTag)
	a.EqString(string(reversed), "")

	reversed, err = rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric-foo",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	})
	checkConversionErrorCode(t, err, CannotInterpolate)
	a.EqString(string(reversed), "")
}

func Test_interpolateTags(t *testing.T) {

	for _, testCase := range []struct {
		pattern  string
		tagSet   api.TagSet
		enforce  bool
		result   string
		succeeds bool
	}{
		// note that the result <fail> indicates that the test case should fail to parse
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box", "D": "other"}, false, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box", "D": "other"}, true, "", false},
		{"no.variable.test", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "no.variable.test", true},
		{"no.variable.test", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "", false},
		{"test.for.%extra%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "", false},
		{"test.for.%extra%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "", false},
	} {
		pattern := testCase.pattern
		tagSet := testCase.tagSet
		result := testCase.result
		enforce := testCase.enforce
		succeeds := testCase.succeeds
		testResult, err := interpolateTags(pattern, tagSet, enforce)
		if succeeds {
			if err != nil {
				t.Errorf("pattern %s fails for tagset %+v", pattern, tagSet)
				continue
			}
			if testResult != result {
				t.Errorf("pattern %s for tagset %+v produces incorrect pattern %s instead of %s (enforce=%v)", pattern, tagSet, testResult, result, enforce)
				continue
			}
			// otherwise, everything is okay since no error occurred and the results match
		} else {
			if err == nil {
				t.Errorf("pattern %s succeeds for tagset %+v producing output %s when it should not succeed (enforce=%v)", pattern, tagSet, testResult, enforce)
				continue
			}
			// otherwise, everything is okay since the match failed
		}
	}

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

package util

import (
	"testing"

	"github.com/square/metrics/api"
	"github.com/square/metrics/testing_support/assert"
)

func checkRuleErrorCode(a assert.Assert, err error, expected RuleErrorCode) {
	a = a.Stack(1)
	if err == nil {
		a.Errorf("No error provided.")
		return
	}
	casted, ok := err.(RuleError)
	if !ok {
		a.Errorf("Invalid Error type: %s", err.Error())
		return
	}
	a.EqInt(int(casted.Code()), int(expected))
}

func checkConversionErrorCode(t *testing.T, err error, expected ConversionErrorCode) {
	casted, ok := err.(ConversionError)
	if !ok {
		t.Errorf("Invalid Error type")
		return
	}
	a := assert.New(t)
	a.EqInt(int(casted.Code()), int(expected))
}

func TestCompile_Good(t *testing.T) {
	a := assert.New(t)
	_, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
}

func TestCompile_Error(t *testing.T) {
	for _, test := range []struct {
		rawRule      RawRule
		expectedCode RuleErrorCode
	}{
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: ""}, InvalidMetricKey},
		{RawRule{Pattern: "prefix.%foo%abc%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.%foo%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.abc.%%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: "test-metric", Regex: map[string]string{"foo": "(bar)"}}, InvalidCustomRegex},
	} {
		_, err := Compile(test.rawRule)
		a := assert.New(t).Contextf("%s", test.rawRule.Pattern)
		checkRuleErrorCode(a, err, test.expectedCode)
	}
}

func TestMatchRule_Simple(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("prefix.abc")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-metric")
	a.EqString(matcher.TagSet["foo"], "abc")

	_, matches = rule.MatchRule("prefix.abc.def")
	if matches {
		t.Errorf("Unexpected matching")
	}
}

func TestMatchRule_FilterTag(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%.%bar%",
		MetricKeyPattern: "test-metric.%bar%",
	})
	a.CheckError(err)
	originalName := "prefix.fooValue.barValue"
	matcher, matched := rule.MatchRule(originalName)
	if !matched {
		t.Errorf("Expected matching but didn't occur")
		return
	}
	a.EqString(string(matcher.MetricKey), "test-metric.barValue")
	a.Eq(matcher.TagSet, api.TagSet(map[string]string{"foo": "fooValue"}))
	// perform the reverse.
	reversed, err := rule.ToGraphiteName(matcher)
	a.CheckError(err)
	a.EqString(string(reversed), originalName)
}

func TestMatchRule_CustomRegex(t *testing.T) {
	a := assert.New(t)
	regex := make(map[string]string)
	regex["name"] = "[a-z]+"
	regex["shard"] = "[0-9]+"
	rule, err := Compile(RawRule{
		Pattern:          "feed.%name%-shard-%shard%",
		MetricKeyPattern: "test-feed-metric",
		Regex:            regex,
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("feed.feedname-shard-12")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-feed-metric")
	a.EqString(matcher.TagSet["name"], "feedname")
	a.EqString(matcher.TagSet["shard"], "12")
}

func TestLoadYAML(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules:
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	a.CheckError(err)
	a.EqInt(len(ruleSet.Rules), 1)
	a.EqString(string(ruleSet.Rules[0].raw.MetricKeyPattern), "abc")
	a.Eq(ruleSet.Rules[0].graphitePatternTags, []string{"tag"})
}

func TestLoadYAML_Invalid(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	checkRuleErrorCode(a, err, InvalidYaml)
	a.EqInt(len(ruleSet.Rules), 0)
}

func TestToGraphiteName(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	tm := api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	}
	reversed, err := rule.ToGraphiteName(tm)
	a.CheckError(err)
	a.EqString(string(reversed), "prefix.fooValue")
}

func TestToGraphiteName_Error(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	reversed, err := rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet(""),
	})
	checkConversionErrorCode(t, err, MissingTag)
	a.EqString(string(reversed), "")

	reversed, err = rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric-foo",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	})
	checkConversionErrorCode(t, err, CannotInterpolate)
	a.EqString(string(reversed), "")
}

func Test_interpolateTags(t *testing.T) {

	for _, testCase := range []struct {
		pattern  string
		tagSet   api.TagSet
		enforce  bool
		result   string
		succeeds bool
	}{
		// note that the result <fail> indicates that the test case should fail to parse
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box", "D": "other"}, false, "cat.dog.foo.bar.box", true},
		{"%A%.%B%.foo.bar.%C%", map[string]string{"A": "cat", "B": "dog", "C": "box", "D": "other"}, true, "", false},
		{"no.variable.test", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "no.variable.test", true},
		{"no.variable.test", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "", false},
		{"test.for.%extra%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, false, "", false},
		{"test.for.%extra%", map[string]string{"A": "cat", "B": "dog", "C": "box"}, true, "", false},
	} {
		pattern := testCase.pattern
		tagSet := testCase.tagSet
		result := testCase.result
		enforce := testCase.enforce
		succeeds := testCase.succeeds
		testResult, err := interpolateTags(pattern, tagSet, enforce)
		if succeeds {
			if err != nil {
				t.Errorf("pattern %s fails for tagset %+v", pattern, tagSet)
				continue
			}
			if testResult != result {
				t.Errorf("pattern %s for tagset %+v produces incorrect pattern %s instead of %s (enforce=%v)", pattern, tagSet, testResult, result, enforce)
				continue
			}
			// otherwise, everything is okay since no error occurred and the results match
		} else {
			if err == nil {
				t.Errorf("pattern %s succeeds for tagset %+v producing output %s when it should not succeed (enforce=%v)", pattern, tagSet, testResult, enforce)
				continue
			}
			// otherwise, everything is okay since the match failed
		}
	}

}
<|endoftext|>


<commit_before>package util

import (
	"testing"

	"github.com/jinzhu/gorm"
)

func TestToDBNameGenerateFriendlyName(t *testing.T) {
	var maps = map[string]string{
		"":                          "",
		"ThisIsATest":               "this_is_a_test",
		"PFAndESI":                  "pf_and_esi",
		"AbcAndJkl":                 "abc_and_jkl",
		"EmployeeID":                "employee_id",
		"SKU_ID":                    "sku_id",
		"HTTPAndSMTP":               "http_and_smtp",
		"HTTPServerHandlerForURLID": "http_server_handler_for_url_id",
		"UUID":     "uuid",
		"HTTPURL":  "http_url",
		"HTTP_URL": "http_url",
		"ThisIsActuallyATestSoWeMayBeAbleToUseThisCodeInGormPackageAlsoIdCanBeUsedAtTheEndAsID": "this_is_actually_a_test_so_we_may_be_able_to_use_this_code_in_gorm_package_also_id_can_be_used_at_the_end_as_id",
	}

	for key, value := range maps {
		if gorm.ToDBName(key) != value {
			t.Errorf("%v ToDBName should equal %v, but got %v", key, value, gorm.ToDBName(key))
		}
	}
}
<commit_msg>[util] Fix  wrong import<commit_after>package util

import (
	"testing"
)

func TestToDBNameGenerateFriendlyName(t *testing.T) {
	var maps = map[string]string{
		"":                          "",
		"ThisIsATest":               "this_is_a_test",
		"PFAndESI":                  "pf_and_esi",
		"AbcAndJkl":                 "abc_and_jkl",
		"EmployeeID":                "employee_id",
		"SKU_ID":                    "sku_id",
		"HTTPAndSMTP":               "http_and_smtp",
		"HTTPServerHandlerForURLID": "http_server_handler_for_url_id",
		"UUID":     "uuid",
		"HTTPURL":  "http_url",
		"HTTP_URL": "http_url",
		"ThisIsActuallyATestSoWeMayBeAbleToUseThisCodeInGormPackageAlsoIdCanBeUsedAtTheEndAsID": "this_is_actually_a_test_so_we_may_be_able_to_use_this_code_in_gorm_package_also_id_can_be_used_at_the_end_as_id",
	}

	for key, value := range maps {
		if ToDBName(key) != value {
			t.Errorf("%v ToDBName should equal %v, but got %v", key, value, ToDBName(key))
		}
	}
}
<|endoftext|>


<commit_before>package utility

import (
    "fmt"
    "log"
    "os"
    "os/user"
    "gopkg.in/ini.v1"
)

type Util struct {
    ConfigPath string
    Apps map[string]*[]string
}

func NewUtil() *Util {
    usr, err := user.Current()
    if err != nil {
        log.Fatalln(err)
    }
    util := &Util {
        ConfigPath: fmt.Sprintf(
            "%s%s.twhelp.ini",
            string(usr.HomeDir),
            string(os.PathSeparator),
        ),
        Apps: make(map[string]*[]string, 8),
    }
    util.Apps["android"] = &[]string {
        "3nVuSoBZnx6U4vzUxf5w",
        "Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys",
    }
    util.Apps["win"] = &[]string {
        "TgHNMa7WZE7Cxi1JbkAMQ",
        "SHy9mBMBPNj3Y17et9BF4g5XeqS4y3vkeW24PttDcY",
    }
    util.Apps["wp"] = &[]string {
        "yN3DUNVO0Me63IAQdhTfCA",
        "c768oTKdzAjIYCmpSNIdZbGaG0t6rOhSFQP0S5uC79g",
    }
    util.Apps["google"] = &[]string {
        "iAtYJ4HpUVfIUoNnif1DA",
        "172fOpzuZoYzNYaU3mMYvE8m8MEyLbztOdbrUolU",
    }
    util.Apps["iphone"] = &[]string {
        "IQKbtAYlXLripLGPWd0HUA",
        "GgDYlkSvaPxGxC4X8liwpUoqKwwr3lCADbz8A7ADU",
    }
    util.Apps["ipad"] = &[]string {
        "CjulERsDeqhhjSme66ECg",
        "IQWdVyqFxghAtURHGeGiWAsmCAGmdW3WmbEx6Hck",
    }
    util.Apps["mac"] = &[]string {
        "3rJOl1ODzm9yZy63FACdg",
        "5jPoQ5kQvMJFDYRNE8bQ4rHuds4xJqhvgNJM4awaE8",
    }
    util.Apps["deck"] = &[]string {
        "yT577ApRtZw51q4NPMPPOQ",
        "3neq3XqN5fO3obqwZoajavGFCUrC42ZfbrLXy5sCv8",
    }
    if _, err := os.Stat(util.ConfigPath); err == nil {
        cfg, err := ini.Load(util.ConfigPath)
        if err != nil {
            log.Fatalln(err)
        }
        for _, name := range cfg.SectionStrings() {
            if name == "DEFAULT" {
                continue
            }
            section := cfg.Section(name)
            ck, ckerr := section.GetKey("ck")
            if ckerr != nil {
                log.Fatalln(fmt.Sprintf(`"ck" for %s does not exist`, name))
            }
            cs, cserr := section.GetKey("cs")
            if cserr != nil {
                log.Fatalln(fmt.Sprintf(`"cs" for %s does not exist`, name))
            }
            util.Apps[name] = &[]string{ck.String(), cs.String()}
        }
    }
    return util
}

func (util *Util) Usage() {
os.Stderr.WriteString(fmt.Sprintf(`Usage: %s [options]
Options:
  -h, --help          Show help.

[ Output Format ]

  Default             Output line by line.
  -t, --twist         Output as TwistOAuth-style constrctive code.
  -v, --var           Output as variable line by line.

[ OAuth Process ]

  Default             DirectOAuth. (xAuth manipulation with OAuth)
  -x, --xauth         Pure xAuth. Only available with official keys.
  -o, --oauth         Pure OAuth. You have to authorize via web browser.

[ OAuth Credentials ]

  Insufficient components are required to input via STDIN.
  Password is masked.

  --ck  <value>       Specify consumer_key in advance.
  --cs  <value>       Specify consumer_secret in advance.
  --sn  <value>       Specify screen_name or email in advance.
  --pw  <value>       Specify password in advance. (DEPRECATED)
  --app <value>       Speficy consumer_key and consumer_secret with app name.

                      app name | full name
                      ------------------------------------
                      android  | Twitter for Andriod
                      win      | Twitter for Andriod
                      wp       | Twitter for Windows Phone
                      google   | Twitter for Google TV
                      iphone   | Twitter for iPhone
                      ipad     | Twitter for iPad
                      mac      | Twitter for Mac
                      deck     | TweetDeck

Your own applications also can be defined in %s
Refer to the documentation.
`, os.Args[0], util.ConfigPath))
}
<commit_msg>Solved usr.Current() issue<commit_after>package utility

import (
    "fmt"
    "log"
    "os"
    "github.com/mitchellh/go-homedir"
    "gopkg.in/ini.v1"
)

type Util struct {
    ConfigPath string
    Apps map[string]*[]string
}

func NewUtil() *Util {
    home, err := homedir.Dir()
    if err != nil {
        log.Fatalln(err)
    }
    util := &Util {
        ConfigPath: fmt.Sprintf(
            "%s%s.twhelp.ini",
            home,
            string(os.PathSeparator),
        ),
        Apps: make(map[string]*[]string, 8),
    }
    util.Apps["android"] = &[]string {
        "3nVuSoBZnx6U4vzUxf5w",
        "Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys",
    }
    util.Apps["win"] = &[]string {
        "TgHNMa7WZE7Cxi1JbkAMQ",
        "SHy9mBMBPNj3Y17et9BF4g5XeqS4y3vkeW24PttDcY",
    }
    util.Apps["wp"] = &[]string {
        "yN3DUNVO0Me63IAQdhTfCA",
        "c768oTKdzAjIYCmpSNIdZbGaG0t6rOhSFQP0S5uC79g",
    }
    util.Apps["google"] = &[]string {
        "iAtYJ4HpUVfIUoNnif1DA",
        "172fOpzuZoYzNYaU3mMYvE8m8MEyLbztOdbrUolU",
    }
    util.Apps["iphone"] = &[]string {
        "IQKbtAYlXLripLGPWd0HUA",
        "GgDYlkSvaPxGxC4X8liwpUoqKwwr3lCADbz8A7ADU",
    }
    util.Apps["ipad"] = &[]string {
        "CjulERsDeqhhjSme66ECg",
        "IQWdVyqFxghAtURHGeGiWAsmCAGmdW3WmbEx6Hck",
    }
    util.Apps["mac"] = &[]string {
        "3rJOl1ODzm9yZy63FACdg",
        "5jPoQ5kQvMJFDYRNE8bQ4rHuds4xJqhvgNJM4awaE8",
    }
    util.Apps["deck"] = &[]string {
        "yT577ApRtZw51q4NPMPPOQ",
        "3neq3XqN5fO3obqwZoajavGFCUrC42ZfbrLXy5sCv8",
    }
    if _, err := os.Stat(util.ConfigPath); err == nil {
        cfg, err := ini.Load(util.ConfigPath)
        if err != nil {
            log.Fatalln(err)
        }
        for _, name := range cfg.SectionStrings() {
            if name == "DEFAULT" {
                continue
            }
            section := cfg.Section(name)
            ck, ckerr := section.GetKey("ck")
            if ckerr != nil {
                log.Fatalln(fmt.Sprintf(`"ck" for %s does not exist`, name))
            }
            cs, cserr := section.GetKey("cs")
            if cserr != nil {
                log.Fatalln(fmt.Sprintf(`"cs" for %s does not exist`, name))
            }
            util.Apps[name] = &[]string{ck.String(), cs.String()}
        }
    }
    return util
}

func (util *Util) Usage() {
os.Stderr.WriteString(fmt.Sprintf(`Usage: %s [options]
Options:
  -h, --help          Show help.

[ Output Format ]

  Default             Output line by line.
  -t, --twist         Output as TwistOAuth-style constrctive code.
  -v, --var           Output as variable line by line.

[ OAuth Process ]

  Default             DirectOAuth. (xAuth manipulation with OAuth)
  -x, --xauth         Pure xAuth. Only available with official keys.
  -o, --oauth         Pure OAuth. You have to authorize via web browser.

[ OAuth Credentials ]

  Insufficient components are required to input via STDIN.
  Password is masked.

  --ck  <value>       Specify consumer_key in advance.
  --cs  <value>       Specify consumer_secret in advance.
  --sn  <value>       Specify screen_name or email in advance.
  --pw  <value>       Specify password in advance. (DEPRECATED)
  --app <value>       Speficy consumer_key and consumer_secret with app name.

                      app name | full name
                      ------------------------------------
                      android  | Twitter for Andriod
                      win      | Twitter for Andriod
                      wp       | Twitter for Windows Phone
                      google   | Twitter for Google TV
                      iphone   | Twitter for iPhone
                      ipad     | Twitter for iPad
                      mac      | Twitter for Mac
                      deck     | TweetDeck

Your own applications also can be defined in %s
Refer to the documentation.
`, os.Args[0], util.ConfigPath))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"http"
	"time"
)

type logRecord struct {
	timeEpochNs         int64
	ip, method, rawpath string
	responseBytes       int64
	responseStatus      int
	userAgent, referer  string

	rw http.ResponseWriter
}

type logHandler struct {
	ch      chan *logRecord
	dir     string
	handler http.Handler
}

func NewLoggingHandler(handler http.Handler, dir string) http.Handler {
	h := &logHandler{
		ch:      make(chan *logRecord),
		dir:     dir,
		handler: handler,
	}
	go h.logFromChannel()
	return h
}

func (h *logHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	lr := &logRecord{
		timeEpochNs:    time.Nanoseconds(),
		ip:             rw.RemoteAddr(),
		method:         r.Method,
		rawpath:        r.URL.RawPath,
		userAgent:      r.UserAgent,
		referer:        r.Referer,
		responseStatus: http.StatusOK,
		rw:             rw,
	}
	h.handler.ServeHTTP(lr, r)
	h.ch <- lr
}

func (h *logHandler) logFromChannel() {
	for {
		lr := <-h.ch
		lr.rw = nil
		logLine := fmt.Sprintf("Request: %#v\n", lr)
		if h.dir == "-" {
			os.Stdout.WriteString(logLine)
		}
	}
}

func (lr *logRecord) Write(p []byte) (int, os.Error) {
	written, err := lr.rw.Write(p)
	lr.responseBytes += int64(written)
	return written, err
}

func (lr *logRecord) WriteHeader(status int) {
	lr.responseStatus = status
	lr.rw.WriteHeader(status)
}

// Boring proxies:  (seems like I should be able to use embedding somehow...)

func (lr *logRecord) RemoteAddr() string {
	return lr.rw.RemoteAddr()
}

func (lr *logRecord) UsingTLS() bool {
	return lr.rw.UsingTLS()
}

func (lr *logRecord) SetHeader(k, v string) {
	lr.rw.SetHeader(k, v)
}

func (lr *logRecord) Flush() {
	lr.rw.Flush()
}

func (lr *logRecord) Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error) {
	return lr.rw.Hijack()
}
<commit_msg>camweb: use Apache's Combined Log Format<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"http"
	"strings"
	"time"
)

type logRecord struct {
	time                *time.Time
	ip, method, rawpath string
	responseBytes       int64
	responseStatus      int
	userAgent, referer  string
	proto               string // "HTTP/1.1"

	rw http.ResponseWriter
}

type logHandler struct {
	ch      chan *logRecord
	dir     string
	handler http.Handler
}

func NewLoggingHandler(handler http.Handler, dir string) http.Handler {
	h := &logHandler{
		ch:      make(chan *logRecord, 1000),
		dir:     dir,
		handler: handler,
	}
	go h.logFromChannel()
	return h
}

func (h *logHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	// Strip port number from address
	addr := rw.RemoteAddr()
	if colon := strings.LastIndex(addr, ":"); colon != -1 {
		addr = addr[:colon]
	}

	lr := &logRecord{
		time:           time.UTC(),
		ip:             addr,
		method:         r.Method,
		rawpath:        r.URL.RawPath,
		userAgent:      r.UserAgent,
		referer:        r.Referer,
		responseStatus: http.StatusOK,
		proto:          r.Proto,
		rw:             rw,
	}
	h.handler.ServeHTTP(lr, r)
	h.ch <- lr
}

var monthAbbr = [12]string{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}

func (h *logHandler) logFromChannel() {
	for {
		lr := <-h.ch
		lr.rw = nil

		// [10/Oct/2000:13:55:36 -0700]
		dateString := fmt.Sprintf("%02d/%s/%04d:%02d:%02d:%02d -0000",
			lr.time.Day,
			monthAbbr[lr.time.Month-1],
			lr.time.Year,
			lr.time.Hour, lr.time.Minute, lr.time.Second)

		// Combined Log Format
		// http://httpd.apache.org/docs/1.3/logs.html#combined
		logLine := fmt.Sprintf("%s - - [%s] %q %d %d %q %q\n",
			lr.ip,
			dateString,
			lr.method+" "+lr.rawpath+" "+lr.proto,
			lr.responseStatus,
			lr.responseBytes,
			lr.referer,
			lr.userAgent,
		)
		if h.dir == "-" {
			os.Stdout.WriteString(logLine)
		}
	}
}

func (lr *logRecord) Write(p []byte) (int, os.Error) {
	written, err := lr.rw.Write(p)
	lr.responseBytes += int64(written)
	return written, err
}

func (lr *logRecord) WriteHeader(status int) {
	lr.responseStatus = status
	lr.rw.WriteHeader(status)
}

// Boring proxies:  (seems like I should be able to use embedding somehow...)

func (lr *logRecord) RemoteAddr() string {
	return lr.rw.RemoteAddr()
}

func (lr *logRecord) UsingTLS() bool {
	return lr.rw.UsingTLS()
}

func (lr *logRecord) SetHeader(k, v string) {
	lr.rw.SetHeader(k, v)
}

func (lr *logRecord) Flush() {
	lr.rw.Flush()
}

func (lr *logRecord) Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error) {
	return lr.rw.Hijack()
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 the go.wde authors

   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 win

import (
	"errors"
	"github.com/AllenDang/w32"
	"image"
	"image/draw"
	"runtime"
	"unsafe"
	"github.com/skelterjohn/go.wde"
)

func init() {
	wde.NewWindow = func(width, height int) (w wde.Window, err error) {
		w, err = NewWindow(width, height)
		return
	}
	ch := make(chan struct{}, 1)
	wde.Run = func() {
		<-ch
	}
	wde.Stop = func() {
		ch <- struct{}{}
	}
}

const (
	WIN_CLASSNAME   = "wde_win"
	TITLEBAR_HEIGHT = 22
)

type Window struct {
	EventData

	hwnd   w32.HWND
	buffer *DIB
	events chan interface{}
}

/*
go func(ready chan struct{}) {
		w, err = win.NewWindow(width, height)
		ready <- struct{}{}
		if winw, ok := w.(*win.Window); ok {
			winw.HandleWndMessages()
		} else {
			panic("windows wgen returned non windows window")
		}
	}(ready)
	<-ready
*/

func makeTheWindow(width, height int) (w *Window, err error) {

	err = RegClassOnlyOnce(WIN_CLASSNAME)
	if err != nil {
		return
	}

	hwnd, err := CreateWindow(WIN_CLASSNAME, nil, w32.WS_EX_CLIENTEDGE, w32.WS_OVERLAPPEDWINDOW, width, height)
	if err != nil {
		return
	}

	w = &Window{
		hwnd:   hwnd,
		buffer: NewDIB(image.Rect(0, 0, width, height+TITLEBAR_HEIGHT)),
		events: make(chan interface{}, 16),
	}
	w.InitEventData()

	RegMsgHandler(w)

	w.Center()

	return
}

func NewWindow(width, height int) (w *Window, err error) {
	ready := make(chan error, 1)

	go func(ready chan error) {
		runtime.LockOSThread()
		var err error
		w, err = makeTheWindow(width, height)
		ready <- err
		w.HandleWndMessages()
	}(ready)

	err = <-ready
	return
}

func (this *Window) SetTitle(title string) {
	w32.SetWindowText(this.hwnd, title)
}

func (this *Window) SetSize(width, height int) {
	x, y := this.Pos()
	w32.MoveWindow(this.hwnd, x, y, width, height+TITLEBAR_HEIGHT, true)
}

func (this *Window) Size() (width, height int) {
	bounds := this.buffer.Bounds()
	return bounds.Dx(), bounds.Dy()
}

func (this *Window) Show() {
	w32.ShowWindow(this.hwnd, w32.SW_SHOWDEFAULT)
}

func (this *Window) Screen() draw.Image {
	return this.buffer
}

func (this *Window) FlushImage() {
	w32.InvalidateRect(this.hwnd, nil, true)
	w32.UpdateWindow(this.hwnd)
}

func (this *Window) EventChan() <-chan interface{} {
	return this.events
}

func (this *Window) Close() error {
	err := w32.SendMessage(this.hwnd, w32.WM_CLOSE, 0, 0)
	if err != 0 {
		return errors.New("Error closing window")
	}
	return nil
}

/////////////////////////////
// Non - interface methods
/////////////////////////////

func (this *Window) blitImage(hdc w32.HDC) {
	bounds := this.buffer.Bounds()
	width := bounds.Dx()
	height := bounds.Dy()

	var bi w32.BITMAPINFO
	bi.BmiHeader.BiSize = uint(unsafe.Sizeof(bi.BmiHeader))
	bi.BmiHeader.BiWidth = width
	bi.BmiHeader.BiHeight = height
	bi.BmiHeader.BiPlanes = 1
	bi.BmiHeader.BiBitCount = 24
	bi.BmiHeader.BiCompression = w32.BI_RGB

	w32.SetDIBitsToDevice(hdc,
		0, 0,
		width, height,
		0, 0,
		0, uint(height),
		this.buffer.Pix, &bi,
		w32.DIB_RGB_COLORS,
	)
}

func (this *Window) HandleWndMessages() {
	var m w32.MSG

	for w32.GetMessage(&m, this.hwnd, 0, 0) != 0 {
		w32.TranslateMessage(&m)
		w32.DispatchMessage(&m)
	}
}

func (this *Window) Pos() (x, y int) {
	rect := w32.GetWindowRect(this.hwnd)
	return int(rect.Left), int(rect.Top)
}

func (this *Window) SetPos(x, y int) {
	w, h := this.Size()
	if w == 0 {
		w = 100
	}
	if h == 0 {
		h = 25
	}
	w32.MoveWindow(this.hwnd, x, y, w, h, true)
}

func (this *Window) Center() {
	sWidth := w32.GetSystemMetrics(w32.SM_CXFULLSCREEN)
	sHeight := w32.GetSystemMetrics(w32.SM_CYFULLSCREEN)

	if sWidth != 0 && sHeight != 0 {
		w, h := this.Size()
		this.SetPos((sWidth/2)-(w/2), (sHeight/2)-(h/2))
	}
}
<commit_msg>no idea what i'm doing<commit_after>/*
   Copyright 2012 the go.wde authors

   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 win

import (
	"errors"
	"github.com/AllenDang/w32"
	"image"
	"image/draw"
	"runtime"
	"unsafe"
	"github.com/skelterjohn/go.wde"
)

func init() {
	wde.NewWindow = func(width, height int) (w wde.Window, err error) {
		w, err = NewWindow(width, height)
		return
	}
	ch := make(chan struct{}, 1)
	wde.Run = func() {
		<-ch
	}
	wde.Stop = func() {
		ch <- struct{}{}
	}
}

const (
	WIN_CLASSNAME   = "wde_win"
	TITLEBAR_HEIGHT = 22
)

type Window struct {
	EventData

	hwnd   w32.HWND
	buffer *DIB
	events chan interface{}
}

/*
go func(ready chan struct{}) {
		w, err = win.NewWindow(width, height)
		ready <- struct{}{}
		if winw, ok := w.(*win.Window); ok {
			winw.HandleWndMessages()
		} else {
			panic("windows wgen returned non windows window")
		}
	}(ready)
	<-ready
*/

func makeTheWindow(width, height int) (w *Window, err error) {

	err = RegClassOnlyOnce(WIN_CLASSNAME)
	if err != nil {
		return
	}

	hwnd, err := CreateWindow(WIN_CLASSNAME, nil, w32.WS_EX_CLIENTEDGE, w32.WS_OVERLAPPEDWINDOW, width, height)
	if err != nil {
		return
	}

	w = &Window{
		hwnd:   hwnd,
		buffer: NewDIB(image.Rect(0, 0, width, height+TITLEBAR_HEIGHT)),
		events: make(chan interface{}, 16),
	}
	w.InitEventData()

	RegMsgHandler(w)

	w.Center()

	return
}

func NewWindow(width, height int) (w *Window, err error) {
	ready := make(chan error, 1)

	go func(ready chan error) {
		runtime.LockOSThread()
		var err error
		w, err = makeTheWindow(width, height)
		ready <- err
		w.HandleWndMessages()
	}(ready)

	err = <-ready
	return
}

func (this *Window) SetTitle(title string) {
	w32.SetWindowText(this.hwnd, title)
}

func (this *Window) SetSize(width, height int) {
	x, y := this.Pos()
	w32.MoveWindow(this.hwnd, x, y, width, height+TITLEBAR_HEIGHT, true)
}

func (this *Window) Size() (width, height int) {
	bounds := this.buffer.Bounds()
	return bounds.Dx(), bounds.Dy()
}

func (this *Window) Show() {
	w32.ShowWindow(this.hwnd, w32.SW_SHOWDEFAULT)
}

func (this *Window) Screen() draw.Image {
	return this.buffer
}

func (this *Window) FlushImage() {
	w32.InvalidateRect(this.hwnd, nil, false)
	w32.UpdateWindow(this.hwnd)
}

func (this *Window) EventChan() <-chan interface{} {
	return this.events
}

func (this *Window) Close() error {
	err := w32.SendMessage(this.hwnd, w32.WM_CLOSE, 0, 0)
	if err != 0 {
		return errors.New("Error closing window")
	}
	return nil
}

/////////////////////////////
// Non - interface methods
/////////////////////////////

func (this *Window) blitImage(hdc w32.HDC) {
	bounds := this.buffer.Bounds()
	width := bounds.Dx()
	height := bounds.Dy()

	var bi w32.BITMAPINFO
	bi.BmiHeader.BiSize = uint(unsafe.Sizeof(bi.BmiHeader))
	bi.BmiHeader.BiWidth = width
	bi.BmiHeader.BiHeight = height
	bi.BmiHeader.BiPlanes = 1
	bi.BmiHeader.BiBitCount = 24
	bi.BmiHeader.BiCompression = w32.BI_RGB

	w32.SetDIBitsToDevice(hdc,
		0, 0,
		width, height,
		0, 0,
		0, uint(height),
		this.buffer.Pix, &bi,
		w32.DIB_RGB_COLORS,
	)
}

func (this *Window) HandleWndMessages() {
	var m w32.MSG

	for w32.GetMessage(&m, this.hwnd, 0, 0) != 0 {
		w32.TranslateMessage(&m)
		w32.DispatchMessage(&m)
	}
}

func (this *Window) Pos() (x, y int) {
	rect := w32.GetWindowRect(this.hwnd)
	return int(rect.Left), int(rect.Top)
}

func (this *Window) SetPos(x, y int) {
	w, h := this.Size()
	if w == 0 {
		w = 100
	}
	if h == 0 {
		h = 25
	}
	w32.MoveWindow(this.hwnd, x, y, w, h, true)
}

func (this *Window) Center() {
	sWidth := w32.GetSystemMetrics(w32.SM_CXFULLSCREEN)
	sHeight := w32.GetSystemMetrics(w32.SM_CYFULLSCREEN)

	if sWidth != 0 && sHeight != 0 {
		w, h := this.Size()
		this.SetPos((sWidth/2)-(w/2), (sHeight/2)-(h/2))
	}
}
<|endoftext|>


<commit_before>package archiver

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"sync/atomic"

	"github.com/itchio/arkive/zip"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/counter"
	"github.com/itchio/wharf/state"
)

func ExtractZip(readerAt io.ReaderAt, size int64, dir string, settings ExtractSettings) (*ExtractResult, error) {
	dirCount := 0
	regCount := 0
	symlinkCount := 0

	reader, err := zip.NewReader(readerAt, size)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	var totalSize int64
	for _, file := range reader.File {
		totalSize += int64(file.UncompressedSize64)
	}

	var doneSize uint64
	var lastDoneIndex int = -1

	func() {
		if settings.ResumeFrom == "" {
			return
		}

		resBytes, resErr := ioutil.ReadFile(settings.ResumeFrom)
		if resErr != nil {
			if !errors.Is(resErr, os.ErrNotExist) {
				settings.Consumer.Warnf("Couldn't read resume file: %s", resErr.Error())
			}
			return
		}

		lastDone64, resErr := strconv.ParseInt(string(resBytes), 10, 64)
		if resErr != nil {
			settings.Consumer.Warnf("Couldn't parse resume file: %s", resErr.Error())
			return
		}

		lastDoneIndex = int(lastDone64)
		settings.Consumer.Infof("Resuming from file %d", lastDoneIndex)
	}()

	warnedAboutWrite := false

	writeProgress := func(fileIndex int) {
		if settings.ResumeFrom == "" {
			return
		}

		payload := fmt.Sprintf("%d", fileIndex)

		wErr := ioutil.WriteFile(settings.ResumeFrom, []byte(payload), 0644)
		if wErr != nil {
			if !warnedAboutWrite {
				warnedAboutWrite = true
				settings.Consumer.Warnf("Couldn't save resume file: %s", wErr.Error())
			}
			return
		}
	}

	defer func() {
		if settings.ResumeFrom == "" {
			return
		}

		rErr := os.Remove(settings.ResumeFrom)
		if rErr != nil {
			settings.Consumer.Warnf("Couldn't remove resume file: %s", rErr.Error())
		}
	}()

	if settings.OnUncompressedSizeKnown != nil {
		settings.OnUncompressedSizeKnown(totalSize)
	}

	windows := runtime.GOOS == "windows"

	numWorkers := settings.Concurrency
	if numWorkers < 0 {
		numWorkers = runtime.NumCPU() - 1
	}
	if numWorkers < 1 {
		numWorkers = 1
	}
	settings.Consumer.Infof("Using %d workers", numWorkers)

	fileIndices := make(chan int)
	errs := make(chan error, numWorkers)

	updateProgress := func() {
		ds := atomic.LoadUint64(&doneSize)
		settings.Consumer.Progress(float64(ds) / float64(totalSize))
	}

	done := func(file *zip.File) {
		if file.FileInfo().IsDir() {
			return
		}

		if settings.OnEntryDone != nil {
			settings.OnEntryDone(filepath.ToSlash(file.Name))
		}
	}

	for i := 0; i < numWorkers; i++ {
		go func() {
			reader, err := zip.NewReader(readerAt, size)
			if err != nil {
				errs <- errors.Wrap(err, 1)
				return
			}

			for fileIndex := range fileIndices {
				file := reader.File[fileIndex]

				if fileIndex <= lastDoneIndex {
					settings.Consumer.Debugf("Skipping file %d")
					done(file)
					atomic.AddUint64(&doneSize, file.UncompressedSize64)
					updateProgress()
					continue
				}

				err = func() error {
					rel := file.Name
					filename := path.Join(dir, filepath.FromSlash(rel))

					info := file.FileInfo()
					mode := info.Mode()

					if info.IsDir() {
						if settings.DryRun {
							// muffin
						} else {
							err = Mkdir(filename)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						}
						dirCount++
					} else if mode&os.ModeSymlink > 0 && !windows {
						fileReader, fErr := file.Open()
						if fErr != nil {
							return errors.Wrap(fErr, 1)
						}
						defer fileReader.Close()

						linkname, lErr := ioutil.ReadAll(fileReader)
						if settings.DryRun {
							// muffin
						} else {
							lErr = Symlink(string(linkname), filename, settings.Consumer)
							if lErr != nil {
								return errors.Wrap(lErr, 1)
							}
						}
						symlinkCount++
					} else {
						regCount++

						fileReader, fErr := file.Open()
						if fErr != nil {
							return errors.Wrap(fErr, 1)
						}
						defer fileReader.Close()

						settings.Consumer.Debugf("extract %s", filename)
						var lastOffset int64
						countingReader := counter.NewReaderCallback(func(offset int64) {
							doneRecently := offset - lastOffset
							lastOffset = offset
							atomic.AddUint64(&doneSize, uint64(doneRecently))
							updateProgress()
						}, fileReader)

						if settings.DryRun {
							_, err = io.Copy(ioutil.Discard, countingReader)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						} else {
							err = CopyFile(filename, os.FileMode(mode&LuckyMode|ModeMask), countingReader)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						}
					}

					return nil
				}()
				if err != nil {
					errs <- errors.Wrap(err, 1)
					return
				}
				writeProgress(fileIndex)
				done(file)
			}

			errs <- nil
		}()
	}

	for fileIndex := range reader.File {
		select {
		case fileIndices <- fileIndex:
			// sent work, yay!
		case err := <-errs:
			// abort everything
			close(fileIndices)
			return nil, err
		}
	}

	close(fileIndices)
	for i := 0; i < numWorkers; i++ {
		err := <-errs
		if err != nil {
			return nil, err
		}
	}

	return &ExtractResult{
		Dirs:     dirCount,
		Files:    regCount,
		Symlinks: symlinkCount,
	}, nil
}

func CompressZip(archiveWriter io.Writer, dir string, consumer *state.Consumer) (*CompressResult, error) {
	var err error
	var uncompressedSize int64
	var compressedSize int64

	archiveCounter := counter.NewWriter(archiveWriter)

	zipWriter := zip.NewWriter(archiveCounter)
	defer zipWriter.Close()
	defer func() {
		if zipWriter != nil {
			if zErr := zipWriter.Close(); err == nil && zErr != nil {
				err = errors.Wrap(zErr, 1)
			}
		}
	}()

	err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		name, wErr := filepath.Rel(dir, path)
		if wErr != nil {
			return wErr
		}

		if name == "." {
			// don't add '.' to zip
			return nil
		}

		name = filepath.ToSlash(name)

		fh, wErr := zip.FileInfoHeader(info)
		if wErr != nil {
			return wErr
		}

		fh.Name = name

		writer, wErr := zipWriter.CreateHeader(fh)
		if wErr != nil {
			return wErr
		}

		if info.IsDir() {
			// good!
		} else if info.Mode()&os.ModeSymlink > 0 {
			dest, wErr := os.Readlink(path)
			if wErr != nil {
				return wErr
			}

			_, wErr = writer.Write([]byte(dest))
			if wErr != nil {
				return wErr
			}
		} else if info.Mode().IsRegular() {
			reader, wErr := os.Open(path)
			if wErr != nil {
				return wErr
			}
			defer reader.Close()

			copiedBytes, wErr := io.Copy(writer, reader)
			if wErr != nil {
				return wErr
			}

			uncompressedSize += copiedBytes
		}

		return nil
	})

	err = zipWriter.Close()
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}
	zipWriter = nil

	compressedSize = archiveCounter.Count()

	return &CompressResult{
		UncompressedSize: uncompressedSize,
		CompressedSize:   compressedSize,
	}, err
}
<commit_msg>archiver/zip: fix output when skipping file<commit_after>package archiver

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"sync/atomic"

	"github.com/itchio/arkive/zip"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/counter"
	"github.com/itchio/wharf/state"
)

func ExtractZip(readerAt io.ReaderAt, size int64, dir string, settings ExtractSettings) (*ExtractResult, error) {
	dirCount := 0
	regCount := 0
	symlinkCount := 0

	reader, err := zip.NewReader(readerAt, size)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	var totalSize int64
	for _, file := range reader.File {
		totalSize += int64(file.UncompressedSize64)
	}

	var doneSize uint64
	var lastDoneIndex int = -1

	func() {
		if settings.ResumeFrom == "" {
			return
		}

		resBytes, resErr := ioutil.ReadFile(settings.ResumeFrom)
		if resErr != nil {
			if !errors.Is(resErr, os.ErrNotExist) {
				settings.Consumer.Warnf("Couldn't read resume file: %s", resErr.Error())
			}
			return
		}

		lastDone64, resErr := strconv.ParseInt(string(resBytes), 10, 64)
		if resErr != nil {
			settings.Consumer.Warnf("Couldn't parse resume file: %s", resErr.Error())
			return
		}

		lastDoneIndex = int(lastDone64)
		settings.Consumer.Infof("Resuming from file %d", lastDoneIndex)
	}()

	warnedAboutWrite := false

	writeProgress := func(fileIndex int) {
		if settings.ResumeFrom == "" {
			return
		}

		payload := fmt.Sprintf("%d", fileIndex)

		wErr := ioutil.WriteFile(settings.ResumeFrom, []byte(payload), 0644)
		if wErr != nil {
			if !warnedAboutWrite {
				warnedAboutWrite = true
				settings.Consumer.Warnf("Couldn't save resume file: %s", wErr.Error())
			}
			return
		}
	}

	defer func() {
		if settings.ResumeFrom == "" {
			return
		}

		rErr := os.Remove(settings.ResumeFrom)
		if rErr != nil {
			settings.Consumer.Warnf("Couldn't remove resume file: %s", rErr.Error())
		}
	}()

	if settings.OnUncompressedSizeKnown != nil {
		settings.OnUncompressedSizeKnown(totalSize)
	}

	windows := runtime.GOOS == "windows"

	numWorkers := settings.Concurrency
	if numWorkers < 0 {
		numWorkers = runtime.NumCPU() - 1
	}
	if numWorkers < 1 {
		numWorkers = 1
	}
	settings.Consumer.Infof("Using %d workers", numWorkers)

	fileIndices := make(chan int)
	errs := make(chan error, numWorkers)

	updateProgress := func() {
		ds := atomic.LoadUint64(&doneSize)
		settings.Consumer.Progress(float64(ds) / float64(totalSize))
	}

	done := func(file *zip.File) {
		if file.FileInfo().IsDir() {
			return
		}

		if settings.OnEntryDone != nil {
			settings.OnEntryDone(filepath.ToSlash(file.Name))
		}
	}

	for i := 0; i < numWorkers; i++ {
		go func() {
			reader, err := zip.NewReader(readerAt, size)
			if err != nil {
				errs <- errors.Wrap(err, 1)
				return
			}

			for fileIndex := range fileIndices {
				file := reader.File[fileIndex]

				if fileIndex <= lastDoneIndex {
					settings.Consumer.Debugf("Skipping file %d", fileIndex)
					done(file)
					atomic.AddUint64(&doneSize, file.UncompressedSize64)
					updateProgress()
					continue
				}

				err = func() error {
					rel := file.Name
					filename := path.Join(dir, filepath.FromSlash(rel))

					info := file.FileInfo()
					mode := info.Mode()

					if info.IsDir() {
						if settings.DryRun {
							// muffin
						} else {
							err = Mkdir(filename)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						}
						dirCount++
					} else if mode&os.ModeSymlink > 0 && !windows {
						fileReader, fErr := file.Open()
						if fErr != nil {
							return errors.Wrap(fErr, 1)
						}
						defer fileReader.Close()

						linkname, lErr := ioutil.ReadAll(fileReader)
						if settings.DryRun {
							// muffin
						} else {
							lErr = Symlink(string(linkname), filename, settings.Consumer)
							if lErr != nil {
								return errors.Wrap(lErr, 1)
							}
						}
						symlinkCount++
					} else {
						regCount++

						fileReader, fErr := file.Open()
						if fErr != nil {
							return errors.Wrap(fErr, 1)
						}
						defer fileReader.Close()

						settings.Consumer.Debugf("extract %s", filename)
						var lastOffset int64
						countingReader := counter.NewReaderCallback(func(offset int64) {
							doneRecently := offset - lastOffset
							lastOffset = offset
							atomic.AddUint64(&doneSize, uint64(doneRecently))
							updateProgress()
						}, fileReader)

						if settings.DryRun {
							_, err = io.Copy(ioutil.Discard, countingReader)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						} else {
							err = CopyFile(filename, os.FileMode(mode&LuckyMode|ModeMask), countingReader)
							if err != nil {
								return errors.Wrap(err, 1)
							}
						}
					}

					return nil
				}()
				if err != nil {
					errs <- errors.Wrap(err, 1)
					return
				}
				writeProgress(fileIndex)
				done(file)
			}

			errs <- nil
		}()
	}

	for fileIndex := range reader.File {
		select {
		case fileIndices <- fileIndex:
			// sent work, yay!
		case err := <-errs:
			// abort everything
			close(fileIndices)
			return nil, err
		}
	}

	close(fileIndices)
	for i := 0; i < numWorkers; i++ {
		err := <-errs
		if err != nil {
			return nil, err
		}
	}

	return &ExtractResult{
		Dirs:     dirCount,
		Files:    regCount,
		Symlinks: symlinkCount,
	}, nil
}

func CompressZip(archiveWriter io.Writer, dir string, consumer *state.Consumer) (*CompressResult, error) {
	var err error
	var uncompressedSize int64
	var compressedSize int64

	archiveCounter := counter.NewWriter(archiveWriter)

	zipWriter := zip.NewWriter(archiveCounter)
	defer zipWriter.Close()
	defer func() {
		if zipWriter != nil {
			if zErr := zipWriter.Close(); err == nil && zErr != nil {
				err = errors.Wrap(zErr, 1)
			}
		}
	}()

	err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		name, wErr := filepath.Rel(dir, path)
		if wErr != nil {
			return wErr
		}

		if name == "." {
			// don't add '.' to zip
			return nil
		}

		name = filepath.ToSlash(name)

		fh, wErr := zip.FileInfoHeader(info)
		if wErr != nil {
			return wErr
		}

		fh.Name = name

		writer, wErr := zipWriter.CreateHeader(fh)
		if wErr != nil {
			return wErr
		}

		if info.IsDir() {
			// good!
		} else if info.Mode()&os.ModeSymlink > 0 {
			dest, wErr := os.Readlink(path)
			if wErr != nil {
				return wErr
			}

			_, wErr = writer.Write([]byte(dest))
			if wErr != nil {
				return wErr
			}
		} else if info.Mode().IsRegular() {
			reader, wErr := os.Open(path)
			if wErr != nil {
				return wErr
			}
			defer reader.Close()

			copiedBytes, wErr := io.Copy(writer, reader)
			if wErr != nil {
				return wErr
			}

			uncompressedSize += copiedBytes
		}

		return nil
	})

	err = zipWriter.Close()
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}
	zipWriter = nil

	compressedSize = archiveCounter.Count()

	return &CompressResult{
		UncompressedSize: uncompressedSize,
		CompressedSize:   compressedSize,
	}, err
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2014  Salsita s.r.o.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program. If not, see {http://www.gnu.org/licenses/}.
*/

package jira

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/url"
)

const (
	LibraryVersion = "0.0.1"

	DefaultMaxPendingRequests = 10

	defaultUserAgent = "go-jira/" + LibraryVersion
)

type (
	L []interface{}
	M map[string]interface{}
)

type Client struct {
	// HTTP client to be used to send all the HTTP requests.
	httpClient *http.Client

	// Base URL of the Jira API that is to be used to form API requests.
	BaseURL *url.URL

	// User-Agent header to be set for every request.
	UserAgent string

	// Me service.
	Myself *MyselfService

	// Project service.
	Projects *ProjectService

	// Issue service.
	Issues *IssueService

	// Remote Issue Link service.
	RemoteIssueLinks *RemoteIssueLinkService

	// Version service.
	Versions *VersionService

	// requestCh is used to limit the number of pending requests.
	requestCh chan struct{}

	// Options
	optMaxPendingRequests int
}

func New(baseURL *url.URL, httpClient *http.Client, options ...func(*Client)) *Client {
	// Create a Client object.
	client := &Client{
		httpClient:            httpClient,
		BaseURL:               baseURL,
		UserAgent:             defaultUserAgent,
		optMaxPendingRequests: DefaultMaxPendingRequests,
	}

	// Set up the API services.
	client.Myself = newMyselfService(client)
	client.Projects = newProjectService(client)
	client.Issues = newIssueService(client)
	client.RemoteIssueLinks = newRemoteIssueLinkService(client)
	client.Versions = newVersionService(client)

	// Set custom options.
	for _, option := range options {
		option(client)
	}

	// Finish initialising the client.
	client.requestCh = make(chan struct{}, client.optMaxPendingRequests)

	// Return the new Client instance.
	return client
}

// SetOptMaxPendingRequests can be used to set a custom queue size
// for the requests that are to be sent to JIRA.
//
// It only makes sense to call this method from an option function.
// Calling it later on will have no effect whatsoever.
func (c *Client) SetOptMaxPendingRequests(limit int) {
	c.optMaxPendingRequests = limit
}

func (c *Client) NewRequest(method, urlPath string, body interface{}) (*http.Request, error) {
	path, err := url.Parse(urlPath)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(path)

	var rawBody bytes.Buffer
	if body != nil {
		if err := json.NewEncoder(&rawBody).Encode(body); err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), &rawBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", c.UserAgent)
	return req, nil
}

func (c *Client) Do(req *http.Request, responseResource interface{}) (*http.Response, error) {
	// Acquire a request slot by sending to the request channel.
	c.requestCh <- struct{}{}
	defer func() {
		// Release the request slot by receiving from the request channel.
		<-c.requestCh
	}()

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode > 299 {
		// Try to parse the body as the error object.
		var errObject Error
		err := json.NewDecoder(resp.Body).Decode(&errObject)
		if err == nil {
			// Fill in the error object on success.
			return resp, &ErrAPI{
				Response: resp,
				Err:      &errObject,
			}
		} else {
			// Otherwise leave the error object empty.
			return resp, &ErrAPI{
				Response: resp,
			}
		}
	}

	if responseResource != nil {
		err = json.NewDecoder(resp.Body).Decode(responseResource)
	}

	return resp, err
}
<commit_msg>Rename New to NewClient<commit_after>/*
   Copyright (C) 2014  Salsita s.r.o.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program. If not, see {http://www.gnu.org/licenses/}.
*/

package jira

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/url"
)

const (
	LibraryVersion = "0.0.1"

	DefaultMaxPendingRequests = 10

	defaultUserAgent = "go-jira/" + LibraryVersion
)

type (
	L []interface{}
	M map[string]interface{}
)

type Client struct {
	// HTTP client to be used to send all the HTTP requests.
	httpClient *http.Client

	// Base URL of the Jira API that is to be used to form API requests.
	BaseURL *url.URL

	// User-Agent header to be set for every request.
	UserAgent string

	// Me service.
	Myself *MyselfService

	// Project service.
	Projects *ProjectService

	// Issue service.
	Issues *IssueService

	// Remote Issue Link service.
	RemoteIssueLinks *RemoteIssueLinkService

	// Version service.
	Versions *VersionService

	// requestCh is used to limit the number of pending requests.
	requestCh chan struct{}

	// Options
	optMaxPendingRequests int
}

func NewClient(baseURL *url.URL, httpClient *http.Client, options ...func(*Client)) *Client {
	// Create a Client object.
	client := &Client{
		httpClient:            httpClient,
		BaseURL:               baseURL,
		UserAgent:             defaultUserAgent,
		optMaxPendingRequests: DefaultMaxPendingRequests,
	}

	// Set up the API services.
	client.Myself = newMyselfService(client)
	client.Projects = newProjectService(client)
	client.Issues = newIssueService(client)
	client.RemoteIssueLinks = newRemoteIssueLinkService(client)
	client.Versions = newVersionService(client)

	// Set custom options.
	for _, option := range options {
		option(client)
	}

	// Finish initialising the client.
	client.requestCh = make(chan struct{}, client.optMaxPendingRequests)

	// Return the new Client instance.
	return client
}

// SetOptMaxPendingRequests can be used to set a custom queue size
// for the requests that are to be sent to JIRA.
//
// It only makes sense to call this method from an option function.
// Calling it later on will have no effect whatsoever.
func (c *Client) SetOptMaxPendingRequests(limit int) {
	c.optMaxPendingRequests = limit
}

func (c *Client) NewRequest(method, urlPath string, body interface{}) (*http.Request, error) {
	path, err := url.Parse(urlPath)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(path)

	var rawBody bytes.Buffer
	if body != nil {
		if err := json.NewEncoder(&rawBody).Encode(body); err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), &rawBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", c.UserAgent)
	return req, nil
}

func (c *Client) Do(req *http.Request, responseResource interface{}) (*http.Response, error) {
	// Acquire a request slot by sending to the request channel.
	c.requestCh <- struct{}{}
	defer func() {
		// Release the request slot by receiving from the request channel.
		<-c.requestCh
	}()

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode > 299 {
		// Try to parse the body as the error object.
		var errObject Error
		err := json.NewDecoder(resp.Body).Decode(&errObject)
		if err == nil {
			// Fill in the error object on success.
			return resp, &ErrAPI{
				Response: resp,
				Err:      &errObject,
			}
		} else {
			// Otherwise leave the error object empty.
			return resp, &ErrAPI{
				Response: resp,
			}
		}
	}

	if responseResource != nil {
		err = json.NewDecoder(resp.Body).Decode(responseResource)
	}

	return resp, err
}
<|endoftext|>


<commit_before>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package utl

import (
	"reflect"
	"testing"

	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/io"
)

func Test_list01(tst *testing.T) {

	verbose()
	io.Pforan("=========")
	chk.PrintTitle("list01. DblList.Append")

	var m DblList
	m.Append(2, 2.0)
	io.Pforan("m = %v\n", m)
	equal := reflect.DeepEqual(m.Vals, [][]float64{{}, {}, {2}})
	if !equal {
		chk.PrintFail("DblList Append")
	}

	m.Append(0, 0.0)
	m.Append(1, 1.0)
	io.Pforan("m = %v\n", m)
	equal = reflect.DeepEqual(m.Vals, [][]float64{{0}, {1}, {2}})
	if !equal {
		chk.PrintFail("DblList Append")
	}
}
<commit_msg>test made silent<commit_after>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package utl

import (
	"reflect"
	"testing"

	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/io"
)

func Test_list01(tst *testing.T) {

	//verbose()
	chk.PrintTitle("list01. DblList.Append")

	var m DblList
	m.Append(2, 2.0)
	io.Pforan("m = %v\n", m)
	equal := reflect.DeepEqual(m.Vals, [][]float64{{}, {}, {2}})
	if !equal {
		chk.PrintFail("DblList Append")
	}

	m.Append(0, 0.0)
	m.Append(1, 1.0)
	io.Pforan("m = %v\n", m)
	equal = reflect.DeepEqual(m.Vals, [][]float64{{0}, {1}, {2}})
	if !equal {
		chk.PrintFail("DblList Append")
	}
}
<|endoftext|>


<commit_before>package servefiles_test

import (
	"log"
	"net/http"
	"time"

	"github.com/spf13/afero"

	"github.com/rickb777/servefiles/v3"
)

func ExampleNewAssetHandler_simple_web_server() {
	// where the assets are stored (replace as required)
	localPath := "."

	// how long we allow user agents to cache assets
	// (this is in addition to conditional requests, see
	// RFC7234 https://tools.ietf.org/html/rfc7234#section-5.2.2.8)
	maxAge := time.Hour

	h := servefiles.NewAssetHandler(localPath).WithMaxAge(maxAge)

	log.Fatal(http.ListenAndServe(":8080", h))
}

func ExampleNewAssetHandlerFS_simple_web_server() {
	// where the assets are stored (replace as required)
	fs := afero.NewOsFs()

	// how long we allow user agents to cache assets
	// (this is in addition to conditional requests, see
	// RFC7234 https://tools.ietf.org/html/rfc7234#section-5.2.2.8)
	maxAge := time.Hour

	h := servefiles.NewAssetHandlerFS(fs).WithMaxAge(maxAge)

	log.Fatal(http.ListenAndServe(":8080", h))
}
<commit_msg>more documentation - correction<commit_after>package servefiles_test

import (
	"log"
	"net/http"
	"time"

	"github.com/spf13/afero"

	"github.com/rickb777/servefiles/v3"
)

func ExampleNewAssetHandler() {
	// A simple webserver

	// where the assets are stored (replace as required)
	localPath := "."

	// how long we allow user agents to cache assets
	// (this is in addition to conditional requests, see
	// RFC7234 https://tools.ietf.org/html/rfc7234#section-5.2.2.8)
	maxAge := time.Hour

	h := servefiles.NewAssetHandler(localPath).WithMaxAge(maxAge)

	log.Fatal(http.ListenAndServe(":8080", h))
}

func ExampleNewAssetHandlerFS() {
	// A simple webserver

	// where the assets are stored (replace as required)
	fs := afero.NewOsFs()

	// how long we allow user agents to cache assets
	// (this is in addition to conditional requests, see
	// RFC7234 https://tools.ietf.org/html/rfc7234#section-5.2.2.8)
	maxAge := time.Hour

	h := servefiles.NewAssetHandlerFS(fs).WithMaxAge(maxAge)

	log.Fatal(http.ListenAndServe(":8080", h))
}
<|endoftext|>


<commit_before>package file

import (
	"fmt"
	"log"

	"github.com/miekg/coredns/middleware"
	"github.com/miekg/coredns/middleware/pkg/rcode"
	"github.com/miekg/coredns/request"

	"github.com/miekg/dns"
)

// isNotify checks if state is a notify message and if so, will *also* check if it
// is from one of the configured masters. If not it will not be a valid notify
// message. If the zone z is not a secondary zone the message will also be ignored.
func (z *Zone) isNotify(state request.Request) bool {
	if state.Req.Opcode != dns.OpcodeNotify {
		return false
	}
	if len(z.TransferFrom) == 0 {
		return false
	}
	remote := middleware.Addr(state.IP()).Normalize()
	for _, from := range z.TransferFrom {
		if from == remote {
			return true
		}
	}
	return false
}

// Notify will send notifies to all configured TransferTo IP addresses.
func (z *Zone) Notify() {
	go notify(z.origin, z.TransferTo)
}

// notify sends notifies to the configured remote servers. It will try up to three times
// before giving up on a specific remote. We will sequentially loop through "to"
// until they all have replied (or have 3 failed attempts).
func notify(zone string, to []string) error {
	m := new(dns.Msg)
	m.SetNotify(zone)
	c := new(dns.Client)

	for _, t := range to {
		if t == "*" {
			continue
		}
		if err := notifyAddr(c, m, t); err != nil {
			log.Printf("[ERROR] " + err.Error())
		} else {
			log.Printf("[INFO] Sent notify for zone %q to %q", zone, t)
		}
	}
	return nil
}

func notifyAddr(c *dns.Client, m *dns.Msg, s string) error {
	code := dns.RcodeSuccess
	for i := 0; i < 3; i++ {
		ret, _, err := c.Exchange(m, s)
		if err != nil {
			continue
		}
		code = ret.Rcode
		if code == dns.RcodeSuccess {
			return nil
		}
	}
	return fmt.Errorf("Notify for zone %q was not accepted by %q: rcode was %q", m.Question[0].Name, s, rcode.ToString(code))
}
<commit_msg>middleware/file: notify better error reporting<commit_after>package file

import (
	"fmt"
	"log"

	"github.com/miekg/coredns/middleware"
	"github.com/miekg/coredns/middleware/pkg/rcode"
	"github.com/miekg/coredns/request"

	"github.com/miekg/dns"
)

// isNotify checks if state is a notify message and if so, will *also* check if it
// is from one of the configured masters. If not it will not be a valid notify
// message. If the zone z is not a secondary zone the message will also be ignored.
func (z *Zone) isNotify(state request.Request) bool {
	if state.Req.Opcode != dns.OpcodeNotify {
		return false
	}
	if len(z.TransferFrom) == 0 {
		return false
	}
	remote := middleware.Addr(state.IP()).Normalize()
	for _, from := range z.TransferFrom {
		if from == remote {
			return true
		}
	}
	return false
}

// Notify will send notifies to all configured TransferTo IP addresses.
func (z *Zone) Notify() {
	go notify(z.origin, z.TransferTo)
}

// notify sends notifies to the configured remote servers. It will try up to three times
// before giving up on a specific remote. We will sequentially loop through "to"
// until they all have replied (or have 3 failed attempts).
func notify(zone string, to []string) error {
	m := new(dns.Msg)
	m.SetNotify(zone)
	c := new(dns.Client)

	for _, t := range to {
		if t == "*" {
			continue
		}
		if err := notifyAddr(c, m, t); err != nil {
			log.Printf("[ERROR] " + err.Error())
		} else {
			log.Printf("[INFO] Sent notify for zone %q to %q", zone, t)
		}
	}
	return nil
}

func notifyAddr(c *dns.Client, m *dns.Msg, s string) (err error) {
	ret := new(dns.Msg)

	code := dns.RcodeServerFailure
	for i := 0; i < 3; i++ {
		ret, _, err = c.Exchange(m, s)
		if err != nil {
			continue
		}
		code = ret.Rcode
		if code == dns.RcodeSuccess {
			return nil
		}
	}
	if err != nil {
		return err
	}
	return fmt.Errorf("Notify for zone %q was not accepted by %q: rcode was %q", m.Question[0].Name, s, rcode.ToString(code))
}
<|endoftext|>