<commit_before>package api

/*
	This file is all serializable types used in Rio
	to define filesets, WareIDs, packing systems, and storage locations.
*/

import (
	"fmt"
	"strings"

	"github.com/polydawn/refmt/obj/atlas"
)

/*
	Ware IDs are content-addressable, cryptographic hashes which uniquely identify
	a "ware" -- a packed filesystem snapshot.

	Ware IDs are serialized as a string in two parts, separated by a colon --
	for example like "git:f23ae1829" or "tar:WJL8or32vD".
	The first part communicates which kind of packing system computed the hash,
	and the second part is the hash itself.
*/
type WareID struct {
	Type string
	Hash string
}

func ParseWareID(x string) (WareID, error) {
	ss := strings.SplitN(x, ":", 2)
	if len(ss) < 2 {
		return WareID{}, fmt.Errorf("wareIDs must have contain a colon character (they are of form \"<type>:<hash>\")")
	}
	return WareID{ss[0], ss[1]}, nil
}

func (x WareID) String() string {
	return x.Type + ":" + x.Hash
}

var WareID_AtlasEntry = atlas.BuildEntry(WareID{}).Transform().
	TransformMarshal(atlas.MakeMarshalTransformFunc(
		func(x WareID) (string, error) {
			return x.String(), nil
		})).
	TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
		func(x string) (WareID, error) {
			return ParseWareID(x)
		})).
	Complete()

type AbsPath string // Identifier for output slots.  Coincidentally, a path.
<commit_msg>api: meditations on warehouse/discovery config.<commit_after>package api

/*
	This file is all serializable types used in Rio
	to define filesets, WareIDs, packing systems, and storage locations.
*/

import (
	"fmt"
	"strings"

	"github.com/polydawn/refmt/obj/atlas"
)

/*
	Ware IDs are content-addressable, cryptographic hashes which uniquely identify
	a "ware" -- a packed filesystem snapshot.

	Ware IDs are serialized as a string in two parts, separated by a colon --
	for example like "git:f23ae1829" or "tar:WJL8or32vD".
	The first part communicates which kind of packing system computed the hash,
	and the second part is the hash itself.
*/
type WareID struct {
	Type string
	Hash string
}

func ParseWareID(x string) (WareID, error) {
	ss := strings.SplitN(x, ":", 2)
	if len(ss) < 2 {
		return WareID{}, fmt.Errorf("wareIDs must have contain a colon character (they are of form \"<type>:<hash>\")")
	}
	return WareID{ss[0], ss[1]}, nil
}

func (x WareID) String() string {
	return x.Type + ":" + x.Hash
}

var WareID_AtlasEntry = atlas.BuildEntry(WareID{}).Transform().
	TransformMarshal(atlas.MakeMarshalTransformFunc(
		func(x WareID) (string, error) {
			return x.String(), nil
		})).
	TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
		func(x string) (WareID, error) {
			return ParseWareID(x)
		})).
	Complete()

type AbsPath string // Identifier for output slots.  Coincidentally, a path.

/*
	WarehouseAddr strings describe a protocol and dial address for talking to
	a storage warehouse.

	The serial format is an opaque string, though they typically resemble
	(and for internal use, are parsed as) URLs.
*/
type WarehouseAddr string

/*
	For workspace configuration: warehouses may involve auth, so
	we definitely don't want them to require redundant declaration:

		{
			"warehouseName": {
				"auth": {...},
				"addr": "...",
				"prio": "9000", // ??
			},
		}

	Should the warehouse name in that doc simply *be* the addr?  Probably.
	(Although in some cases things may be more complicated.
	For example, for IPFS, that might be bootstrap node addr *list*;
	the warehouseName would still probably want to carry a semantic though:
	it would likely bear a prefix path, or IPNS key, or something.)

	For hitch: we don't generally want to provide auth, nor would
	prioritization overrides be sane, so, there, the warehouse name and
	addr info most definitely default to being one and the same.

	The nature of things as strings alone for hitch would seem to indicate
	that that string should be the join column for everyone:
	repeatr formulas with discovery hint sections should use that string as well.

	For formulas: ahhhhhh.  Here things get truly strange.

	For formulas, you may want to give a warehouse name hint per input path.
	Or, per hash.  (That's roughly the same thing, unless the same hash shows
	up multiple times, which is a rare coincidence we can effectively ignore.)
	Or, per import name.

	Formulas also need the warehouse names *again* for *saving outputs*.
	This is often simpler, because the most sensible user story is to upload things
	to one(!) storage (usually, a local disk...!), and mirror thereafter.
	But what if you have two outputs, one more secret than the other?
	Or two outputs, one of which is simply a totally different pack type
	(perhaps you have a trans-pack-mirror-fanout step -- hah!)?
	Sensible defaults will carry us a long way for most of the time, but
	some defined way to deal with the interesting cases is also needed.

	For formula outputs, then, we have learned something: they *definitely* need
	to be able to specify a warehouseName per path.
	There simply isn't anything else to go by!  Tags don't belong in
	formulas anymore; that's a thing we definitely know now in this
	brave new world with hitch and the clear separation of planners and execution.

	What else do we know about the story for formula inputs?

	  - increasingly, formulas are being treated as halfway to assembly: they're allowed to be a tad uggo.
	  - warehouse info still *absolutely* must go in a top level "discovery" section and be joinable, *not* in inputs.
	  - i guess it coudl be in the imports but that seems wrong, and uncongruent with how outputs could never be.
	  - imports is also a bad idea simply because repeatr itself is still not supposed to *see* imports, really.  merely be tolerant of them being in the same doc as the (rest?  no, *real*) formula.
	  - paths are a red herring, though.  aren't they?  this should be more like "have hash; inquire with db/daemons where to get it"

	But that's a SIGINT leak.

	Let's focus back to SIGINT, then, as a success heuristic.

	In short: that means some sort of naming layer needs to be the root of deciding
	what lookup attempts to make.  (The fact it may give us a chance to save ourself
	from the shittiness of the git protocol's ability to advertise available objects
	is merely "coincidental" (though admittedly also critical).)

	Addntl user story: usually, things come in *pools*.
	There's the public mirror pool of popular upstream stuff.
	There's probably going to be a rix objects pool.  Just makes sense, for budgetary reasons.
	There's probably going to be a *private* pool at your office.
	Git repos each act like their own pools and they're really shits for this.
	And you might have a *private* pool at home for your side projects or consultancy gigs or whatever.

	There's an interesting dichotomy here:
	with *public* objects, you don't really mind over-asking about them;
	with *private* objects (or git), you're quite worried about over-asking.
	(N.b. Even if you mind your SIGINT so much that you don't want to ask your $dayjob
	storage pools at phpcompany about your nodejs asset needs, you solve that by just
	*not listing* that private storage pool in that workspace.  You still have workspaces.)

	(There's also the outlier of non-CAS / single-ware warehouses.  Those are odd enough
	that they can have their own entire dang schema section; we can disregard them here.)

	So maybe this gives us leverage on the safe defaults thing.
	We just ask *all* your pools.
	Unless it's got a specific one listed.

	Voilà;
	you can give explicits for git, so we can literally even;
	you can say nothing at all by default, and get sensible results sans fuss;
	and if you're a company that's paranoid af, you can either generate quite verbose
	override-ridden documents, or, come to think of it, just *don't have* public pools
	in the first place (mirroring is easy by design, after all, so why not?).

*/
<|endoftext|>


<commit_before>package ethlog

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"testing"
	"time"
)

type TestLogSystem struct {
	Output string
	level  LogLevel
}

func (t *TestLogSystem) Println(v ...interface{}) {
	t.Output += fmt.Sprintln(v...)
}

func (t *TestLogSystem) Printf(format string, v ...interface{}) {
	t.Output += fmt.Sprintf(format, v...)
}

func (t *TestLogSystem) SetLogLevel(i LogLevel) {
	t.level = i
}

func (t *TestLogSystem) GetLogLevel() LogLevel {
	return t.level
}

func TestLoggerFlush(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	for i := 0; i < 5; i++ {
		logger.Errorf(".")
	}
	Flush()
	output := testLogSystem.Output
	if output != "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] ." {
		t.Error("Expected complete logger output '[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .', got ", output)
	}
}

func TestLoggerPrintln(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	logger.Errorln("error")
	logger.Warnln("warn")
	logger.Infoln("info")
	logger.Debugln("debug")
	Flush()
	output := testLogSystem.Output
	if output != "[TEST] error\n[TEST] warn\n" {
		t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", output)
	}
}

func TestLoggerPrintf(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	logger.Errorf("error to %v\n", *testLogSystem)
	logger.Warnf("warn")
	logger.Infof("info")
	logger.Debugf("debug")
	Flush()
	output := testLogSystem.Output
	if output != "[TEST] error to { 2}\n[TEST] warn" {
		t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", output)
	}
}

func TestMultipleLogSystems(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem0 := &TestLogSystem{level: ErrorLevel}
	testLogSystem1 := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem0)
	AddLogSystem(testLogSystem1)
	logger.Errorln("error")
	logger.Warnln("warn")
	Flush()
	output0 := testLogSystem0.Output
	output1 := testLogSystem1.Output
	if output0 != "[TEST] error\n" {
		t.Error("Expected logger 0 output '[TEST] error\\n', got ", output0)
	}
	if output1 != "[TEST] error\n[TEST] warn\n" {
		t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", output1)
	}
}

func TestFileLogSystem(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	filename := "test.log"
	file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
	testLogSystem := NewStdLogSystem(file, 0, WarnLevel)
	AddLogSystem(testLogSystem)
	logger.Errorf("error to %s\n", filename)
	logger.Warnln("warn")
	Flush()
	contents, _ := ioutil.ReadFile(filename)
	output := string(contents)
	if output != "[TEST] error to test.log\n[TEST] warn\n" {
		t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output)
	} else {
		os.Remove(filename)
	}
}

func TestNoLogSystem(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	logger.Warnln("warn")
	Flush()
}

func TestConcurrentAddSystem(t *testing.T) {
	rand.Seed(time.Now().Unix())
	Reset()

	logger := NewLogger("TEST")
	stop := make(chan struct{})
	writer := func() {
		select {
		case <-stop:
			return
		default:
			logger.Infof("foo")
			Flush()
		}
	}

	go writer()
	go writer()

	stopTime := time.Now().Add(100 * time.Millisecond)
	for time.Now().Before(stopTime) {
		time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond)
		AddLogSystem(&TestLogSystem{level: InfoLevel})
	}
	close(stop)
}
<commit_msg>ethlog: improve TestLogSystem<commit_after>package ethlog

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"sync"
	"testing"
	"time"
)

type TestLogSystem struct {
	mutex  sync.Mutex
	output string
	level  LogLevel
}

func (ls *TestLogSystem) Println(v ...interface{}) {
	ls.mutex.Lock()
	ls.output += fmt.Sprintln(v...)
	ls.mutex.Unlock()
}

func (ls *TestLogSystem) Printf(format string, v ...interface{}) {
	ls.mutex.Lock()
	ls.output += fmt.Sprintf(format, v...)
	ls.mutex.Unlock()
}

func (ls *TestLogSystem) SetLogLevel(i LogLevel) {
	ls.mutex.Lock()
	ls.level = i
	ls.mutex.Unlock()
}

func (ls *TestLogSystem) GetLogLevel() LogLevel {
	ls.mutex.Lock()
	defer ls.mutex.Unlock()
	return ls.level
}

func (ls *TestLogSystem) CheckOutput(t *testing.T, expected string) {
	ls.mutex.Lock()
	output := ls.output
	ls.mutex.Unlock()
	if output != expected {
		t.Errorf("log output mismatch:\n   got: %q\n  want: %q\n", output, expected)
	}
}

}

func TestLoggerFlush(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	for i := 0; i < 5; i++ {
		logger.Errorf(".")
	}
	Flush()
	output := testLogSystem.Output
	if output != "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] ." {
		t.Error("Expected complete logger output '[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .', got ", output)
	}
}

func TestLoggerPrintln(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	logger.Errorln("error")
	logger.Warnln("warn")
	logger.Infoln("info")
	logger.Debugln("debug")
	Flush()

	testLogSystem.CheckOutput(t, "[TEST] error\n[TEST] warn\n")
}

func TestLoggerPrintf(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem)
	logger.Errorf("error to %v\n", []int{1, 2, 3})
	logger.Warnf("warn")
	logger.Infof("info")
	logger.Debugf("debug")
	Flush()
	testLogSystem.CheckOutput(t, "[TEST] error to [1 2 3]\n[TEST] warn")
}

func TestMultipleLogSystems(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	testLogSystem0 := &TestLogSystem{level: ErrorLevel}
	testLogSystem1 := &TestLogSystem{level: WarnLevel}
	AddLogSystem(testLogSystem0)
	AddLogSystem(testLogSystem1)
	logger.Errorln("error")
	logger.Warnln("warn")
	Flush()

	testLogSystem0.CheckOutput(t, "[TEST] error\n")
	testLogSystem1.CheckOutput(t, "[TEST] error\n[TEST] warn\n")
}

func TestFileLogSystem(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	filename := "test.log"
	file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
	testLogSystem := NewStdLogSystem(file, 0, WarnLevel)
	AddLogSystem(testLogSystem)
	logger.Errorf("error to %s\n", filename)
	logger.Warnln("warn")
	Flush()
	contents, _ := ioutil.ReadFile(filename)
	output := string(contents)
	if output != "[TEST] error to test.log\n[TEST] warn\n" {
		t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output)
	} else {
		os.Remove(filename)
	}
}

func TestNoLogSystem(t *testing.T) {
	Reset()

	logger := NewLogger("TEST")
	logger.Warnln("warn")
	Flush()
}

func TestConcurrentAddSystem(t *testing.T) {
	rand.Seed(time.Now().Unix())
	Reset()

	logger := NewLogger("TEST")
	stop := make(chan struct{})
	writer := func() {
		select {
		case <-stop:
			return
		default:
			logger.Infoln("foo")
			Flush()
		}
	}

	go writer()
	go writer()

	stopTime := time.Now().Add(100 * time.Millisecond)
	for time.Now().Before(stopTime) {
		time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond)
		AddLogSystem(&TestLogSystem{level: InfoLevel})
	}
	close(stop)
}
<|endoftext|>


<commit_before>package numerizer

import (
	"testing"
)

var (
	Examples = map[string]string{
		"one":            "1",
		"two and a half": "2.5",
		"five":           "5",
		"ten":            "10",
		"eleven":         "11",
		"twelve":         "12",
		"thirteen":       "13",
		"fourteen":       "14",
		"fifteen":        "15",
		"sixteen":        "16",
		"seventeen":      "17",
		"eighteen":       "18",
		"nineteen":       "19",
		"twenty":         "20",
		"twenty seven":   "27",
		"thirty-one":     "31",
		"thirty-seven":   "37",
		"forty one":      "41",
		"fourty two":     "42",
		"fifty nine":     "59",
		//"a hundred":                                         "100",
		"one hundred":                                       "100",
		"one hundred and fifty":                             "150",
		"two-hundred":                                       "200",
		"5 hundred":                                         "500",
		"nine hundred and ninety nine":                      "999",
		"one thousand":                                      "1000",
		"twelve hundred":                                    "1200",
		"one thousand two hundred":                          "1200",
		"seventeen thousand":                                "17000",
		"twentyone-thousand-four-hundred-and-seventy-three": "21473",
		"seventy four thousand and two":                     "74002",
		"ninety nine thousand nine hundred ninety nine":     "99999",
		"100 thousand":                                      "100000",
		"two hundred fifty thousand":                        "250000",
		"one million":                                       "1000000",
		"one million two hundred fifty thousand and seven":  "1250007",
		"one billion":                                       "1000000000",
		"one billion and one":                               "1000000001",
	}

	Ordinals = map[string]string{
		"first":               "1st",
		"second":              "second",
		"third":               "3rd",
		"fifth":               "5th",
		"seventh":             "7th",
		"eighth":              "8th",
		"tenth":               "10th",
		"eleventh":            "11th",
		"twelfth":             "12th",
		"thirteenth":          "13th",
		"sixteenth":           "16th",
		"twentieth":           "20th",
		"twenty-third":        "23rd",
		"thirtieth":           "30th",
		"thirty-first":        "31st",
		"fourtieth":           "40th",
		"fourty ninth":        "49th",
		"fiftieth":            "50th",
		"sixtieth":            "60th",
		"seventieth":          "70th",
		"eightieth":           "80th",
		"ninetieth":           "90th",
		"hundredth":           "100th",
		"thousandth":          "1000th",
		"millionth":           "1000000th",
		"billionth":           "1000000000th",
		"trillionth":          "1000000000000th",
		"first day month two": "1st day month 2",
	}
)

func Test_CombinedDoubleDigits(t *testing.T) {
	number := Numerize("thirtyseven")

	if number != "37" {
		t.Error("Number not parsed")
	}

}

//func Test_A_Million(t *testing.T) {
//number, err := Numerize("a million")

//if err != nil {
//t.Error("Number not parsed, error: " + err.Error())
//}

//if number != "1000000" {
//t.Error("Number not parsed")
//}
//}

func Test_DirectNums(t *testing.T) {
	number := Numerize("eleven")

	if number != "11" {
		t.Error("Number not parsed")
	}
}

func Test_TenPrefix(t *testing.T) {
	number := Numerize("thirty")

	if number != "30" {
		t.Error("Number not parsed")
	}
}

func Test_Fraction_1(t *testing.T) {
	number := Numerize("a fifth")

	if number != "1/5" {
		t.Error("Number not parsed")
	}
}

func Test_Fractions_2(t *testing.T) {
	number := Numerize("two fifths")

	if number != "2/5" {
		t.Error("Number not parsed")
	}
}

func Test_DirectOrdinal(t *testing.T) {
	number := Numerize("ninth")

	if number != "9th" {
		t.Error("Number not parsed")
	}
}

func Test_SingleOrdinal(t *testing.T) {
	number := Numerize("third")

	if number != "3rd" {
		t.Error("Number not parsed")
	}
}

func Test_CleanFraction(t *testing.T) {
	number := Numerize("one and two fifths")

	if number != "1.4" {
		t.Error("Number not parsed")
	}
}

func Test_BigPrefix(t *testing.T) {
	number := Numerize("two trillion")

	if number != "2000000000000" {
		t.Error("Number not parsed")
	}
}

func Test_Numbers(t *testing.T) {
	for text, numberStr := range Examples {
		result := Numerize(text)

		if result != numberStr {
			t.Errorf("Failed test. %s:  %s != %s", text, numberStr, result)
		}
	}
}

func Test_Ordinals(t *testing.T) {
	for text, numberStr := range Ordinals {
		result := Numerize(text)

		if result != numberStr {
			t.Errorf("Failed test. %s:  %s != %s", text, numberStr, result)
		}
	}
}

func Test_Compatability(t *testing.T) {
	if "1/2" != Numerize("1/2") {
		t.Error("Number not parsed correctly.")
	}

	if "05/06" != Numerize("05/06") {
		t.Error("Number not parsed correctly.")
	}

	if "3.5 hours" != Numerize("three and a half hours") {
		println(Numerize("three and a half hours"))
		t.Error("Number not parsed correctly.")
	}
}

func Test_MultipleSlashesShouldNotBeEvaluated(t *testing.T) {
	if "11/02/2007" != Numerize("11/02/2007") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_Edges(t *testing.T) {
	if "27 Oct 2006 7:30am" != Numerize("27 Oct 2006 7:30am") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_WordWithANumber(t *testing.T) {
	if "pennyweight" != Numerize("pennyweight") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_FractionalAddition(t *testing.T) {
	if "1.25" != Numerize("one and a quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "2.375" != Numerize("two and three eighths") {
		t.Error("Number not parsed correctly.")
	}
	if "3.5 hours" != Numerize("three and a half hours") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_CombinedDoubleDigets(t *testing.T) {
	if "21" != Numerize("twentyone") {
		t.Error("Number not parsed correctly.")
	}
	if "37" != Numerize("thirtyseven") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_FractionsInWords(t *testing.T) {
	if "1/4" != Numerize("1 quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/4" != Numerize("one quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/4" != Numerize("a quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/8" != Numerize("one eighth") {
		t.Error("Number not parsed correctly.")
	}

	if "3/4" != Numerize("three quarters") {
		t.Error("Number not parsed correctly.")
	}
	if "2/4" != Numerize("two fourths") {
		t.Error("Number not parsed correctly.")
	}
	if "3/8" != Numerize("three eighths") {
		t.Error("Number not parsed correctly.")
	}
}
<commit_msg>Add benchmark for the Numerize function.<commit_after>package numerizer

import (
	"testing"
)

var (
	Examples = map[string]string{
		"one":            "1",
		"two and a half": "2.5",
		"five":           "5",
		"ten":            "10",
		"eleven":         "11",
		"twelve":         "12",
		"thirteen":       "13",
		"fourteen":       "14",
		"fifteen":        "15",
		"sixteen":        "16",
		"seventeen":      "17",
		"eighteen":       "18",
		"nineteen":       "19",
		"twenty":         "20",
		"twenty seven":   "27",
		"thirty-one":     "31",
		"thirty-seven":   "37",
		"forty one":      "41",
		"fourty two":     "42",
		"fifty nine":     "59",
		//"a hundred":                                         "100",
		"one hundred":                                       "100",
		"one hundred and fifty":                             "150",
		"two-hundred":                                       "200",
		"5 hundred":                                         "500",
		"nine hundred and ninety nine":                      "999",
		"one thousand":                                      "1000",
		"twelve hundred":                                    "1200",
		"one thousand two hundred":                          "1200",
		"seventeen thousand":                                "17000",
		"twentyone-thousand-four-hundred-and-seventy-three": "21473",
		"seventy four thousand and two":                     "74002",
		"ninety nine thousand nine hundred ninety nine":     "99999",
		"100 thousand":                                      "100000",
		"two hundred fifty thousand":                        "250000",
		"one million":                                       "1000000",
		"one million two hundred fifty thousand and seven":  "1250007",
		"one billion":                                       "1000000000",
		"one billion and one":                               "1000000001",
	}

	Ordinals = map[string]string{
		"first":               "1st",
		"second":              "second",
		"third":               "3rd",
		"fifth":               "5th",
		"seventh":             "7th",
		"eighth":              "8th",
		"tenth":               "10th",
		"eleventh":            "11th",
		"twelfth":             "12th",
		"thirteenth":          "13th",
		"sixteenth":           "16th",
		"twentieth":           "20th",
		"twenty-third":        "23rd",
		"thirtieth":           "30th",
		"thirty-first":        "31st",
		"fourtieth":           "40th",
		"fourty ninth":        "49th",
		"fiftieth":            "50th",
		"sixtieth":            "60th",
		"seventieth":          "70th",
		"eightieth":           "80th",
		"ninetieth":           "90th",
		"hundredth":           "100th",
		"thousandth":          "1000th",
		"millionth":           "1000000th",
		"billionth":           "1000000000th",
		"trillionth":          "1000000000000th",
		"first day month two": "1st day month 2",
	}
)

func Test_CombinedDoubleDigits(t *testing.T) {
	number := Numerize("thirtyseven")

	if number != "37" {
		t.Error("Number not parsed")
	}

}

//func Test_A_Million(t *testing.T) {
//number, err := Numerize("a million")

//if err != nil {
//t.Error("Number not parsed, error: " + err.Error())
//}

//if number != "1000000" {
//t.Error("Number not parsed")
//}
//}

func Test_DirectNums(t *testing.T) {
	number := Numerize("eleven")

	if number != "11" {
		t.Error("Number not parsed")
	}
}

func Test_TenPrefix(t *testing.T) {
	number := Numerize("thirty")

	if number != "30" {
		t.Error("Number not parsed")
	}
}

func Test_Fraction_1(t *testing.T) {
	number := Numerize("a fifth")

	if number != "1/5" {
		t.Error("Number not parsed")
	}
}

func Test_Fractions_2(t *testing.T) {
	number := Numerize("two fifths")

	if number != "2/5" {
		t.Error("Number not parsed")
	}
}

func Test_DirectOrdinal(t *testing.T) {
	number := Numerize("ninth")

	if number != "9th" {
		t.Error("Number not parsed")
	}
}

func Test_SingleOrdinal(t *testing.T) {
	number := Numerize("third")

	if number != "3rd" {
		t.Error("Number not parsed")
	}
}

func Test_CleanFraction(t *testing.T) {
	number := Numerize("one and two fifths")

	if number != "1.4" {
		t.Error("Number not parsed")
	}
}

func Test_BigPrefix(t *testing.T) {
	number := Numerize("two trillion")

	if number != "2000000000000" {
		t.Error("Number not parsed")
	}
}

func Test_Numbers(t *testing.T) {
	for text, numberStr := range Examples {
		result := Numerize(text)

		if result != numberStr {
			t.Errorf("Failed test. %s:  %s != %s", text, numberStr, result)
		}
	}
}

func Test_Ordinals(t *testing.T) {
	for text, numberStr := range Ordinals {
		result := Numerize(text)

		if result != numberStr {
			t.Errorf("Failed test. %s:  %s != %s", text, numberStr, result)
		}
	}
}

func Test_Compatability(t *testing.T) {
	if "1/2" != Numerize("1/2") {
		t.Error("Number not parsed correctly.")
	}

	if "05/06" != Numerize("05/06") {
		t.Error("Number not parsed correctly.")
	}

	if "3.5 hours" != Numerize("three and a half hours") {
		println(Numerize("three and a half hours"))
		t.Error("Number not parsed correctly.")
	}
}

func Test_MultipleSlashesShouldNotBeEvaluated(t *testing.T) {
	if "11/02/2007" != Numerize("11/02/2007") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_Edges(t *testing.T) {
	if "27 Oct 2006 7:30am" != Numerize("27 Oct 2006 7:30am") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_WordWithANumber(t *testing.T) {
	if "pennyweight" != Numerize("pennyweight") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_FractionalAddition(t *testing.T) {
	if "1.25" != Numerize("one and a quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "2.375" != Numerize("two and three eighths") {
		t.Error("Number not parsed correctly.")
	}
	if "3.5 hours" != Numerize("three and a half hours") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_CombinedDoubleDigets(t *testing.T) {
	if "21" != Numerize("twentyone") {
		t.Error("Number not parsed correctly.")
	}
	if "37" != Numerize("thirtyseven") {
		t.Error("Number not parsed correctly.")
	}
}

func Test_FractionsInWords(t *testing.T) {
	if "1/4" != Numerize("1 quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/4" != Numerize("one quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/4" != Numerize("a quarter") {
		t.Error("Number not parsed correctly.")
	}
	if "1/8" != Numerize("one eighth") {
		t.Error("Number not parsed correctly.")
	}

	if "3/4" != Numerize("three quarters") {
		t.Error("Number not parsed correctly.")
	}
	if "2/4" != Numerize("two fourths") {
		t.Error("Number not parsed correctly.")
	}
	if "3/8" != Numerize("three eighths") {
		t.Error("Number not parsed correctly.")
	}
}

func Benchmark_Numerize(b *testing.B) {
	for n := 0; n < b.N; n++ {
		for text, _ := range Examples {
			Numerize(text)
		}

		for text, _ := range Ordinals {
			Numerize(text)
		}
	}
}
<|endoftext|>


<commit_before>package hwio

// A driver for Raspberry Pi where device tree is supported (linux kernel 3.7+)
//
// Things known to work (tested on raspian 3.10+ kernel, rev 1 board):
// - digital write on all support ed GPIO pins
// - digital read on all GPIO pins, for modes INPUT.
//
// Known issues:
// - INPUT_PULLUP and INPUT_PULLDOWN not implemented yet.
// - no support yet for SPI, serial
//
// References:
// - http://elinux.org/RPi_Low-level_peripherals
// - https://projects.drogon.net/raspberry-pi/wiringpi/
// - BCM2835 technical reference

import (
	"os/exec"
	"strings"
	"fmt"
)

type raspberry_board_revision int

const (
	type0ne = iota
	typeTwo
	typeAplusBPlusZeroPi2
)

type RaspberryPiDTDriver struct { // all pins understood by the driver
	pinConfigs []*DTPinConfig

	// a map of module names to module objects, created at initialisation
	modules map[string]Module
}

func NewRaspPiDTDriver() *RaspberryPiDTDriver {
	return &RaspberryPiDTDriver{}
}

func (d *RaspberryPiDTDriver) MatchesHardwareConfig() bool {
	cpuinfo, e := exec.Command("cat", "/proc/cpuinfo").Output()
	if e != nil {
		return false
	}
	s := string(cpuinfo)
	if strings.Contains(s, "BCM2708") || strings.Contains(s, "BCM2709") || strings.Contains(s, "BCM2835") {
		fmt.Println("Matching Raspi")
		return true
	}

	return false
}

func (d *RaspberryPiDTDriver) Init() error {
	d.createPinData()
	d.initialiseModules()

	return nil
}

// http://www.hobbytronics.co.uk/raspberry-pi-gpio-pinout
func (d *RaspberryPiDTDriver) createPinData() {
	fmt.Println("Creating Pin Data")
	switch d.BoardRevision() {
	case type0ne:
		fmt.Println("Creating Type One")
		d.pinConfigs = []*DTPinConfig{
			&DTPinConfig{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			&DTPinConfig{[]string{"3.3v"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"5v"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"sda"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"do-not-connect-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"scl"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"ground"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			&DTPinConfig{[]string{"txd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"do-not-connect-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"rxd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			&DTPinConfig{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			&DTPinConfig{[]string{"gpio21"}, []string{"gpio"}, 21, 0},
			&DTPinConfig{[]string{"do-not-connect-3"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			&DTPinConfig{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			&DTPinConfig{[]string{"do-not-connect-4"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			&DTPinConfig{[]string{"mosi"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"do-not-connect-5"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"miso"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			&DTPinConfig{[]string{"sclk"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"ce0n"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"do-not-connect-6"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"ce1n"}, []string{"spi"}, 0, 0},
		}
	case typeTwo:
		fmt.Println("Creating Type Two")
		d.pinConfigs = []*DTPinConfig{
			&DTPinConfig{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			&DTPinConfig{[]string{"3.3v-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"5v-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"sda"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"5v-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"scl"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"ground-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			&DTPinConfig{[]string{"txd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"ground-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"rxd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			&DTPinConfig{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			&DTPinConfig{[]string{"gpio27"}, []string{"gpio"}, 27, 0},
			&DTPinConfig{[]string{"ground-3"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			&DTPinConfig{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			&DTPinConfig{[]string{"3.3v-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			&DTPinConfig{[]string{"mosi"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"ground-4"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"miso"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			&DTPinConfig{[]string{"sclk"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"gpio8"}, []string{"gpio"}, 8, 0},
			&DTPinConfig{[]string{"ground-5"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio7"}, []string{"gpio"}, 7, 0},
		}
	case typeAplusBPlusZeroPi2: // B+
		fmt.Println("Creating Type PLUS")
		d.pinConfigs = []*DTPinConfig{
			&DTPinConfig{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			&DTPinConfig{[]string{"3.3v-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"5v-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"sda"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"5v-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"scl"}, []string{"i2c"}, 0, 0},
			&DTPinConfig{[]string{"ground-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			&DTPinConfig{[]string{"txd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"ground-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"rxd"}, []string{"serial"}, 0, 0},
			&DTPinConfig{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			&DTPinConfig{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			&DTPinConfig{[]string{"gpio27"}, []string{"gpio"}, 21, 0},
			&DTPinConfig{[]string{"ground-3"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			&DTPinConfig{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			&DTPinConfig{[]string{"3.3v-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			&DTPinConfig{[]string{"mosi"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"ground-4"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"miso"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			&DTPinConfig{[]string{"sclk"}, []string{"spi"}, 0, 0},
			&DTPinConfig{[]string{"gpio8"}, []string{"gpio"}, 8, 0},
			&DTPinConfig{[]string{"ground-5"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio7"}, []string{"gpio"}, 7, 0},
			&DTPinConfig{[]string{"do-not-connect-1"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"do-not-connect-2"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio5"}, []string{"gpio"}, 5, 0},
			&DTPinConfig{[]string{"ground-6"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio6"}, []string{"gpio"}, 6, 0},
			&DTPinConfig{[]string{"gpio12"}, []string{"gpio"}, 12, 0},
			&DTPinConfig{[]string{"gpio13"}, []string{"gpio"}, 13, 0},
			&DTPinConfig{[]string{"ground-7"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio19"}, []string{"gpio"}, 19, 0},
			&DTPinConfig{[]string{"gpio16"}, []string{"gpio"}, 16, 0},
			&DTPinConfig{[]string{"gpio26"}, []string{"gpio"}, 26, 0},
			&DTPinConfig{[]string{"gpio20"}, []string{"gpio"}, 20, 0},
			&DTPinConfig{[]string{"ground-8"}, []string{"unassignable"}, 0, 0},
			&DTPinConfig{[]string{"gpio21"}, []string{"gpio"}, 21, 0},
		}
	}
}

func (d *RaspberryPiDTDriver) initialiseModules() error {
	d.modules = make(map[string]Module)

	gpio := NewDTGPIOModule("gpio")
	e := gpio.SetOptions(d.getGPIOOptions())
	if e != nil {
		return e
	}

	i2c := NewDTI2CModule("i2c")
	e = i2c.SetOptions(d.getI2COptions())
	if e != nil {
		return e
	}

	// Create the leds module which is BBB-specific. There are no options.
	leds := NewDTLEDModule("leds")
	e = leds.SetOptions(d.getLEDOptions("leds"))
	if e != nil {
		return e
	}

	d.modules["gpio"] = gpio
	d.modules["i2c"] = i2c
	d.modules["leds"] = leds

	return nil
}

// Get options for GPIO module, derived from the pin structure
func (d *RaspberryPiDTDriver) getGPIOOptions() map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTGPIOModulePinDefMap)

	// Add the GPIO pins to this map
	for i, hw := range d.pinConfigs {
		if hw.modules[0] == "gpio" {
			pins[Pin(i)] = &DTGPIOModulePinDef{pin: Pin(i), gpioLogical: hw.gpioLogical}
		}
	}
	result["pins"] = pins

	return result
}

func (d *RaspberryPiDTDriver) getI2COptions() map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTI2CModulePins, 0)
	pins = append(pins, Pin(3))
	pins = append(pins, Pin(5))

	result["pins"] = pins

	if d.BoardRevision() == 1 {
		result["device"] = "/dev/i2c-0"
	} else {
		result["device"] = "/dev/i2c-1"
	}

	return result
}

func (d *RaspberryPiDTDriver) getLEDOptions(name string) map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTLEDModulePins)
	pins["ok"] = "/sys/class/leds/led0/"

	result["pins"] = pins

	return result
}

// Determine the version of Raspberry Pi.
// This discussion http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=23989
// was used to determine the algorithm, specifically the comment by gordon@drogon.net
// It will return 1 or 2.
func (d *RaspberryPiDTDriver) BoardRevision() int {
	revision := CpuInfo(0, "Revision")
	switch revision {
	case "0002", "0003":
		return type0ne
	case "0010":
		return typeAplusBPlusZeroPi2
	}

	// Pi 2 boards have different strings, but pinout is the same as B+
	revision = CpuInfo(0, "CPU revision")
	switch revision {
	case "5":
		return typeAplusBPlusZeroPi2
	case "7": //PI zero +
		return typeAplusBPlusZeroPi2
	}

	return typeTwo
}

func (d *RaspberryPiDTDriver) GetModules() map[string]Module {
	return d.modules
}

func (d *RaspberryPiDTDriver) Close() {
	// Disable all the modules
	for _, module := range d.modules {
		module.Disable()
	}
}

func (d *RaspberryPiDTDriver) PinMap() (pinMap HardwarePinMap) {
	pinMap = make(HardwarePinMap)

	for i, hw := range d.pinConfigs {
		pinMap.add(Pin(i), hw.names, hw.modules)
	}

	return
}
<commit_msg>cleanup code<commit_after>package hwio

// A driver for Raspberry Pi where device tree is supported (linux kernel 3.7+)
//
// Things known to work (tested on raspian 3.10+ kernel, rev 1 board):
// - digital write on all support ed GPIO pins
// - digital read on all GPIO pins, for modes INPUT.
//
// Known issues:
// - INPUT_PULLUP and INPUT_PULLDOWN not implemented yet.
// - no support yet for SPI, serial
//
// References:
// - http://elinux.org/RPi_Low-level_peripherals
// - https://projects.drogon.net/raspberry-pi/wiringpi/
// - BCM2835 technical reference

import (
	"os/exec"
	"strings"
)

type pinoutRevision int
const (
	//type0ne is used for a Raspberry 1
	type0ne = iota
	//typeTwo is used for a Raspberry 2
	typeTwo
	//typeAplusBPlusZeroPi2 is used fo  Raspberry Pi 1 Models A+ and B+, Pi 2 Model B, Pi 3 Model B and Pi Zero (and Zero W)
	typeAplusBPlusZeroPi2
)

type RaspberryPiDTDriver struct { // all pins understood by the driver
	pinConfigs []*DTPinConfig

	// a map of module names to module objects, created at initialisation
	modules map[string]Module
}

func NewRaspPiDTDriver() *RaspberryPiDTDriver {
	return &RaspberryPiDTDriver{}
}

func (d *RaspberryPiDTDriver) MatchesHardwareConfig() bool {
	cpuinfo, e := exec.Command("cat", "/proc/cpuinfo").Output()
	if e != nil {
		return false
	}
	s := string(cpuinfo)
	if strings.Contains(s, "BCM2708") || strings.Contains(s, "BCM2709") || strings.Contains(s, "BCM2835") {
		return true
	}

	return false
}

func (d *RaspberryPiDTDriver) Init() error {
	d.createPinData()
	d.initialiseModules()

	return nil
}

// http://www.hobbytronics.co.uk/raspberry-pi-gpio-pinout
func (d *RaspberryPiDTDriver) createPinData() {
	switch d.BoardRevision() {
	case type0ne:
		d.pinConfigs = []*DTPinConfig{
			{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			{[]string{"3.3v"}, []string{"unassignable"}, 0, 0},
			{[]string{"5v"}, []string{"unassignable"}, 0, 0},
			{[]string{"sda"}, []string{"i2c"}, 0, 0},
			{[]string{"do-not-connect-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"scl"}, []string{"i2c"}, 0, 0},
			{[]string{"ground"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			{[]string{"txd"}, []string{"serial"}, 0, 0},
			{[]string{"do-not-connect-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"rxd"}, []string{"serial"}, 0, 0},
			{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			{[]string{"gpio21"}, []string{"gpio"}, 21, 0},
			{[]string{"do-not-connect-3"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			{[]string{"do-not-connect-4"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			{[]string{"mosi"}, []string{"spi"}, 0, 0},
			{[]string{"do-not-connect-5"}, []string{"unassignable"}, 0, 0},
			{[]string{"miso"}, []string{"spi"}, 0, 0},
			{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			{[]string{"sclk"}, []string{"spi"}, 0, 0},
			{[]string{"ce0n"}, []string{"spi"}, 0, 0},
			{[]string{"do-not-connect-6"}, []string{"unassignable"}, 0, 0},
			{[]string{"ce1n"}, []string{"spi"}, 0, 0},
		}
	case typeTwo:
		d.pinConfigs = []*DTPinConfig{
			{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			{[]string{"3.3v-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"5v-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"sda"}, []string{"i2c"}, 0, 0},
			{[]string{"5v-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"scl"}, []string{"i2c"}, 0, 0},
			{[]string{"ground-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			{[]string{"txd"}, []string{"serial"}, 0, 0},
			{[]string{"ground-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"rxd"}, []string{"serial"}, 0, 0},
			{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			{[]string{"gpio27"}, []string{"gpio"}, 27, 0},
			{[]string{"ground-3"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			{[]string{"3.3v-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			{[]string{"mosi"}, []string{"spi"}, 0, 0},
			{[]string{"ground-4"}, []string{"unassignable"}, 0, 0},
			{[]string{"miso"}, []string{"spi"}, 0, 0},
			{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			{[]string{"sclk"}, []string{"spi"}, 0, 0},
			{[]string{"gpio8"}, []string{"gpio"}, 8, 0},
			{[]string{"ground-5"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio7"}, []string{"gpio"}, 7, 0},
		}
	case typeAplusBPlusZeroPi2: // B+
		d.pinConfigs = []*DTPinConfig{
			{[]string{"null"}, []string{"unassignable"}, 0, 0}, // 0 - spacer
			{[]string{"3.3v-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"5v-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"sda"}, []string{"i2c"}, 0, 0},
			{[]string{"5v-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"scl"}, []string{"i2c"}, 0, 0},
			{[]string{"ground-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio4"}, []string{"gpio"}, 4, 0},
			{[]string{"txd"}, []string{"serial"}, 0, 0},
			{[]string{"ground-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"rxd"}, []string{"serial"}, 0, 0},
			{[]string{"gpio17"}, []string{"gpio"}, 17, 0},
			{[]string{"gpio18"}, []string{"gpio"}, 18, 0}, // also supports PWM
			{[]string{"gpio27"}, []string{"gpio"}, 21, 0},
			{[]string{"ground-3"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio22"}, []string{"gpio"}, 22, 0},
			{[]string{"gpio23"}, []string{"gpio"}, 23, 0},
			{[]string{"3.3v-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio24"}, []string{"gpio"}, 24, 0},
			{[]string{"mosi"}, []string{"spi"}, 0, 0},
			{[]string{"ground-4"}, []string{"unassignable"}, 0, 0},
			{[]string{"miso"}, []string{"spi"}, 0, 0},
			{[]string{"gpio25"}, []string{"gpio"}, 25, 0},
			{[]string{"sclk"}, []string{"spi"}, 0, 0},
			{[]string{"gpio8"}, []string{"gpio"}, 8, 0},
			{[]string{"ground-5"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio7"}, []string{"gpio"}, 7, 0},
			{[]string{"do-not-connect-1"}, []string{"unassignable"}, 0, 0},
			{[]string{"do-not-connect-2"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio5"}, []string{"gpio"}, 5, 0},
			{[]string{"ground-6"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio6"}, []string{"gpio"}, 6, 0},
			{[]string{"gpio12"}, []string{"gpio"}, 12, 0},
			{[]string{"gpio13"}, []string{"gpio"}, 13, 0},
			{[]string{"ground-7"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio19"}, []string{"gpio"}, 19, 0},
			{[]string{"gpio16"}, []string{"gpio"}, 16, 0},
			{[]string{"gpio26"}, []string{"gpio"}, 26, 0},
			{[]string{"gpio20"}, []string{"gpio"}, 20, 0},
			{[]string{"ground-8"}, []string{"unassignable"}, 0, 0},
			{[]string{"gpio21"}, []string{"gpio"}, 21, 0},
		}
	}
}

func (d *RaspberryPiDTDriver) initialiseModules() error {
	d.modules = make(map[string]Module)

	gpio := NewDTGPIOModule("gpio")
	e := gpio.SetOptions(d.getGPIOOptions())
	if e != nil {
		return e
	}

	i2c := NewDTI2CModule("i2c")
	e = i2c.SetOptions(d.getI2COptions())
	if e != nil {
		return e
	}

	// Create the leds module which is BBB-specific. There are no options.
	leds := NewDTLEDModule("leds")
	e = leds.SetOptions(d.getLEDOptions("leds"))
	if e != nil {
		return e
	}

	d.modules["gpio"] = gpio
	d.modules["i2c"] = i2c
	d.modules["leds"] = leds

	return nil
}

// Get options for GPIO module, derived from the pin structure
func (d *RaspberryPiDTDriver) getGPIOOptions() map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTGPIOModulePinDefMap)

	// Add the GPIO pins to this map
	for i, hw := range d.pinConfigs {
		if hw.modules[0] == "gpio" {
			pins[Pin(i)] = &DTGPIOModulePinDef{pin: Pin(i), gpioLogical: hw.gpioLogical}
		}
	}
	result["pins"] = pins

	return result
}

func (d *RaspberryPiDTDriver) getI2COptions() map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTI2CModulePins, 0)
	pins = append(pins, Pin(3))
	pins = append(pins, Pin(5))

	result["pins"] = pins

	if d.BoardRevision() ==  type0ne {
		result["device"] = "/dev/i2c-0"
	} else {
		result["device"] = "/dev/i2c-1"
	}

	return result
}

func (d *RaspberryPiDTDriver) getLEDOptions(name string) map[string]interface{} {
	result := make(map[string]interface{})

	pins := make(DTLEDModulePins)
	pins["ok"] = "/sys/class/leds/led0/"

	result["pins"] = pins

	return result
}

// Determine the version of Raspberry Pi.
// This discussion http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=23989
// was used to determine the algorithm, specifically the comment by gordon@drogon.net
// It will return 1 or 2.
func (d *RaspberryPiDTDriver) BoardRevision() pinoutRevision {
	revision := CpuInfo(0, "Revision")
	switch revision {
	case "0002", "0003":
		return type0ne
	case "0010":
		return typeAplusBPlusZeroPi2
	}

	// Pi 2 boards have different strings, but pinout is the same as B+
	revision = CpuInfo(0, "CPU revision")
	switch revision {
	case "5":
		return typeAplusBPlusZeroPi2
	case "7": //PI zero +
		return typeAplusBPlusZeroPi2
	}

	return typeTwo
}

func (d *RaspberryPiDTDriver) GetModules() map[string]Module {
	return d.modules
}

func (d *RaspberryPiDTDriver) Close() {
	// Disable all the modules
	for _, module := range d.modules {
		module.Disable()
	}
}

func (d *RaspberryPiDTDriver) PinMap() (pinMap HardwarePinMap) {
	pinMap = make(HardwarePinMap)

	for i, hw := range d.pinConfigs {
		pinMap.add(Pin(i), hw.names, hw.modules)
	}

	return
}
<|endoftext|>


<commit_before>package logrus

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"time"
)

var (
	bufferPool *sync.Pool

	// qualified package name, cached at first use
	logrusPackage string

	// Positions in the call stack when tracing to report the calling method
	minimumCallerDepth int

	// Used for caller information initialisation
	callerInitOnce sync.Once
)

const (
	maximumCallerDepth int = 25
	knownLogrusFrames  int = 4
)

func init() {
	bufferPool = &sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}

	// start at the bottom of the stack before the package-name cache is primed
	minimumCallerDepth = 1
}

// Defines the key when adding errors using WithError.
var ErrorKey = "error"

// An entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
// reused and passed around as much as you wish to avoid field duplication.
type Entry struct {
	Logger *Logger

	// Contains all the fields set by the user.
	Data Fields

	// Time at which the log entry was created
	Time time.Time

	// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
	// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
	Level Level

	// Calling method, with package name
	Caller *runtime.Frame

	// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
	Message string

	// When formatter is called in entry.log(), a Buffer may be set to entry
	Buffer *bytes.Buffer

	// Contains the context set by the user. Useful for hook processing etc.
	Context context.Context

	// err may contain a field formatting error
	err string
}

func NewEntry(logger *Logger) *Entry {
	return &Entry{
		Logger: logger,
		// Default is three fields, plus one optional.  Give a little extra room.
		Data: make(Fields, 6),
	}
}

// Returns the bytes representation of this entry from the formatter.
func (entry *Entry) Bytes() ([]byte, error) {
	return entry.Logger.Formatter.Format(entry)
}

// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
	serialized, err := entry.Bytes()
	if err != nil {
		return "", err
	}
	str := string(serialized)
	return str, nil
}

// Add an error as single field (using the key defined in ErrorKey) to the Entry.
func (entry *Entry) WithError(err error) *Entry {
	return entry.WithField(ErrorKey, err)
}

// Add a context to the Entry.
func (entry *Entry) WithContext(ctx context.Context) *Entry {
	dataCopy := make(Fields, len(entry.Data))
	for k, v := range entry.Data {
		dataCopy[k] = v
	}
	return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
}

// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
	return entry.WithFields(Fields{key: value})
}

// Add a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	data := make(Fields, len(entry.Data)+len(fields))
	for k, v := range entry.Data {
		data[k] = v
	}
	fieldErr := entry.err
	for k, v := range fields {
		isErrField := false
		if t := reflect.TypeOf(v); t != nil {
			switch t.Kind() {
			case reflect.Func:
				isErrField = true
			case reflect.Ptr:
				isErrField = t.Elem().Kind() == reflect.Func
			}
		}
		if isErrField {
			tmp := fmt.Sprintf("can not add field %q", k)
			if fieldErr != "" {
				fieldErr = entry.err + ", " + tmp
			} else {
				fieldErr = tmp
			}
		} else {
			data[k] = v
		}
	}
	return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}

// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
	dataCopy := make(Fields, len(entry.Data))
	for k, v := range entry.Data {
		dataCopy[k] = v
	}
	return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
}

// getPackageName reduces a fully qualified function name to the package name
// There really ought to be to be a better way...
func getPackageName(f string) string {
	for {
		lastPeriod := strings.LastIndex(f, ".")
		lastSlash := strings.LastIndex(f, "/")
		if lastPeriod > lastSlash {
			f = f[:lastPeriod]
		} else {
			break
		}
	}

	return f
}

// getCaller retrieves the name of the first non-logrus calling function
func getCaller() *runtime.Frame {

	// cache this package's fully-qualified name
	callerInitOnce.Do(func() {
		pcs := make([]uintptr, 2)
		_ = runtime.Callers(0, pcs)
		logrusPackage = getPackageName(funcName(pcs))

		// now that we have the cache, we can skip a minimum count of known-logrus functions
		// XXX this is dubious, the number of frames may vary
		minimumCallerDepth = knownLogrusFrames
	})

	// Restrict the lookback frames to avoid runaway lookups
	pcs := make([]uintptr, maximumCallerDepth)
	depth := runtime.Callers(minimumCallerDepth, pcs)
	frames := runtime.CallersFrames(pcs[:depth])

	for f, again := frames.Next(); again; f, again = frames.Next() {
		pkg := getPackageName(f.Function)

		// If the caller isn't part of this package, we're done
		if pkg != logrusPackage {
			return &f //nolint:scopelint
		}
	}

	// if we got here, we failed to find the caller's context
	return nil
}

func (entry Entry) HasCaller() (has bool) {
	return entry.Logger != nil &&
		entry.Logger.ReportCaller &&
		entry.Caller != nil
}

// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	var buffer *bytes.Buffer

	// Default to now, but allow users to override if they want.
	//
	// We don't have to worry about polluting future calls to Entry#log()
	// with this assignment because this function is declared with a
	// non-pointer receiver.
	if entry.Time.IsZero() {
		entry.Time = time.Now()
	}

	entry.Level = level
	entry.Message = msg
	if entry.Logger.ReportCaller {
		entry.Caller = getCaller()
	}

	entry.fireHooks()

	buffer = bufferPool.Get().(*bytes.Buffer)
	buffer.Reset()
	defer bufferPool.Put(buffer)
	entry.Buffer = buffer

	entry.write()

	entry.Buffer = nil

	// To avoid Entry#log() returning a value that only would make sense for
	// panic() to use in Entry#Panic(), we avoid the allocation by checking
	// directly here.
	if level <= PanicLevel {
		panic(&entry)
	}
}

func (entry *Entry) fireHooks() {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	err := entry.Logger.Hooks.Fire(entry.Level, entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
	}
}

func (entry *Entry) write() {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	serialized, err := entry.Logger.Formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
		return
	}
	if _, err = entry.Logger.Out.Write(serialized); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
	}
}

func (entry *Entry) Log(level Level, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.log(level, fmt.Sprint(args...))
	}
}

func (entry *Entry) Trace(args ...interface{}) {
	entry.Log(TraceLevel, args...)
}

func (entry *Entry) Debug(args ...interface{}) {
	entry.Log(DebugLevel, args...)
}

func (entry *Entry) Print(args ...interface{}) {
	entry.Info(args...)
}

func (entry *Entry) Info(args ...interface{}) {
	entry.Log(InfoLevel, args...)
}

func (entry *Entry) Warn(args ...interface{}) {
	entry.Log(WarnLevel, args...)
}

func (entry *Entry) Warning(args ...interface{}) {
	entry.Warn(args...)
}

func (entry *Entry) Error(args ...interface{}) {
	entry.Log(ErrorLevel, args...)
}

func (entry *Entry) Fatal(args ...interface{}) {
	entry.Log(FatalLevel, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panic(args ...interface{}) {
	entry.Log(PanicLevel, args...)
	panic(fmt.Sprint(args...))
}

// Entry Printf family functions

func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.Log(level, fmt.Sprintf(format, args...))
	}
}

func (entry *Entry) Tracef(format string, args ...interface{}) {
	entry.Logf(TraceLevel, format, args...)
}

func (entry *Entry) Debugf(format string, args ...interface{}) {
	entry.Logf(DebugLevel, format, args...)
}

func (entry *Entry) Infof(format string, args ...interface{}) {
	entry.Logf(InfoLevel, format, args...)
}

func (entry *Entry) Printf(format string, args ...interface{}) {
	entry.Infof(format, args...)
}

func (entry *Entry) Warnf(format string, args ...interface{}) {
	entry.Logf(WarnLevel, format, args...)
}

func (entry *Entry) Warningf(format string, args ...interface{}) {
	entry.Warnf(format, args...)
}

func (entry *Entry) Errorf(format string, args ...interface{}) {
	entry.Logf(ErrorLevel, format, args...)
}

func (entry *Entry) Fatalf(format string, args ...interface{}) {
	entry.Logf(FatalLevel, format, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panicf(format string, args ...interface{}) {
	entry.Logf(PanicLevel, format, args...)
}

// Entry Println family functions

func (entry *Entry) Logln(level Level, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.Log(level, entry.sprintlnn(args...))
	}
}

func (entry *Entry) Traceln(args ...interface{}) {
	entry.Logln(TraceLevel, args...)
}

func (entry *Entry) Debugln(args ...interface{}) {
	entry.Logln(DebugLevel, args...)
}

func (entry *Entry) Infoln(args ...interface{}) {
	entry.Logln(InfoLevel, args...)
}

func (entry *Entry) Println(args ...interface{}) {
	entry.Infoln(args...)
}

func (entry *Entry) Warnln(args ...interface{}) {
	entry.Logln(WarnLevel, args...)
}

func (entry *Entry) Warningln(args ...interface{}) {
	entry.Warnln(args...)
}

func (entry *Entry) Errorln(args ...interface{}) {
	entry.Logln(ErrorLevel, args...)
}

func (entry *Entry) Fatalln(args ...interface{}) {
	entry.Logln(FatalLevel, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panicln(args ...interface{}) {
	entry.Logln(PanicLevel, args...)
}

// Sprintlnn => Sprint no newline. This is to get the behavior of how
// fmt.Sprintln where spaces are always added between operands, regardless of
// their type. Instead of vendoring the Sprintln implementation to spare a
// string allocation, we do the simplest thing.
func (entry *Entry) sprintlnn(args ...interface{}) string {
	msg := fmt.Sprintln(args...)
	return msg[:len(msg)-1]
}
<commit_msg>fix deadlock in previous entry race condition fix<commit_after>package logrus

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"time"
)

var (
	bufferPool *sync.Pool

	// qualified package name, cached at first use
	logrusPackage string

	// Positions in the call stack when tracing to report the calling method
	minimumCallerDepth int

	// Used for caller information initialisation
	callerInitOnce sync.Once
)

const (
	maximumCallerDepth int = 25
	knownLogrusFrames  int = 4
)

func init() {
	bufferPool = &sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}

	// start at the bottom of the stack before the package-name cache is primed
	minimumCallerDepth = 1
}

// Defines the key when adding errors using WithError.
var ErrorKey = "error"

// An entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
// reused and passed around as much as you wish to avoid field duplication.
type Entry struct {
	Logger *Logger

	// Contains all the fields set by the user.
	Data Fields

	// Time at which the log entry was created
	Time time.Time

	// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
	// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
	Level Level

	// Calling method, with package name
	Caller *runtime.Frame

	// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
	Message string

	// When formatter is called in entry.log(), a Buffer may be set to entry
	Buffer *bytes.Buffer

	// Contains the context set by the user. Useful for hook processing etc.
	Context context.Context

	// err may contain a field formatting error
	err string
}

func NewEntry(logger *Logger) *Entry {
	return &Entry{
		Logger: logger,
		// Default is three fields, plus one optional.  Give a little extra room.
		Data: make(Fields, 6),
	}
}

// Returns the bytes representation of this entry from the formatter.
func (entry *Entry) Bytes() ([]byte, error) {
	return entry.Logger.Formatter.Format(entry)
}

// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
	serialized, err := entry.Bytes()
	if err != nil {
		return "", err
	}
	str := string(serialized)
	return str, nil
}

// Add an error as single field (using the key defined in ErrorKey) to the Entry.
func (entry *Entry) WithError(err error) *Entry {
	return entry.WithField(ErrorKey, err)
}

// Add a context to the Entry.
func (entry *Entry) WithContext(ctx context.Context) *Entry {
	dataCopy := make(Fields, len(entry.Data))
	for k, v := range entry.Data {
		dataCopy[k] = v
	}
	return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
}

// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
	return entry.WithFields(Fields{key: value})
}

// Add a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	data := make(Fields, len(entry.Data)+len(fields))
	for k, v := range entry.Data {
		data[k] = v
	}
	fieldErr := entry.err
	for k, v := range fields {
		isErrField := false
		if t := reflect.TypeOf(v); t != nil {
			switch t.Kind() {
			case reflect.Func:
				isErrField = true
			case reflect.Ptr:
				isErrField = t.Elem().Kind() == reflect.Func
			}
		}
		if isErrField {
			tmp := fmt.Sprintf("can not add field %q", k)
			if fieldErr != "" {
				fieldErr = entry.err + ", " + tmp
			} else {
				fieldErr = tmp
			}
		} else {
			data[k] = v
		}
	}
	return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}

// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
	dataCopy := make(Fields, len(entry.Data))
	for k, v := range entry.Data {
		dataCopy[k] = v
	}
	return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
}

// getPackageName reduces a fully qualified function name to the package name
// There really ought to be to be a better way...
func getPackageName(f string) string {
	for {
		lastPeriod := strings.LastIndex(f, ".")
		lastSlash := strings.LastIndex(f, "/")
		if lastPeriod > lastSlash {
			f = f[:lastPeriod]
		} else {
			break
		}
	}

	return f
}

// getCaller retrieves the name of the first non-logrus calling function
func getCaller() *runtime.Frame {

	// cache this package's fully-qualified name
	callerInitOnce.Do(func() {
		pcs := make([]uintptr, 2)
		_ = runtime.Callers(0, pcs)
		logrusPackage = getPackageName(funcName(pcs))

		// now that we have the cache, we can skip a minimum count of known-logrus functions
		// XXX this is dubious, the number of frames may vary
		minimumCallerDepth = knownLogrusFrames
	})

	// Restrict the lookback frames to avoid runaway lookups
	pcs := make([]uintptr, maximumCallerDepth)
	depth := runtime.Callers(minimumCallerDepth, pcs)
	frames := runtime.CallersFrames(pcs[:depth])

	for f, again := frames.Next(); again; f, again = frames.Next() {
		pkg := getPackageName(f.Function)

		// If the caller isn't part of this package, we're done
		if pkg != logrusPackage {
			return &f //nolint:scopelint
		}
	}

	// if we got here, we failed to find the caller's context
	return nil
}

func (entry Entry) HasCaller() (has bool) {
	return entry.Logger != nil &&
		entry.Logger.ReportCaller &&
		entry.Caller != nil
}

// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {

	var buffer *bytes.Buffer

	// Default to now, but allow users to override if they want.
	//
	// We don't have to worry about polluting future calls to Entry#log()
	// with this assignment because this function is declared with a
	// non-pointer receiver.
	if entry.Time.IsZero() {
		entry.Time = time.Now()
	}

	entry.Level = level
	entry.Message = msg
	entry.Logger.mu.Lock()
	if entry.Logger.ReportCaller {
		entry.Caller = getCaller()
	}
	entry.Logger.mu.Unlock()

	entry.fireHooks()

	buffer = bufferPool.Get().(*bytes.Buffer)
	buffer.Reset()
	defer bufferPool.Put(buffer)
	entry.Buffer = buffer

	entry.write()

	entry.Buffer = nil

	// To avoid Entry#log() returning a value that only would make sense for
	// panic() to use in Entry#Panic(), we avoid the allocation by checking
	// directly here.
	if level <= PanicLevel {
		panic(&entry)
	}
}

func (entry *Entry) fireHooks() {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	err := entry.Logger.Hooks.Fire(entry.Level, entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
	}
}

func (entry *Entry) write() {
	entry.Logger.mu.Lock()
	defer entry.Logger.mu.Unlock()
	serialized, err := entry.Logger.Formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
		return
	}
	if _, err = entry.Logger.Out.Write(serialized); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
	}
}

func (entry *Entry) Log(level Level, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.log(level, fmt.Sprint(args...))
	}
}

func (entry *Entry) Trace(args ...interface{}) {
	entry.Log(TraceLevel, args...)
}

func (entry *Entry) Debug(args ...interface{}) {
	entry.Log(DebugLevel, args...)
}

func (entry *Entry) Print(args ...interface{}) {
	entry.Info(args...)
}

func (entry *Entry) Info(args ...interface{}) {
	entry.Log(InfoLevel, args...)
}

func (entry *Entry) Warn(args ...interface{}) {
	entry.Log(WarnLevel, args...)
}

func (entry *Entry) Warning(args ...interface{}) {
	entry.Warn(args...)
}

func (entry *Entry) Error(args ...interface{}) {
	entry.Log(ErrorLevel, args...)
}

func (entry *Entry) Fatal(args ...interface{}) {
	entry.Log(FatalLevel, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panic(args ...interface{}) {
	entry.Log(PanicLevel, args...)
	panic(fmt.Sprint(args...))
}

// Entry Printf family functions

func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.Log(level, fmt.Sprintf(format, args...))
	}
}

func (entry *Entry) Tracef(format string, args ...interface{}) {
	entry.Logf(TraceLevel, format, args...)
}

func (entry *Entry) Debugf(format string, args ...interface{}) {
	entry.Logf(DebugLevel, format, args...)
}

func (entry *Entry) Infof(format string, args ...interface{}) {
	entry.Logf(InfoLevel, format, args...)
}

func (entry *Entry) Printf(format string, args ...interface{}) {
	entry.Infof(format, args...)
}

func (entry *Entry) Warnf(format string, args ...interface{}) {
	entry.Logf(WarnLevel, format, args...)
}

func (entry *Entry) Warningf(format string, args ...interface{}) {
	entry.Warnf(format, args...)
}

func (entry *Entry) Errorf(format string, args ...interface{}) {
	entry.Logf(ErrorLevel, format, args...)
}

func (entry *Entry) Fatalf(format string, args ...interface{}) {
	entry.Logf(FatalLevel, format, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panicf(format string, args ...interface{}) {
	entry.Logf(PanicLevel, format, args...)
}

// Entry Println family functions

func (entry *Entry) Logln(level Level, args ...interface{}) {
	if entry.Logger.IsLevelEnabled(level) {
		entry.Log(level, entry.sprintlnn(args...))
	}
}

func (entry *Entry) Traceln(args ...interface{}) {
	entry.Logln(TraceLevel, args...)
}

func (entry *Entry) Debugln(args ...interface{}) {
	entry.Logln(DebugLevel, args...)
}

func (entry *Entry) Infoln(args ...interface{}) {
	entry.Logln(InfoLevel, args...)
}

func (entry *Entry) Println(args ...interface{}) {
	entry.Infoln(args...)
}

func (entry *Entry) Warnln(args ...interface{}) {
	entry.Logln(WarnLevel, args...)
}

func (entry *Entry) Warningln(args ...interface{}) {
	entry.Warnln(args...)
}

func (entry *Entry) Errorln(args ...interface{}) {
	entry.Logln(ErrorLevel, args...)
}

func (entry *Entry) Fatalln(args ...interface{}) {
	entry.Logln(FatalLevel, args...)
	entry.Logger.Exit(1)
}

func (entry *Entry) Panicln(args ...interface{}) {
	entry.Logln(PanicLevel, args...)
}

// Sprintlnn => Sprint no newline. This is to get the behavior of how
// fmt.Sprintln where spaces are always added between operands, regardless of
// their type. Instead of vendoring the Sprintln implementation to spare a
// string allocation, we do the simplest thing.
func (entry *Entry) sprintlnn(args ...interface{}) string {
	msg := fmt.Sprintln(args...)
	return msg[:len(msg)-1]
}
<|endoftext|>


<commit_before>// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

// #include <yara.h>
import "C"
import (
	"errors"
	"fmt"
)

func newError(code C.int) error {
	if code == 0 {
		return nil
	}
	if str, ok := errorStrings[code]; ok {
		return errors.New(str)
	}
	return fmt.Errorf("unknown error %d", code)
}

// FIXME: This should be generated from yara/error.h
var errorStrings = map[C.int]string{
	C.ERROR_INSUFICIENT_MEMORY:           "insuficient memory",
	C.ERROR_COULD_NOT_ATTACH_TO_PROCESS:  "could not attach to process",
	C.ERROR_COULD_NOT_OPEN_FILE:          "could not open file",
	C.ERROR_COULD_NOT_MAP_FILE:           "could not map file",
	C.ERROR_INVALID_FILE:                 "invalid file",
	C.ERROR_CORRUPT_FILE:                 "corrupt file",
	C.ERROR_UNSUPPORTED_FILE_VERSION:     "unsupported file version",
	C.ERROR_INVALID_REGULAR_EXPRESSION:   "invalid regular expression",
	C.ERROR_INVALID_HEX_STRING:           "invalid hex string",
	C.ERROR_SYNTAX_ERROR:                 "syntax error",
	C.ERROR_LOOP_NESTING_LIMIT_EXCEEDED:  "loop nesting limit exceeded",
	C.ERROR_DUPLICATED_LOOP_IDENTIFIER:   "duplicated loop identifier",
	C.ERROR_DUPLICATED_IDENTIFIER:        "duplicated identifier",
	C.ERROR_DUPLICATED_TAG_IDENTIFIER:    "duplicated tag identifier",
	C.ERROR_DUPLICATED_META_IDENTIFIER:   "duplicated meta identifier",
	C.ERROR_DUPLICATED_STRING_IDENTIFIER: "duplicated string identifier",
	C.ERROR_UNREFERENCED_STRING:          "unreferenced string",
	C.ERROR_UNDEFINED_STRING:             "undefined string",
	C.ERROR_UNDEFINED_IDENTIFIER:         "undefined identifier",
	C.ERROR_MISPLACED_ANONYMOUS_STRING:   "misplaced anonymous string",
	C.ERROR_INCLUDES_CIRCULAR_REFERENCE:  "includes circular reference",
	C.ERROR_INCLUDE_DEPTH_EXCEEDED:       "include depth exceeded",
	C.ERROR_WRONG_TYPE:                   "wrong type",
	C.ERROR_EXEC_STACK_OVERFLOW:          "exec stack overflow",
	C.ERROR_SCAN_TIMEOUT:                 "scan timeout",
	C.ERROR_TOO_MANY_SCAN_THREADS:        "too many scan threads",
	C.ERROR_CALLBACK_ERROR:               "callback error",
	C.ERROR_INVALID_ARGUMENT:             "invalid argument",
	C.ERROR_TOO_MANY_MATCHES:             "too many matches",
	C.ERROR_INTERNAL_FATAL_ERROR:         "internal fatal error",
	C.ERROR_NESTED_FOR_OF_LOOP:           "nested for of loop",
	C.ERROR_INVALID_FIELD_NAME:           "invalid field name",
	C.ERROR_UNKNOWN_MODULE:               "unknown module",
	C.ERROR_NOT_A_STRUCTURE:              "not a structure",
	C.ERROR_NOT_INDEXABLE:                "not indexable",
	C.ERROR_NOT_A_FUNCTION:               "not a function",
	C.ERROR_INVALID_FORMAT:               "invalid format",
	C.ERROR_TOO_MANY_ARGUMENTS:           "too many arguments",
	C.ERROR_WRONG_ARGUMENTS:              "wrong arguments",
	C.ERROR_WRONG_RETURN_TYPE:            "wrong return type",
	C.ERROR_DUPLICATED_STRUCTURE_MEMBER:  "duplicated structure member",
}
<commit_msg>Fix typo in error message<commit_after>// Copyright © 2015 Hilko Bengen <bengen@hilluzination.de>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

// #include <yara.h>
import "C"
import (
	"errors"
	"fmt"
)

func newError(code C.int) error {
	if code == 0 {
		return nil
	}
	if str, ok := errorStrings[code]; ok {
		return errors.New(str)
	}
	return fmt.Errorf("unknown error %d", code)
}

// FIXME: This should be generated from yara/error.h
var errorStrings = map[C.int]string{
	C.ERROR_INSUFICIENT_MEMORY:           "insufficient memory",
	C.ERROR_COULD_NOT_ATTACH_TO_PROCESS:  "could not attach to process",
	C.ERROR_COULD_NOT_OPEN_FILE:          "could not open file",
	C.ERROR_COULD_NOT_MAP_FILE:           "could not map file",
	C.ERROR_INVALID_FILE:                 "invalid file",
	C.ERROR_CORRUPT_FILE:                 "corrupt file",
	C.ERROR_UNSUPPORTED_FILE_VERSION:     "unsupported file version",
	C.ERROR_INVALID_REGULAR_EXPRESSION:   "invalid regular expression",
	C.ERROR_INVALID_HEX_STRING:           "invalid hex string",
	C.ERROR_SYNTAX_ERROR:                 "syntax error",
	C.ERROR_LOOP_NESTING_LIMIT_EXCEEDED:  "loop nesting limit exceeded",
	C.ERROR_DUPLICATED_LOOP_IDENTIFIER:   "duplicated loop identifier",
	C.ERROR_DUPLICATED_IDENTIFIER:        "duplicated identifier",
	C.ERROR_DUPLICATED_TAG_IDENTIFIER:    "duplicated tag identifier",
	C.ERROR_DUPLICATED_META_IDENTIFIER:   "duplicated meta identifier",
	C.ERROR_DUPLICATED_STRING_IDENTIFIER: "duplicated string identifier",
	C.ERROR_UNREFERENCED_STRING:          "unreferenced string",
	C.ERROR_UNDEFINED_STRING:             "undefined string",
	C.ERROR_UNDEFINED_IDENTIFIER:         "undefined identifier",
	C.ERROR_MISPLACED_ANONYMOUS_STRING:   "misplaced anonymous string",
	C.ERROR_INCLUDES_CIRCULAR_REFERENCE:  "includes circular reference",
	C.ERROR_INCLUDE_DEPTH_EXCEEDED:       "include depth exceeded",
	C.ERROR_WRONG_TYPE:                   "wrong type",
	C.ERROR_EXEC_STACK_OVERFLOW:          "exec stack overflow",
	C.ERROR_SCAN_TIMEOUT:                 "scan timeout",
	C.ERROR_TOO_MANY_SCAN_THREADS:        "too many scan threads",
	C.ERROR_CALLBACK_ERROR:               "callback error",
	C.ERROR_INVALID_ARGUMENT:             "invalid argument",
	C.ERROR_TOO_MANY_MATCHES:             "too many matches",
	C.ERROR_INTERNAL_FATAL_ERROR:         "internal fatal error",
	C.ERROR_NESTED_FOR_OF_LOOP:           "nested for of loop",
	C.ERROR_INVALID_FIELD_NAME:           "invalid field name",
	C.ERROR_UNKNOWN_MODULE:               "unknown module",
	C.ERROR_NOT_A_STRUCTURE:              "not a structure",
	C.ERROR_NOT_INDEXABLE:                "not indexable",
	C.ERROR_NOT_A_FUNCTION:               "not a function",
	C.ERROR_INVALID_FORMAT:               "invalid format",
	C.ERROR_TOO_MANY_ARGUMENTS:           "too many arguments",
	C.ERROR_WRONG_ARGUMENTS:              "wrong arguments",
	C.ERROR_WRONG_RETURN_TYPE:            "wrong return type",
	C.ERROR_DUPLICATED_STRUCTURE_MEMBER:  "duplicated structure member",
}
<|endoftext|>


<commit_before>package resource

import (
	"github.com/qor/qor"
	"github.com/qor/qor/rules"

	"go/ast"
	"reflect"
)

type attrs struct {
	indexAttrs []string
	newAttrs   []string
	editAttrs  []string
	showAttrs  []string
}

func (a *attrs) Index(columns ...string) {
	a.indexAttrs = columns
}

func (a *attrs) New(columns ...string) {
	a.newAttrs = columns
}

func (a *attrs) Edit(columns ...string) {
	a.editAttrs = columns
}

func (a *attrs) Show(columns ...string) {
	a.showAttrs = columns
}

func (resource *Resource) getMetas(attrsSlice ...[]string) []Meta {
	var attrs []string
	for _, value := range attrsSlice {
		if value != nil {
			attrs = value
			break
		}
	}

	if attrs == nil {
		attrs = []string{}
		indirectValue := reflect.Indirect(reflect.ValueOf(resource.Model))
		scopeTyp := indirectValue.Type()
		for i := 0; i < scopeTyp.NumField(); i++ {
			fieldStruct := scopeTyp.Field(i)
			if !ast.IsExported(fieldStruct.Name) {
				continue
			}
			attrs = append(attrs, fieldStruct.Name)
		}
	}

	metas := []Meta{}
	for _, attr := range attrs {
		metaFound := false
		for _, meta := range resource.meta.metas {
			if meta.Name == attr {
				metas = append(metas, meta)
				metaFound = true
				break
			}
		}
		if !metaFound {
			var _meta Meta
			_meta = Meta{Name: attr, base: resource}
			_meta.updateMeta()
			metas = append(metas, _meta)
		}
	}

	primaryKeyMeta := Meta{Name: "_id", Type: "hidden", GetValue: func(value interface{}, context *qor.Context) interface{} {
		return context.DB.NewScope(value).PrimaryKeyValue()
	}}
	primaryKeyMeta.updateMeta()

	return append(metas, primaryKeyMeta)
}

func (resource *Resource) IndexAttrs() []Meta {
	return resource.getMetas(resource.attrs.indexAttrs, resource.attrs.showAttrs)
}

func (resource *Resource) NewAttrs() []Meta {
	return resource.getMetas(resource.attrs.newAttrs, resource.attrs.editAttrs)
}

func (resource *Resource) EditAttrs() []Meta {
	return resource.getMetas(resource.attrs.editAttrs)
}

func (resource *Resource) ShowAttrs() []Meta {
	return resource.getMetas(resource.attrs.showAttrs, resource.attrs.editAttrs)
}

func (resource *Resource) AllAttrs() []Meta {
	return resource.getMetas()
}

func (resource *Resource) AllowedMetas(attrs []Meta, context *qor.Context, rules ...rules.PermissionMode) []Meta {
	var metas = []Meta{}
	for _, meta := range attrs {
		for _, rule := range rules {
			if meta.HasPermission(rule, context) {
				metas = append(metas, meta)
				break
			}
		}
	}
	return metas
}
<commit_msg>Don't show primary key in index<commit_after>package resource

import (
	"github.com/qor/qor"
	"github.com/qor/qor/rules"

	"go/ast"
	"reflect"
)

type attrs struct {
	indexAttrs []string
	newAttrs   []string
	editAttrs  []string
	showAttrs  []string
}

func (a *attrs) Index(columns ...string) {
	a.indexAttrs = columns
}

func (a *attrs) New(columns ...string) {
	a.newAttrs = columns
}

func (a *attrs) Edit(columns ...string) {
	a.editAttrs = columns
}

func (a *attrs) Show(columns ...string) {
	a.showAttrs = columns
}

func (resource *Resource) getMetas(attrsSlice ...[]string) []Meta {
	var attrs []string
	for _, value := range attrsSlice {
		if value != nil {
			attrs = value
			break
		}
	}

	if attrs == nil {
		attrs = []string{}
		indirectValue := reflect.Indirect(reflect.ValueOf(resource.Model))
		scopeTyp := indirectValue.Type()
		for i := 0; i < scopeTyp.NumField(); i++ {
			fieldStruct := scopeTyp.Field(i)
			if !ast.IsExported(fieldStruct.Name) {
				continue
			}
			attrs = append(attrs, fieldStruct.Name)
		}
	}

	metas := []Meta{}
	for _, attr := range attrs {
		metaFound := false
		for _, meta := range resource.meta.metas {
			if meta.Name == attr {
				metas = append(metas, meta)
				metaFound = true
				break
			}
		}
		if !metaFound {
			var _meta Meta
			_meta = Meta{Name: attr, base: resource}
			_meta.updateMeta()
			metas = append(metas, _meta)
		}
	}

	return metas
}

func (resource *Resource) IndexAttrs() []Meta {
	return resource.getMetas(resource.attrs.indexAttrs, resource.attrs.showAttrs)
}

func (resource *Resource) NewAttrs() []Meta {
	return resource.getMetas(resource.attrs.newAttrs, resource.attrs.editAttrs)
}

func (resource *Resource) EditAttrs() []Meta {
	return appendPrimaryKey(resource.getMetas(resource.attrs.editAttrs))
}

func (resource *Resource) ShowAttrs() []Meta {
	return resource.getMetas(resource.attrs.showAttrs, resource.attrs.editAttrs)
}

func (resource *Resource) AllAttrs() []Meta {
	return appendPrimaryKey(resource.getMetas())
}

func appendPrimaryKey(metas []Meta) []Meta {
	primaryKeyMeta := Meta{Name: "_id", Type: "hidden", GetValue: func(value interface{}, context *qor.Context) interface{} {
		return context.DB.NewScope(value).PrimaryKeyValue()
	}}
	primaryKeyMeta.updateMeta()

	return append(metas, primaryKeyMeta)
}

func (resource *Resource) AllowedMetas(attrs []Meta, context *qor.Context, rules ...rules.PermissionMode) []Meta {
	var metas = []Meta{}
	for _, meta := range attrs {
		for _, rule := range rules {
			if meta.HasPermission(rule, context) {
				metas = append(metas, meta)
				break
			}
		}
	}
	return metas
}
<|endoftext|>


<commit_before>package resource

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"

	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
	"github.com/imdario/mergo"
)

// Name and description of the resource
const shellResourceType = "shell"
const shellResourceDesc = "executes shell commands"

// ShellResource type is a resource which executes shell commands
type ShellResource struct {
	BaseResource `hcl:",squash"`

	Command string `hcl:"command" json:"command"`

	Creates string `hcl:"creates" json:"creates"`
}

// NewShellResource creates a new resource for executing shell commands
func NewShellResource(name string, obj *ast.ObjectItem) (Resource, error) {
	// Resource defaults
	defaults := &ShellResource{
		BaseResource: BaseResource{
			Name:  name,
			Type:  shellResourceType,
			State: StatePresent,
		},
		Command: name,
	}

	var s ShellResource
	err := hcl.DecodeObject(&s, obj)
	if err != nil {
		return nil, err
	}

	// Merge the decoded object with the resource defaults
	err = mergo.Merge(&s, defaults)

	return &s, err
}

// Validate validates the shell resource
func (s *ShellResource) Validate() error {
	err := s.BaseResource.Validate()
	if err != nil {
		return err
	}

	if s.Creates == "" {
		return fmt.Errorf("Missing required field 'creates' in %s", s.ResourceID())
	}

	return nil
}

// Evaluate evaluates the state of the resource
func (s *ShellResource) Evaluate() (State, error) {
	resourceState := State{
		Current: StateUnknown,
		Want:    s.State,
		Update:  false,
	}

	_, err := os.Stat(s.Creates)
	if os.IsNotExist(err) {
		resourceState.Current = StateAbsent
	} else {
		resourceState.Current = StatePresent
	}

	return resourceState, nil
}

// Create executes the shell command
func (s *ShellResource) Create(w io.Writer) error {
	s.Printf(w, "executing command")

	args := strings.Fields(s.Command)
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()

	s.Printf(w, string(out))

	return err
}

// Delete is a no-op
func (s *ShellResource) Delete(w io.Writer) error {
	return nil
}

// Update is a no-op
func (s *ShellResource) Update(w io.Writer) error {
	return nil
}

func init() {
	item := RegistryItem{
		Name:        shellResourceType,
		Description: shellResourceDesc,
		Provider:    NewShellResource,
	}

	Register(item)
}
<commit_msg>shell resource: do not make 'creates' a required parameter<commit_after>package resource

import (
	"io"
	"os"
	"os/exec"
	"strings"

	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
	"github.com/imdario/mergo"
)

// Name and description of the resource
const shellResourceType = "shell"
const shellResourceDesc = "executes shell commands"

// ShellResource type is a resource which executes shell commands
type ShellResource struct {
	BaseResource `hcl:",squash"`

	Command string `hcl:"command" json:"command"`

	Creates string `hcl:"creates" json:"creates"`
}

// NewShellResource creates a new resource for executing shell commands
func NewShellResource(name string, obj *ast.ObjectItem) (Resource, error) {
	// Resource defaults
	defaults := &ShellResource{
		BaseResource: BaseResource{
			Name:  name,
			Type:  shellResourceType,
			State: StatePresent,
		},
		Command: name,
	}

	var s ShellResource
	err := hcl.DecodeObject(&s, obj)
	if err != nil {
		return nil, err
	}

	// Merge the decoded object with the resource defaults
	err = mergo.Merge(&s, defaults)

	return &s, err
}

// Evaluate evaluates the state of the resource
func (s *ShellResource) Evaluate() (State, error) {
	// Asumes that the command to be executed is idempotent
	//
	// Sets the current state to absent and wanted to be present,
	// which will cause the command to be executed.
	//
	// If the command to be executed is not idempotent on it's own,
	// in order to ensure idempotency we should specify a file,
	// that can be checked for existence.
	resourceState := State{
		Current: StateAbsent,
		Want:    s.State,
		Update:  false,
	}

	if s.Creates != "" {
		_, err := os.Stat(s.Creates)
		if os.IsNotExist(err) {
			resourceState.Current = StateAbsent
		} else {
			resourceState.Current = StatePresent
		}
	}

	return resourceState, nil
}

// Create executes the shell command
func (s *ShellResource) Create(w io.Writer) error {
	s.Printf(w, "executing command")

	args := strings.Fields(s.Command)
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()

	s.Printf(w, string(out))

	return err
}

// Delete is a no-op
func (s *ShellResource) Delete(w io.Writer) error {
	return nil
}

// Update is a no-op
func (s *ShellResource) Update(w io.Writer) error {
	return nil
}

func init() {
	item := RegistryItem{
		Name:        shellResourceType,
		Description: shellResourceDesc,
		Provider:    NewShellResource,
	}

	Register(item)
}
<|endoftext|>


<commit_before>package fscache

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Cache works like a concurrent-safe map for streams.
type Cache interface {

	// Get manages access to the streams in the cache.
	// If the key does not exist, w != nil and you can start writing to the stream.
	// If the key does exist, w == nil.
	// r will always be non-nil as long as err == nil and you must close r when you're done reading.
	// Get can be called concurrently, and writing and reading is concurrent safe.
	Get(key string) (ReadAtCloser, io.WriteCloser, error)

	// Remove deletes the stream from the cache, blocking until the underlying
	// file can be deleted (all active streams finish with it).
	// It is safe to call Remove concurrently with Get.
	Remove(key string) error

	// Exists checks if a key is in the cache.
	// It is safe to call Exists concurrently with Get.
	Exists(key string) bool

	// Clean will empty the cache and delete the cache folder.
	// Clean is not safe to call while streams are being read/written.
	Clean() error
}

type cache struct {
	mu    sync.RWMutex
	files map[string]fileStream
	grim  Reaper
	fs    FileSystem
}

// ReadAtCloser is an io.ReadCloser, and an io.ReaderAt. It supports both so that Range
// Requests are possible.
type ReadAtCloser interface {
	io.ReadCloser
	io.ReaderAt
}

type fileStream interface {
	next() (ReadAtCloser, error)
	inUse() bool
	io.WriteCloser
	Remove() error
	Name() string
}

// New creates a new Cache using NewFs(dir, perms).
// expiry is the duration after which an un-accessed key will be removed from
// the cache, a zero value expiro means never expire.
func New(dir string, perms os.FileMode, expiry time.Duration) (Cache, error) {
	fs, err := NewFs(dir, perms)
	if err != nil {
		return nil, err
	}
	var grim Reaper
	if expiry > 0 {
		grim = &reaper{
			expiry: expiry,
			period: expiry,
		}
	}
	return NewCache(fs, grim)
}

// NewCache creates a new Cache based on FileSystem fs.
// fs.Files() are loaded using the name they were created with as a key.
// Reaper is used to determine when files expire, nil means never expire.
func NewCache(fs FileSystem, grim Reaper) (Cache, error) {
	c := &cache{
		files: make(map[string]fileStream),
		grim:  grim,
		fs:    fs,
	}
	err := c.load()
	if err != nil {
		return nil, err
	}
	if grim != nil {
		c.haunter()
	}
	return c, nil
}

func (c *cache) haunter() {
	c.haunt()
	time.AfterFunc(c.grim.Next(), c.haunter)
}

func (c *cache) haunt() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, f := range c.files {
		if f.inUse() {
			continue
		}

		lastRead, lastWrite, err := c.fs.AccessTimes(f.Name())
		if err != nil {
			continue
		}

		if c.grim.Reap(key, lastRead, lastWrite) {
			delete(c.files, key)
			c.fs.Remove(f.Name())
		}
	}
	return
}

func (c *cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.fs.Reload(func(key, name string) {
		c.files[key] = c.oldFile(name)
	})
}

func (c *cache) Exists(key string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	_, ok := c.files[key]
	return ok
}

func (c *cache) Get(key string) (r ReadAtCloser, w io.WriteCloser, err error) {
	c.mu.RLock()
	f, ok := c.files[key]
	if ok {
		r, err = f.next()
		c.mu.RUnlock()
		return r, nil, err
	}
	c.mu.RUnlock()

	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok = c.files[key]
	if ok {
		r, err = f.next()
		return r, nil, err
	}

	f, err = c.newFile(key)
	if err != nil {
		return nil, nil, err
	}

	r, err = f.next()
	if err != nil {
		f.Close()
		c.fs.Remove(f.Name())
		return nil, nil, err
	}

	c.files[key] = f

	return r, f, err
}

func (c *cache) Remove(key string) error {
	c.mu.Lock()
	f, ok := c.files[key]
	delete(c.files, key)
	c.mu.Unlock()

	if ok {
		return f.Remove()
	}
	return nil
}

func (c *cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]fileStream)
	return c.fs.RemoveAll()
}

type cachedFile struct {
	stream *stream.Stream
	handleCounter
}

func (c *cache) newFile(name string) (fileStream, error) {
	s, err := stream.NewStream(name, c.fs)
	if err != nil {
		return nil, err
	}
	cf := &cachedFile{
		stream: s,
	}
	cf.inc()
	return cf, nil
}

func (c *cache) oldFile(name string) fileStream {
	return &reloadedFile{
		fs:   c.fs,
		name: name,
	}
}

type reloadedFile struct {
	fs   FileSystem
	name string
	handleCounter
	io.WriteCloser // nop Write & Close methods. will never be called.
}

func (f *reloadedFile) Name() string { return f.name }

func (f *reloadedFile) Remove() error {
	f.waitUntilFree()
	return f.fs.Remove(f.name)
}

func (f *reloadedFile) next() (r ReadAtCloser, err error) {
	r, err = f.fs.Open(f.name)
	if err == nil {
		f.inc()
	}
	return &cacheReader{r: r, cnt: &f.handleCounter}, err
}

func (f *cachedFile) Name() string { return f.stream.Name() }

func (f *cachedFile) Remove() error { return f.stream.Remove() }

func (f *cachedFile) next() (r ReadAtCloser, err error) {
	reader, err := f.stream.NextReader()
	if err != nil {
		return nil, err
	}
	f.inc()
	return &cacheReader{
		r:   reader,
		cnt: &f.handleCounter,
	}, nil
}

func (f *cachedFile) Write(p []byte) (int, error) {
	return f.stream.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.dec()
	return f.stream.Close()
}

type cacheReader struct {
	r   ReadAtCloser
	cnt *handleCounter
}

func (r *cacheReader) ReadAt(p []byte, off int64) (n int, err error) {
	return r.r.ReadAt(p, off)
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	return r.r.Read(p)
}

func (r *cacheReader) Close() error {
	defer r.cnt.dec()
	return r.r.Close()
}

type handleCounter struct {
	cnt int64
	grp sync.WaitGroup
}

func (h *handleCounter) inc() {
	h.grp.Add(1)
	atomic.AddInt64(&h.cnt, 1)
}

func (h *handleCounter) dec() {
	atomic.AddInt64(&h.cnt, -1)
	h.grp.Done()
}

func (h *handleCounter) inUse() bool {
	return atomic.LoadInt64(&h.cnt) > 0
}

func (h *handleCounter) waitUntilFree() {
	h.grp.Wait()
}
<commit_msg>goimports needs to stop removing this import<commit_after>package fscache

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"gopkg.in/djherbis/stream.v1"
)

// Cache works like a concurrent-safe map for streams.
type Cache interface {

	// Get manages access to the streams in the cache.
	// If the key does not exist, w != nil and you can start writing to the stream.
	// If the key does exist, w == nil.
	// r will always be non-nil as long as err == nil and you must close r when you're done reading.
	// Get can be called concurrently, and writing and reading is concurrent safe.
	Get(key string) (ReadAtCloser, io.WriteCloser, error)

	// Remove deletes the stream from the cache, blocking until the underlying
	// file can be deleted (all active streams finish with it).
	// It is safe to call Remove concurrently with Get.
	Remove(key string) error

	// Exists checks if a key is in the cache.
	// It is safe to call Exists concurrently with Get.
	Exists(key string) bool

	// Clean will empty the cache and delete the cache folder.
	// Clean is not safe to call while streams are being read/written.
	Clean() error
}

type cache struct {
	mu    sync.RWMutex
	files map[string]fileStream
	grim  Reaper
	fs    FileSystem
}

// ReadAtCloser is an io.ReadCloser, and an io.ReaderAt. It supports both so that Range
// Requests are possible.
type ReadAtCloser interface {
	io.ReadCloser
	io.ReaderAt
}

type fileStream interface {
	next() (ReadAtCloser, error)
	inUse() bool
	io.WriteCloser
	Remove() error
	Name() string
}

// New creates a new Cache using NewFs(dir, perms).
// expiry is the duration after which an un-accessed key will be removed from
// the cache, a zero value expiro means never expire.
func New(dir string, perms os.FileMode, expiry time.Duration) (Cache, error) {
	fs, err := NewFs(dir, perms)
	if err != nil {
		return nil, err
	}
	var grim Reaper
	if expiry > 0 {
		grim = &reaper{
			expiry: expiry,
			period: expiry,
		}
	}
	return NewCache(fs, grim)
}

// NewCache creates a new Cache based on FileSystem fs.
// fs.Files() are loaded using the name they were created with as a key.
// Reaper is used to determine when files expire, nil means never expire.
func NewCache(fs FileSystem, grim Reaper) (Cache, error) {
	c := &cache{
		files: make(map[string]fileStream),
		grim:  grim,
		fs:    fs,
	}
	err := c.load()
	if err != nil {
		return nil, err
	}
	if grim != nil {
		c.haunter()
	}
	return c, nil
}

func (c *cache) haunter() {
	c.haunt()
	time.AfterFunc(c.grim.Next(), c.haunter)
}

func (c *cache) haunt() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, f := range c.files {
		if f.inUse() {
			continue
		}

		lastRead, lastWrite, err := c.fs.AccessTimes(f.Name())
		if err != nil {
			continue
		}

		if c.grim.Reap(key, lastRead, lastWrite) {
			delete(c.files, key)
			c.fs.Remove(f.Name())
		}
	}
	return
}

func (c *cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.fs.Reload(func(key, name string) {
		c.files[key] = c.oldFile(name)
	})
}

func (c *cache) Exists(key string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	_, ok := c.files[key]
	return ok
}

func (c *cache) Get(key string) (r ReadAtCloser, w io.WriteCloser, err error) {
	c.mu.RLock()
	f, ok := c.files[key]
	if ok {
		r, err = f.next()
		c.mu.RUnlock()
		return r, nil, err
	}
	c.mu.RUnlock()

	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok = c.files[key]
	if ok {
		r, err = f.next()
		return r, nil, err
	}

	f, err = c.newFile(key)
	if err != nil {
		return nil, nil, err
	}

	r, err = f.next()
	if err != nil {
		f.Close()
		c.fs.Remove(f.Name())
		return nil, nil, err
	}

	c.files[key] = f

	return r, f, err
}

func (c *cache) Remove(key string) error {
	c.mu.Lock()
	f, ok := c.files[key]
	delete(c.files, key)
	c.mu.Unlock()

	if ok {
		return f.Remove()
	}
	return nil
}

func (c *cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]fileStream)
	return c.fs.RemoveAll()
}

type cachedFile struct {
	stream *stream.Stream
	handleCounter
}

func (c *cache) newFile(name string) (fileStream, error) {
	s, err := stream.NewStream(name, c.fs)
	if err != nil {
		return nil, err
	}
	cf := &cachedFile{
		stream: s,
	}
	cf.inc()
	return cf, nil
}

func (c *cache) oldFile(name string) fileStream {
	return &reloadedFile{
		fs:   c.fs,
		name: name,
	}
}

type reloadedFile struct {
	fs   FileSystem
	name string
	handleCounter
	io.WriteCloser // nop Write & Close methods. will never be called.
}

func (f *reloadedFile) Name() string { return f.name }

func (f *reloadedFile) Remove() error {
	f.waitUntilFree()
	return f.fs.Remove(f.name)
}

func (f *reloadedFile) next() (r ReadAtCloser, err error) {
	r, err = f.fs.Open(f.name)
	if err == nil {
		f.inc()
	}
	return &cacheReader{r: r, cnt: &f.handleCounter}, err
}

func (f *cachedFile) Name() string { return f.stream.Name() }

func (f *cachedFile) Remove() error { return f.stream.Remove() }

func (f *cachedFile) next() (r ReadAtCloser, err error) {
	reader, err := f.stream.NextReader()
	if err != nil {
		return nil, err
	}
	f.inc()
	return &cacheReader{
		r:   reader,
		cnt: &f.handleCounter,
	}, nil
}

func (f *cachedFile) Write(p []byte) (int, error) {
	return f.stream.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.dec()
	return f.stream.Close()
}

type cacheReader struct {
	r   ReadAtCloser
	cnt *handleCounter
}

func (r *cacheReader) ReadAt(p []byte, off int64) (n int, err error) {
	return r.r.ReadAt(p, off)
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	return r.r.Read(p)
}

func (r *cacheReader) Close() error {
	defer r.cnt.dec()
	return r.r.Close()
}

type handleCounter struct {
	cnt int64
	grp sync.WaitGroup
}

func (h *handleCounter) inc() {
	h.grp.Add(1)
	atomic.AddInt64(&h.cnt, 1)
}

func (h *handleCounter) dec() {
	atomic.AddInt64(&h.cnt, -1)
	h.grp.Done()
}

func (h *handleCounter) inUse() bool {
	return atomic.LoadInt64(&h.cnt) > 0
}

func (h *handleCounter) waitUntilFree() {
	h.grp.Wait()
}
<|endoftext|>