<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 docPrinter

import (
	"ast";
	"fmt";
	"io";
	"token";
	"unicode";
	"utf8";
	"vector";

	"astprinter";
)

// ----------------------------------------------------------------------------
// Elementary support

// TODO this should be an AST method
func isExported(name *ast.Ident) bool {
	ch, len := utf8.DecodeRuneInString(name.Value, 0);
	return unicode.IsUpper(ch);
}

func hasExportedNames(names []*ast.Ident) bool {
	for i, name := range names {
		if isExported(name) {
			return true;
		}
	}
	return false;
}

func hasExportedSpecs(specs []ast.Spec) bool {
	for i, s := range specs {
		// only called for []astSpec lists of *ast.ValueSpec
		return hasExportedNames(s.(*ast.ValueSpec).Names);
	}
	return false;
}

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

type valueDoc struct {
	decl *ast.GenDecl;  // len(decl.Specs) >= 1, and the element type is *ast.ValueSpec
}

type funcDoc struct {
	decl *ast.FuncDecl;
}

type typeDoc struct {
	decl *ast.GenDecl;  // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
	factories map[string] *funcDoc;
	methods map[string] *funcDoc;
}

type PackageDoc struct {
	name string;  // package name
	doc ast.Comments;  // package documentation, if any
	consts *vector.Vector;  // list of *valueDoc
	types map[string] *typeDoc;
	vars *vector.Vector;  // list of *valueDoc
	funcs map[string] *funcDoc;
}

func (doc *PackageDoc) PackageName() string {
	return doc.name;
}

// PackageDoc initializes a document to collect package documentation.
// The package name is provided as initial argument. Use AddPackage to
// add the AST for each source file belonging to the same package.
//
func (doc *PackageDoc) Init(name string) {
	doc.name = name;
	doc.consts = vector.New(0);
	doc.types = make(map[string] *typeDoc);
	doc.vars = vector.New(0);
	doc.funcs = make(map[string] *funcDoc);
}

func baseTypeName(typ ast.Expr) string {
	switch t := typ.(type) {
	case *ast.Ident:
		return string(t.Value);
	case *ast.StarExpr:
		return baseTypeName(t.X);
	}
	return "";
}

func (doc *PackageDoc) lookupTypeDoc(typ ast.Expr) *typeDoc {
	tdoc, found := doc.types[baseTypeName(typ)];
	if found {
		return tdoc;
	}
	return nil;
}

func (doc *PackageDoc) addType(decl *ast.GenDecl) {
	typ := decl.Specs[0].(*ast.TypeSpec);
	name := typ.Name.Value;
	tdoc := &typeDoc{decl, make(map[string] *funcDoc), make(map[string] *funcDoc)};
	doc.types[name] = tdoc;
}

func (doc *PackageDoc) addFunc(fun *ast.FuncDecl) {
	name := fun.Name.Value;
	fdoc := &funcDoc{fun};

	// determine if it should be associated with a type
	var typ *typeDoc;
	if fun.Recv != nil {
		// method
		typ = doc.lookupTypeDoc(fun.Recv.Type);
		if typ != nil {
			typ.methods[name] = fdoc;
			return;
		}
	} else {
		// perhaps a factory function
		// determine result type, if any
		if len(fun.Type.Results) >= 1 {
			res := fun.Type.Results[0];
			if len(res.Names) <= 1 {
				// exactly one (named or anonymous) result type
				typ = doc.lookupTypeDoc(res.Type);
				if typ != nil {
					typ.factories[name] = fdoc;
					return;
				}
			}
		}
	}
	// TODO other heuristics (e.g. name is "NewTypename"?)

	// ordinary function
	doc.funcs[name] = fdoc;
}

func (doc *PackageDoc) addDecl(decl ast.Decl) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		if len(d.Specs) > 0 {
			switch d.Tok {
			case token.IMPORT:
				// ignore
			case token.CONST:
				// constants are always handled as a group
				if hasExportedSpecs(d.Specs) {
					doc.consts.Push(&valueDoc{d});
				}
			case token.TYPE:
				// types are handled individually
				for i, spec := range d.Specs {
					s := spec.(*ast.TypeSpec);
					if isExported(s.Name) {
						// make a (fake) GenDecl node for this TypeSpec
						// (we need to do this here - as opposed to just
						// for printing - so we don't loose the GenDecl
						// documentation)
						var noPos token.Position;
						doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{s}, noPos});
					}
				}
			case token.VAR:
				// variables are always handled as a group
				if hasExportedSpecs(d.Specs) {
					doc.vars.Push(&valueDoc{d});
				}
			}
		}
	case *ast.FuncDecl:
		if isExported(d.Name) {
			doc.addFunc(d);
		}
	}
}

// AddProgram adds the AST of a source file belonging to the same
// package. The package names must match. If the source was added
// before, AddProgram is a no-op.
//
func (doc *PackageDoc) AddProgram(prog *ast.Program) {
	if doc.name != prog.Name.Value {
		panic("package names don't match");
	}

	// add package documentation
	// TODO what to do if there are multiple files?
	if prog.Doc != nil {
		doc.doc = prog.Doc
	}

	// add all exported declarations
	for i, decl := range prog.Decls {
		doc.addDecl(decl);
	}
}

// ----------------------------------------------------------------------------
// Printing

func htmlEscape(s []byte) []byte {
	var buf io.ByteBuffer;

	i0 := 0;
	for i := 0; i < len(s); i++ {
		var esc string;
		switch s[i] {
		case '<': esc = "<";
		case '&': esc = "&";
		default: continue;
		}
		fmt.Fprintf(&buf, "%s%s", s[i0 : i], esc);
		i0 := i+1;  // skip escaped char
	}

	// write the rest
	if i0 > 0 {
		buf.Write(s[i0 : len(s)]);
		s = buf.Data();
	}
	return s;
}

// Reduce contiguous sequences of '\t' in a string to a single '\t'.
// This will produce better results when the string is printed via
// a tabwriter.
// TODO make this functionality optional.
//
func untabify(s []byte) []byte {
	var buf io.ByteBuffer;

	i0 := 0;
	for i := 0; i < len(s); i++ {
		if s[i] == '\t' {
			i++;  // include '\t'
			buf.Write(s[i0 : i]);
			// skip additional tabs
			for i < len(s) && s[i] == '\t' {
				i++;
			}
			i0 := i;
		} else {
			i++;
		}
	}

	// write the rest
	if i0 > 0 {
		buf.Write(s[i0 : len(s)]);
		s = buf.Data();
	}
	return s;
}

func stripWhiteSpace(s []byte) []byte {
	i, j := 0, len(s);
	for i < len(s) && s[i] <= ' ' {
		i++;
	}
	for j > i && s[j-1] <= ' ' {
		j--
	}
	return s[i : j];
}

func stripCommentDelimiters(s []byte) []byte {
	switch s[1] {
	case '/': return s[2 : len(s)-1];
	case '*': return s[2 : len(s)-2];
	}
	panic();
	return nil;
}

const /* formatting mode */ (
	in_gap = iota;
	in_paragraph;
	in_preformatted;
)

func printLine(p *astPrinter.Printer, line []byte, mode int) int {
	indented := len(line) > 0 && line[0] == '\t';
	line = stripWhiteSpace(line);
	if len(line) == 0 {
		// empty line
		switch mode {
		case in_paragraph:
			p.Printf("
\n");
			mode = in_gap;
		case in_preformatted:
			p.Printf("\n");
			// remain in preformatted
		}
	} else {
		// non-empty line
		if indented {
			switch mode {
			case in_gap:
				p.Printf("
\n");
			case in_paragraph:
				p.Printf("
\n");
				p.Printf("
\n");
			}
			mode = in_preformatted;
		} else {
			switch mode {
			case in_gap:
				p.Printf("
\n");
			case in_preformatted:
				p.Printf("
\n");
				p.Printf("
\n");
			}
			mode = in_paragraph;
		}
		// print line
		p.Printf("%s\n", untabify(htmlEscape(line)));
	}
	return mode;
}

func closeMode(p *astPrinter.Printer, mode int) {
	switch mode {
	case in_paragraph:
		p.Printf("
\n");
	case in_preformatted:
		p.Printf("
\n");
	}
}

func printComments(p *astPrinter.Printer, comment ast.Comments) {
	mode := in_gap;
	for i, c := range comment {
		s := stripCommentDelimiters(c.Text);

		// split comment into lines and print the lines
 		i0 := 0;  // beginning of current line
		for i := 0; i < len(s); i++ {
			if s[i] == '\n' {
				// reached line end - print current line
				mode = printLine(p, s[i0 : i], mode);
				i0 = i + 1;  // beginning of next line; skip '\n'
			}
		}

		// print last line
		mode = printLine(p, s[i0 : len(s)], mode);
	}
	closeMode(p, mode);
}

func (c *valueDoc) print(p *astPrinter.Printer) {
	printComments(p, c.decl.Doc);
	p.Printf("
");
	p.DoGenDecl(c.decl);
	p.Printf("
\n");
}

func (f *funcDoc) print(p *astPrinter.Printer, hsize int) {
	d := f.decl;
	if d.Recv != nil {
		p.Printf("<h%d>func (", hsize);
		p.Expr(d.Recv.Type);
		p.Printf(") %s</h%d>\n", d.Name.Value, hsize);
	} else {
		p.Printf("<h%d>func %s</h%d>\n", hsize, d.Name.Value, hsize);
	}
	p.Printf("
");
	p.DoFuncDecl(d);
	p.Printf("
\n");
	printComments(p, d.Doc);
}

func (t *typeDoc) print(p *astPrinter.Printer) {
	d := t.decl;
	s := d.Specs[0].(*ast.TypeSpec);
	p.Printf("
type %s
\n", s.Name.Value);
	p.Printf("

");
	p.DoGenDecl(d);
	p.Printf("

\n");
	printComments(p, s.Doc);

	// print associated methods, if any
	for name, m := range t.factories {
		m.print(p, 3);
	}

	for name, m := range t.methods {
		m.print(p, 3);
	}
}

func (doc *PackageDoc) Print(writer io.Write) {
	var p astPrinter.Printer;
	p.Init(writer, nil, true);

	// program header
	fmt.Fprintf(writer, "
package %s
\n", doc.name);
	fmt.Fprintf(writer, "
import \"%s\"
\n", doc.name);
	printComments(&p, doc.doc);

	// constants
	if doc.consts.Len() > 0 {
		fmt.Fprintln(writer, "
");
		fmt.Fprintln(writer, "
Constants
");
		for i := 0; i < doc.consts.Len(); i++ {
			doc.consts.At(i).(*valueDoc).print(&p);
		}
	}

	// variables
	if doc.vars.Len() > 0 {
		fmt.Fprintln(writer, "
");
		fmt.Fprintln(writer, "
Variables
");
		for i := 0; i < doc.vars.Len(); i++ {
			doc.vars.At(i).(*valueDoc).print(&p);
		}
	}

	// functions
	if len(doc.funcs) > 0 {
		fmt.Fprintln(writer, "
");
		for name, f := range doc.funcs {
			f.print(&p, 2);
		}
	}

	// types
	for name, t := range doc.types {
		fmt.Fprintln(writer, "
");
		t.print(&p);
	}
}
<commit_msg>- don't show methods of non-exported types (even if the methods are exported)<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 docPrinter

import (
	"ast";
	"fmt";
	"io";
	"token";
	"unicode";
	"utf8";
	"vector";

	"astprinter";
)

// ----------------------------------------------------------------------------
// Elementary support

// TODO this should be an AST method
func isExported(name *ast.Ident) bool {
	ch, len := utf8.DecodeRuneInString(name.Value, 0);
	return unicode.IsUpper(ch);
}

func hasExportedNames(names []*ast.Ident) bool {
	for i, name := range names {
		if isExported(name) {
			return true;
		}
	}
	return false;
}

func hasExportedSpecs(specs []ast.Spec) bool {
	for i, s := range specs {
		// only called for []astSpec lists of *ast.ValueSpec
		return hasExportedNames(s.(*ast.ValueSpec).Names);
	}
	return false;
}

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

type valueDoc struct {
	decl *ast.GenDecl;  // len(decl.Specs) >= 1, and the element type is *ast.ValueSpec
}

type funcDoc struct {
	decl *ast.FuncDecl;
}

type typeDoc struct {
	decl *ast.GenDecl;  // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
	factories map[string] *funcDoc;
	methods map[string] *funcDoc;
}

type PackageDoc struct {
	name string;  // package name
	doc ast.Comments;  // package documentation, if any
	consts *vector.Vector;  // list of *valueDoc
	types map[string] *typeDoc;
	vars *vector.Vector;  // list of *valueDoc
	funcs map[string] *funcDoc;
}

func (doc *PackageDoc) PackageName() string {
	return doc.name;
}

// PackageDoc initializes a document to collect package documentation.
// The package name is provided as initial argument. Use AddPackage to
// add the AST for each source file belonging to the same package.
//
func (doc *PackageDoc) Init(name string) {
	doc.name = name;
	doc.consts = vector.New(0);
	doc.types = make(map[string] *typeDoc);
	doc.vars = vector.New(0);
	doc.funcs = make(map[string] *funcDoc);
}

func baseTypeName(typ ast.Expr) string {
	switch t := typ.(type) {
	case *ast.Ident:
		return string(t.Value);
	case *ast.StarExpr:
		return baseTypeName(t.X);
	}
	return "";
}

func (doc *PackageDoc) lookupTypeDoc(typ ast.Expr) *typeDoc {
	tdoc, found := doc.types[baseTypeName(typ)];
	if found {
		return tdoc;
	}
	return nil;
}

func (doc *PackageDoc) addType(decl *ast.GenDecl) {
	typ := decl.Specs[0].(*ast.TypeSpec);
	name := typ.Name.Value;
	tdoc := &typeDoc{decl, make(map[string] *funcDoc), make(map[string] *funcDoc)};
	doc.types[name] = tdoc;
}

func (doc *PackageDoc) addFunc(fun *ast.FuncDecl) {
	name := fun.Name.Value;
	fdoc := &funcDoc{fun};

	// determine if it should be associated with a type
	var typ *typeDoc;
	if fun.Recv != nil {
		// method
		// (all receiver types must be declared before they are used)
		typ = doc.lookupTypeDoc(fun.Recv.Type);
		if typ != nil {
			// type found (i.e., exported)
			typ.methods[name] = fdoc;
		}
		// if the type wasn't found, it wasn't exported

	} else {
		// perhaps a factory function
		// determine result type, if any
		if len(fun.Type.Results) >= 1 {
			res := fun.Type.Results[0];
			if len(res.Names) <= 1 {
				// exactly one (named or anonymous) result type
				typ = doc.lookupTypeDoc(res.Type);
				if typ != nil {
					typ.factories[name] = fdoc;
					return;
				}
			}
		}

		// ordinary function
		doc.funcs[name] = fdoc;
	}
}

func (doc *PackageDoc) addDecl(decl ast.Decl) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		if len(d.Specs) > 0 {
			switch d.Tok {
			case token.IMPORT:
				// ignore
			case token.CONST:
				// constants are always handled as a group
				if hasExportedSpecs(d.Specs) {
					doc.consts.Push(&valueDoc{d});
				}
			case token.TYPE:
				// types are handled individually
				for i, spec := range d.Specs {
					s := spec.(*ast.TypeSpec);
					if isExported(s.Name) {
						// make a (fake) GenDecl node for this TypeSpec
						// (we need to do this here - as opposed to just
						// for printing - so we don't loose the GenDecl
						// documentation)
						var noPos token.Position;
						doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{s}, noPos});
					}
				}
			case token.VAR:
				// variables are always handled as a group
				if hasExportedSpecs(d.Specs) {
					doc.vars.Push(&valueDoc{d});
				}
			}
		}
	case *ast.FuncDecl:
		if isExported(d.Name) {
			doc.addFunc(d);
		}
	}
}

// AddProgram adds the AST of a source file belonging to the same
// package. The package names must match. If the source was added
// before, AddProgram is a no-op.
//
func (doc *PackageDoc) AddProgram(prog *ast.Program) {
	if doc.name != prog.Name.Value {
		panic("package names don't match");
	}

	// add package documentation
	// TODO what to do if there are multiple files?
	if prog.Doc != nil {
		doc.doc = prog.Doc
	}

	// add all exported declarations
	for i, decl := range prog.Decls {
		doc.addDecl(decl);
	}
}

// ----------------------------------------------------------------------------
// Printing

func htmlEscape(s []byte) []byte {
	var buf io.ByteBuffer;

	i0 := 0;
	for i := 0; i < len(s); i++ {
		var esc string;
		switch s[i] {
		case '<': esc = "<";
		case '&': esc = "&";
		default: continue;
		}
		fmt.Fprintf(&buf, "%s%s", s[i0 : i], esc);
		i0 := i+1;  // skip escaped char
	}

	// write the rest
	if i0 > 0 {
		buf.Write(s[i0 : len(s)]);
		s = buf.Data();
	}
	return s;
}

// Reduce contiguous sequences of '\t' in a string to a single '\t'.
// This will produce better results when the string is printed via
// a tabwriter.
// TODO make this functionality optional.
//
func untabify(s []byte) []byte {
	var buf io.ByteBuffer;

	i0 := 0;
	for i := 0; i < len(s); i++ {
		if s[i] == '\t' {
			i++;  // include '\t'
			buf.Write(s[i0 : i]);
			// skip additional tabs
			for i < len(s) && s[i] == '\t' {
				i++;
			}
			i0 := i;
		} else {
			i++;
		}
	}

	// write the rest
	if i0 > 0 {
		buf.Write(s[i0 : len(s)]);
		s = buf.Data();
	}
	return s;
}

func stripWhiteSpace(s []byte) []byte {
	i, j := 0, len(s);
	for i < len(s) && s[i] <= ' ' {
		i++;
	}
	for j > i && s[j-1] <= ' ' {
		j--
	}
	return s[i : j];
}

func stripCommentDelimiters(s []byte) []byte {
	switch s[1] {
	case '/': return s[2 : len(s)-1];
	case '*': return s[2 : len(s)-2];
	}
	panic();
	return nil;
}

const /* formatting mode */ (
	in_gap = iota;
	in_paragraph;
	in_preformatted;
)

func printLine(p *astPrinter.Printer, line []byte, mode int) int {
	indented := len(line) > 0 && line[0] == '\t';
	line = stripWhiteSpace(line);
	if len(line) == 0 {
		// empty line
		switch mode {
		case in_paragraph:
			p.Printf("
\n");
			mode = in_gap;
		case in_preformatted:
			p.Printf("\n");
			// remain in preformatted
		}
	} else {
		// non-empty line
		if indented {
			switch mode {
			case in_gap:
				p.Printf("
\n");
			case in_paragraph:
				p.Printf("
\n");
				p.Printf("
\n");
			}
			mode = in_preformatted;
		} else {
			switch mode {
			case in_gap:
				p.Printf("
\n");
			case in_preformatted:
				p.Printf("
\n");
				p.Printf("
\n");
			}
			mode = in_paragraph;
		}
		// print line
		p.Printf("%s\n", untabify(htmlEscape(line)));
	}
	return mode;
}

func closeMode(p *astPrinter.Printer, mode int) {
	switch mode {
	case in_paragraph:
		p.Printf("
\n");
	case in_preformatted:
		p.Printf("
\n");
	}
}

func printComments(p *astPrinter.Printer, comment ast.Comments) {
	mode := in_gap;
	for i, c := range comment {
		s := stripCommentDelimiters(c.Text);

		// split comment into lines and print the lines
 		i0 := 0;  // beginning of current line
		for i := 0; i < len(s); i++ {
			if s[i] == '\n' {
				// reached line end - print current line
				mode = printLine(p, s[i0 : i], mode);
				i0 = i + 1;  // beginning of next line; skip '\n'
			}
		}

		// print last line
		mode = printLine(p, s[i0 : len(s)], mode);
	}
	closeMode(p, mode);
}

func (c *valueDoc) print(p *astPrinter.Printer) {
	printComments(p, c.decl.Doc);
	p.Printf("
");
	p.DoGenDecl(c.decl);
	p.Printf("
\n");
}

func (f *funcDoc) print(p *astPrinter.Printer, hsize int) {
	d := f.decl;
	if d.Recv != nil {
		p.Printf("<h%d>func (", hsize);
		p.Expr(d.Recv.Type);
		p.Printf(") %s</h%d>\n", d.Name.Value, hsize);
	} else {
		p.Printf("<h%d>func %s</h%d>\n", hsize, d.Name.Value, hsize);
	}
	p.Printf("
");
	p.DoFuncDecl(d);
	p.Printf("
\n");
	printComments(p, d.Doc);
}

func (t *typeDoc) print(p *astPrinter.Printer) {
	d := t.decl;
	s := d.Specs[0].(*ast.TypeSpec);
	p.Printf("
type %s
\n", s.Name.Value);
	p.Printf("

");
	p.DoGenDecl(d);
	p.Printf("

\n");
	printComments(p, s.Doc);

	// print associated methods, if any
	for name, m := range t.factories {
		m.print(p, 3);
	}

	for name, m := range t.methods {
		m.print(p, 3);
	}
}

func (doc *PackageDoc) Print(writer io.Write) {
	var p astPrinter.Printer;
	p.Init(writer, nil, true);

	// program header
	fmt.Fprintf(writer, "
package %s
\n", doc.name);
	fmt.Fprintf(writer, "
import \"%s\"
\n", doc.name);
	printComments(&p, doc.doc);

	// constants
	if doc.consts.Len() > 0 {
		fmt.Fprintln(writer, "
");
		fmt.Fprintln(writer, "
Constants
");
		for i := 0; i < doc.consts.Len(); i++ {
			doc.consts.At(i).(*valueDoc).print(&p);
		}
	}

	// variables
	if doc.vars.Len() > 0 {
		fmt.Fprintln(writer, "
");
		fmt.Fprintln(writer, "
Variables
");
		for i := 0; i < doc.vars.Len(); i++ {
			doc.vars.At(i).(*valueDoc).print(&p);
		}
	}

	// functions
	if len(doc.funcs) > 0 {
		fmt.Fprintln(writer, "
");
		for name, f := range doc.funcs {
			f.print(&p, 2);
		}
	}

	// types
	for name, t := range doc.types {
		fmt.Fprintln(writer, "
");
		t.print(&p);
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"

	"github.com/cloudfoundry-community/firehose_exporter/collectors"
	"github.com/cloudfoundry-community/firehose_exporter/filters"
	"github.com/cloudfoundry-community/firehose_exporter/firehosenozzle"
	"github.com/cloudfoundry-community/firehose_exporter/metrics"
	"github.com/cloudfoundry-community/firehose_exporter/uaatokenrefresher"
)

var (
	uaaUrl = flag.String(
		"uaa.url", "",
		"Cloud Foundry UAA URL ($FIREHOSE_EXPORTER_UAA_URL).",
	)

	uaaClientID = flag.String(
		"uaa.client-id", "",
		"Cloud Foundry UAA Client ID ($FIREHOSE_EXPORTER_UAA_CLIENT_ID).",
	)

	uaaClientSecret = flag.String(
		"uaa.client-secret", "",
		"Cloud Foundry UAA Client Secret ($FIREHOSE_EXPORTER_UAA_CLIENT_SECRET).",
	)

	dopplerUrl = flag.String(
		"doppler.url", "",
		"Cloud Foundry Doppler URL ($FIREHOSE_EXPORTER_DOPPLER_URL).",
	)

	dopplerSubscriptionID = flag.String(
		"doppler.subscription-id", "prometheus",
		"Cloud Foundry Doppler Subscription ID ($FIREHOSE_EXPORTER_DOPPLER_SUBSCRIPTION_ID).",
	)

	dopplerIdleTimeoutSeconds = flag.Uint(
		"doppler.idle-timeout-seconds", 5,
		"Cloud Foundry Doppler Idle Timeout in seconds ($FIREHOSE_EXPORTER_DOPPLER_IDLE_TIMEOUT_SECONDS).",
	)

	dopplerMetricExpiration = flag.Duration(
		"doppler.metric-expiration", 5*time.Minute,
		"How long a Cloud Foundry Doppler metric is valid ($FIREHOSE_EXPORTER_DOPPLER_METRIC_EXPIRATION).",
	)

	dopplerDeployments = flag.String(
		"doppler.deployments", "",
		"Comma separated deployments to filter ($FIREHOSE_EXPORTER_DOPPLER_DEPLOYMENTS)",
	)

	dopplerEvents = flag.String(
		"doppler.events", "",
		"Comma separated events to filter (ContainerMetric,CounterEvent,ValueMetric) ($FIREHOSE_EXPORTER_DOPPLER_EVENTS).",
	)

	skipSSLValidation = flag.Bool(
		"skip-ssl-verify", false,
		"Disable SSL Verify ($FIREHOSE_EXPORTER_SKIP_SSL_VERIFY).",
	)

	metricsNamespace = flag.String(
		"metrics.namespace", "firehose_exporter",
		"Metrics Namespace ($FIREHOSE_EXPORTER_METRICS_NAMESPACE).",
	)

	metricsCleanupInterval = flag.Duration(
		"metrics.cleanup-interval", 2*time.Minute,
		"Metrics clean up interval ($FIREHOSE_EXPORTER_METRICS_CLEANUP_INTERVAL).",
	)

	showVersion = flag.Bool(
		"version", false,
		"Print version information.",
	)

	listenAddress = flag.String(
		"web.listen-address", ":9186",
		"Address to listen on for web interface and telemetry ($FIREHOSE_EXPORTER_WEB_LISTEN_ADDRESS).",
	)

	metricsPath = flag.String(
		"web.telemetry-path", "/metrics",
		"Path under which to expose Prometheus metrics ($FIREHOSE_EXPORTER_WEB_TELEMETRY_PATH).",
	)
)

func init() {
	prometheus.MustRegister(version.NewCollector(*metricsNamespace))
}

func overrideFlagsWithEnvVars() {
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_URL", uaaUrl)
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_CLIENT_ID", uaaClientID)
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_CLIENT_SECRET", uaaClientSecret)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_URL", dopplerUrl)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_SUBSCRIPTION_ID", dopplerSubscriptionID)
	overrideWithEnvUint("FIREHOSE_EXPORTER_DOPPLER_IDLE_TIMEOUT_SECONDS", dopplerIdleTimeoutSeconds)
	overrideWithEnvDuration("FIREHOSE_EXPORTER_DOPPLER_METRIC_EXPIRATION", dopplerMetricExpiration)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_DEPLOYMENTS", dopplerDeployments)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_EVENTS", dopplerEvents)
	overrideWithEnvBool("FIREHOSE_EXPORTER_SKIP_SSL_VERIFY", skipSSLValidation)
	overrideWithEnvVar("FIREHOSE_EXPORTER_METRICS_NAMESPACE", metricsNamespace)
	overrideWithEnvDuration("FIREHOSE_EXPORTER_METRICS_CLEANUP_INTERVAL", metricsCleanupInterval)
	overrideWithEnvVar("FIREHOSE_EXPORTER_WEB_LISTEN_ADDRESS", listenAddress)
	overrideWithEnvVar("FIREHOSE_EXPORTER_WEB_TELEMETRY_PATH", metricsPath)
}

func overrideWithEnvVar(name string, value *string) {
	envValue := os.Getenv(name)
	if envValue != "" {
		*value = envValue
	}
}

func overrideWithEnvUint(name string, value *uint) {
	envValue := os.Getenv(name)
	if envValue != "" {
		intValue, err := strconv.Atoi(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
		*value = uint(intValue)
	}
}

func overrideWithEnvDuration(name string, value *time.Duration) {
	envValue := os.Getenv(name)
	if envValue != "" {
		var err error
		*value, err = time.ParseDuration(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
	}
}

func overrideWithEnvBool(name string, value *bool) {
	envValue := os.Getenv(name)
	if envValue != "" {
		var err error
		*value, err = strconv.ParseBool(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
	}
}

func main() {
	flag.Parse()
	overrideFlagsWithEnvVars()

	if *showVersion {
		fmt.Fprintln(os.Stdout, version.Print("firehose_exporter"))
		os.Exit(0)
	}

	log.Infoln("Starting firehose_exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	authTokenRefresher, err := uaatokenrefresher.New(
		*uaaUrl,
		*uaaClientID,
		*uaaClientSecret,
		*skipSSLValidation,
	)
	if err != nil {
		log.Errorf("Error creating UAA client: %s", err.Error())
		os.Exit(1)
	}

	deploymentFilter := filters.NewDeploymentFilter(strings.Split(*dopplerDeployments, ","))

	eventFilter, err := filters.NewEventFilter(strings.Split(*dopplerEvents, ","))
	if err != nil {
		log.Error(err)
		os.Exit(1)
	}

	metricsStore := metrics.NewStore(*dopplerMetricExpiration, *metricsCleanupInterval, deploymentFilter, eventFilter)

	nozzle := firehosenozzle.New(
		*dopplerUrl,
		*skipSSLValidation,
		*dopplerSubscriptionID,
		uint32(*dopplerIdleTimeoutSeconds),
		authTokenRefresher,
		metricsStore,
	)
	go func() {
		log.Fatal(nozzle.Start())
	}()

	internalMetricsCollector := collectors.NewInternalMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(internalMetricsCollector)

	containerMetricsCollector := collectors.NewContainerMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(containerMetricsCollector)

	counterEventsCollector := collectors.NewCounterEventsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(counterEventsCollector)

	valueMetricsCollector := collectors.NewValueMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(valueMetricsCollector)

	http.Handle(*metricsPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Cloud Foundry Firehose Exporter</title>

Cloud Foundry Firehose Exporter

<a href='` + *metricsPath + `'>Metrics

             `))
	})

	log.Infoln("Listening on", *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<commit_msg>Fix deployment and event filter<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"

	"github.com/cloudfoundry-community/firehose_exporter/collectors"
	"github.com/cloudfoundry-community/firehose_exporter/filters"
	"github.com/cloudfoundry-community/firehose_exporter/firehosenozzle"
	"github.com/cloudfoundry-community/firehose_exporter/metrics"
	"github.com/cloudfoundry-community/firehose_exporter/uaatokenrefresher"
)

var (
	uaaUrl = flag.String(
		"uaa.url", "",
		"Cloud Foundry UAA URL ($FIREHOSE_EXPORTER_UAA_URL).",
	)

	uaaClientID = flag.String(
		"uaa.client-id", "",
		"Cloud Foundry UAA Client ID ($FIREHOSE_EXPORTER_UAA_CLIENT_ID).",
	)

	uaaClientSecret = flag.String(
		"uaa.client-secret", "",
		"Cloud Foundry UAA Client Secret ($FIREHOSE_EXPORTER_UAA_CLIENT_SECRET).",
	)

	dopplerUrl = flag.String(
		"doppler.url", "",
		"Cloud Foundry Doppler URL ($FIREHOSE_EXPORTER_DOPPLER_URL).",
	)

	dopplerSubscriptionID = flag.String(
		"doppler.subscription-id", "prometheus",
		"Cloud Foundry Doppler Subscription ID ($FIREHOSE_EXPORTER_DOPPLER_SUBSCRIPTION_ID).",
	)

	dopplerIdleTimeoutSeconds = flag.Uint(
		"doppler.idle-timeout-seconds", 5,
		"Cloud Foundry Doppler Idle Timeout in seconds ($FIREHOSE_EXPORTER_DOPPLER_IDLE_TIMEOUT_SECONDS).",
	)

	dopplerMetricExpiration = flag.Duration(
		"doppler.metric-expiration", 5*time.Minute,
		"How long a Cloud Foundry Doppler metric is valid ($FIREHOSE_EXPORTER_DOPPLER_METRIC_EXPIRATION).",
	)

	dopplerDeployments = flag.String(
		"doppler.deployments", "",
		"Comma separated deployments to filter ($FIREHOSE_EXPORTER_DOPPLER_DEPLOYMENTS)",
	)

	dopplerEvents = flag.String(
		"doppler.events", "",
		"Comma separated events to filter (ContainerMetric,CounterEvent,ValueMetric) ($FIREHOSE_EXPORTER_DOPPLER_EVENTS).",
	)

	skipSSLValidation = flag.Bool(
		"skip-ssl-verify", false,
		"Disable SSL Verify ($FIREHOSE_EXPORTER_SKIP_SSL_VERIFY).",
	)

	metricsNamespace = flag.String(
		"metrics.namespace", "firehose_exporter",
		"Metrics Namespace ($FIREHOSE_EXPORTER_METRICS_NAMESPACE).",
	)

	metricsCleanupInterval = flag.Duration(
		"metrics.cleanup-interval", 2*time.Minute,
		"Metrics clean up interval ($FIREHOSE_EXPORTER_METRICS_CLEANUP_INTERVAL).",
	)

	showVersion = flag.Bool(
		"version", false,
		"Print version information.",
	)

	listenAddress = flag.String(
		"web.listen-address", ":9186",
		"Address to listen on for web interface and telemetry ($FIREHOSE_EXPORTER_WEB_LISTEN_ADDRESS).",
	)

	metricsPath = flag.String(
		"web.telemetry-path", "/metrics",
		"Path under which to expose Prometheus metrics ($FIREHOSE_EXPORTER_WEB_TELEMETRY_PATH).",
	)
)

func init() {
	prometheus.MustRegister(version.NewCollector(*metricsNamespace))
}

func overrideFlagsWithEnvVars() {
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_URL", uaaUrl)
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_CLIENT_ID", uaaClientID)
	overrideWithEnvVar("FIREHOSE_EXPORTER_UAA_CLIENT_SECRET", uaaClientSecret)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_URL", dopplerUrl)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_SUBSCRIPTION_ID", dopplerSubscriptionID)
	overrideWithEnvUint("FIREHOSE_EXPORTER_DOPPLER_IDLE_TIMEOUT_SECONDS", dopplerIdleTimeoutSeconds)
	overrideWithEnvDuration("FIREHOSE_EXPORTER_DOPPLER_METRIC_EXPIRATION", dopplerMetricExpiration)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_DEPLOYMENTS", dopplerDeployments)
	overrideWithEnvVar("FIREHOSE_EXPORTER_DOPPLER_EVENTS", dopplerEvents)
	overrideWithEnvBool("FIREHOSE_EXPORTER_SKIP_SSL_VERIFY", skipSSLValidation)
	overrideWithEnvVar("FIREHOSE_EXPORTER_METRICS_NAMESPACE", metricsNamespace)
	overrideWithEnvDuration("FIREHOSE_EXPORTER_METRICS_CLEANUP_INTERVAL", metricsCleanupInterval)
	overrideWithEnvVar("FIREHOSE_EXPORTER_WEB_LISTEN_ADDRESS", listenAddress)
	overrideWithEnvVar("FIREHOSE_EXPORTER_WEB_TELEMETRY_PATH", metricsPath)
}

func overrideWithEnvVar(name string, value *string) {
	envValue := os.Getenv(name)
	if envValue != "" {
		*value = envValue
	}
}

func overrideWithEnvUint(name string, value *uint) {
	envValue := os.Getenv(name)
	if envValue != "" {
		intValue, err := strconv.Atoi(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
		*value = uint(intValue)
	}
}

func overrideWithEnvDuration(name string, value *time.Duration) {
	envValue := os.Getenv(name)
	if envValue != "" {
		var err error
		*value, err = time.ParseDuration(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
	}
}

func overrideWithEnvBool(name string, value *bool) {
	envValue := os.Getenv(name)
	if envValue != "" {
		var err error
		*value, err = strconv.ParseBool(envValue)
		if err != nil {
			log.Fatalf("Invalid `%s`: %s", name, err)
		}
	}
}

func main() {
	flag.Parse()
	overrideFlagsWithEnvVars()

	if *showVersion {
		fmt.Fprintln(os.Stdout, version.Print("firehose_exporter"))
		os.Exit(0)
	}

	log.Infoln("Starting firehose_exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	authTokenRefresher, err := uaatokenrefresher.New(
		*uaaUrl,
		*uaaClientID,
		*uaaClientSecret,
		*skipSSLValidation,
	)
	if err != nil {
		log.Errorf("Error creating UAA client: %s", err.Error())
		os.Exit(1)
	}

	var deployments []string
	if *dopplerDeployments != "" {
		deployments = strings.Split(*dopplerDeployments, ",")
	}
	deploymentFilter := filters.NewDeploymentFilter(deployments)

	var events []string
	if *dopplerEvents != "" {
		events = strings.Split(*dopplerEvents, ",")
	}
	eventFilter, err := filters.NewEventFilter(events)
	if err != nil {
		log.Error(err)
		os.Exit(1)
	}

	metricsStore := metrics.NewStore(*dopplerMetricExpiration, *metricsCleanupInterval, deploymentFilter, eventFilter)

	nozzle := firehosenozzle.New(
		*dopplerUrl,
		*skipSSLValidation,
		*dopplerSubscriptionID,
		uint32(*dopplerIdleTimeoutSeconds),
		authTokenRefresher,
		metricsStore,
	)
	go func() {
		log.Fatal(nozzle.Start())
	}()

	internalMetricsCollector := collectors.NewInternalMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(internalMetricsCollector)

	containerMetricsCollector := collectors.NewContainerMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(containerMetricsCollector)

	counterEventsCollector := collectors.NewCounterEventsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(counterEventsCollector)

	valueMetricsCollector := collectors.NewValueMetricsCollector(*metricsNamespace, metricsStore)
	prometheus.MustRegister(valueMetricsCollector)

	http.Handle(*metricsPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
             <title>Cloud Foundry Firehose Exporter</title>

Cloud Foundry Firehose Exporter

<a href='` + *metricsPath + `'>Metrics

             `))
	})

	log.Infoln("Listening on", *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<|endoftext|>


<commit_before>package backoff

import (
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

// This is an example that demonstrates how this package could be used
// to perform various advanced operations.
//
// It executes an HTTP GET request with exponential backoff,
// while errors are logged and failed responses are closed, as required by net/http package.
//
// Note we define a condition function which is used inside the operation to
// determine whether the operation succeeded or failed.
func Example() error {
	res, err := GetWithRetry(
		"http://localhost:9999",
		ErrorIfStatusCodeIsNot(http.StatusOK),
		NewExponentialBackOff())

	if err != nil {
		// Close response body of last (failed) attempt.
		// The Last attempt isn't handled by the notify-on-error function,
		// which closes the body of all the previous attempts.
		if e := res.Body.Close(); e != nil {
			log.Printf("error closing last attempt's response body: %s", e)
		}
		log.Printf("too many failed request attempts: %s", err)
		return err
	}
	defer res.Body.Close() // The response's Body must be closed.

	// Read body
	_, _ = ioutil.ReadAll(res.Body)

	// Do more stuff
	return nil
}

// GetWithRetry is a helper function that performs an HTTP GET request
// to the given URL, and retries with the given backoff using the given condition function.
//
// It also uses a notify-on-error function which logs
// and closes the response body of the failed request.
func GetWithRetry(url string, condition Condition, bck BackOff) (*http.Response, error) {
	var res *http.Response
	err := RetryNotify(
		func() error {
			var err error
			res, err = http.Get(url)
			if err != nil {
				return err
			}
			return condition(res)
		},
		bck,
		LogAndClose())

	return res, err
}

// Condition is a retry condition function.
// It receives a response, and returns an error
// if the response failed the condition.
type Condition func(*http.Response) error

// ErrorIfStatusCodeIsNot returns a retry condition function.
// The condition returns an error
// if the given response's status code is not the given HTTP status code.
func ErrorIfStatusCodeIsNot(status int) Condition {
	return func(res *http.Response) error {
		if res.StatusCode != status {
			return NewError(res)
		}
		return nil
	}
}

// Error is returned on ErrorIfX() condition functions throughout this package.
type Error struct {
	Response *http.Response
}

func NewError(res *http.Response) *Error {
	// Sanity check
	if res == nil {
		panic("response object is nil")
	}
	return &Error{Response: res}
}
func (err *Error) Error() string { return "request failed" }

// LogAndClose is a notify-on-error function.
// It logs the error and closes the response body.
func LogAndClose() Notify {
	return func(err error, wait time.Duration) {
		switch e := err.(type) {
		case *Error:
			defer e.Response.Body.Close()

			b, err := ioutil.ReadAll(e.Response.Body)
			var body string
			if err != nil {
				body = "can't read body"
			} else {
				body = string(b)
			}

			log.Printf("%s: %s", e.Response.Status, body)
		default:
			log.Println(err)
		}
	}
}
<commit_msg>remove an example, too complex<commit_after><|endoftext|>


<commit_before>// Package fserrors provides errors and error handling
package fserrors

import (
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strings"
	"time"

	"github.com/pkg/errors"
)

// Retrier is an optional interface for error as to whether the
// operation should be retried at a high level.
//
// This should be returned from Update or Put methods as required
type Retrier interface {
	error
	Retry() bool
}

// retryError is a type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// wrappedRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedRetryError struct {
	error
}

// Retry interface
func (err wrappedRetryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = wrappedRetryError{error(nil)}

// RetryError makes an error which indicates it would like to be retried
func RetryError(err error) error {
	if err == nil {
		err = errors.New("needs retry")
	}
	return wrappedRetryError{err}
}

// IsRetryError returns true if err conforms to the Retry interface
// and calling the Retry method returns true.
func IsRetryError(err error) bool {
	if err == nil {
		return false
	}
	_, err = Cause(err)
	if r, ok := err.(Retrier); ok {
		return r.Retry()
	}
	return false
}

// Fataler is an optional interface for error as to whether the
// operation should cause the entire operation to finish immediately.
//
// This should be returned from Update or Put methods as required
type Fataler interface {
	error
	Fatal() bool
}

// wrappedFatalError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedFatalError struct {
	error
}

// Fatal interface
func (err wrappedFatalError) Fatal() bool {
	return true
}

// Check interface
var _ Fataler = wrappedFatalError{error(nil)}

// FatalError makes an error which indicates it is a fatal error and
// the sync should stop.
func FatalError(err error) error {
	if err == nil {
		err = errors.New("fatal error")
	}
	return wrappedFatalError{err}
}

// IsFatalError returns true if err conforms to the Fatal interface
// and calling the Fatal method returns true.
func IsFatalError(err error) bool {
	if err == nil {
		return false
	}
	_, err = Cause(err)
	if r, ok := err.(Fataler); ok {
		return r.Fatal()
	}
	return false
}

// NoRetrier is an optional interface for error as to whether the
// operation should not be retried at a high level.
//
// If only NoRetry errors are returned in a sync then the sync won't
// be retried.
//
// This should be returned from Update or Put methods as required
type NoRetrier interface {
	error
	NoRetry() bool
}

// wrappedNoRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedNoRetryError struct {
	error
}

// NoRetry interface
func (err wrappedNoRetryError) NoRetry() bool {
	return true
}

// Check interface
var _ NoRetrier = wrappedNoRetryError{error(nil)}

// NoRetryError makes an error which indicates the sync shouldn't be
// retried.
func NoRetryError(err error) error {
	return wrappedNoRetryError{err}
}

// IsNoRetryError returns true if err conforms to the NoRetry
// interface and calling the NoRetry method returns true.
func IsNoRetryError(err error) bool {
	if err == nil {
		return false
	}
	_, err = Cause(err)
	if r, ok := err.(NoRetrier); ok {
		return r.NoRetry()
	}
	return false
}

// RetryAfter is an optional interface for error as to whether the
// operation should be retried after a given delay
//
// This should be returned from Update or Put methods as required and
// will cause the entire sync to be retried after a delay.
type RetryAfter interface {
	error
	RetryAfter() time.Time
}

// ErrorRetryAfter is an error which expresses a time that should be
// waited for until trying again
type ErrorRetryAfter time.Time

// NewErrorRetryAfter returns an ErrorRetryAfter with the given
// duration as an endpoint
func NewErrorRetryAfter(d time.Duration) ErrorRetryAfter {
	return ErrorRetryAfter(time.Now().Add(d))
}

// Error returns the textual version of the error
func (e ErrorRetryAfter) Error() string {
	return fmt.Sprintf("try again after %v (%v)", time.Time(e).Format(time.RFC3339Nano), time.Time(e).Sub(time.Now()))
}

// RetryAfter returns the time the operation should be retried at or
// after
func (e ErrorRetryAfter) RetryAfter() time.Time {
	return time.Time(e)
}

// Check interface
var _ RetryAfter = ErrorRetryAfter{}

// RetryAfterErrorTime returns the time that the RetryAfter error
// indicates or a Zero time.Time
func RetryAfterErrorTime(err error) time.Time {
	if err == nil {
		return time.Time{}
	}
	_, err = Cause(err)
	if do, ok := err.(RetryAfter); ok {
		return do.RetryAfter()
	}
	return time.Time{}
}

// IsRetryAfterError returns true if err is an ErrorRetryAfter
func IsRetryAfterError(err error) bool {
	return !RetryAfterErrorTime(err).IsZero()
}

// Cause is a souped up errors.Cause which can unwrap some standard
// library errors too.  It returns true if any of the intermediate
// errors had a Timeout() or Temporary() method which returned true.
func Cause(cause error) (retriable bool, err error) {
	err = cause
	for prev := err; err != nil; prev = err {
		// Check for net error Timeout()
		if x, ok := err.(interface {
			Timeout() bool
		}); ok && x.Timeout() {
			retriable = true
		}

		// Check for net error Temporary()
		if x, ok := err.(interface {
			Temporary() bool
		}); ok && x.Temporary() {
			retriable = true
		}

		// Unwrap 1 level if possible
		err = errors.Cause(err)
		if err == nil {
			// errors.Cause can return nil which isn't
			// desirable so pick the previous error in
			// this case.
			err = prev
		}
		if reflect.DeepEqual(err, prev) {
			// Unpack any struct or *struct with a field
			// of name Err which satisfies the error
			// interface.  This includes *url.Error,
			// *net.OpError, *os.SyscallError and many
			// others in the stdlib
			errType := reflect.TypeOf(err)
			errValue := reflect.ValueOf(err)
			if errValue.IsValid() && errType.Kind() == reflect.Ptr {
				errType = errType.Elem()
				errValue = errValue.Elem()
			}
			if errValue.IsValid() && errType.Kind() == reflect.Struct {
				if errField := errValue.FieldByName("Err"); errField.IsValid() {
					errFieldValue := errField.Interface()
					if newErr, ok := errFieldValue.(error); ok {
						err = newErr
					}
				}
			}
		}
		if reflect.DeepEqual(err, prev) {
			break
		}
	}
	return retriable, err
}

// retriableErrorStrings is a list of phrases which when we find it
// in an an error, we know it is a networking error which should be
// retried.
//
// This is incredibly ugly - if only errors.Cause worked for all
// errors and all errors were exported from the stdlib.
var retriableErrorStrings = []string{
	"use of closed network connection", // internal/poll/fd.go
	"unexpected EOF reading trailer",   // net/http/transfer.go
	"transport connection broken",      // net/http/transport.go
	"http: ContentLength=",             // net/http/transfer.go
	"server closed idle connection",    // net/http/transport.go
}

// Errors which indicate networking errors which should be retried
//
// These are added to in retriable_errors*.go
var retriableErrors = []error{
	io.EOF,
	io.ErrUnexpectedEOF,
}

// ShouldRetry looks at an error and tries to work out if retrying the
// operation that caused it would be a good idea. It returns true if
// the error implements Timeout() or Temporary() or if the error
// indicates a premature closing of the connection.
func ShouldRetry(err error) bool {
	if err == nil {
		return false
	}

	// Find root cause if available
	retriable, err := Cause(err)
	if retriable {
		return true
	}

	// Check if it is a retriable error
	for _, retriableErr := range retriableErrors {
		if err == retriableErr {
			return true
		}
	}

	// Check error strings (yuch!) too
	errString := err.Error()
	for _, phrase := range retriableErrorStrings {
		if strings.Contains(errString, phrase) {
			return true
		}
	}

	return false
}

// ShouldRetryHTTP returns a boolean as to whether this resp deserves.
// It checks to see if the HTTP response code is in the slice
// retryErrorCodes.
func ShouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool {
	if resp == nil {
		return false
	}
	for _, e := range retryErrorCodes {
		if resp.StatusCode == e {
			return true
		}
	}
	return false
}
<commit_msg>fserrors: use errors.Walk for the wrapped error types<commit_after>// Package fserrors provides errors and error handling
package fserrors

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/ncw/rclone/lib/errors"
)

// Retrier is an optional interface for error as to whether the
// operation should be retried at a high level.
//
// This should be returned from Update or Put methods as required
type Retrier interface {
	error
	Retry() bool
}

// retryError is a type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// wrappedRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedRetryError struct {
	error
}

// Retry interface
func (err wrappedRetryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = wrappedRetryError{error(nil)}

// RetryError makes an error which indicates it would like to be retried
func RetryError(err error) error {
	if err == nil {
		err = errors.New("needs retry")
	}
	return wrappedRetryError{err}
}

func (err wrappedRetryError) Cause() error {
	return err.error
}

// IsRetryError returns true if err conforms to the Retry interface
// and calling the Retry method returns true.
func IsRetryError(err error) (isRetry bool) {
	errors.Walk(err, func(err error) bool {
		if r, ok := err.(Retrier); ok {
			isRetry = r.Retry()
			return true
		}
		return false
	})
	return
}

// Fataler is an optional interface for error as to whether the
// operation should cause the entire operation to finish immediately.
//
// This should be returned from Update or Put methods as required
type Fataler interface {
	error
	Fatal() bool
}

// wrappedFatalError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedFatalError struct {
	error
}

// Fatal interface
func (err wrappedFatalError) Fatal() bool {
	return true
}

// Check interface
var _ Fataler = wrappedFatalError{error(nil)}

// FatalError makes an error which indicates it is a fatal error and
// the sync should stop.
func FatalError(err error) error {
	if err == nil {
		err = errors.New("fatal error")
	}
	return wrappedFatalError{err}
}

func (err wrappedFatalError) Cause() error {
	return err.error
}

// IsFatalError returns true if err conforms to the Fatal interface
// and calling the Fatal method returns true.
func IsFatalError(err error) (isFatal bool) {
	errors.Walk(err, func(err error) bool {
		if r, ok := err.(Fataler); ok {
			isFatal = r.Fatal()
			return true
		}
		return false
	})
	return
}

// NoRetrier is an optional interface for error as to whether the
// operation should not be retried at a high level.
//
// If only NoRetry errors are returned in a sync then the sync won't
// be retried.
//
// This should be returned from Update or Put methods as required
type NoRetrier interface {
	error
	NoRetry() bool
}

// wrappedNoRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedNoRetryError struct {
	error
}

// NoRetry interface
func (err wrappedNoRetryError) NoRetry() bool {
	return true
}

// Check interface
var _ NoRetrier = wrappedNoRetryError{error(nil)}

// NoRetryError makes an error which indicates the sync shouldn't be
// retried.
func NoRetryError(err error) error {
	return wrappedNoRetryError{err}
}

func (err wrappedNoRetryError) Cause() error {
	return err.error
}

// IsNoRetryError returns true if err conforms to the NoRetry
// interface and calling the NoRetry method returns true.
func IsNoRetryError(err error) (isNoRetry bool) {
	errors.Walk(err, func(err error) bool {
		if r, ok := err.(NoRetrier); ok {
			isNoRetry = r.NoRetry()
			return true
		}
		return false
	})
	return
}

// RetryAfter is an optional interface for error as to whether the
// operation should be retried after a given delay
//
// This should be returned from Update or Put methods as required and
// will cause the entire sync to be retried after a delay.
type RetryAfter interface {
	error
	RetryAfter() time.Time
}

// ErrorRetryAfter is an error which expresses a time that should be
// waited for until trying again
type ErrorRetryAfter time.Time

// NewErrorRetryAfter returns an ErrorRetryAfter with the given
// duration as an endpoint
func NewErrorRetryAfter(d time.Duration) ErrorRetryAfter {
	return ErrorRetryAfter(time.Now().Add(d))
}

// Error returns the textual version of the error
func (e ErrorRetryAfter) Error() string {
	return fmt.Sprintf("try again after %v (%v)", time.Time(e).Format(time.RFC3339Nano), time.Time(e).Sub(time.Now()))
}

// RetryAfter returns the time the operation should be retried at or
// after
func (e ErrorRetryAfter) RetryAfter() time.Time {
	return time.Time(e)
}

// Check interface
var _ RetryAfter = ErrorRetryAfter{}

// RetryAfterErrorTime returns the time that the RetryAfter error
// indicates or a Zero time.Time
func RetryAfterErrorTime(err error) (retryAfter time.Time) {
	errors.Walk(err, func(err error) bool {
		if r, ok := err.(RetryAfter); ok {
			retryAfter = r.RetryAfter()
			return true
		}
		return false
	})
	return
}

// IsRetryAfterError returns true if err is an ErrorRetryAfter
func IsRetryAfterError(err error) bool {
	return !RetryAfterErrorTime(err).IsZero()
}

// Cause is a souped up errors.Cause which can unwrap some standard
// library errors too.  It returns true if any of the intermediate
// errors had a Timeout() or Temporary() method which returned true.
func Cause(cause error) (retriable bool, err error) {
	errors.Walk(cause, func(c error) bool {
		// Check for net error Timeout()
		if x, ok := err.(interface {
			Timeout() bool
		}); ok && x.Timeout() {
			retriable = true
		}

		// Check for net error Temporary()
		if x, ok := err.(interface {
			Temporary() bool
		}); ok && x.Temporary() {
			retriable = true
		}
		err = c
		return false
	})
	return
}

// retriableErrorStrings is a list of phrases which when we find it
// in an an error, we know it is a networking error which should be
// retried.
//
// This is incredibly ugly - if only errors.Cause worked for all
// errors and all errors were exported from the stdlib.
var retriableErrorStrings = []string{
	"use of closed network connection", // internal/poll/fd.go
	"unexpected EOF reading trailer",   // net/http/transfer.go
	"transport connection broken",      // net/http/transport.go
	"http: ContentLength=",             // net/http/transfer.go
	"server closed idle connection",    // net/http/transport.go
}

// Errors which indicate networking errors which should be retried
//
// These are added to in retriable_errors*.go
var retriableErrors = []error{
	io.EOF,
	io.ErrUnexpectedEOF,
}

// ShouldRetry looks at an error and tries to work out if retrying the
// operation that caused it would be a good idea. It returns true if
// the error implements Timeout() or Temporary() or if the error
// indicates a premature closing of the connection.
func ShouldRetry(err error) bool {
	if err == nil {
		return false
	}

	// Find root cause if available
	retriable, err := Cause(err)
	if retriable {
		return true
	}

	// Check if it is a retriable error
	for _, retriableErr := range retriableErrors {
		if err == retriableErr {
			return true
		}
	}

	// Check error strings (yuch!) too
	errString := err.Error()
	for _, phrase := range retriableErrorStrings {
		if strings.Contains(errString, phrase) {
			return true
		}
	}

	return false
}

// ShouldRetryHTTP returns a boolean as to whether this resp deserves.
// It checks to see if the HTTP response code is in the slice
// retryErrorCodes.
func ShouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool {
	if resp == nil {
		return false
	}
	for _, e := range retryErrorCodes {
		if resp.StatusCode == e {
			return true
		}
	}
	return false
}

type causer interface {
	Cause() error
}

var (
	_ causer = wrappedRetryError{}
	_ causer = wrappedFatalError{}
	_ causer = wrappedNoRetryError{}
)
<|endoftext|>


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

// TODO: Rewrite using package syscall not cgo

package fuse

/*

// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
// which carries this notice:
//
// The files in this directory are subject to the following license.
//
// The author of this software is Russ Cox.
//
//         Copyright (c) 2006 Russ Cox
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
// FITNESS FOR ANY PARTICULAR PURPOSE.

#include <stdlib.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

#define nil ((void*)0)

static int
mountfuse(char *mtpt, char **err)
{
	int i, pid, fd, r;
	char buf[200];
	struct vfsconf vfs;
	char *f;

	if(getvfsbyname("osxfusefs", &vfs) < 0){
		if(access(f="/Library/Filesystems/osxfusefs.fs"
			"/Support/load_osxfusefs", 0) < 0){
		         *err = strdup("cannot find load_fusefs");
		   	return -1;
		}
		if((r=system(f)) < 0){
			snprintf(buf, sizeof buf, "%s: %s", f, strerror(errno));
			*err = strdup(buf);
			return -1;
		}
		if(r != 0){
			snprintf(buf, sizeof buf, "load_fusefs failed: exit %d", r);
			*err = strdup(buf);
			return -1;
		}
		if(getvfsbyname("osxfusefs", &vfs) < 0){
			snprintf(buf, sizeof buf, "getvfsbyname osxfusefs: %s", strerror(errno));
			*err = strdup(buf);
			return -1;
		}
	}

	// Look for available FUSE device.
	for(i=0;; i++){
		snprintf(buf, sizeof buf, "/dev/osxfuse%d", i);
		if(access(buf, 0) < 0){
			*err = strdup("no available fuse devices");
			return -1;
		}
		if((fd = open(buf, O_RDWR)) >= 0)
			break;
	}

	pid = fork();
	if(pid < 0)
		return -1;
	if(pid == 0){
		snprintf(buf, sizeof buf, "%d", fd);
		setenv("MOUNT_FUSEFS_CALL_BY_LIB", "", 1);
		// Different versions of MacFUSE put the
		// mount_fusefs binary in different places.
		// Try all.
		// Leopard location
		setenv("MOUNT_FUSEFS_DAEMON_PATH",
			   "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 1);
		execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
			  "mount_osxfusefs",
			  "-o", "iosize=4096", buf, mtpt, nil);
		fprintf(stderr, "exec mount_osxfusefs: %s\n", strerror(errno));
		_exit(1);
	}
	return fd;
}

*/
import "C"
import (
	"fmt"
	"log"
	"os/exec"
	"syscall"
	"unsafe"
)

func mount(dir string, options string) (int, error) {
	errp := (**C.char)(C.malloc(16))
	*errp = nil
	defer C.free(unsafe.Pointer(errp))
	cdir := C.CString(dir)
	defer C.free(unsafe.Pointer(cdir))
	fd := C.mountfuse(cdir, errp)
	if *errp != nil {
		return -1, mountError(C.GoString(*errp))
	}
	return int(fd), nil
}

type mountError string

func (m mountError) Error() string {
	return string(m)
}

func unmount(mountPoint string) error {
	if err := syscall.Unmount(mountPoint, 0); err != nil {
		return fmt.Errorf("umount(%q): %v", mountPoint, err)
	}
	return nil
}

var umountBinary string

func init() {
	var err error
	umountBinary, err = exec.LookPath("umount")
	if err != nil {
		log.Fatalf("Could not find umount binary: %v", err)
	}
}
<commit_msg>Remove leading string constants from mount_darwin.go C code.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO: Rewrite using package syscall not cgo

package fuse

/*

// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
// which carries this notice:
//
// The files in this directory are subject to the following license.
//
// The author of this software is Russ Cox.
//
//         Copyright (c) 2006 Russ Cox
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
// FITNESS FOR ANY PARTICULAR PURPOSE.

#include <stdlib.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

#define nil ((void*)0)

static int
mountfuse(char *mtpt, char **err)
{
	int i, pid, fd, r;
	char buf[200];
	struct vfsconf vfs;
	char *f;

	if(getvfsbyname("osxfusefs", &vfs) < 0){
		if(access(f="/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs", 0) < 0){
		         *err = strdup("cannot find load_fusefs");
		   	return -1;
		}
		if((r=system(f)) < 0){
			snprintf(buf, sizeof buf, "%s: %s", f, strerror(errno));
			*err = strdup(buf);
			return -1;
		}
		if(r != 0){
			snprintf(buf, sizeof buf, "load_fusefs failed: exit %d", r);
			*err = strdup(buf);
			return -1;
		}
		if(getvfsbyname("osxfusefs", &vfs) < 0){
			snprintf(buf, sizeof buf, "getvfsbyname osxfusefs: %s", strerror(errno));
			*err = strdup(buf);
			return -1;
		}
	}

	// Look for available FUSE device.
	for(i=0;; i++){
		snprintf(buf, sizeof buf, "/dev/osxfuse%d", i);
		if(access(buf, 0) < 0){
			*err = strdup("no available fuse devices");
			return -1;
		}
		if((fd = open(buf, O_RDWR)) >= 0)
			break;
	}

	pid = fork();
	if(pid < 0)
		return -1;
	if(pid == 0){
		snprintf(buf, sizeof buf, "%d", fd);
		setenv("MOUNT_FUSEFS_CALL_BY_LIB", "", 1);
		// Different versions of MacFUSE put the
		// mount_fusefs binary in different places.
		// Try all.
		// Leopard location
		setenv("MOUNT_FUSEFS_DAEMON_PATH", "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 1);
		execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", "mount_osxfusefs", "-o", "iosize=4096", buf, mtpt, nil);
		fprintf(stderr, "exec mount_osxfusefs: %s\n", strerror(errno));
		_exit(1);
	}
	return fd;
}

*/
import "C"
import (
	"fmt"
	"log"
	"os/exec"
	"syscall"
	"unsafe"
)

func mount(dir string, options string) (int, error) {
	errp := (**C.char)(C.malloc(16))
	*errp = nil
	defer C.free(unsafe.Pointer(errp))
	cdir := C.CString(dir)
	defer C.free(unsafe.Pointer(cdir))
	fd := C.mountfuse(cdir, errp)
	if *errp != nil {
		return -1, mountError(C.GoString(*errp))
	}
	return int(fd), nil
}

type mountError string

func (m mountError) Error() string {
	return string(m)
}

func unmount(mountPoint string) error {
	if err := syscall.Unmount(mountPoint, 0); err != nil {
		return fmt.Errorf("umount(%q): %v", mountPoint, err)
	}
	return nil
}

var umountBinary string

func init() {
	var err error
	umountBinary, err = exec.LookPath("umount")
	if err != nil {
		log.Fatalf("Could not find umount binary: %v", err)
	}
}
<|endoftext|>


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

package fuseops

import (
	"flag"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/jacobsa/bazilfuse"
	"github.com/jacobsa/reqtrace"
	"golang.org/x/net/context"
	"golang.org/x/sys/unix"
)

var fTraceByPID = flag.Bool(
	"fuse.trace_by_pid",
	false,
	"Enable a hacky mode that uses reqtrace to group all ops from each "+
		"individual PID. Not a good idea to use in production; races, bugs, and "+
		"resource leaks likely lurk.")

// A helper for embedding common behavior.
type commonOp struct {
	// The context exposed to the user.
	ctx context.Context

	// The op in which this struct is embedded.
	op Op

	// The underlying bazilfuse request for this op.
	bazilReq bazilfuse.Request

	// A function that can be used to log information about the op. The first
	// argument is a call depth.
	log func(int, string, ...interface{})

	// A function that is invoked with the error given to Respond, for use in
	// closing off traces and reporting back to the connection.
	finish func(error)
}

var gPIDMapMu sync.Mutex

// A map from PID to a traced context for that PID.
//
// GUARDED_BY(gPIDMapMu)
var gPIDMap = make(map[int]context.Context)

// Wait until the process completes, then close off the trace and remove the
// context from the map.
func reportWhenPIDGone(
	pid int,
	ctx context.Context,
	report reqtrace.ReportFunc) {
	// HACK(jacobsa): Poll until the process no longer exists.
	const pollPeriod = 50 * time.Millisecond
	for {
		// The man page for kill(2) says that if the signal is zero, then "no
		// signal is sent, but error checking is still performed; this can be used
		// to check for the existence of a process ID".
		err := unix.Kill(pid, 0)

		// ESRCH means the process is gone.
		if err == unix.ESRCH {
			break
		}

		// If we receive EPERM, we're not going to be able to do what we want. We
		// don't really have any choice but to print info and leak.
		if err == unix.EPERM {
			log.Printf("Failed to kill(2) PID %v; no permissions. Leaking trace.", pid)
			return
		}

		// Otherwise, panic.
		if err != nil {
			panic(fmt.Errorf("Kill(%v): %v", pid, err))
		}

		time.Sleep(pollPeriod)
	}

	// Finish up.
	report(nil)

	gPIDMapMu.Lock()
	delete(gPIDMap, pid)
	gPIDMapMu.Unlock()
}

func (o *commonOp) maybeTraceByPID(
	in context.Context,
	pid int) (out context.Context) {
	// Is there anything to do?
	if !reqtrace.Enabled() || !*fTraceByPID {
		out = in
		return
	}

	gPIDMapMu.Lock()
	defer gPIDMapMu.Unlock()

	// Do we already have a traced context for this PID?
	if existing, ok := gPIDMap[pid]; ok {
		out = existing
		return
	}

	// Set up a new one and stick it in the map.
	var report reqtrace.ReportFunc
	out, report = reqtrace.Trace(in, fmt.Sprintf("Requests from PID %v", pid))
	gPIDMap[pid] = out

	// Ensure we close the trace and remove it from the map eventually.
	go reportWhenPIDGone(pid, out, report)

	return
}

func (o *commonOp) ShortDesc() (desc string) {
	opName := reflect.TypeOf(o.op).String()

	// Attempt to better handle the usual case: a string that looks like
	// "*fuseops.GetInodeAttributesOp".
	const prefix = "*fuseops."
	const suffix = "Op"
	if strings.HasPrefix(opName, prefix) && strings.HasSuffix(opName, suffix) {
		opName = opName[len(prefix) : len(opName)-len(suffix)]
	}

	// Include the inode number to which the op applies.
	desc = fmt.Sprintf("%s(inode=%v)", opName, o.bazilReq.Hdr().Node)

	return
}

func (o *commonOp) init(
	ctx context.Context,
	op Op,
	bazilReq bazilfuse.Request,
	log func(int, string, ...interface{}),
	finish func(error)) {
	// Initialize basic fields.
	o.ctx = ctx
	o.op = op
	o.bazilReq = bazilReq
	o.log = log
	o.finish = finish

	// Set up a context that reflects per-PID tracing if appropriate.
	o.ctx = o.maybeTraceByPID(o.ctx, int(bazilReq.Hdr().Pid))

	// Set up a trace span for this op.
	var reportForTrace reqtrace.ReportFunc
	o.ctx, reportForTrace = reqtrace.StartSpan(ctx, o.op.ShortDesc())

	// When the op is finished, report to both reqtrace and the connection.
	prevFinish := o.finish
	o.finish = func(err error) {
		reportForTrace(err)
		prevFinish(err)
	}
}

func (o *commonOp) Header() OpHeader {
	bh := o.bazilReq.Hdr()
	return OpHeader{
		Uid: bh.Uid,
		Gid: bh.Gid,
	}
}

func (o *commonOp) Context() context.Context {
	return o.ctx
}

func (o *commonOp) Logf(format string, v ...interface{}) {
	const calldepth = 2
	o.log(calldepth, format, v...)
}

func (o *commonOp) respondErr(err error) {
	if err == nil {
		panic("Expect non-nil here.")
	}

	o.report(err)

	o.Logf(
		"-> (%s) error: %v",
		o.op.ShortDesc(),
		err)

	o.bazilReq.RespondError(err)
}

// Respond with the supplied response struct, which must be accepted by a
// method called Respond on o.bazilReq.
//
// Special case: nil means o.bazilReq.Respond accepts no parameters.
func (o *commonOp) respond(resp interface{}) {
	// We were successful.
	o.report(nil)

	// Find the Respond method.
	v := reflect.ValueOf(o.bazilReq)
	respond := v.MethodByName("Respond")

	// Special case: handle successful ops with no response struct.
	if resp == nil {
		o.Logf("-> (%s) OK", o.op.ShortDesc())
		respond.Call([]reflect.Value{})
		return
	}

	// Otherwise, pass along the response struct.
	o.Logf("-> %v", resp)
	respond.Call([]reflect.Value{reflect.ValueOf(resp)})
}
<commit_msg>commonOp.respondErr<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuseops

import (
	"flag"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/jacobsa/bazilfuse"
	"github.com/jacobsa/reqtrace"
	"golang.org/x/net/context"
	"golang.org/x/sys/unix"
)

var fTraceByPID = flag.Bool(
	"fuse.trace_by_pid",
	false,
	"Enable a hacky mode that uses reqtrace to group all ops from each "+
		"individual PID. Not a good idea to use in production; races, bugs, and "+
		"resource leaks likely lurk.")

// A helper for embedding common behavior.
type commonOp struct {
	// The context exposed to the user.
	ctx context.Context

	// The op in which this struct is embedded.
	op Op

	// The underlying bazilfuse request for this op.
	bazilReq bazilfuse.Request

	// A function that can be used to log information about the op. The first
	// argument is a call depth.
	log func(int, string, ...interface{})

	// A function that is invoked with the error given to Respond, for use in
	// closing off traces and reporting back to the connection.
	finish func(error)
}

var gPIDMapMu sync.Mutex

// A map from PID to a traced context for that PID.
//
// GUARDED_BY(gPIDMapMu)
var gPIDMap = make(map[int]context.Context)

// Wait until the process completes, then close off the trace and remove the
// context from the map.
func reportWhenPIDGone(
	pid int,
	ctx context.Context,
	report reqtrace.ReportFunc) {
	// HACK(jacobsa): Poll until the process no longer exists.
	const pollPeriod = 50 * time.Millisecond
	for {
		// The man page for kill(2) says that if the signal is zero, then "no
		// signal is sent, but error checking is still performed; this can be used
		// to check for the existence of a process ID".
		err := unix.Kill(pid, 0)

		// ESRCH means the process is gone.
		if err == unix.ESRCH {
			break
		}

		// If we receive EPERM, we're not going to be able to do what we want. We
		// don't really have any choice but to print info and leak.
		if err == unix.EPERM {
			log.Printf("Failed to kill(2) PID %v; no permissions. Leaking trace.", pid)
			return
		}

		// Otherwise, panic.
		if err != nil {
			panic(fmt.Errorf("Kill(%v): %v", pid, err))
		}

		time.Sleep(pollPeriod)
	}

	// Finish up.
	report(nil)

	gPIDMapMu.Lock()
	delete(gPIDMap, pid)
	gPIDMapMu.Unlock()
}

func (o *commonOp) maybeTraceByPID(
	in context.Context,
	pid int) (out context.Context) {
	// Is there anything to do?
	if !reqtrace.Enabled() || !*fTraceByPID {
		out = in
		return
	}

	gPIDMapMu.Lock()
	defer gPIDMapMu.Unlock()

	// Do we already have a traced context for this PID?
	if existing, ok := gPIDMap[pid]; ok {
		out = existing
		return
	}

	// Set up a new one and stick it in the map.
	var report reqtrace.ReportFunc
	out, report = reqtrace.Trace(in, fmt.Sprintf("Requests from PID %v", pid))
	gPIDMap[pid] = out

	// Ensure we close the trace and remove it from the map eventually.
	go reportWhenPIDGone(pid, out, report)

	return
}

func (o *commonOp) ShortDesc() (desc string) {
	opName := reflect.TypeOf(o.op).String()

	// Attempt to better handle the usual case: a string that looks like
	// "*fuseops.GetInodeAttributesOp".
	const prefix = "*fuseops."
	const suffix = "Op"
	if strings.HasPrefix(opName, prefix) && strings.HasSuffix(opName, suffix) {
		opName = opName[len(prefix) : len(opName)-len(suffix)]
	}

	// Include the inode number to which the op applies.
	desc = fmt.Sprintf("%s(inode=%v)", opName, o.bazilReq.Hdr().Node)

	return
}

func (o *commonOp) init(
	ctx context.Context,
	op Op,
	bazilReq bazilfuse.Request,
	log func(int, string, ...interface{}),
	finish func(error)) {
	// Initialize basic fields.
	o.ctx = ctx
	o.op = op
	o.bazilReq = bazilReq
	o.log = log
	o.finish = finish

	// Set up a context that reflects per-PID tracing if appropriate.
	o.ctx = o.maybeTraceByPID(o.ctx, int(bazilReq.Hdr().Pid))

	// Set up a trace span for this op.
	var reportForTrace reqtrace.ReportFunc
	o.ctx, reportForTrace = reqtrace.StartSpan(ctx, o.op.ShortDesc())

	// When the op is finished, report to both reqtrace and the connection.
	prevFinish := o.finish
	o.finish = func(err error) {
		reportForTrace(err)
		prevFinish(err)
	}
}

func (o *commonOp) Header() OpHeader {
	bh := o.bazilReq.Hdr()
	return OpHeader{
		Uid: bh.Uid,
		Gid: bh.Gid,
	}
}

func (o *commonOp) Context() context.Context {
	return o.ctx
}

func (o *commonOp) Logf(format string, v ...interface{}) {
	const calldepth = 2
	o.log(calldepth, format, v...)
}

func (o *commonOp) respondErr(err error) {
	if err == nil {
		panic("Expect non-nil here.")
	}

	o.Logf(
		"-> (%s) error: %v",
		o.op.ShortDesc(),
		err)

	// Send a response to the kernel.
	o.bazilReq.RespondError(err)

	// Report back to the connection that we are finished.
	o.finish(err)
}

// Respond with the supplied response struct, which must be accepted by a
// method called Respond on o.bazilReq.
//
// Special case: nil means o.bazilReq.Respond accepts no parameters.
func (o *commonOp) respond(resp interface{}) {
	// We were successful.
	o.report(nil)

	// Find the Respond method.
	v := reflect.ValueOf(o.bazilReq)
	respond := v.MethodByName("Respond")

	// Special case: handle successful ops with no response struct.
	if resp == nil {
		o.Logf("-> (%s) OK", o.op.ShortDesc())
		respond.Call([]reflect.Value{})
		return
	}

	// Otherwise, pass along the response struct.
	o.Logf("-> %v", resp)
	respond.Call([]reflect.Value{reflect.ValueOf(resp)})
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// +build 386 amd64

package sha512

//go:noescape

func block(dig *digest, p []byte)
<commit_msg>crypto/sha512: avoid duplicate block declaration on 386<commit_after>// Copyright 2013 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.

// +build amd64

package sha512

//go:noescape

func block(dig *digest, p []byte)
<|endoftext|>


<commit_before>
package main

import (
	"testing"
	"github.com/jarcoal/httpmock"
	"github.com/dontpanic92/wxGo/wx"
)

func commonTestStart() *MainStatusWindowImpl {
	// initialize the handlers for all image formats so that wx.Bitmap routines can load all
	// supported image formats from disk
	wx.InitAllImageHandlers()

	app := wx.NewApp()
	frame := InitMainStatusWindowImpl(true, func() *Options {
		return &Options{}
	})
	frame.app = app
	app.SetTopWindow(frame)
	msg("showing frame")
	frame.Show()
	return frame
}

func TestExactLastPage(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	frame := commonTestStart()
	fake_oauth_token := "fakeoauth123"
	msg("setting mock oauth token: %s", fake_oauth_token)
	frame.main_obj.options.authorization_oauth = &fake_oauth_token
	frame.main_obj._auth_oauth = fake_oauth_token

	msg("set small pages")
	frame.main_obj.queryPageSize = 1

	msg("creating channel watcher")
	frame.main_obj.main_loop_iter = frame.main_obj.NewChannelWatcher()

	msg("mocking username call")
	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken",
		httpmock.NewStringResponder(200, `{"token": {"user_name": "fakeusername"}}`))

	msg("mocking call to get followed channels")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/users/fakeusername/follows/channels?limit=1&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "follows": [{"notifications": true, "channel": {
		  "id": 123,
		  "display_name": "FakeChannel",
		  "url": "https://twitch.tv/fakechannel",
		  "status": "somestatus",
		  "logo": null
		}}]}`))

	msg("mocking first call to see what streams are up")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=1&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "streams": [
			{"channel": {
				  "id": 123,
				  "display_name": "FakeChannel",
				  "url": "https://twitch.tv/fakechannel",
				  "status": "somestatus",
				  "logo": null
				},
			 "is_playlist": false,
			 "id": 456,
			 "created_at": "2016-01-01T01:01:01Z",
			 "game": "a vidya game"
			}
		]}`))

	msg("doing iterator call")
	next_wait := frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online := frame.list_online.GetCount()
	streams_offline := frame.list_offline.GetCount()
	assertEqual(1, streams_online, "streams online")
	assertEqual(0, streams_offline, "streams offline")

	frame.Shutdown()
}

func TestStreamsGoOffline(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	frame := commonTestStart()

	fake_oauth_token := "fakeoauth123"
	msg("setting mock oauth token: %s", fake_oauth_token)
	frame.main_obj.options.authorization_oauth = &fake_oauth_token
	frame.main_obj._auth_oauth = fake_oauth_token

	msg("creating channel watcher")
	frame.main_obj.main_loop_iter = frame.main_obj.NewChannelWatcher()

	msg("mocking username call")
	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken",
		httpmock.NewStringResponder(200, `{"token": {"user_name": "fakeusername"}}`))

	msg("mocking call to get followed channels")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/users/fakeusername/follows/channels?limit=25&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "follows": [{"notifications": true, "channel": {
		  "id": 123,
		  "display_name": "FakeChannel",
		  "url": "https://twitch.tv/fakechannel",
		  "status": "somestatus",
		  "logo": null
		}}]}`))

	msg("mocking first call to see what streams are up")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "streams": [
			{"channel": {
				  "id": 123,
				  "display_name": "FakeChannel",
				  "url": "https://twitch.tv/fakechannel",
				  "status": "somestatus",
				  "logo": null
				},
			 "is_playlist": false,
			 "id": 456,
			 "created_at": "2016-01-01T01:01:01Z",
			 "game": "a vidya game"
			}
		]}`))

	msg("doing iterator call")
	next_wait := frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online := frame.list_online.GetCount()
	streams_offline := frame.list_offline.GetCount()
	assertEqual(1, streams_online, "streams online")
	assertEqual(0, streams_offline, "streams offline")

	msg("mocking a second follow call where the stream has gone offline")
	httpmock.Reset()

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 0, "streams": []}`))

	msg("do the next poll right away")
	next_wait = frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online = frame.list_online.GetCount()
	streams_offline = frame.list_offline.GetCount()
	assertEqual(0, streams_online, "streams online")
	assertEqual(1, streams_offline, "streams offline")

	frame.Shutdown()
}

func assertEqual(expectedValue uint, actualValue uint, desc string) {
	assert(expectedValue == actualValue, "%s expected %v, got %v", desc, expectedValue, actualValue)
}
<commit_msg>Updated tests to expect stream_type=live param in streams/followed request that was missing before<commit_after>
package main

import (
	"testing"
	"github.com/jarcoal/httpmock"
	"github.com/dontpanic92/wxGo/wx"
)

func commonTestStart() *MainStatusWindowImpl {
	// initialize the handlers for all image formats so that wx.Bitmap routines can load all
	// supported image formats from disk
	wx.InitAllImageHandlers()

	app := wx.NewApp()
	frame := InitMainStatusWindowImpl(true, func() *Options {
		return &Options{}
	})
	frame.app = app
	app.SetTopWindow(frame)
	msg("showing frame")
	frame.Show()
	return frame
}

func TestExactLastPage(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	frame := commonTestStart()
	fake_oauth_token := "fakeoauth123"
	msg("setting mock oauth token: %s", fake_oauth_token)
	frame.main_obj.options.authorization_oauth = &fake_oauth_token
	frame.main_obj._auth_oauth = fake_oauth_token

	msg("set small pages")
	frame.main_obj.queryPageSize = 1

	msg("creating channel watcher")
	frame.main_obj.main_loop_iter = frame.main_obj.NewChannelWatcher()

	msg("mocking username call")
	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken",
		httpmock.NewStringResponder(200, `{"token": {"user_name": "fakeusername"}}`))

	msg("mocking call to get followed channels")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/users/fakeusername/follows/channels?limit=1&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "follows": [{"notifications": true, "channel": {
		  "id": 123,
		  "display_name": "FakeChannel",
		  "url": "https://twitch.tv/fakechannel",
		  "status": "somestatus",
		  "logo": null
		}}]}`))

	msg("mocking first call to see what streams are up")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=1&offset=0&stream_type=live",
		httpmock.NewStringResponder(200, `{"_total": 1, "streams": [
			{"channel": {
				  "id": 123,
				  "display_name": "FakeChannel",
				  "url": "https://twitch.tv/fakechannel",
				  "status": "somestatus",
				  "logo": null
				},
			 "is_playlist": false,
			 "id": 456,
			 "created_at": "2016-01-01T01:01:01Z",
			 "game": "a vidya game"
			}
		]}`))

	msg("doing iterator call")
	next_wait := frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online := frame.list_online.GetCount()
	streams_offline := frame.list_offline.GetCount()
	assertEqual(1, streams_online, "streams online")
	assertEqual(0, streams_offline, "streams offline")

	frame.Shutdown()
}

func TestStreamsGoOffline(t *testing.T) {
	httpmock.Activate()
	defer httpmock.DeactivateAndReset()

	frame := commonTestStart()

	fake_oauth_token := "fakeoauth123"
	msg("setting mock oauth token: %s", fake_oauth_token)
	frame.main_obj.options.authorization_oauth = &fake_oauth_token
	frame.main_obj._auth_oauth = fake_oauth_token

	msg("creating channel watcher")
	frame.main_obj.main_loop_iter = frame.main_obj.NewChannelWatcher()

	msg("mocking username call")
	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken",
		httpmock.NewStringResponder(200, `{"token": {"user_name": "fakeusername"}}`))

	msg("mocking call to get followed channels")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/users/fakeusername/follows/channels?limit=25&offset=0",
		httpmock.NewStringResponder(200, `{"_total": 1, "follows": [{"notifications": true, "channel": {
		  "id": 123,
		  "display_name": "FakeChannel",
		  "url": "https://twitch.tv/fakechannel",
		  "status": "somestatus",
		  "logo": null
		}}]}`))

	msg("mocking first call to see what streams are up")

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0&stream_type=live",
		httpmock.NewStringResponder(200, `{"_total": 1, "streams": [
			{"channel": {
				  "id": 123,
				  "display_name": "FakeChannel",
				  "url": "https://twitch.tv/fakechannel",
				  "status": "somestatus",
				  "logo": null
				},
			 "is_playlist": false,
			 "id": 456,
			 "created_at": "2016-01-01T01:01:01Z",
			 "game": "a vidya game"
			}
		]}`))

	msg("doing iterator call")
	next_wait := frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online := frame.list_online.GetCount()
	streams_offline := frame.list_offline.GetCount()
	assertEqual(1, streams_online, "streams online")
	assertEqual(0, streams_offline, "streams offline")

	msg("mocking a second follow call where the stream has gone offline")
	httpmock.Reset()

	httpmock.RegisterResponder("GET", "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0&stream_type=live",
		httpmock.NewStringResponder(200, `{"_total": 0, "streams": []}`))

	msg("do the next poll right away")
	next_wait = frame.main_obj.main_loop_iter.next()
	frame.main_obj.log(next_wait.reason)

	msg("checks")
	streams_online = frame.list_online.GetCount()
	streams_offline = frame.list_offline.GetCount()
	assertEqual(0, streams_online, "streams online")
	assertEqual(1, streams_offline, "streams offline")

	frame.Shutdown()
}

func assertEqual(expectedValue uint, actualValue uint, desc string) {
	assert(expectedValue == actualValue, "%s expected %v, got %v", desc, expectedValue, actualValue)
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, 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 etcdserver

import (
	"crypto/sha1"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net/url"
	"sort"
	"strings"

	"github.com/coreos/etcd/pkg/flags"
	"github.com/coreos/etcd/pkg/types"
)

// Cluster is a list of Members that belong to the same raft cluster
type Cluster struct {
	id      uint64
	name    string
	members map[uint64]*Member
}

func NewCluster(clusterName string) *Cluster {
	c := &Cluster{name: clusterName, members: make(map[uint64]*Member)}
	return c
}

func (c Cluster) FindName(name string) *Member {
	for _, m := range c.members {
		if m.Name == name {
			return m
		}
	}
	return nil
}

func (c Cluster) FindID(id uint64) *Member {
	return c.members[id]
}

func (c Cluster) Add(m Member) error {
	if c.FindID(m.ID) != nil {
		return fmt.Errorf("Member exists with identical ID %v", m)
	}
	c.members[m.ID] = &m
	return nil
}

func (c *Cluster) AddSlice(mems []Member) error {
	for _, m := range mems {
		err := c.Add(m)
		if err != nil {
			return err
		}
	}

	return nil
}

// Pick chooses a random address from a given Member's addresses, and returns it as
// an addressible URI. If the given member does not exist, an empty string is returned.
func (c Cluster) Pick(id uint64) string {
	if m := c.FindID(id); m != nil {
		urls := m.PeerURLs
		if len(urls) == 0 {
			return ""
		}
		return urls[rand.Intn(len(urls))]
	}

	return ""
}

// AddMembersFromFlag parses a sets of names to IPs either from the command line or discovery formatted like:
// mach0=http://1.1.1.1,mach0=http://2.2.2.2,mach0=http://1.1.1.1,mach1=http://2.2.2.2,mach1=http://3.3.3.3
func (c *Cluster) SetMembersFromString(s string) error {
	c.members = make(map[uint64]*Member)
	v, err := url.ParseQuery(strings.Replace(s, ",", "&", -1))
	if err != nil {
		return err
	}

	for name, urls := range v {
		if len(urls) == 0 || urls[0] == "" {
			return fmt.Errorf("Empty URL given for %q", name)
		}

		m := newMember(name, types.URLs(*flags.NewURLsValue(strings.Join(urls, ","))), c.name, nil)
		err := c.Add(*m)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Cluster) AddMemberFromURLs(name string, urls types.URLs) (*Member, error) {
	m := newMember(name, urls, c.name, nil)
	err := c.Add(*m)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (c *Cluster) GenID(salt []byte) {
	mIDs := c.MemberIDs()
	b := make([]byte, 8*len(mIDs))
	for i, id := range mIDs {
		binary.BigEndian.PutUint64(b[8*i:], id)
	}
	b = append(b, salt...)
	hash := sha1.Sum(b)
	c.id = binary.BigEndian.Uint64(hash[:8])
}

func (c Cluster) String() string {
	sl := []string{}
	for _, m := range c.members {
		for _, u := range m.PeerURLs {
			sl = append(sl, fmt.Sprintf("%s=%s", m.Name, u))
		}
	}
	sort.Strings(sl)
	return strings.Join(sl, ",")
}

func (c Cluster) ID() uint64 { return c.id }

func (c Cluster) Members() map[uint64]*Member { return c.members }

func (c Cluster) MemberIDs() []uint64 {
	var ids []uint64
	for _, m := range c.members {
		ids = append(ids, m.ID)
	}
	sort.Sort(types.Uint64Slice(ids))
	return ids
}

// PeerURLs returns a list of all peer addresses. Each address is prefixed
// with the scheme (currently "http://"). The returned list is sorted in
// ascending lexicographical order.
func (c Cluster) PeerURLs() []string {
	endpoints := make([]string, 0)
	for _, p := range c.members {
		for _, addr := range p.PeerURLs {
			endpoints = append(endpoints, addr)
		}
	}
	sort.Strings(endpoints)
	return endpoints
}

// ClientURLs returns a list of all client addresses. Each address is prefixed
// with the scheme (currently "http://"). The returned list is sorted in
// ascending lexicographical order.
func (c Cluster) ClientURLs() []string {
	urls := make([]string, 0)
	for _, p := range c.members {
		for _, url := range p.ClientURLs {
			urls = append(urls, url)
		}
	}
	sort.Strings(urls)
	return urls
}
<commit_msg>fix wrong name<commit_after>/*
   Copyright 2014 CoreOS, 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 etcdserver

import (
	"crypto/sha1"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net/url"
	"sort"
	"strings"

	"github.com/coreos/etcd/pkg/flags"
	"github.com/coreos/etcd/pkg/types"
)

// Cluster is a list of Members that belong to the same raft cluster
type Cluster struct {
	id      uint64
	name    string
	members map[uint64]*Member
}

func NewCluster(clusterName string) *Cluster {
	c := &Cluster{name: clusterName, members: make(map[uint64]*Member)}
	return c
}

func (c Cluster) FindName(name string) *Member {
	for _, m := range c.members {
		if m.Name == name {
			return m
		}
	}
	return nil
}

func (c Cluster) FindID(id uint64) *Member {
	return c.members[id]
}

func (c Cluster) Add(m Member) error {
	if c.FindID(m.ID) != nil {
		return fmt.Errorf("Member exists with identical ID %v", m)
	}
	c.members[m.ID] = &m
	return nil
}

func (c *Cluster) AddSlice(mems []Member) error {
	for _, m := range mems {
		err := c.Add(m)
		if err != nil {
			return err
		}
	}

	return nil
}

// Pick chooses a random address from a given Member's addresses, and returns it as
// an addressible URI. If the given member does not exist, an empty string is returned.
func (c Cluster) Pick(id uint64) string {
	if m := c.FindID(id); m != nil {
		urls := m.PeerURLs
		if len(urls) == 0 {
			return ""
		}
		return urls[rand.Intn(len(urls))]
	}

	return ""
}

// SetMembersFromString parses a sets of names to IPs either from the command line or discovery formatted like:
// mach0=http://1.1.1.1,mach0=http://2.2.2.2,mach0=http://1.1.1.1,mach1=http://2.2.2.2,mach1=http://3.3.3.3
func (c *Cluster) SetMembersFromString(s string) error {
	c.members = make(map[uint64]*Member)
	v, err := url.ParseQuery(strings.Replace(s, ",", "&", -1))
	if err != nil {
		return err
	}

	for name, urls := range v {
		if len(urls) == 0 || urls[0] == "" {
			return fmt.Errorf("Empty URL given for %q", name)
		}

		m := newMember(name, types.URLs(*flags.NewURLsValue(strings.Join(urls, ","))), c.name, nil)
		err := c.Add(*m)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Cluster) AddMemberFromURLs(name string, urls types.URLs) (*Member, error) {
	m := newMember(name, urls, c.name, nil)
	err := c.Add(*m)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (c *Cluster) GenID(salt []byte) {
	mIDs := c.MemberIDs()
	b := make([]byte, 8*len(mIDs))
	for i, id := range mIDs {
		binary.BigEndian.PutUint64(b[8*i:], id)
	}
	b = append(b, salt...)
	hash := sha1.Sum(b)
	c.id = binary.BigEndian.Uint64(hash[:8])
}

func (c Cluster) String() string {
	sl := []string{}
	for _, m := range c.members {
		for _, u := range m.PeerURLs {
			sl = append(sl, fmt.Sprintf("%s=%s", m.Name, u))
		}
	}
	sort.Strings(sl)
	return strings.Join(sl, ",")
}

func (c Cluster) ID() uint64 { return c.id }

func (c Cluster) Members() map[uint64]*Member { return c.members }

func (c Cluster) MemberIDs() []uint64 {
	var ids []uint64
	for _, m := range c.members {
		ids = append(ids, m.ID)
	}
	sort.Sort(types.Uint64Slice(ids))
	return ids
}

// PeerURLs returns a list of all peer addresses. Each address is prefixed
// with the scheme (currently "http://"). The returned list is sorted in
// ascending lexicographical order.
func (c Cluster) PeerURLs() []string {
	endpoints := make([]string, 0)
	for _, p := range c.members {
		for _, addr := range p.PeerURLs {
			endpoints = append(endpoints, addr)
		}
	}
	sort.Strings(endpoints)
	return endpoints
}

// ClientURLs returns a list of all client addresses. Each address is prefixed
// with the scheme (currently "http://"). The returned list is sorted in
// ascending lexicographical order.
func (c Cluster) ClientURLs() []string {
	urls := make([]string, 0)
	for _, p := range c.members {
		for _, url := range p.ClientURLs {
			urls = append(urls, url)
		}
	}
	sort.Strings(urls)
	return urls
}
<|endoftext|>


<commit_before>package lpc8xx

var ChipInfo = map[int]string{
	0x8100: "- LPC810: 4 KB flash, 1 KB RAM, DIP8",
	0x8110: "- LPC811: 8 KB flash, 2 KB RAM, TSSOP16",
	0x8120: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP16",
	0x8121: "- LPC812: 16 KB flash, 4 KB RAM, SO20",
	0x8122: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8221: "- LPC822: 16 KB flash, 4 KB RAM, HVQFN33",
	0x8222: "- LPC822: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8241: "- LPC824: 32 KB flash, 8 KB RAM, HVQFN33",
	0x8242: "- LPC824: 32 KB flash, 8 KB RAM, TSSOP20",
}
<commit_msg>tweak<commit_after>package lpc8xx

var ChipInfo = map[int]string{
	0x8100: "LPC810: 4 KB flash, 1 KB RAM, DIP8",
	0x8110: "LPC811: 8 KB flash, 2 KB RAM, TSSOP16",
	0x8120: "LPC812: 16 KB flash, 4 KB RAM, TSSOP16",
	0x8121: "LPC812: 16 KB flash, 4 KB RAM, SO20",
	0x8122: "LPC812: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8221: "LPC822: 16 KB flash, 4 KB RAM, HVQFN33",
	0x8222: "LPC822: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8241: "LPC824: 32 KB flash, 8 KB RAM, HVQFN33",
	0x8242: "LPC824: 32 KB flash, 8 KB RAM, TSSOP20",
}
<|endoftext|>