<commit_before>// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// 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 version

import "fmt"

const MAJOR uint = 2
const MINOR uint = 17
const PATCH uint = 0

var COMMIT string = ""
var IDENTIFIER string = ""
var METADATA string = ""

func Version() string {
	var suffix string = ""
	if len(IDENTIFIER) > 0 {
		suffix = fmt.Sprintf("-%s", IDENTIFIER)
	}

	if len(COMMIT) > 0 || len(METADATA) > 0 {
		suffix = suffix + "+"
	}

	if len(COMMIT) > 0 {
		suffix = fmt.Sprintf("%s"+"commit.%s", suffix, COMMIT)

	}

	if len(METADATA) > 0 {
		if len(COMMIT) > 0 {
			suffix = suffix + "."
		}
		suffix = suffix + METADATA
	}

	return fmt.Sprintf("%d.%d.%d%s", MAJOR, MINOR, PATCH, suffix)
}
<commit_msg>v2.18.0<commit_after>// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// 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 version

import "fmt"

const MAJOR uint = 2
const MINOR uint = 18
const PATCH uint = 0

var COMMIT string = ""
var IDENTIFIER string = ""
var METADATA string = ""

func Version() string {
	var suffix string = ""
	if len(IDENTIFIER) > 0 {
		suffix = fmt.Sprintf("-%s", IDENTIFIER)
	}

	if len(COMMIT) > 0 || len(METADATA) > 0 {
		suffix = suffix + "+"
	}

	if len(COMMIT) > 0 {
		suffix = fmt.Sprintf("%s"+"commit.%s", suffix, COMMIT)

	}

	if len(METADATA) > 0 {
		if len(COMMIT) > 0 {
			suffix = suffix + "."
		}
		suffix = suffix + METADATA
	}

	return fmt.Sprintf("%d.%d.%d%s", MAJOR, MINOR, PATCH, suffix)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strings"
)

type Element struct {
	Name  string
	Attrs map[string]string
}

func NewElement(name string) *Element {
	e := new(Element)
	e.Name = name
	e.Attrs = make(map[string]string)
	return e
}

func main() {
	input, err := parseInput(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
		os.Exit(1)
	}
	dec := xml.NewDecoder(os.Stdin)
	var stack []xml.StartElement
	for {
		tok, err := dec.Token()
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
			os.Exit(1)
		}
		switch tok := tok.(type) {
		case xml.StartElement:
			stack = append(stack, tok)
		case xml.EndElement:
			stack = stack[:len(stack)-1]
		case xml.CharData:
			if containsAll(stack, input) {
				printStack(stack, tok)
			}
		}
	}
}

func parseInput(input []string) (elements []*Element, err error) {
	if len(input) > 0 && strings.Contains(input[0], "=") {
		return nil, fmt.Errorf("attribute before tag name: %s", input[0])
	}

	var e *Element // Previous element added to elements.
	for _, s := range input {
		if strings.Contains(s, "=") {
			a := strings.SplitN(s, "=", 2)
			e.Attrs[a[0]] = a[1]
		} else {
			e = NewElement(s)
			elements = append(elements, e)
		}
	}
	return
}

func printStack(st []xml.StartElement, tok interface{}) {
	names := make([]string, 0, len(st))
	for _, e := range st {
		names = append(names, e.Name.Local)
	}
	fmt.Printf("%s: %s\n", strings.Join(names, " "), tok)
}

func containsAll(stack []xml.StartElement, search []*Element) bool {

	for len(search) <= len(stack) {
		if len(search) == 0 {
			return true
		}
		if stack[0].Name.Local == search[0].Name {
			search = search[1:]
		}
		stack = stack[1:]
	}
	return false
}
<commit_msg>[7.17] Added filer for attrs.<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strings"
)

type Element struct {
	Name  string
	Attrs map[string]string
}

func NewElement(name string) *Element {
	e := new(Element)
	e.Name = name
	e.Attrs = make(map[string]string)
	return e
}

func main() {
	input, err := parseInput(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
		os.Exit(1)
	}
	dec := xml.NewDecoder(os.Stdin)
	var stack []xml.StartElement
	for {
		tok, err := dec.Token()
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
			os.Exit(1)
		}
		switch tok := tok.(type) {
		case xml.StartElement:
			stack = append(stack, tok)
		case xml.EndElement:
			stack = stack[:len(stack)-1]
		case xml.CharData:
			if containsAll(stack, input) {
				printStack(stack, tok)
			}
		}
	}
}

func parseInput(input []string) (elements []*Element, err error) {
	if len(input) > 0 && strings.Contains(input[0], "=") {
		return nil, fmt.Errorf("attribute before tag name: %s", input[0])
	}

	var e *Element // Previous element added to elements.
	for _, s := range input {
		if strings.Contains(s, "=") {
			a := strings.SplitN(s, "=", 2)
			e.Attrs[a[0]] = a[1]
		} else {
			e = NewElement(s)
			elements = append(elements, e)
		}
	}
	return
}

func printStack(st []xml.StartElement, tok interface{}) {
	names := make([]string, 0, len(st))
	for _, e := range st {
		names = append(names, e.Name.Local)
	}
	fmt.Printf("%s: %s\n", strings.Join(names, " "), tok)
}

func containsAll(stack []xml.StartElement, search []*Element) bool {

	for len(search) <= len(stack) {
		if len(search) == 0 {
			return true
		}
		if stack[0].Name.Local == search[0].Name {
			var catch int
			for _, a := range stack[0].Attr {
				if v, ok := search[0].Attrs[a.Name.Local]; ok && a.Value == v {
					catch++
				}
			}
			if catch == len(search[0].Attrs) {
				search = search[1:]
			}
		}
		stack = stack[1:]
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2017 Sergey Safonov
// 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 panel_test

import (
	"encoding/json"
	"reflect"
	"testing"

	"github.com/kr/pretty"
	"github.com/spoof/go-grafana/grafana/panel"
	jsontools "github.com/spoof/go-grafana/pkg/json"
)

func TestSinglestat_MarshalJSON(t *testing.T) {
	panel := panel.NewSinglestat()
	panel.ValueName = "max"
	panel.ValueFontSize = "50%"
	panel.Prefix = "prefix"
	panel.PrefixFontSize = "75%"
	panel.Postfix = "postfix"
	panel.PostfixFontSize = "25%"
	panel.Format = "currencyJPY"
	panel.ColorBackground = true
	panel.ColorValue = true
	panel.Thresholds = "20,80"
	panel.Colors = []string{"rgba(10, 172, 45, 0.97)", "rgba(20, 172, 45, 0.97)", "rgba(30, 172, 45, 0.97)"}

	panel.SparkLine.Show = true
	panel.SparkLine.FullHeight = true
	panel.SparkLine.LineColor = "rgb(31, 120, 193)"
	panel.SparkLine.FillColor = "rgba(50, 61, 71, 0.18)"

	panel.Gauge.Show = true
	panel.Gauge.MaxValue = 100
	panel.Gauge.MinValue = 50
	panel.Gauge.ThresholdLabels = true
	panel.Gauge.ThresholdMarkers = true

	options := panel.GeneralOptions()
	options.Title = "New Panel"
	options.Description = "Panel Description"
	options.Height = "250px"
	options.MinSpan = 1
	options.Span = 12
	options.Transparent = true

	got, err := json.MarshalIndent(panel, "", "\t\t")
	if err != nil {
		t.Fatalf("TextPanel.MarshalJSON returned error %s", err)
	}
	expected := []byte(`{
		"valueName": "max",
		"valueFontSize": "50%",
		"prefix": "prefix",
		"prefixFontSize": "75%",
		"postfix": "postfix",
		"postfixFontSize": "25%",
		"format": "currencyJPY",
		"colorBackground": true,
		"colorValue": true,
		"thresholds": "20,80",
		"colors": [
			"rgba(10, 172, 45, 0.97)",
			"rgba(20, 172, 45, 0.97)",
			"rgba(30, 172, 45, 0.97)"
		],
		"sparkline": {
			"show": true,
			"full": true,
			"lineColor": "rgb(31, 120, 193)",
			"fillColor": "rgba(50, 61, 71, 0.18)"
		},
		"gauge": {
			"show": true,
			"maxValue": 100,
			"minValue": 50,
			"thresholdLabels": true,
			"thresholdMarkers": true
		}
	}`)
	if eq, err := jsontools.BytesEqual(expected, got); err != nil {
		t.Fatalf("Singlestat.MarshalJSON returned error %s", err)
	} else if !eq {
		t.Errorf("Singlestat.MarshalJSON: %s", pretty.Diff(expected, &got))
	}
}

func TestSinglestat_UnmarshalJSON(t *testing.T) {
	expected := panel.NewSinglestat()
	expected.ValueName = "max"
	expected.ValueFontSize = "50%"
	expected.Prefix = "prefix"
	expected.PrefixFontSize = "75%"
	expected.Postfix = "postfix"
	expected.PostfixFontSize = "25%"
	expected.Format = "currencyJPY"
	expected.ColorBackground = true
	expected.ColorValue = true
	expected.Thresholds = "20,80"
	expected.Colors = []string{"rgba(10, 172, 45, 0.97)", "rgba(20, 172, 45, 0.97)", "rgba(30, 172, 45, 0.97)"}

	expected.SparkLine.Show = true
	expected.SparkLine.FullHeight = true
	expected.SparkLine.LineColor = "rgb(31, 120, 193)"
	expected.SparkLine.FillColor = "rgba(50, 61, 71, 0.18)"

	expected.Gauge.Show = true
	expected.Gauge.MaxValue = 100
	expected.Gauge.MinValue = 50
	expected.Gauge.ThresholdLabels = true
	expected.Gauge.ThresholdMarkers = true

	data := []byte(`{
		"valueName": "max",
		"valueFontSize": "50%",
		"postfix": "postfix",
		"postfixFontSize": "25%",
		"prefix": "prefix",
		"prefixFontSize": "75%",
		"format": "currencyJPY",
		"colorBackground": true,
		"colorValue": true,
		"thresholds": "20,80",
		"colors": [
		"rgba(10, 172, 45, 0.97)",
		"rgba(20, 172, 45, 0.97)",
		"rgba(30, 172, 45, 0.97)"
		],
		"sparkline": {
			"show": true,
			"full": true,
			"lineColor": "rgb(31, 120, 193)",
			"fillColor": "rgba(50, 61, 71, 0.18)"
		},
		"gauge": {
			"show": true,
			"maxValue": 100,
			"minValue": 50,
			"thresholdLabels": true,
			"thresholdMarkers": true
		}
	}`)
	var got panel.Singlestat
	err := json.Unmarshal(data, &got)
	if err != nil {
		t.Fatalf("Singlestat.UnmarshalJSON returned error %s", err)
	}

	if !reflect.DeepEqual(expected, &got) {
		t.Errorf("Singlestat.UnmarshalJSON: %s", pretty.Diff(expected, &got))
	}
}
<commit_msg>Fixed typo<commit_after>// Copyright 2017 Sergey Safonov
// 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 panel_test

import (
	"encoding/json"
	"reflect"
	"testing"

	"github.com/kr/pretty"
	"github.com/spoof/go-grafana/grafana/panel"
	jsontools "github.com/spoof/go-grafana/pkg/json"
)

func TestSinglestat_MarshalJSON(t *testing.T) {
	panel := panel.NewSinglestat()
	panel.ValueName = "max"
	panel.ValueFontSize = "50%"
	panel.Prefix = "prefix"
	panel.PrefixFontSize = "75%"
	panel.Postfix = "postfix"
	panel.PostfixFontSize = "25%"
	panel.Format = "currencyJPY"
	panel.ColorBackground = true
	panel.ColorValue = true
	panel.Thresholds = "20,80"
	panel.Colors = []string{"rgba(10, 172, 45, 0.97)", "rgba(20, 172, 45, 0.97)", "rgba(30, 172, 45, 0.97)"}

	panel.SparkLine.Show = true
	panel.SparkLine.FullHeight = true
	panel.SparkLine.LineColor = "rgb(31, 120, 193)"
	panel.SparkLine.FillColor = "rgba(50, 61, 71, 0.18)"

	panel.Gauge.Show = true
	panel.Gauge.MaxValue = 100
	panel.Gauge.MinValue = 50
	panel.Gauge.ThresholdLabels = true
	panel.Gauge.ThresholdMarkers = true

	options := panel.GeneralOptions()
	options.Title = "New Panel"
	options.Description = "Panel Description"
	options.Height = "250px"
	options.MinSpan = 1
	options.Span = 12
	options.Transparent = true

	got, err := json.MarshalIndent(panel, "", "\t\t")
	if err != nil {
		t.Fatalf("Singlestat.MarshalJSON returned error %s", err)
	}
	expected := []byte(`{
		"valueName": "max",
		"valueFontSize": "50%",
		"prefix": "prefix",
		"prefixFontSize": "75%",
		"postfix": "postfix",
		"postfixFontSize": "25%",
		"format": "currencyJPY",
		"colorBackground": true,
		"colorValue": true,
		"thresholds": "20,80",
		"colors": [
			"rgba(10, 172, 45, 0.97)",
			"rgba(20, 172, 45, 0.97)",
			"rgba(30, 172, 45, 0.97)"
		],
		"sparkline": {
			"show": true,
			"full": true,
			"lineColor": "rgb(31, 120, 193)",
			"fillColor": "rgba(50, 61, 71, 0.18)"
		},
		"gauge": {
			"show": true,
			"maxValue": 100,
			"minValue": 50,
			"thresholdLabels": true,
			"thresholdMarkers": true
		}
	}`)
	if eq, err := jsontools.BytesEqual(expected, got); err != nil {
		t.Fatalf("Singlestat.MarshalJSON returned error %s", err)
	} else if !eq {
		t.Errorf("Singlestat.MarshalJSON: %s", pretty.Diff(expected, &got))
	}
}

func TestSinglestat_UnmarshalJSON(t *testing.T) {
	expected := panel.NewSinglestat()
	expected.ValueName = "max"
	expected.ValueFontSize = "50%"
	expected.Prefix = "prefix"
	expected.PrefixFontSize = "75%"
	expected.Postfix = "postfix"
	expected.PostfixFontSize = "25%"
	expected.Format = "currencyJPY"
	expected.ColorBackground = true
	expected.ColorValue = true
	expected.Thresholds = "20,80"
	expected.Colors = []string{"rgba(10, 172, 45, 0.97)", "rgba(20, 172, 45, 0.97)", "rgba(30, 172, 45, 0.97)"}

	expected.SparkLine.Show = true
	expected.SparkLine.FullHeight = true
	expected.SparkLine.LineColor = "rgb(31, 120, 193)"
	expected.SparkLine.FillColor = "rgba(50, 61, 71, 0.18)"

	expected.Gauge.Show = true
	expected.Gauge.MaxValue = 100
	expected.Gauge.MinValue = 50
	expected.Gauge.ThresholdLabels = true
	expected.Gauge.ThresholdMarkers = true

	data := []byte(`{
		"valueName": "max",
		"valueFontSize": "50%",
		"postfix": "postfix",
		"postfixFontSize": "25%",
		"prefix": "prefix",
		"prefixFontSize": "75%",
		"format": "currencyJPY",
		"colorBackground": true,
		"colorValue": true,
		"thresholds": "20,80",
		"colors": [
		"rgba(10, 172, 45, 0.97)",
		"rgba(20, 172, 45, 0.97)",
		"rgba(30, 172, 45, 0.97)"
		],
		"sparkline": {
			"show": true,
			"full": true,
			"lineColor": "rgb(31, 120, 193)",
			"fillColor": "rgba(50, 61, 71, 0.18)"
		},
		"gauge": {
			"show": true,
			"maxValue": 100,
			"minValue": 50,
			"thresholdLabels": true,
			"thresholdMarkers": true
		}
	}`)
	var got panel.Singlestat
	err := json.Unmarshal(data, &got)
	if err != nil {
		t.Fatalf("Singlestat.UnmarshalJSON returned error %s", err)
	}

	if !reflect.DeepEqual(expected, &got) {
		t.Errorf("Singlestat.UnmarshalJSON: %s", pretty.Diff(expected, &got))
	}
}
<|endoftext|>


<commit_before>package schemabuilder

import (
	"bytes"
	"context"
	"fmt"
	"reflect"
	"strings"
	"unicode"

	"github.com/samsarahq/thunder/graphql"
)

// makeGraphql converts a field name "MyField" into a graphQL field name "myField".
func makeGraphql(s string) string {
	var b bytes.Buffer
	for i, c := range s {
		if i == 0 {
			b.WriteRune(unicode.ToLower(c))
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

// reverseGraphqlFieldName converts a graphql field name "myField" into a
// non-graphQL field name "MyField".
func reverseGraphqlFieldName(s string) string {
	var b bytes.Buffer
	for i, c := range s {
		if i == 0 {
			b.WriteRune(unicode.ToUpper(c))
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

// graphQLFieldInfo contains basic struct field information related to GraphQL.
type graphQLFieldInfo struct {
	// Skipped indicates that this field should not be included in GraphQL.
	Skipped bool

	// Name is the GraphQL field name that should be exposed for this field.
	Name string

	// KeyField indicates that this field should be treated as a Object Key field.
	KeyField bool
}

// parseGraphQLFieldInfo parses a struct field and returns a struct with the
// parsed information about the field (tag info, name, etc).
func parseGraphQLFieldInfo(field reflect.StructField) (*graphQLFieldInfo, error) {
	if field.PkgPath != "" {
		return &graphQLFieldInfo{Skipped: true}, nil
	}
	tags := strings.Split(field.Tag.Get("graphql"), ",")
	var name string
	if len(tags) > 0 {
		name = tags[0]
	}
	if name == "" {
		name = makeGraphql(field.Name)
	}
	if name == "-" {
		return &graphQLFieldInfo{Skipped: true}, nil
	}

	var key bool

	if len(tags) > 1 {
		for _, tag := range tags[1:] {
			if tag != "key" || key {
				return nil, fmt.Errorf("field %s has unexpected tag %s", name, tag)
			}
			key = true
		}
	}
	return &graphQLFieldInfo{Name: name, KeyField: key}, nil
}

// Common Types that we will need to perform type assertions against.
var errType = reflect.TypeOf((*error)(nil)).Elem()
var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
var selectionSetType = reflect.TypeOf(&graphql.SelectionSet{})

<commit_msg>go schemabuilder: Inline TextMarshaler/TextUnmarshaler types<commit_after>package schemabuilder

import (
	"bytes"
	"context"
	"encoding"
	"fmt"
	"reflect"
	"strings"
	"unicode"

	"github.com/samsarahq/thunder/graphql"
)

// makeGraphql converts a field name "MyField" into a graphQL field name "myField".
func makeGraphql(s string) string {
	var b bytes.Buffer
	for i, c := range s {
		if i == 0 {
			b.WriteRune(unicode.ToLower(c))
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

// reverseGraphqlFieldName converts a graphql field name "myField" into a
// non-graphQL field name "MyField".
func reverseGraphqlFieldName(s string) string {
	var b bytes.Buffer
	for i, c := range s {
		if i == 0 {
			b.WriteRune(unicode.ToUpper(c))
		} else {
			b.WriteRune(c)
		}
	}
	return b.String()
}

// graphQLFieldInfo contains basic struct field information related to GraphQL.
type graphQLFieldInfo struct {
	// Skipped indicates that this field should not be included in GraphQL.
	Skipped bool

	// Name is the GraphQL field name that should be exposed for this field.
	Name string

	// KeyField indicates that this field should be treated as a Object Key field.
	KeyField bool
}

// parseGraphQLFieldInfo parses a struct field and returns a struct with the
// parsed information about the field (tag info, name, etc).
func parseGraphQLFieldInfo(field reflect.StructField) (*graphQLFieldInfo, error) {
	if field.PkgPath != "" {
		return &graphQLFieldInfo{Skipped: true}, nil
	}
	tags := strings.Split(field.Tag.Get("graphql"), ",")
	var name string
	if len(tags) > 0 {
		name = tags[0]
	}
	if name == "" {
		name = makeGraphql(field.Name)
	}
	if name == "-" {
		return &graphQLFieldInfo{Skipped: true}, nil
	}

	var key bool

	if len(tags) > 1 {
		for _, tag := range tags[1:] {
			if tag != "key" || key {
				return nil, fmt.Errorf("field %s has unexpected tag %s", name, tag)
			}
			key = true
		}
	}
	return &graphQLFieldInfo{Name: name, KeyField: key}, nil
}

// Common Types that we will need to perform type assertions against.
var errType = reflect.TypeOf((*error)(nil)).Elem()
var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
var selectionSetType = reflect.TypeOf(&graphql.SelectionSet{})
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

/* Tests for savvy backup utility */

/*
	Empty directory can be backed up.
*/
func Test001_Empy(t *testing.T) {

	// make dir
	// run savvy on it
	// verify results
	t.Error("not implemented\n")
}

/*
	Directory with small number of files can be backed up.
*/
func Test002_Simple(t *testing.T) {
	t.Error("not implemented\n")
}

/*
	Directory with names containing spaces & special characters can be backed.
*/
func Test003_SpecialCharName(t *testing.T) {
	t.Error("not implemented\n")
}

/*
	Directory with "savvyignore" inside is actually ignored.
*/
func Test004_Ignore(t *testing.T) {
	t.Error("not implemented\n")
}

/*
	Way to set destination directory is working.
	1. Set destination directory:  savvy --dest <dir>
	2. Invoke savvy as usual
*/
func Test005_DestinationDirectory(t *testing.T) {
	t.Error("not implemented\n")

	// remove any .savvy file

	// make dir and populate

	// invoke savvy to specify dest directory (--dest <dir> )

	// verify that .savvy file is created

	// invoke savvy

	// verify that archive is created into dest directory
}

/*
	Cache of backed-up files is working correctly.
	(Useful for write-only destination directories)
*/
func Test006_CacheIsWorking(t *testing.T) {
	t.Error("not implemented\n")

	// remove any .savvy file

	// make dir and populate

	// invoke savvy to specify dest directory (--dest <dir> )

	// verify that .savvy file is created

	// invoke savvy

	// verify that archive is created into dest directory as expected
}
<commit_msg>Test suite v0.0<commit_after>package main

import (
	"testing"
	"os"
	"os/exec"
)

/* Tests for savvy backup utility */

var safeEnvironment = false

func safeToRun(t *testing.T) {
	if !safeEnvironment {
		t.Fatal("unsafe env")
	}
}

func Test000_SetupDirs(t *testing.T) {

	// make dir
	err := os.Mkdir("test/", os.ModeDir | 0777)
	//if err != nil && err != os.ErrExist {
	//	t.Fatal(err)
	//}

	err = os.Chdir("test")
	if err != nil {
		t.Fatal(err)
	}

	wd, err2 := os.Getwd()
	if err2 == nil {
		safeEnvironment = true
	}
	t.Log("Working dir:", wd)
}

/*
	Empty directory can be backed up.
*/
func Test001_Empty(t *testing.T) {

	safeToRun(t)

	err := os.Mkdir("a00", os.ModeDir | 0777)
	err = err
	//if err != nil {
	//	t.Fatal(err)
	//}

	// run savvy on it
	out, err2 := exec.Command("../savvy").Output()

	if err2 != nil {
		t.Fatal(err2)
	}

	t.Log(string(out))
	err2 = err2

	// verify results
	//t.Error("not implemented\n")

	//os.RemoveAll("*")
}

/*
	Directory with small number of files can be backed up.
*/
func Test002_Simple(t *testing.T) {
	t.Error("not implemented\n")

	safeToRun(t)
}

/*
	Directory with names containing spaces & special characters can be backed.
*/
func Test003_SpecialCharName(t *testing.T) {
	t.Error("not implemented\n")

	safeToRun(t)
}

/*
	Directory with "savvyignore" inside is actually ignored.
*/
func Test004_Ignore(t *testing.T) {
	t.Error("not implemented\n")

	safeToRun(t)
}

/*
	Way to set destination directory is working.
	1. Set destination directory:  savvy --dest <dir>
	2. Invoke savvy as usual
*/
func Test005_DestinationDirectory(t *testing.T) {
	t.Error("not implemented\n")

	safeToRun(t)

	// remove any .savvy file

	// make dir and populate

	// invoke savvy to specify dest directory (--dest <dir> )

	// verify that .savvy file is created

	// invoke savvy

	// verify that archive is created into dest directory
}

/*
	Cache of backed-up files is working correctly.
	(Useful for write-only destination directories)
*/
func Test006_CacheIsWorking(t *testing.T) {
	t.Error("not implemented\n")

	safeToRun(t)

	// remove any .savvy file

	// make dir and populate

	// invoke savvy to specify dest directory (--dest <dir> )

	// verify that .savvy file is created

	// invoke savvy

	// verify that archive is created into dest directory as expected
}
<|endoftext|>


<commit_before>package lnwallet

import (
	"errors"
	"fmt"
	"sync"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
	"github.com/lightningnetwork/lnd/lntypes"
)

// AddressType is an enum-like type which denotes the possible address types
// WalletController supports.
type AddressType uint8

const (
	// WitnessPubKey represents a p2wkh address.
	WitnessPubKey AddressType = iota

	// NestedWitnessPubKey represents a p2sh output which is itself a
	// nested p2wkh output.
	NestedWitnessPubKey

	// UnknownAddressType represents an output with an unknown or non-standard
	// script.
	UnknownAddressType
)

var (
	// DefaultPublicPassphrase is the default public passphrase used for the
	// wallet.
	DefaultPublicPassphrase = []byte("public")

	// DefaultPrivatePassphrase is the default private passphrase used for
	// the wallet.
	DefaultPrivatePassphrase = []byte("hello")

	// ErrDoubleSpend is returned from PublishTransaction in case the
	// tx being published is spending an output spent by a conflicting
	// transaction.
	ErrDoubleSpend = errors.New("Transaction rejected: output already spent")

	// ErrNotMine is an error denoting that a WalletController instance is
	// unable to spend a specified output.
	ErrNotMine = errors.New("the passed output doesn't belong to the wallet")
)

// Utxo is an unspent output denoted by its outpoint, and output value of the
// original output.
type Utxo struct {
	AddressType   AddressType
	Value         btcutil.Amount
	Confirmations int64
	PkScript      []byte
	RedeemScript  []byte
	WitnessScript []byte
	wire.OutPoint
}

// TransactionDetail describes a transaction with either inputs which belong to
// the wallet, or has outputs that pay to the wallet.
type TransactionDetail struct {
	// Hash is the transaction hash of the transaction.
	Hash chainhash.Hash

	// Value is the net value of this transaction (in satoshis) from the
	// PoV of the wallet. If this transaction purely spends from the
	// wallet's funds, then this value will be negative. Similarly, if this
	// transaction credits the wallet, then this value will be positive.
	Value btcutil.Amount

	// NumConfirmations is the number of confirmations this transaction
	// has. If the transaction is unconfirmed, then this value will be
	// zero.
	NumConfirmations int32

	// BlockHeight is the hash of the block which includes this
	// transaction. Unconfirmed transactions will have a nil value for this
	// field.
	BlockHash *chainhash.Hash

	// BlockHeight is the height of the block including this transaction.
	// Unconfirmed transaction will show a height of zero.
	BlockHeight int32

	// Timestamp is the unix timestamp of the block including this
	// transaction. If the transaction is unconfirmed, then this will be a
	// timestamp of txn creation.
	Timestamp int64

	// TotalFees is the total fee in satoshis paid by this transaction.
	TotalFees int64

	// DestAddresses are the destinations for a transaction
	DestAddresses []btcutil.Address
}

// TransactionSubscription is an interface which describes an object capable of
// receiving notifications of new transaction related to the underlying wallet.
// TODO(roasbeef): add balance updates?
type TransactionSubscription interface {
	// ConfirmedTransactions returns a channel which will be sent on as new
	// relevant transactions are confirmed.
	ConfirmedTransactions() chan *TransactionDetail

	// UnconfirmedTransactions returns a channel which will be sent on as
	// new relevant transactions are seen within the network.
	UnconfirmedTransactions() chan *TransactionDetail

	// Cancel finalizes the subscription, cleaning up any resources
	// allocated.
	Cancel()
}

// WalletController defines an abstract interface for controlling a local Pure
// Go wallet, a local or remote wallet via an RPC mechanism, or possibly even
// a daemon assisted hardware wallet. This interface serves the purpose of
// allowing LightningWallet to be seamlessly compatible with several wallets
// such as: uspv, btcwallet, Bitcoin Core, Electrum, etc. This interface then
// serves as a "base wallet", with Lightning Network awareness taking place at
// a "higher" level of abstraction. Essentially, an overlay wallet.
// Implementors of this interface must closely adhere to the documented
// behavior of all interface methods in order to ensure identical behavior
// across all concrete implementations.
type WalletController interface {
	// FetchInputInfo queries for the WalletController's knowledge of the
	// passed outpoint. If the base wallet determines this output is under
	// its control, then the original txout should be returned.  Otherwise,
	// a non-nil error value of ErrNotMine should be returned instead.
	FetchInputInfo(prevOut *wire.OutPoint) (*wire.TxOut, error)

	// ConfirmedBalance returns the sum of all the wallet's unspent outputs
	// that have at least confs confirmations. If confs is set to zero,
	// then all unspent outputs, including those currently in the mempool
	// will be included in the final sum.
	//
	// NOTE: Only witness outputs should be included in the computation of
	// the total spendable balance of the wallet. We require this as only
	// witness inputs can be used for funding channels.
	ConfirmedBalance(confs int32) (btcutil.Amount, error)

	// NewAddress returns the next external or internal address for the
	// wallet dictated by the value of the `change` parameter. If change is
	// true, then an internal address should be used, otherwise an external
	// address should be returned. The type of address returned is dictated
	// by the wallet's capabilities, and may be of type: p2sh, p2wkh,
	// p2wsh, etc.
	NewAddress(addrType AddressType, change bool) (btcutil.Address, error)

	// LastUnusedAddress returns the last *unused* address known by the
	// wallet. An address is unused if it hasn't received any payments.
	// This can be useful in UIs in order to continually show the
	// "freshest" address without having to worry about "address inflation"
	// caused by continual refreshing. Similar to NewAddress it can derive
	// a specified address type. By default, this is a non-change address.
	LastUnusedAddress(addrType AddressType) (btcutil.Address, error)

	// IsOurAddress checks if the passed address belongs to this wallet
	IsOurAddress(a btcutil.Address) bool

	// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying
	// out to the specified outputs. In the case the wallet has insufficient
	// funds, or the outputs are non-standard, an error should be returned.
	// This method also takes the target fee expressed in sat/kw that should
	// be used when crafting the transaction.
	SendOutputs(outputs []*wire.TxOut,
		feeRate SatPerKWeight) (*wire.MsgTx, error)

	// ListUnspentWitness returns all unspent outputs which are version 0
	// witness programs. The 'minconfirms' and 'maxconfirms' parameters
	// indicate the minimum and maximum number of confirmations an output
	// needs in order to be returned by this method. Passing -1 as
	// 'minconfirms' indicates that even unconfirmed outputs should be
	// returned. Using MaxInt32 as 'maxconfirms' implies returning all
	// outputs with at least 'minconfirms'.
	ListUnspentWitness(minconfirms, maxconfirms int32) ([]*Utxo, error)

	// ListTransactionDetails returns a list of all transactions which are
	// relevant to the wallet.
	ListTransactionDetails() ([]*TransactionDetail, error)

	// LockOutpoint marks an outpoint as locked meaning it will no longer
	// be deemed as eligible for coin selection. Locking outputs are
	// utilized in order to avoid race conditions when selecting inputs for
	// usage when funding a channel.
	LockOutpoint(o wire.OutPoint)

	// UnlockOutpoint unlocks a previously locked output, marking it
	// eligible for coin selection.
	UnlockOutpoint(o wire.OutPoint)

	// PublishTransaction performs cursory validation (dust checks, etc),
	// then finally broadcasts the passed transaction to the Bitcoin network.
	// If the transaction is rejected because it is conflicting with an
	// already known transaction, ErrDoubleSpend is returned. If the
	// transaction is already known (published already), no error will be
	// returned. Other error returned depends on the currently active chain
	// backend.
	PublishTransaction(tx *wire.MsgTx) error

	// SubscribeTransactions returns a TransactionSubscription client which
	// is capable of receiving async notifications as new transactions
	// related to the wallet are seen within the network, or found in
	// blocks.
	//
	// NOTE: a non-nil error should be returned if notifications aren't
	// supported.
	//
	// TODO(roasbeef): make distinct interface?
	SubscribeTransactions() (TransactionSubscription, error)

	// IsSynced returns a boolean indicating if from the PoV of the wallet,
	// it has fully synced to the current best block in the main chain.
	// It also returns an int64 indicating the timestamp of the best block
	// known to the wallet, expressed in Unix epoch time
	IsSynced() (bool, int64, error)

	// Start initializes the wallet, making any necessary connections,
	// starting up required goroutines etc.
	Start() error

	// Stop signals the wallet for shutdown. Shutdown may entail closing
	// any active sockets, database handles, stopping goroutines, etc.
	Stop() error

	// BackEnd returns a name for the wallet's backing chain service,
	// which could be e.g. btcd, bitcoind, neutrino, or another consensus
	// service.
	BackEnd() string
}

// BlockChainIO is a dedicated source which will be used to obtain queries
// related to the current state of the blockchain. The data returned by each of
// the defined methods within this interface should always return the most up
// to date data possible.
//
// TODO(roasbeef): move to diff package perhaps?
// TODO(roasbeef): move publish txn here?
type BlockChainIO interface {
	// GetBestBlock returns the current height and block hash of the valid
	// most-work chain the implementation is aware of.
	GetBestBlock() (*chainhash.Hash, int32, error)

	// GetUtxo attempts to return the passed outpoint if it's still a
	// member of the utxo set. The passed height hint should be the "birth
	// height" of the passed outpoint. The script passed should be the
	// script that the outpoint creates. In the case that the output is in
	// the UTXO set, then the output corresponding to that output is
	// returned.  Otherwise, a non-nil error will be returned.
	GetUtxo(op *wire.OutPoint, pkScript []byte,
		heightHint uint32) (*wire.TxOut, error)

	// GetBlockHash returns the hash of the block in the best blockchain
	// at the given height.
	GetBlockHash(blockHeight int64) (*chainhash.Hash, error)

	// GetBlock returns the block in the main chain identified by the given
	// hash.
	GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error)
}

// MessageSigner represents an abstract object capable of signing arbitrary
// messages. The capabilities of this interface are used to sign announcements
// to the network, or just arbitrary messages that leverage the wallet's keys
// to attest to some message.
type MessageSigner interface {
	// SignMessage attempts to sign a target message with the private key
	// that corresponds to the passed public key. If the target private key
	// is unable to be found, then an error will be returned. The actual
	// digest signed is the double SHA-256 of the passed message.
	SignMessage(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error)
}

// PreimageCache is an interface that represents a global cache for preimages.
// We'll utilize this cache to communicate the discovery of new preimages
// across sub-systems.
type PreimageCache interface {
	// LookupPreimage attempts to look up a preimage according to its hash.
	// If found, the preimage is returned along with true for the second
	// argument. Otherwise, it'll return false.
	LookupPreimage(hash lntypes.Hash) (lntypes.Preimage, bool)

	// AddPreimages adds a batch of newly discovered preimages to the global
	// cache, and also signals any subscribers of the newly discovered
	// witness.
	AddPreimages(preimages ...lntypes.Preimage) error
}

// WalletDriver represents a "driver" for a particular concrete
// WalletController implementation. A driver is identified by a globally unique
// string identifier along with a 'New()' method which is responsible for
// initializing a particular WalletController concrete implementation.
type WalletDriver struct {
	// WalletType is a string which uniquely identifies the
	// WalletController that this driver, drives.
	WalletType string

	// New creates a new instance of a concrete WalletController
	// implementation given a variadic set up arguments. The function takes
	// a variadic number of interface parameters in order to provide
	// initialization flexibility, thereby accommodating several potential
	// WalletController implementations.
	New func(args ...interface{}) (WalletController, error)

	// BackEnds returns a list of available chain service drivers for the
	// wallet driver. This could be e.g. bitcoind, btcd, neutrino, etc.
	BackEnds func() []string
}

var (
	wallets     = make(map[string]*WalletDriver)
	registerMtx sync.Mutex
)

// RegisteredWallets returns a slice of all currently registered notifiers.
//
// NOTE: This function is safe for concurrent access.
func RegisteredWallets() []*WalletDriver {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	registeredWallets := make([]*WalletDriver, 0, len(wallets))
	for _, wallet := range wallets {
		registeredWallets = append(registeredWallets, wallet)
	}

	return registeredWallets
}

// RegisterWallet registers a WalletDriver which is capable of driving a
// concrete WalletController interface. In the case that this driver has
// already been registered, an error is returned.
//
// NOTE: This function is safe for concurrent access.
func RegisterWallet(driver *WalletDriver) error {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	if _, ok := wallets[driver.WalletType]; ok {
		return fmt.Errorf("wallet already registered")
	}

	wallets[driver.WalletType] = driver

	return nil
}

// SupportedWallets returns a slice of strings that represents the wallet
// drivers that have been registered and are therefore supported.
//
// NOTE: This function is safe for concurrent access.
func SupportedWallets() []string {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	supportedWallets := make([]string, 0, len(wallets))
	for walletName := range wallets {
		supportedWallets = append(supportedWallets, walletName)
	}

	return supportedWallets
}
<commit_msg>lnwallet/interface: add CreateSimpleTx to wallet interface<commit_after>package lnwallet

import (
	"errors"
	"fmt"
	"sync"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcwallet/wallet/txauthor"
	"github.com/lightningnetwork/lnd/lntypes"
)

// AddressType is an enum-like type which denotes the possible address types
// WalletController supports.
type AddressType uint8

const (
	// WitnessPubKey represents a p2wkh address.
	WitnessPubKey AddressType = iota

	// NestedWitnessPubKey represents a p2sh output which is itself a
	// nested p2wkh output.
	NestedWitnessPubKey

	// UnknownAddressType represents an output with an unknown or non-standard
	// script.
	UnknownAddressType
)

var (
	// DefaultPublicPassphrase is the default public passphrase used for the
	// wallet.
	DefaultPublicPassphrase = []byte("public")

	// DefaultPrivatePassphrase is the default private passphrase used for
	// the wallet.
	DefaultPrivatePassphrase = []byte("hello")

	// ErrDoubleSpend is returned from PublishTransaction in case the
	// tx being published is spending an output spent by a conflicting
	// transaction.
	ErrDoubleSpend = errors.New("Transaction rejected: output already spent")

	// ErrNotMine is an error denoting that a WalletController instance is
	// unable to spend a specified output.
	ErrNotMine = errors.New("the passed output doesn't belong to the wallet")
)

// Utxo is an unspent output denoted by its outpoint, and output value of the
// original output.
type Utxo struct {
	AddressType   AddressType
	Value         btcutil.Amount
	Confirmations int64
	PkScript      []byte
	RedeemScript  []byte
	WitnessScript []byte
	wire.OutPoint
}

// TransactionDetail describes a transaction with either inputs which belong to
// the wallet, or has outputs that pay to the wallet.
type TransactionDetail struct {
	// Hash is the transaction hash of the transaction.
	Hash chainhash.Hash

	// Value is the net value of this transaction (in satoshis) from the
	// PoV of the wallet. If this transaction purely spends from the
	// wallet's funds, then this value will be negative. Similarly, if this
	// transaction credits the wallet, then this value will be positive.
	Value btcutil.Amount

	// NumConfirmations is the number of confirmations this transaction
	// has. If the transaction is unconfirmed, then this value will be
	// zero.
	NumConfirmations int32

	// BlockHeight is the hash of the block which includes this
	// transaction. Unconfirmed transactions will have a nil value for this
	// field.
	BlockHash *chainhash.Hash

	// BlockHeight is the height of the block including this transaction.
	// Unconfirmed transaction will show a height of zero.
	BlockHeight int32

	// Timestamp is the unix timestamp of the block including this
	// transaction. If the transaction is unconfirmed, then this will be a
	// timestamp of txn creation.
	Timestamp int64

	// TotalFees is the total fee in satoshis paid by this transaction.
	TotalFees int64

	// DestAddresses are the destinations for a transaction
	DestAddresses []btcutil.Address
}

// TransactionSubscription is an interface which describes an object capable of
// receiving notifications of new transaction related to the underlying wallet.
// TODO(roasbeef): add balance updates?
type TransactionSubscription interface {
	// ConfirmedTransactions returns a channel which will be sent on as new
	// relevant transactions are confirmed.
	ConfirmedTransactions() chan *TransactionDetail

	// UnconfirmedTransactions returns a channel which will be sent on as
	// new relevant transactions are seen within the network.
	UnconfirmedTransactions() chan *TransactionDetail

	// Cancel finalizes the subscription, cleaning up any resources
	// allocated.
	Cancel()
}

// WalletController defines an abstract interface for controlling a local Pure
// Go wallet, a local or remote wallet via an RPC mechanism, or possibly even
// a daemon assisted hardware wallet. This interface serves the purpose of
// allowing LightningWallet to be seamlessly compatible with several wallets
// such as: uspv, btcwallet, Bitcoin Core, Electrum, etc. This interface then
// serves as a "base wallet", with Lightning Network awareness taking place at
// a "higher" level of abstraction. Essentially, an overlay wallet.
// Implementors of this interface must closely adhere to the documented
// behavior of all interface methods in order to ensure identical behavior
// across all concrete implementations.
type WalletController interface {
	// FetchInputInfo queries for the WalletController's knowledge of the
	// passed outpoint. If the base wallet determines this output is under
	// its control, then the original txout should be returned.  Otherwise,
	// a non-nil error value of ErrNotMine should be returned instead.
	FetchInputInfo(prevOut *wire.OutPoint) (*wire.TxOut, error)

	// ConfirmedBalance returns the sum of all the wallet's unspent outputs
	// that have at least confs confirmations. If confs is set to zero,
	// then all unspent outputs, including those currently in the mempool
	// will be included in the final sum.
	//
	// NOTE: Only witness outputs should be included in the computation of
	// the total spendable balance of the wallet. We require this as only
	// witness inputs can be used for funding channels.
	ConfirmedBalance(confs int32) (btcutil.Amount, error)

	// NewAddress returns the next external or internal address for the
	// wallet dictated by the value of the `change` parameter. If change is
	// true, then an internal address should be used, otherwise an external
	// address should be returned. The type of address returned is dictated
	// by the wallet's capabilities, and may be of type: p2sh, p2wkh,
	// p2wsh, etc.
	NewAddress(addrType AddressType, change bool) (btcutil.Address, error)

	// LastUnusedAddress returns the last *unused* address known by the
	// wallet. An address is unused if it hasn't received any payments.
	// This can be useful in UIs in order to continually show the
	// "freshest" address without having to worry about "address inflation"
	// caused by continual refreshing. Similar to NewAddress it can derive
	// a specified address type. By default, this is a non-change address.
	LastUnusedAddress(addrType AddressType) (btcutil.Address, error)

	// IsOurAddress checks if the passed address belongs to this wallet
	IsOurAddress(a btcutil.Address) bool

	// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying
	// out to the specified outputs. In the case the wallet has insufficient
	// funds, or the outputs are non-standard, an error should be returned.
	// This method also takes the target fee expressed in sat/kw that should
	// be used when crafting the transaction.
	SendOutputs(outputs []*wire.TxOut,
		feeRate SatPerKWeight) (*wire.MsgTx, error)

	// CreateSimpleTx creates a Bitcoin transaction paying to the specified
	// outputs. The transaction is not broadcasted to the network. In the
	// case the wallet has insufficient funds, or the outputs are
	// non-standard, an error should be returned. This method also takes
	// the target fee expressed in sat/kw that should be used when crafting
	// the transaction.
	//
	// NOTE: The dryRun argument can be set true to create a tx that
	// doesn't alter the database. A tx created with this set to true
	// SHOULD NOT be broadcasted.
	CreateSimpleTx(outputs []*wire.TxOut, feeRate SatPerKWeight,
		dryRun bool) (*txauthor.AuthoredTx, error)

	// ListUnspentWitness returns all unspent outputs which are version 0
	// witness programs. The 'minconfirms' and 'maxconfirms' parameters
	// indicate the minimum and maximum number of confirmations an output
	// needs in order to be returned by this method. Passing -1 as
	// 'minconfirms' indicates that even unconfirmed outputs should be
	// returned. Using MaxInt32 as 'maxconfirms' implies returning all
	// outputs with at least 'minconfirms'.
	ListUnspentWitness(minconfirms, maxconfirms int32) ([]*Utxo, error)

	// ListTransactionDetails returns a list of all transactions which are
	// relevant to the wallet.
	ListTransactionDetails() ([]*TransactionDetail, error)

	// LockOutpoint marks an outpoint as locked meaning it will no longer
	// be deemed as eligible for coin selection. Locking outputs are
	// utilized in order to avoid race conditions when selecting inputs for
	// usage when funding a channel.
	LockOutpoint(o wire.OutPoint)

	// UnlockOutpoint unlocks a previously locked output, marking it
	// eligible for coin selection.
	UnlockOutpoint(o wire.OutPoint)

	// PublishTransaction performs cursory validation (dust checks, etc),
	// then finally broadcasts the passed transaction to the Bitcoin network.
	// If the transaction is rejected because it is conflicting with an
	// already known transaction, ErrDoubleSpend is returned. If the
	// transaction is already known (published already), no error will be
	// returned. Other error returned depends on the currently active chain
	// backend.
	PublishTransaction(tx *wire.MsgTx) error

	// SubscribeTransactions returns a TransactionSubscription client which
	// is capable of receiving async notifications as new transactions
	// related to the wallet are seen within the network, or found in
	// blocks.
	//
	// NOTE: a non-nil error should be returned if notifications aren't
	// supported.
	//
	// TODO(roasbeef): make distinct interface?
	SubscribeTransactions() (TransactionSubscription, error)

	// IsSynced returns a boolean indicating if from the PoV of the wallet,
	// it has fully synced to the current best block in the main chain.
	// It also returns an int64 indicating the timestamp of the best block
	// known to the wallet, expressed in Unix epoch time
	IsSynced() (bool, int64, error)

	// Start initializes the wallet, making any necessary connections,
	// starting up required goroutines etc.
	Start() error

	// Stop signals the wallet for shutdown. Shutdown may entail closing
	// any active sockets, database handles, stopping goroutines, etc.
	Stop() error

	// BackEnd returns a name for the wallet's backing chain service,
	// which could be e.g. btcd, bitcoind, neutrino, or another consensus
	// service.
	BackEnd() string
}

// BlockChainIO is a dedicated source which will be used to obtain queries
// related to the current state of the blockchain. The data returned by each of
// the defined methods within this interface should always return the most up
// to date data possible.
//
// TODO(roasbeef): move to diff package perhaps?
// TODO(roasbeef): move publish txn here?
type BlockChainIO interface {
	// GetBestBlock returns the current height and block hash of the valid
	// most-work chain the implementation is aware of.
	GetBestBlock() (*chainhash.Hash, int32, error)

	// GetUtxo attempts to return the passed outpoint if it's still a
	// member of the utxo set. The passed height hint should be the "birth
	// height" of the passed outpoint. The script passed should be the
	// script that the outpoint creates. In the case that the output is in
	// the UTXO set, then the output corresponding to that output is
	// returned.  Otherwise, a non-nil error will be returned.
	GetUtxo(op *wire.OutPoint, pkScript []byte,
		heightHint uint32) (*wire.TxOut, error)

	// GetBlockHash returns the hash of the block in the best blockchain
	// at the given height.
	GetBlockHash(blockHeight int64) (*chainhash.Hash, error)

	// GetBlock returns the block in the main chain identified by the given
	// hash.
	GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error)
}

// MessageSigner represents an abstract object capable of signing arbitrary
// messages. The capabilities of this interface are used to sign announcements
// to the network, or just arbitrary messages that leverage the wallet's keys
// to attest to some message.
type MessageSigner interface {
	// SignMessage attempts to sign a target message with the private key
	// that corresponds to the passed public key. If the target private key
	// is unable to be found, then an error will be returned. The actual
	// digest signed is the double SHA-256 of the passed message.
	SignMessage(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error)
}

// PreimageCache is an interface that represents a global cache for preimages.
// We'll utilize this cache to communicate the discovery of new preimages
// across sub-systems.
type PreimageCache interface {
	// LookupPreimage attempts to look up a preimage according to its hash.
	// If found, the preimage is returned along with true for the second
	// argument. Otherwise, it'll return false.
	LookupPreimage(hash lntypes.Hash) (lntypes.Preimage, bool)

	// AddPreimages adds a batch of newly discovered preimages to the global
	// cache, and also signals any subscribers of the newly discovered
	// witness.
	AddPreimages(preimages ...lntypes.Preimage) error
}

// WalletDriver represents a "driver" for a particular concrete
// WalletController implementation. A driver is identified by a globally unique
// string identifier along with a 'New()' method which is responsible for
// initializing a particular WalletController concrete implementation.
type WalletDriver struct {
	// WalletType is a string which uniquely identifies the
	// WalletController that this driver, drives.
	WalletType string

	// New creates a new instance of a concrete WalletController
	// implementation given a variadic set up arguments. The function takes
	// a variadic number of interface parameters in order to provide
	// initialization flexibility, thereby accommodating several potential
	// WalletController implementations.
	New func(args ...interface{}) (WalletController, error)

	// BackEnds returns a list of available chain service drivers for the
	// wallet driver. This could be e.g. bitcoind, btcd, neutrino, etc.
	BackEnds func() []string
}

var (
	wallets     = make(map[string]*WalletDriver)
	registerMtx sync.Mutex
)

// RegisteredWallets returns a slice of all currently registered notifiers.
//
// NOTE: This function is safe for concurrent access.
func RegisteredWallets() []*WalletDriver {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	registeredWallets := make([]*WalletDriver, 0, len(wallets))
	for _, wallet := range wallets {
		registeredWallets = append(registeredWallets, wallet)
	}

	return registeredWallets
}

// RegisterWallet registers a WalletDriver which is capable of driving a
// concrete WalletController interface. In the case that this driver has
// already been registered, an error is returned.
//
// NOTE: This function is safe for concurrent access.
func RegisterWallet(driver *WalletDriver) error {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	if _, ok := wallets[driver.WalletType]; ok {
		return fmt.Errorf("wallet already registered")
	}

	wallets[driver.WalletType] = driver

	return nil
}

// SupportedWallets returns a slice of strings that represents the wallet
// drivers that have been registered and are therefore supported.
//
// NOTE: This function is safe for concurrent access.
func SupportedWallets() []string {
	registerMtx.Lock()
	defer registerMtx.Unlock()

	supportedWallets := make([]string, 0, len(wallets))
	for walletName := range wallets {
		supportedWallets = append(supportedWallets, walletName)
	}

	return supportedWallets
}
<|endoftext|>


<commit_before>package the_platinum_searcher

import "testing"

type assert struct {
	patterns []string
	file     file
	expect   bool
}

type file struct {
	path  string
	isDir bool
}

func TestGenericIgnoreMatch(t *testing.T) {
	asserts := []assert{
		assert{[]string{"a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir"}, file{"dir", true}, true},
		assert{[]string{"dir"}, file{"dir/a.txt", false}, false},
	}

	for _, assert := range asserts {
		gi := genericIgnore(assert.patterns)
		result := gi.Match(assert.file.path, assert.file.isDir)
		if result != assert.expect {
			t.Errorf("Match should return %t, got %t on %v", assert.expect, result, assert)
		}

	}
}

func TestGitIgnoreMatch(t *testing.T) {

	asserts := []assert{
		assert{[]string{"a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"dir/a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir/*.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir2/a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir3/a.txt"}, file{"dir1/dir2/dir3/a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir2/a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir"}, file{"dir", true}, true},
		assert{[]string{"dir/"}, file{"dir", true}, true},
		assert{[]string{"dir/"}, file{"dir", false}, false},
		assert{[]string{"/a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"/dir/a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"/dir1/a.txt"}, file{"dir/dir1/a.txt", false}, false},
		assert{[]string{"/a.txt"}, file{"dir/a.txt", false}, false},
		assert{[]string{"a.txt", "b.txt"}, file{"dir/b.txt", false}, true},
		assert{[]string{"*.txt", "!b.txt"}, file{"dir/b.txt", false}, false},
		assert{[]string{"dir/*.txt", "!dir/b.txt"}, file{"dir/b.txt", false}, false},
		assert{[]string{"dir/*.txt", "!/b.txt"}, file{"dir/b.txt", false}, true},
	}

	for _, assert := range asserts {
		gi := newGitIgnore(".", 1, assert.patterns)
		result := gi.Match(assert.file.path, assert.file.isDir)
		if result != assert.expect {
			t.Errorf("Match should return %t, got %t on %v", assert.expect, result, assert)
		}
	}
}
<commit_msg>Added a test that exist subdirectory gitignore and same directory struct.<commit_after>package the_platinum_searcher

import "testing"

type assert struct {
	patterns []string
	file     file
	expect   bool
}

type file struct {
	path  string
	isDir bool
}

func TestGenericIgnoreMatch(t *testing.T) {
	asserts := []assert{
		assert{[]string{"a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir"}, file{"dir", true}, true},
		assert{[]string{"dir"}, file{"dir/a.txt", false}, false},
	}

	for _, assert := range asserts {
		gi := genericIgnore(assert.patterns)
		result := gi.Match(assert.file.path, assert.file.isDir)
		if result != assert.expect {
			t.Errorf("Match should return %t, got %t on %v", assert.expect, result, assert)
		}

	}
}

func TestGitIgnoreMatch(t *testing.T) {

	asserts := []assert{
		assert{[]string{"a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"dir/a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir/*.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir2/a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir3/a.txt"}, file{"dir1/dir2/dir3/a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir2/a.txt"}, file{"dir1/dir2/a.txt", false}, true},
		assert{[]string{"dir"}, file{"dir", true}, true},
		assert{[]string{"dir/"}, file{"dir", true}, true},
		assert{[]string{"dir/"}, file{"dir", false}, false},
		assert{[]string{"/a.txt"}, file{"a.txt", false}, true},
		assert{[]string{"/dir/a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"/dir1/a.txt"}, file{"dir/dir1/a.txt", false}, false},
		assert{[]string{"/a.txt"}, file{"dir/a.txt", false}, false},
		assert{[]string{"a.txt", "b.txt"}, file{"dir/b.txt", false}, true},
		assert{[]string{"*.txt", "!b.txt"}, file{"dir/b.txt", false}, false},
		assert{[]string{"dir/*.txt", "!dir/b.txt"}, file{"dir/b.txt", false}, false},
		assert{[]string{"dir/*.txt", "!/b.txt"}, file{"dir/b.txt", false}, true},
	}

	for _, assert := range asserts {
		gi := newGitIgnore(".", 1, assert.patterns)
		result := gi.Match(assert.file.path, assert.file.isDir)
		if result != assert.expect {
			t.Errorf("Match should return %t, got %t on %v", assert.expect, result, assert)
		}
	}
}

func TestGitIgnoreMatchOnSubDirectory(t *testing.T) {

	asserts := []assert{
		assert{[]string{"a.txt"}, file{"dir/a.txt", false}, true},
		assert{[]string{"dir/a.txt"}, file{"dir/a.txt", false}, false},
		assert{[]string{"dir/a.txt"}, file{"dir/dir/a.txt", false}, true},
	}

	for _, assert := range asserts {
		gi := newGitIgnore(".", 2, assert.patterns)
		result := gi.Match(assert.file.path, assert.file.isDir)
		if result != assert.expect {
			t.Errorf("Match should return %t, got %t on %v", assert.expect, result, assert)
		}
	}
}
<|endoftext|>


<commit_before>package e2e

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"testing"
	"time"
	"strings"

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

func isSuccess(execCmd *exec.Cmd, retries int, keyword string) (bool, string) {
	numAttempts := retries
	success := false
	var out bytes.Buffer

	for numAttempts > 0 {
		time.Sleep(2 * time.Second)

		cmd := *execCmd
		cmd.Stdout = &out

		err := cmd.Run()
		if err != nil {
			return false, ""
		}

		success = (out.String() != "" && !strings.Contains(out.String(), keyword))
		if success {
			return success, out.String()
		}

		out.Reset()
		numAttempts -= 1
	}

	return success, out.String()
}

func allNomadNodesAreReady(retries int) (bool, string) {
	cmd := exec.Command("nomad", "node-status")
	return isSuccess(cmd, retries, "initializing")
}

func jobIsReady(retries int, jobName string) (bool, string) {
	cmd := exec.Command("nomad", "job", "status", jobName)
	return isSuccess(cmd, retries, "pending")
}

// requires nomad executable on the path
func startCluster(clusterConfig []string) (func(), error) {
	cmds := make([]*exec.Cmd, 0)

	for _, agentConfig := range clusterConfig {
		cmd := exec.Command("nomad", "agent", "-config", agentConfig)
		err := cmd.Start()

		if err != nil {
			return func() {}, err
		}

		cmds = append(cmds, cmd)
	}

	f := func() {
		for _, cmd := range cmds {
			cmd.Process.Kill()
		}
	}

	return f, nil
}

func TestJobMigrations(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	clusterConfig := []string{"server.hcl", "client1.hcl", "client2.hcl"}
	stopCluster, err := startCluster(clusterConfig)
	assert.Nil(err)
	defer stopCluster()

	isReady, _ := allNomadNodesAreReady(10)
	assert.True(isReady)

	fh, err := ioutil.TempFile("", "nomad-sleep-1")
	assert.Nil(err)

	defer os.Remove(fh.Name())
	_, err = fh.WriteString(`
	job "sleep" {
		type = "batch"
		datacenters = ["dc1"]
		constraint {
			attribute = "${meta.secondary}"
			value     = 1
		}
		group "group1" {
			restart {
				mode = "fail"
			}
			count = 1
			ephemeral_disk {
				migrate = true
				sticky = true
			}
			task "sleep" {
				template {
					data = "hello world"
					destination = "/local/hello-world"
				}
				driver = "exec"
				config {
					command = "/bin/sleep"
					args = [ "infinity" ]
				}
			}
		}
	}`)

	assert.Nil(err)

	jobCmd := exec.Command("nomad", "run", fh.Name())
	err = jobCmd.Run()
	assert.Nil(err)

	isFirstJobReady, firstJoboutput := jobIsReady(20, "sleep")
	assert.True(isFirstJobReady)
	assert.NotContains(firstJoboutput, "failed")

	fh2, err := ioutil.TempFile("", "nomad-sleep-2")
	assert.Nil(err)

	defer os.Remove(fh2.Name())
	_, err = fh2.WriteString(`
	job "sleep" {
		type = "batch"
		datacenters = ["dc1"]
		constraint {
			attribute = "${meta.secondary}"
			value     = 1
		}
		group "group1" {
			restart {
				mode     = "fail"
			}
			count = 1
			ephemeral_disk {
				migrate = true
				sticky = true
			}
			task "sleep" {
				driver = "exec"

				config {
					command = "test"
					args = [ "-f", "/local/hello-world" ]
				}
			}
		}
	}`)

	assert.Nil(err)

	secondJobCmd := exec.Command("nomad", "run", fh2.Name())
	err = secondJobCmd.Run()
	assert.Nil(err)

	isReady, jobOutput := jobIsReady(20, "sleep")
	assert.True(isReady)
	assert.NotContains(jobOutput, "failed")
	assert.Contains(jobOutput, "complete")
}
<commit_msg>fix up goimports<commit_after>package e2e

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"

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

func isSuccess(execCmd *exec.Cmd, retries int, keyword string) (bool, string) {
	numAttempts := retries
	success := false
	var out bytes.Buffer

	for numAttempts > 0 {
		time.Sleep(2 * time.Second)

		cmd := *execCmd
		cmd.Stdout = &out

		err := cmd.Run()
		if err != nil {
			return false, ""
		}

		success = (out.String() != "" && !strings.Contains(out.String(), keyword))
		if success {
			return success, out.String()
		}

		out.Reset()
		numAttempts -= 1
	}

	return success, out.String()
}

func allNomadNodesAreReady(retries int) (bool, string) {
	cmd := exec.Command("nomad", "node-status")
	return isSuccess(cmd, retries, "initializing")
}

func jobIsReady(retries int, jobName string) (bool, string) {
	cmd := exec.Command("nomad", "job", "status", jobName)
	return isSuccess(cmd, retries, "pending")
}

// requires nomad executable on the path
func startCluster(clusterConfig []string) (func(), error) {
	cmds := make([]*exec.Cmd, 0)

	for _, agentConfig := range clusterConfig {
		cmd := exec.Command("nomad", "agent", "-config", agentConfig)
		err := cmd.Start()

		if err != nil {
			return func() {}, err
		}

		cmds = append(cmds, cmd)
	}

	f := func() {
		for _, cmd := range cmds {
			cmd.Process.Kill()
		}
	}

	return f, nil
}

func TestJobMigrations(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	clusterConfig := []string{"server.hcl", "client1.hcl", "client2.hcl"}
	stopCluster, err := startCluster(clusterConfig)
	assert.Nil(err)
	defer stopCluster()

	isReady, _ := allNomadNodesAreReady(10)
	assert.True(isReady)

	fh, err := ioutil.TempFile("", "nomad-sleep-1")
	assert.Nil(err)

	defer os.Remove(fh.Name())
	_, err = fh.WriteString(`
	job "sleep" {
		type = "batch"
		datacenters = ["dc1"]
		constraint {
			attribute = "${meta.secondary}"
			value     = 1
		}
		group "group1" {
			restart {
				mode = "fail"
			}
			count = 1
			ephemeral_disk {
				migrate = true
				sticky = true
			}
			task "sleep" {
				template {
					data = "hello world"
					destination = "/local/hello-world"
				}
				driver = "exec"
				config {
					command = "/bin/sleep"
					args = [ "infinity" ]
				}
			}
		}
	}`)

	assert.Nil(err)

	jobCmd := exec.Command("nomad", "run", fh.Name())
	err = jobCmd.Run()
	assert.Nil(err)

	isFirstJobReady, firstJoboutput := jobIsReady(20, "sleep")
	assert.True(isFirstJobReady)
	assert.NotContains(firstJoboutput, "failed")

	fh2, err := ioutil.TempFile("", "nomad-sleep-2")
	assert.Nil(err)

	defer os.Remove(fh2.Name())
	_, err = fh2.WriteString(`
	job "sleep" {
		type = "batch"
		datacenters = ["dc1"]
		constraint {
			attribute = "${meta.secondary}"
			value     = 1
		}
		group "group1" {
			restart {
				mode     = "fail"
			}
			count = 1
			ephemeral_disk {
				migrate = true
				sticky = true
			}
			task "sleep" {
				driver = "exec"

				config {
					command = "test"
					args = [ "-f", "/local/hello-world" ]
				}
			}
		}
	}`)

	assert.Nil(err)

	secondJobCmd := exec.Command("nomad", "run", fh2.Name())
	err = secondJobCmd.Run()
	assert.Nil(err)

	isReady, jobOutput := jobIsReady(20, "sleep")
	assert.True(isReady)
	assert.NotContains(jobOutput, "failed")
	assert.Contains(jobOutput, "complete")
}
<|endoftext|>


<commit_before>package query

import (
	"database/sql"
	"strings"
	"time"

	"github.com/Rican7/retry/jitter"
	"github.com/canonical/go-dqlite/driver"
	"github.com/mattn/go-sqlite3"
	"github.com/pkg/errors"

	"github.com/lxc/lxd/shared/logger"
)

const maxRetries = 250

// Retry wraps a function that interacts with the database, and retries it in
// case a transient error is hit.
//
// This should by typically used to wrap transactions.
func Retry(f func() error) error {
	// TODO: the retry loop should be configurable.
	var err error
	for i := 0; i < maxRetries; i++ {
		err = f()
		if err != nil {
			// No point in re-trying or logging a no-row error.
			if err == sql.ErrNoRows {
				break
			}

			// Process actual errors.
			logger.Debugf("Database error: %#v", err)
			if IsRetriableError(err) {
				if i == maxRetries {
					logger.Warnf("Give up retrying database error: %v", err)
					break
				}
				logger.Debugf("Retry failed db interaction (%v)", err)
				time.Sleep(jitter.Deviation(nil, 0.8)(100 * time.Millisecond))
				continue
			}
		}
		break
	}

	return err
}

// IsRetriableError returns true if the given error might be transient and the
// interaction can be safely retried.
func IsRetriableError(err error) bool {
	err = errors.Cause(err)
	if err == nil {
		return false
	}

	if err == sqlite3.ErrLocked || err == sqlite3.ErrBusy {
		return true
	}

	if strings.Contains(err.Error(), "database is locked") {
		return true
	}

	if strings.Contains(err.Error(), "bad connection") {
		return true
	}

	return false
}
<commit_msg>db: Always retry driver.ErrBusy, regardless of the error message<commit_after>package query

import (
	"database/sql"
	"strings"
	"time"

	"github.com/Rican7/retry/jitter"
	"github.com/canonical/go-dqlite/driver"
	"github.com/mattn/go-sqlite3"
	"github.com/pkg/errors"

	"github.com/lxc/lxd/shared/logger"
)

const maxRetries = 250

// Retry wraps a function that interacts with the database, and retries it in
// case a transient error is hit.
//
// This should by typically used to wrap transactions.
func Retry(f func() error) error {
	// TODO: the retry loop should be configurable.
	var err error
	for i := 0; i < maxRetries; i++ {
		err = f()
		if err != nil {
			// No point in re-trying or logging a no-row error.
			if err == sql.ErrNoRows {
				break
			}

			// Process actual errors.
			logger.Debugf("Database error: %#v", err)
			if IsRetriableError(err) {
				if i == maxRetries {
					logger.Warnf("Give up retrying database error: %v", err)
					break
				}
				logger.Debugf("Retry failed db interaction (%v)", err)
				time.Sleep(jitter.Deviation(nil, 0.8)(100 * time.Millisecond))
				continue
			}
		}
		break
	}

	return err
}

// IsRetriableError returns true if the given error might be transient and the
// interaction can be safely retried.
func IsRetriableError(err error) bool {
	err = errors.Cause(err)
	if err == nil {
		return false
	}

	if err, ok := err.(driver.Error); ok && err.Code == driver.ErrBusy {
		return true
	}

	if err == sqlite3.ErrLocked || err == sqlite3.ErrBusy {
		return true
	}

	if strings.Contains(err.Error(), "database is locked") {
		return true
	}

	if strings.Contains(err.Error(), "bad connection") {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"regexp"
	"strconv"
)

func networkValidName(value string) error {
	// Validate the length
	if len(value) < 2 {
		return fmt.Errorf("Interface name is too short (minimum 2 characters)")
	}

	if len(value) > 15 {
		return fmt.Errorf("Interface name is too long (maximum 15 characters)")
	}

	// Validate the character set
	match, _ := regexp.MatchString("^[-a-zA-Z0-9]*$", value)
	if !match {
		return fmt.Errorf("Interface name contains invalid characters")
	}

	return nil
}

func networkValidPort(value string) error {
	if value == "" {
		return nil
	}

	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return fmt.Errorf("Invalid value for an integer: %s", value)
	}

	if valueInt < 1 || valueInt > 65536 {
		return fmt.Errorf("Invalid port number: %s", value)
	}

	return nil
}

func networkValidAddress(value string) error {
	err := networkValidAddressV4(value)
	if err == nil {
		return nil
	}

	err = networkValidAddressV6(value)
	if err == nil {
		return nil
	}

	return fmt.Errorf("Not a valid address: %s", value)
}

func networkValidAddressV6(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() != nil {
		return fmt.Errorf("Not an IPv6 address: %s", value)
	}

	if ip.String() == net.IP.String() {
		return fmt.Errorf("Not a usable IPv6 address: %s", value)
	}

	return nil
}

func networkValidNetworkV6(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() != nil {
		return fmt.Errorf("Not an IPv6 network: %s", value)
	}

	if ip.String() != net.IP.String() {
		return fmt.Errorf("Not an IPv6 network address: %s", value)
	}

	return nil
}

func networkValidAddressV4(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() == nil {
		return fmt.Errorf("Not an IPv4 address: %s", value)
	}

	if ip.String() == net.IP.String() {
		return fmt.Errorf("Not a usable IPv4 address: %s", value)
	}

	return nil
}

func networkValidNetworkV4(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() == nil {
		return fmt.Errorf("Not an IPv4 network: %s", value)
	}

	if ip.String() != net.IP.String() {
		return fmt.Errorf("Not an IPv4 network address: %s", value)
	}

	return nil
}
<commit_msg>network: Add support for auto subnet generation<commit_after>package main

import (
	"bufio"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"math"
	"math/big"
	"math/rand"
	"net"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

func networkGetIP(subnet *net.IPNet, host int64) net.IP {
	// Convert IP to a big int
	bigIP := big.NewInt(0)
	bigIP.SetBytes(subnet.IP.To16())

	// Deal with negative offsets
	bigHost := big.NewInt(host)
	bigCount := big.NewInt(host)
	if host < 0 {
		mask, size := subnet.Mask.Size()

		bigHosts := big.NewFloat(0)
		bigHosts.SetFloat64((math.Pow(2, float64(size-mask))))
		bigHostsInt, _ := bigHosts.Int(nil)

		bigCount.Set(bigHostsInt)
		bigCount.Add(bigCount, bigHost)
	}

	// Get the new IP int
	bigIP.Add(bigIP, bigCount)

	// Generate an IPv6
	if subnet.IP.To4() == nil {
		newIp := make(net.IP, 16)
		newIp = bigIP.Bytes()
		return newIp
	}

	// Generate an IPv4
	newIp := make(net.IP, 4)
	binary.BigEndian.PutUint32(newIp, uint32(bigIP.Int64()))
	return newIp
}

func networkPingSubnet(subnet *net.IPNet) bool {
	var fail bool
	var failLock sync.Mutex
	var wgChecks sync.WaitGroup

	ping := func(ip net.IP) {
		defer wgChecks.Done()

		cmd := "ping"
		if ip.To4() == nil {
			cmd = "ping6"
		}

		_, err := exec.Command(cmd, "-n", "-q", ip.String(), "-c", "1", "-W", "1").CombinedOutput()
		if err != nil {
			// Remote didn't answer
			return
		}

		// Remote answered
		failLock.Lock()
		fail = true
		failLock.Unlock()
	}

	poke := func(ip net.IP) {
		defer wgChecks.Done()

		addr := fmt.Sprintf("%s:22", ip.String())
		if ip.To4() == nil {
			addr = fmt.Sprintf("[%s]:22", ip.String())
		}

		_, err := net.DialTimeout("tcp", addr, time.Second)
		if err == nil {
			// Remote answered
			failLock.Lock()
			fail = true
			failLock.Unlock()
			return
		}
	}

	// Ping first IP
	wgChecks.Add(1)
	go ping(networkGetIP(subnet, 1))

	// Poke port on first IP
	wgChecks.Add(1)
	go poke(networkGetIP(subnet, 1))

	// Ping check
	if subnet.IP.To4() != nil {
		// Ping last IP
		wgChecks.Add(1)
		go ping(networkGetIP(subnet, -2))

		// Poke port on last IP
		wgChecks.Add(1)
		go poke(networkGetIP(subnet, -2))
	}

	wgChecks.Wait()

	return fail
}

func networkInRoutingTable(subnet *net.IPNet) bool {
	filename := "route"
	if subnet.IP.To4() == nil {
		filename = "ipv6_route"
	}

	file, err := os.Open(fmt.Sprintf("/proc/net/%s", filename))
	if err != nil {
		return false
	}
	defer file.Close()

	scanner := bufio.NewReader(file)
	for {
		line, _, err := scanner.ReadLine()
		if err != nil {
			break
		}

		fields := strings.Fields(string(line))

		// Get the IP
		ip := net.IP{}
		if filename == "ipv6_route" {
			ip, err = hex.DecodeString(fields[0])
			if err != nil {
				continue
			}
		} else {
			bytes, err := hex.DecodeString(fields[1])
			if err != nil {
				continue
			}

			ip = net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
		}

		// Get the mask
		mask := net.IPMask{}
		if filename == "ipv6_route" {
			size, err := strconv.ParseInt(fmt.Sprintf("0x%s", fields[1]), 0, 64)
			if err != nil {
				continue
			}

			mask = net.CIDRMask(int(size), 128)
		} else {
			bytes, err := hex.DecodeString(fields[7])
			if err != nil {
				continue
			}

			mask = net.IPv4Mask(bytes[3], bytes[2], bytes[1], bytes[0])
		}

		// Generate a new network
		lineNet := net.IPNet{IP: ip, Mask: mask}

		// Ignore default gateway
		if lineNet.IP.Equal(net.ParseIP("::")) {
			continue
		}

		if lineNet.IP.Equal(net.ParseIP("0.0.0.0")) {
			continue
		}

		// Check if we have a route to our new subnet
		if lineNet.Contains(subnet.IP) {
			return true
		}
	}

	return false
}

func networkRandomSubnetV4() string {
	var cidr string

	for {
		cidr = fmt.Sprintf("10.%d.%d.1/24", rand.Intn(255), rand.Intn(255))
		_, subnet, err := net.ParseCIDR(cidr)
		if err != nil {
			continue
		}

		if networkInRoutingTable(subnet) {
			continue
		}

		if networkPingSubnet(subnet) {
			continue
		}

		break
	}

	return cidr
}

func networkRandomSubnetV6() string {
	var cidr string

	for {
		cidr = fmt.Sprintf("fd00:%x:%x:%x::1/64", rand.Intn(65535), rand.Intn(65535), rand.Intn(65535))
		_, subnet, err := net.ParseCIDR(cidr)
		if err != nil {
			continue
		}

		if networkInRoutingTable(subnet) {
			continue
		}

		if networkPingSubnet(subnet) {
			continue
		}

		break
	}

	return cidr
}

func networkValidName(value string) error {
	// Validate the length
	if len(value) < 2 {
		return fmt.Errorf("Interface name is too short (minimum 2 characters)")
	}

	if len(value) > 15 {
		return fmt.Errorf("Interface name is too long (maximum 15 characters)")
	}

	// Validate the character set
	match, _ := regexp.MatchString("^[-a-zA-Z0-9]*$", value)
	if !match {
		return fmt.Errorf("Interface name contains invalid characters")
	}

	return nil
}

func networkValidPort(value string) error {
	if value == "" {
		return nil
	}

	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return fmt.Errorf("Invalid value for an integer: %s", value)
	}

	if valueInt < 1 || valueInt > 65536 {
		return fmt.Errorf("Invalid port number: %s", value)
	}

	return nil
}

func networkValidAddress(value string) error {
	err := networkValidAddressV4(value)
	if err == nil {
		return nil
	}

	err = networkValidAddressV6(value)
	if err == nil {
		return nil
	}

	return fmt.Errorf("Not a valid address: %s", value)
}

func networkValidAddressV6(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() != nil {
		return fmt.Errorf("Not an IPv6 address: %s", value)
	}

	if ip.String() == net.IP.String() {
		return fmt.Errorf("Not a usable IPv6 address: %s", value)
	}

	return nil
}

func networkValidNetworkV6(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() != nil {
		return fmt.Errorf("Not an IPv6 network: %s", value)
	}

	if ip.String() != net.IP.String() {
		return fmt.Errorf("Not an IPv6 network address: %s", value)
	}

	return nil
}

func networkValidAddressV4(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() == nil {
		return fmt.Errorf("Not an IPv4 address: %s", value)
	}

	if ip.String() == net.IP.String() {
		return fmt.Errorf("Not a usable IPv4 address: %s", value)
	}

	return nil
}

func networkValidNetworkV4(value string) error {
	if value == "" {
		return nil
	}

	ip, net, err := net.ParseCIDR(value)
	if err != nil {
		return err
	}

	if ip.To4() == nil {
		return fmt.Errorf("Not an IPv4 network: %s", value)
	}

	if ip.String() != net.IP.String() {
		return fmt.Errorf("Not an IPv4 network address: %s", value)
	}

	return nil
}
<|endoftext|>


<commit_before>package m_etcd

import (
	"fmt"
	"os"
	"strings"

	"code.google.com/p/go-uuid/uuid"

	"github.com/coreos/go-etcd/etcd"
	"github.com/lytics/metafora"
)

type EtcdCoordinator struct {
	Client    *etcd.Client
	cordCtx   metafora.CoordinatorContext
	Namespace string
	TaskPath  string

	taskWatcher *EtcdWatcher

	NodeId         string
	CommandPath    string
	commandWatcher *EtcdWatcher
}

type Watcher func(cordCtx metafora.CoordinatorContext)
type EtcdWatcher struct {
	cordCtx      metafora.CoordinatorContext
	path         string
	responseChan chan *etcd.Response
	stopChan     chan bool
	errorChan    chan error
	client       *etcd.Client
}

func (w *EtcdWatcher) StartWatching() {
	go func() {
		const recursive = true
		const etcdIndex = uint64(0) //0 == latest version

		//TODO, Im guessing that watch only picks up new nodes.
		//   We need to manually do an ls at startup and dump the results to taskWatcherResponses,
		//   after we filter out all non-claimed tasks.
		_, err := w.client.Watch(
			w.path,
			etcdIndex,
			recursive,
			w.responseChan,
			w.stopChan)
		w.errorChan <- err
	}()
}

func (w *EtcdWatcher) Close() error {
	w.stopChan <- true

	select {
	case err := <-w.errorChan:
		return err
	default:
	}
	return nil
}

/*
Etcd paths:
/{namespace}/tasks/{task_id}/
/{namespace}/tasks/{task_id}/owner/

/{namespace}/node/{node_id}/command

TODO do we need a EtcdCoordinatorConfig?

*/
func NewEtcdCoordinator(nodeId, namespace string, client *etcd.Client) metafora.Coordinator {
	namespace = strings.Trim(namespace, "/ ")

	if nodeId == "" {
		hn, _ := os.Hostname()
		//Adding the UUID incase we run two nodes on the same box.
		// TODO lets move this to the Readme as part of the example of calling NewEtcdCoordinator.
		// Then just remove the Autocreated nodeId.
		nodeId = hn + string(uuid.NewRandom())
	}

	nodeId = strings.Trim(nodeId, "/ ")

	etcd := &EtcdCoordinator{
		Client:    client,
		Namespace: namespace,

		TaskPath:    fmt.Sprintf("/%s/%s", namespace, TasksPath), //TODO MAKE A PACKAGE FUNC TO CREATE THIS PATH.
		taskWatcher: nil,

		NodeId:         nodeId,
		CommandPath:    fmt.Sprintf("/%s/%s/%s/%s", namespace, NodesPath, nodeId, CommandsPath),
		commandWatcher: nil,
	}

	return etcd
}

// Init is called once by the consumer to provide a Logger to Coordinator
// implementations.
func (ec *EtcdCoordinator) Init(cordCtx metafora.CoordinatorContext) {

	ec.cordCtx = cordCtx
	ec.taskWatcher = &EtcdWatcher{
		cordCtx:      cordCtx,
		path:         ec.TaskPath,
		responseChan: make(chan *etcd.Response),
		stopChan:     make(chan bool),
		errorChan:    make(chan error),
		client:       ec.Client,
	}

	ec.commandWatcher = &EtcdWatcher{
		cordCtx:      cordCtx,
		path:         ec.CommandPath,
		responseChan: make(chan *etcd.Response),
		stopChan:     make(chan bool),
		errorChan:    make(chan error),
		client:       ec.Client,
	}
	//start up the watchers.
	//  Doing this in Init() incase we need access to the Ctx object...
	ec.taskWatcher.StartWatching()
	ec.commandWatcher.StartWatching()
}

// Watch should do a blocking watch on the broker and return a task ID that
// can be claimed.
func (ec *EtcdCoordinator) Watch() (taskID string, err error) {
	for {
		select {
		case resp := <-ec.taskWatcher.responseChan:
			taskId := ""
			ec.cordCtx.Log(metafora.LogLevelDebug, "New response from %s, res %v", ec.TaskPath, resp)
			if resp.Action != "create" {
				continue
			}
			if strings.Contains(resp.Node.Key, "owner") {
				continue
			}
			if resp.Node == nil {
				//TODO log
				continue
			}
			taskpath := strings.Split(resp.Node.Key, "/")
			if len(taskpath) == 0 {
				//TODO log
				continue
			}
			if !resp.Node.Dir {
				ec.cordCtx.Log(metafora.LogLevelWarn, "TaskID node shouldn't be a directory but a key.")
			}
			taskId = taskpath[len(taskpath)-1]

			return taskId, nil
		case err := <-ec.taskWatcher.errorChan:
			//if the watcher sends a nil, its because the etcd watcher was shutdown by Close()
			return "", err
		}
	}
}

// Claim is called by the Consumer when a Balancer has determined that a task
// ID can be claimed. Claim returns false if another consumer has already
// claimed the ID.
func (ec *EtcdCoordinator) Claim(taskID string) bool {
	key := fmt.Sprintf("%s/%s/owner", ec.TaskPath, taskID)
	res, err := ec.Client.CreateDir(key, ClaimTTL)
	if err != nil {
		ec.cordCtx.Log(metafora.LogLevelDebug, "Claim failed: err %v", err)
		return false
	}
	ec.cordCtx.Log(metafora.LogLevelDebug, "Claim successful: resp %v", res)
	return true
}

// Release deletes the claim directory.
func (ec *EtcdCoordinator) Release(taskID string) {
	key := fmt.Sprintf("%s/%s/owner", ec.TaskPath, taskID)
	//FIXME Conditionally delete only if this node is actually the owner
	_, err := ec.Client.DeleteDir(key)
	if err != nil {
		//TODO Pause and retry?!
		ec.cordCtx.Log(metafora.LogLevelError, "Release failed: %v", err)
	}
}

// Command blocks until a command for this node is received from the broker
// by the coordinator.
func (ec *EtcdCoordinator) Command() (cmd string, err error) {
	<-ec.commandWatcher.responseChan
	return "", nil
	/*  TODO 1) cleanup the log here to match that of Watch
	         2) discuss the schema for the command channel...
	         3) Add code to the close method.
	select {
	case resp := <-ec.commandWatcherResponses:
		taskId := ""
		if resp.Node.Dir {
			taskId = resp.Node.Key
		} else {
			ec.cordCtx.Log(LogLevelWarning, "Command node needs to be a dir, not a key.")
			taskId = resp.Node.Key
		}
		return taskId, nil
	case err := <-ec.commandWatcherErrs:
		return "", err
	}
	*/
}

func (ec *EtcdCoordinator) Close() error {
	ec.taskWatcher.Close()
	ec.commandWatcher.Close()
	return nil
}
<commit_msg>Link to issue #32<commit_after>package m_etcd

import (
	"fmt"
	"os"
	"strings"

	"code.google.com/p/go-uuid/uuid"

	"github.com/coreos/go-etcd/etcd"
	"github.com/lytics/metafora"
)

type EtcdCoordinator struct {
	Client    *etcd.Client
	cordCtx   metafora.CoordinatorContext
	Namespace string
	TaskPath  string

	taskWatcher *EtcdWatcher

	NodeId         string
	CommandPath    string
	commandWatcher *EtcdWatcher
}

type Watcher func(cordCtx metafora.CoordinatorContext)
type EtcdWatcher struct {
	cordCtx      metafora.CoordinatorContext
	path         string
	responseChan chan *etcd.Response
	stopChan     chan bool
	errorChan    chan error
	client       *etcd.Client
}

func (w *EtcdWatcher) StartWatching() {
	go func() {
		const recursive = true
		const etcdIndex = uint64(0) //0 == latest version

		//TODO, Im guessing that watch only picks up new nodes.
		//   We need to manually do an ls at startup and dump the results to taskWatcherResponses,
		//   after we filter out all non-claimed tasks.
		_, err := w.client.Watch(
			w.path,
			etcdIndex,
			recursive,
			w.responseChan,
			w.stopChan)
		w.errorChan <- err
	}()
}

func (w *EtcdWatcher) Close() error {
	w.stopChan <- true

	select {
	case err := <-w.errorChan:
		return err
	default:
	}
	return nil
}

/*
Etcd paths:
/{namespace}/tasks/{task_id}/
/{namespace}/tasks/{task_id}/owner/

/{namespace}/node/{node_id}/command

TODO do we need a EtcdCoordinatorConfig?

*/
func NewEtcdCoordinator(nodeId, namespace string, client *etcd.Client) metafora.Coordinator {
	namespace = strings.Trim(namespace, "/ ")

	if nodeId == "" {
		hn, _ := os.Hostname()
		//Adding the UUID incase we run two nodes on the same box.
		// TODO lets move this to the Readme as part of the example of calling NewEtcdCoordinator.
		// Then just remove the Autocreated nodeId.
		nodeId = hn + string(uuid.NewRandom())
	}

	nodeId = strings.Trim(nodeId, "/ ")

	etcd := &EtcdCoordinator{
		Client:    client,
		Namespace: namespace,

		TaskPath:    fmt.Sprintf("/%s/%s", namespace, TasksPath), //TODO MAKE A PACKAGE FUNC TO CREATE THIS PATH.
		taskWatcher: nil,

		NodeId:         nodeId,
		CommandPath:    fmt.Sprintf("/%s/%s/%s/%s", namespace, NodesPath, nodeId, CommandsPath),
		commandWatcher: nil,
	}

	return etcd
}

// Init is called once by the consumer to provide a Logger to Coordinator
// implementations.
func (ec *EtcdCoordinator) Init(cordCtx metafora.CoordinatorContext) {

	ec.cordCtx = cordCtx
	ec.taskWatcher = &EtcdWatcher{
		cordCtx:      cordCtx,
		path:         ec.TaskPath,
		responseChan: make(chan *etcd.Response),
		stopChan:     make(chan bool),
		errorChan:    make(chan error),
		client:       ec.Client,
	}

	ec.commandWatcher = &EtcdWatcher{
		cordCtx:      cordCtx,
		path:         ec.CommandPath,
		responseChan: make(chan *etcd.Response),
		stopChan:     make(chan bool),
		errorChan:    make(chan error),
		client:       ec.Client,
	}
	//start up the watchers.
	//  Doing this in Init() incase we need access to the Ctx object...
	ec.taskWatcher.StartWatching()
	ec.commandWatcher.StartWatching()
}

// Watch should do a blocking watch on the broker and return a task ID that
// can be claimed.
func (ec *EtcdCoordinator) Watch() (taskID string, err error) {
	for {
		select {
		case resp := <-ec.taskWatcher.responseChan:
			taskId := ""
			ec.cordCtx.Log(metafora.LogLevelDebug, "New response from %s, res %v", ec.TaskPath, resp)
			if resp.Action != "create" {
				continue
			}
			//FIXME There's gotta be a better way to only detect tasks #32
			if strings.Contains(resp.Node.Key, "owner") {
				continue
			}
			if resp.Node == nil {
				//TODO log
				continue
			}
			taskpath := strings.Split(resp.Node.Key, "/")
			if len(taskpath) == 0 {
				//TODO log
				continue
			}
			if !resp.Node.Dir {
				ec.cordCtx.Log(metafora.LogLevelWarn, "TaskID node shouldn't be a directory but a key.")
			}
			taskId = taskpath[len(taskpath)-1]

			return taskId, nil
		case err := <-ec.taskWatcher.errorChan:
			//if the watcher sends a nil, its because the etcd watcher was shutdown by Close()
			return "", err
		}
	}
}

// Claim is called by the Consumer when a Balancer has determined that a task
// ID can be claimed. Claim returns false if another consumer has already
// claimed the ID.
func (ec *EtcdCoordinator) Claim(taskID string) bool {
	key := fmt.Sprintf("%s/%s/owner", ec.TaskPath, taskID)
	res, err := ec.Client.CreateDir(key, ClaimTTL)
	if err != nil {
		ec.cordCtx.Log(metafora.LogLevelDebug, "Claim failed: err %v", err)
		return false
	}
	ec.cordCtx.Log(metafora.LogLevelDebug, "Claim successful: resp %v", res)
	return true
}

// Release deletes the claim directory.
func (ec *EtcdCoordinator) Release(taskID string) {
	key := fmt.Sprintf("%s/%s/owner", ec.TaskPath, taskID)
	//FIXME Conditionally delete only if this node is actually the owner
	_, err := ec.Client.DeleteDir(key)
	if err != nil {
		//TODO Pause and retry?!
		ec.cordCtx.Log(metafora.LogLevelError, "Release failed: %v", err)
	}
}

// Command blocks until a command for this node is received from the broker
// by the coordinator.
func (ec *EtcdCoordinator) Command() (cmd string, err error) {
	<-ec.commandWatcher.responseChan
	return "", nil
	/*  TODO 1) cleanup the log here to match that of Watch
	         2) discuss the schema for the command channel...
	         3) Add code to the close method.
	select {
	case resp := <-ec.commandWatcherResponses:
		taskId := ""
		if resp.Node.Dir {
			taskId = resp.Node.Key
		} else {
			ec.cordCtx.Log(LogLevelWarning, "Command node needs to be a dir, not a key.")
			taskId = resp.Node.Key
		}
		return taskId, nil
	case err := <-ec.commandWatcherErrs:
		return "", err
	}
	*/
}

func (ec *EtcdCoordinator) Close() error {
	ec.taskWatcher.Close()
	ec.commandWatcher.Close()
	return nil
}
<|endoftext|>