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

package kola

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"

	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/coreos/pkg/capnslog"

	// Tests imported for registration side effects.
	_ "github.com/coreos/mantle/kola/tests/coretest"
	_ "github.com/coreos/mantle/kola/tests/etcd"
	_ "github.com/coreos/mantle/kola/tests/flannel"
	_ "github.com/coreos/mantle/kola/tests/fleet"
	_ "github.com/coreos/mantle/kola/tests/ignition"
	_ "github.com/coreos/mantle/kola/tests/kubernetes"
	_ "github.com/coreos/mantle/kola/tests/metadata"
	_ "github.com/coreos/mantle/kola/tests/misc"
	_ "github.com/coreos/mantle/kola/tests/rkt"
	_ "github.com/coreos/mantle/kola/tests/systemd"
)

var (
	plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola")

	QEMUOptions platform.QEMUOptions // glue to set platform options from main
	GCEOptions  platform.GCEOptions  // glue to set platform options from main
	AWSOptions  platform.AWSOptions  // glue to set platform options from main

	TestParallelism int //glue var to set test parallelism from main

	testOptions = make(map[string]string, 0)
)

// RegisterTestOption registers any options that need visibility inside
// a Test. Panics if existing option is already registered. Each test
// has global view of options.
func RegisterTestOption(name, option string) {
	_, ok := testOptions[name]
	if ok {
		panic("test option already registered with same name")
	}
	testOptions[name] = option
}

// NativeRunner is a closure passed to all kola test functions and used
// to run native go functions directly on kola machines. It is necessary
// glue until kola does introspection.
type NativeRunner func(funcName string, m platform.Machine) error

type result struct {
	test     *register.Test
	result   error
	duration time.Duration
}

func testRunner(platform string, done <-chan struct{}, tests chan *register.Test, results chan *result) {
	for test := range tests {
		plog.Noticef("=== RUN %s on %s", test.Name, platform)
		start := time.Now()
		err := RunTest(test, platform)
		duration := time.Since(start)

		select {
		case results <- &result{test, err, duration}:
		case <-done:
			return
		}
	}
}

func filterTests(tests map[string]*register.Test, pattern, platform string, version semver.Version) (map[string]*register.Test, error) {
	r := make(map[string]*register.Test)

	for name, t := range tests {
		match, err := filepath.Match(pattern, t.Name)
		if err != nil {
			return nil, err
		}
		if !match {
			continue
		}

		// Skip the test if Manual is set and the name doesn't fully match.
		if t.Manual && t.Name != pattern {
			continue
		}

		// Check the test's min and end versions when running more then one test
		if t.Name != pattern && versionOutsideRange(version, t.MinVersion, t.EndVersion) {
			continue
		}

		allowed := true
		for _, p := range t.Platforms {
			if p == platform {
				allowed = true
				break
			} else {
				allowed = false
			}
		}
		if !allowed {
			continue
		}

		r[name] = t
	}

	return r, nil
}

// versionOutsideRange checks to see if version is outside [min, end). If end
// is a zero value, it is ignored and there is no upper bound.
func versionOutsideRange(version, minVersion, endVersion semver.Version) bool {
	if version.LessThan(minVersion) {
		return false
	}

	if (endVersion != semver.Version{}) && !version.LessThan(endVersion) {
		return false
	}

	return true
}

// RunTests is a harness for running multiple tests in parallel. Filters
// tests based on a glob pattern and by platform. Has access to all
// tests either registered in this package or by imported packages that
// register tests in their init() function.
func RunTests(pattern, pltfrm string) error {
	var passed, failed, skipped int
	var wg sync.WaitGroup

	// Avoid incurring cost of starting machine in getClusterSemver when
	// either:
	// 1) we already know 0 tests will run
	// 2) glob is an exact match which means minVersion will be ignored
	//    either way
	tests, err := filterTests(register.Tests, pattern, pltfrm, semver.Version{})
	if err != nil {
		plog.Fatal(err)
	}

	var skipGetVersion bool
	if len(tests) == 0 {
		skipGetVersion = true
	} else if len(tests) == 1 {
		for name := range tests {
			if name == pattern {
				skipGetVersion = true
			}
		}
	}

	if !skipGetVersion {
		version, err := getClusterSemver(pltfrm)
		if err != nil {
			plog.Fatal(err)
		}

		// one more filter pass now that we know real version
		tests, err = filterTests(tests, pattern, pltfrm, *version)
		if err != nil {
			plog.Fatal(err)
		}
	}

	done := make(chan struct{})
	defer close(done)
	testc := make(chan *register.Test)
	resc := make(chan *result)

	wg.Add(TestParallelism)

	for i := 0; i < TestParallelism; i++ {
		go func() {
			testRunner(pltfrm, done, testc, resc)
			wg.Done()
		}()
	}
	go func() {
		wg.Wait()
		close(resc)
	}()

	// feed pipeline
	go func() {
		for _, t := range tests {
			testc <- t

			// don't go too fast, in case we're talking to a rate limiting api like AWS EC2.
			time.Sleep(2 * time.Second)
		}
		close(testc)
	}()

	for r := range resc {
		t := r.test
		err := r.result
		seconds := r.duration.Seconds()
		if err != nil && err == register.Skip {
			plog.Errorf("--- SKIP: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			skipped++
		} else if err != nil {
			plog.Errorf("--- FAIL: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			plog.Errorf("        %v", err)
			failed++
		} else {
			plog.Noticef("--- PASS: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			passed++
		}
	}

	plog.Noticef("%d passed %d failed %d skipped out of %d total", passed, failed, skipped, passed+failed+skipped)
	if failed > 0 {
		return fmt.Errorf("%d tests failed", failed)
	}
	return nil
}

// getClusterSemVer returns the CoreOS semantic version via starting a
// machine and checking
func getClusterSemver(pltfrm string) (*semver.Version, error) {
	var err error
	var cluster platform.Cluster

	switch pltfrm {
	case "qemu":
		cluster, err = platform.NewQemuCluster(QEMUOptions)
	case "gce":
		cluster, err = platform.NewGCECluster(GCEOptions)
	case "aws":
		cluster, err = platform.NewAWSCluster(AWSOptions)
	default:
		err = fmt.Errorf("invalid platform %q", pltfrm)
	}

	if err != nil {
		return nil, fmt.Errorf("creating cluster for semver check: %v", err)
	}
	defer func() {
		if err := cluster.Destroy(); err != nil {
			plog.Errorf("cluster.Destroy(): %v", err)
		}
	}()

	m, err := cluster.NewMachine("#cloud-config")
	if err != nil {
		return nil, fmt.Errorf("creating new machine for semver check: %v", err)
	}

	out, err := m.SSH("grep ^VERSION_ID= /etc/os-release")
	if err != nil {
		return nil, fmt.Errorf("parsing /etc/os-release: %v", err)
	}

	version, err := semver.NewVersion(strings.Split(string(out), "=")[1])
	if err != nil {
		return nil, fmt.Errorf("parsing os-release semver: %v", err)
	}

	return version, nil
}

// RunTest is a harness for running a single test. It is used by
// RunTests but can also be used directly by binaries that aim to run a
// single test. Using RunTest directly means that TestCluster flags used
// to filter out tests such as 'Platforms', 'Manual', or 'MinVersion'
// are not respected.
func RunTest(t *register.Test, pltfrm string) error {
	var err error
	var cluster platform.Cluster

	switch pltfrm {
	case "qemu":
		cluster, err = platform.NewQemuCluster(QEMUOptions)
	case "gce":
		cluster, err = platform.NewGCECluster(GCEOptions)
	case "aws":
		cluster, err = platform.NewAWSCluster(AWSOptions)
	default:
		err = fmt.Errorf("invalid platform %q", pltfrm)
	}

	if err != nil {
		return fmt.Errorf("Cluster failed: %v", err)
	}
	defer func() {
		if err := cluster.Destroy(); err != nil {
			plog.Errorf("cluster.Destroy(): %v", err)
		}
	}()

	url, err := cluster.GetDiscoveryURL(t.ClusterSize)
	if err != nil {
		return fmt.Errorf("Failed to create discovery endpoint: %v", err)
	}

	cfgs := makeConfigs(url, t.UserData, t.ClusterSize)

	if t.ClusterSize > 0 {
		_, err := platform.NewMachines(cluster, cfgs)
		if err != nil {
			return fmt.Errorf("Cluster failed starting machines: %v", err)
		}
	}

	// pass along all registered native functions
	var names []string
	for k := range t.NativeFuncs {
		names = append(names, k)
	}

	// prevent unsafe access if tests ever become parallel and access
	tempTestOptions := make(map[string]string, 0)
	for k, v := range testOptions {
		tempTestOptions[k] = v
	}

	// Cluster -> TestCluster
	tcluster := platform.TestCluster{
		Name:        t.Name,
		NativeFuncs: names,
		Options:     tempTestOptions,
		Cluster:     cluster,
	}

	// drop kolet binary on machines
	if t.NativeFuncs != nil {
		err = scpKolet(tcluster)
		if err != nil {
			return fmt.Errorf("dropping kolet binary: %v", err)
		}
	}

	// run test
	err = t.Run(tcluster)

	// give some time for the remote journal to be flushed so it can be read
	// before we run the deferred machine destruction
	if err != nil {
		time.Sleep(10 * time.Second)
	}

	return err
}

// scpKolet searches for a kolet binary and copies it to the machine.
func scpKolet(t platform.TestCluster) error {
	// TODO: determine the GOARCH for the remote machine
	mArch := "amd64"
	for _, d := range []string{
		".",
		filepath.Dir(os.Args[0]),
		filepath.Join("/usr/lib/kola", mArch),
	} {
		kolet := filepath.Join(d, "kolet")
		if _, err := os.Stat(kolet); err == nil {
			return t.DropFile(kolet)
		}
	}
	return fmt.Errorf("Unable to locate kolet binary for %s", mArch)
}

// replaces $discovery with discover url in etcd cloud config and
// replaces $name with a unique name
func makeConfigs(url, cfg string, csize int) []string {
	cfg = strings.Replace(cfg, "$discovery", url, -1)

	var cfgs []string
	for i := 0; i < csize; i++ {
		cfgs = append(cfgs, strings.Replace(cfg, "$name", "instance"+strconv.Itoa(i), -1))
	}
	return cfgs
}
<commit_msg>Kola: fix inverted version logic<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package kola

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"

	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
	"github.com/coreos/mantle/Godeps/_workspace/src/github.com/coreos/pkg/capnslog"

	// Tests imported for registration side effects.
	_ "github.com/coreos/mantle/kola/tests/coretest"
	_ "github.com/coreos/mantle/kola/tests/etcd"
	_ "github.com/coreos/mantle/kola/tests/flannel"
	_ "github.com/coreos/mantle/kola/tests/fleet"
	_ "github.com/coreos/mantle/kola/tests/ignition"
	_ "github.com/coreos/mantle/kola/tests/kubernetes"
	_ "github.com/coreos/mantle/kola/tests/metadata"
	_ "github.com/coreos/mantle/kola/tests/misc"
	_ "github.com/coreos/mantle/kola/tests/rkt"
	_ "github.com/coreos/mantle/kola/tests/systemd"
)

var (
	plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola")

	QEMUOptions platform.QEMUOptions // glue to set platform options from main
	GCEOptions  platform.GCEOptions  // glue to set platform options from main
	AWSOptions  platform.AWSOptions  // glue to set platform options from main

	TestParallelism int //glue var to set test parallelism from main

	testOptions = make(map[string]string, 0)
)

// RegisterTestOption registers any options that need visibility inside
// a Test. Panics if existing option is already registered. Each test
// has global view of options.
func RegisterTestOption(name, option string) {
	_, ok := testOptions[name]
	if ok {
		panic("test option already registered with same name")
	}
	testOptions[name] = option
}

// NativeRunner is a closure passed to all kola test functions and used
// to run native go functions directly on kola machines. It is necessary
// glue until kola does introspection.
type NativeRunner func(funcName string, m platform.Machine) error

type result struct {
	test     *register.Test
	result   error
	duration time.Duration
}

func testRunner(platform string, done <-chan struct{}, tests chan *register.Test, results chan *result) {
	for test := range tests {
		plog.Noticef("=== RUN %s on %s", test.Name, platform)
		start := time.Now()
		err := RunTest(test, platform)
		duration := time.Since(start)

		select {
		case results <- &result{test, err, duration}:
		case <-done:
			return
		}
	}
}

func filterTests(tests map[string]*register.Test, pattern, platform string, version semver.Version) (map[string]*register.Test, error) {
	r := make(map[string]*register.Test)

	for name, t := range tests {
		match, err := filepath.Match(pattern, t.Name)
		if err != nil {
			return nil, err
		}
		if !match {
			continue
		}

		// Skip the test if Manual is set and the name doesn't fully match.
		if t.Manual && t.Name != pattern {
			continue
		}

		// Check the test's min and end versions when running more then one test
		if t.Name != pattern && versionOutsideRange(version, t.MinVersion, t.EndVersion) {
			continue
		}

		allowed := true
		for _, p := range t.Platforms {
			if p == platform {
				allowed = true
				break
			} else {
				allowed = false
			}
		}
		if !allowed {
			continue
		}

		r[name] = t
	}

	return r, nil
}

// versionOutsideRange checks to see if version is outside [min, end). If end
// is a zero value, it is ignored and there is no upper bound.
func versionOutsideRange(version, minVersion, endVersion semver.Version) bool {
	if version.LessThan(minVersion) {
		return true
	}

	if (endVersion != semver.Version{}) && !version.LessThan(endVersion) {
		return true
	}

	return false
}

// RunTests is a harness for running multiple tests in parallel. Filters
// tests based on a glob pattern and by platform. Has access to all
// tests either registered in this package or by imported packages that
// register tests in their init() function.
func RunTests(pattern, pltfrm string) error {
	var passed, failed, skipped int
	var wg sync.WaitGroup

	// Avoid incurring cost of starting machine in getClusterSemver when
	// either:
	// 1) we already know 0 tests will run
	// 2) glob is an exact match which means minVersion will be ignored
	//    either way
	tests, err := filterTests(register.Tests, pattern, pltfrm, semver.Version{})
	if err != nil {
		plog.Fatal(err)
	}

	var skipGetVersion bool
	if len(tests) == 0 {
		skipGetVersion = true
	} else if len(tests) == 1 {
		for name := range tests {
			if name == pattern {
				skipGetVersion = true
			}
		}
	}

	if !skipGetVersion {
		version, err := getClusterSemver(pltfrm)
		if err != nil {
			plog.Fatal(err)
		}

		// one more filter pass now that we know real version
		tests, err = filterTests(tests, pattern, pltfrm, *version)
		if err != nil {
			plog.Fatal(err)
		}
	}

	done := make(chan struct{})
	defer close(done)
	testc := make(chan *register.Test)
	resc := make(chan *result)

	wg.Add(TestParallelism)

	for i := 0; i < TestParallelism; i++ {
		go func() {
			testRunner(pltfrm, done, testc, resc)
			wg.Done()
		}()
	}
	go func() {
		wg.Wait()
		close(resc)
	}()

	// feed pipeline
	go func() {
		for _, t := range tests {
			testc <- t

			// don't go too fast, in case we're talking to a rate limiting api like AWS EC2.
			time.Sleep(2 * time.Second)
		}
		close(testc)
	}()

	for r := range resc {
		t := r.test
		err := r.result
		seconds := r.duration.Seconds()
		if err != nil && err == register.Skip {
			plog.Errorf("--- SKIP: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			skipped++
		} else if err != nil {
			plog.Errorf("--- FAIL: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			plog.Errorf("        %v", err)
			failed++
		} else {
			plog.Noticef("--- PASS: %s on %s (%.3fs)", t.Name, pltfrm, seconds)
			passed++
		}
	}

	plog.Noticef("%d passed %d failed %d skipped out of %d total", passed, failed, skipped, passed+failed+skipped)
	if failed > 0 {
		return fmt.Errorf("%d tests failed", failed)
	}
	return nil
}

// getClusterSemVer returns the CoreOS semantic version via starting a
// machine and checking
func getClusterSemver(pltfrm string) (*semver.Version, error) {
	var err error
	var cluster platform.Cluster

	switch pltfrm {
	case "qemu":
		cluster, err = platform.NewQemuCluster(QEMUOptions)
	case "gce":
		cluster, err = platform.NewGCECluster(GCEOptions)
	case "aws":
		cluster, err = platform.NewAWSCluster(AWSOptions)
	default:
		err = fmt.Errorf("invalid platform %q", pltfrm)
	}

	if err != nil {
		return nil, fmt.Errorf("creating cluster for semver check: %v", err)
	}
	defer func() {
		if err := cluster.Destroy(); err != nil {
			plog.Errorf("cluster.Destroy(): %v", err)
		}
	}()

	m, err := cluster.NewMachine("#cloud-config")
	if err != nil {
		return nil, fmt.Errorf("creating new machine for semver check: %v", err)
	}

	out, err := m.SSH("grep ^VERSION_ID= /etc/os-release")
	if err != nil {
		return nil, fmt.Errorf("parsing /etc/os-release: %v", err)
	}

	version, err := semver.NewVersion(strings.Split(string(out), "=")[1])
	if err != nil {
		return nil, fmt.Errorf("parsing os-release semver: %v", err)
	}

	return version, nil
}

// RunTest is a harness for running a single test. It is used by
// RunTests but can also be used directly by binaries that aim to run a
// single test. Using RunTest directly means that TestCluster flags used
// to filter out tests such as 'Platforms', 'Manual', or 'MinVersion'
// are not respected.
func RunTest(t *register.Test, pltfrm string) error {
	var err error
	var cluster platform.Cluster

	switch pltfrm {
	case "qemu":
		cluster, err = platform.NewQemuCluster(QEMUOptions)
	case "gce":
		cluster, err = platform.NewGCECluster(GCEOptions)
	case "aws":
		cluster, err = platform.NewAWSCluster(AWSOptions)
	default:
		err = fmt.Errorf("invalid platform %q", pltfrm)
	}

	if err != nil {
		return fmt.Errorf("Cluster failed: %v", err)
	}
	defer func() {
		if err := cluster.Destroy(); err != nil {
			plog.Errorf("cluster.Destroy(): %v", err)
		}
	}()

	url, err := cluster.GetDiscoveryURL(t.ClusterSize)
	if err != nil {
		return fmt.Errorf("Failed to create discovery endpoint: %v", err)
	}

	cfgs := makeConfigs(url, t.UserData, t.ClusterSize)

	if t.ClusterSize > 0 {
		_, err := platform.NewMachines(cluster, cfgs)
		if err != nil {
			return fmt.Errorf("Cluster failed starting machines: %v", err)
		}
	}

	// pass along all registered native functions
	var names []string
	for k := range t.NativeFuncs {
		names = append(names, k)
	}

	// prevent unsafe access if tests ever become parallel and access
	tempTestOptions := make(map[string]string, 0)
	for k, v := range testOptions {
		tempTestOptions[k] = v
	}

	// Cluster -> TestCluster
	tcluster := platform.TestCluster{
		Name:        t.Name,
		NativeFuncs: names,
		Options:     tempTestOptions,
		Cluster:     cluster,
	}

	// drop kolet binary on machines
	if t.NativeFuncs != nil {
		err = scpKolet(tcluster)
		if err != nil {
			return fmt.Errorf("dropping kolet binary: %v", err)
		}
	}

	// run test
	err = t.Run(tcluster)

	// give some time for the remote journal to be flushed so it can be read
	// before we run the deferred machine destruction
	if err != nil {
		time.Sleep(10 * time.Second)
	}

	return err
}

// scpKolet searches for a kolet binary and copies it to the machine.
func scpKolet(t platform.TestCluster) error {
	// TODO: determine the GOARCH for the remote machine
	mArch := "amd64"
	for _, d := range []string{
		".",
		filepath.Dir(os.Args[0]),
		filepath.Join("/usr/lib/kola", mArch),
	} {
		kolet := filepath.Join(d, "kolet")
		if _, err := os.Stat(kolet); err == nil {
			return t.DropFile(kolet)
		}
	}
	return fmt.Errorf("Unable to locate kolet binary for %s", mArch)
}

// replaces $discovery with discover url in etcd cloud config and
// replaces $name with a unique name
func makeConfigs(url, cfg string, csize int) []string {
	cfg = strings.Replace(cfg, "$discovery", url, -1)

	var cfgs []string
	for i := 0; i < csize; i++ {
		cfgs = append(cfgs, strings.Replace(cfg, "$name", "instance"+strconv.Itoa(i), -1))
	}
	return cfgs
}
<|endoftext|>


<commit_before>package l10n

func Strings(lang string) map[string]string {
	switch lang {
	case "hu":
		return phrasesHU
	default:
		return phrases
	}
}
<commit_msg>Document Strings() func<commit_after>package l10n

// Strings returns a translation set that will take any term and return its
// translation.
func Strings(lang string) map[string]string {
	switch lang {
	case "hu":
		return phrasesHU
	default:
		return phrases
	}
}
<|endoftext|>


<commit_before>package lang

import "fmt"

func Compile(mod Module) Bytecode {
	if virt, ok := mod.(*VirtualModule); ok {
		main := compileProgram(mod, virt.Scope(), virt.ast)
		return main
	}

	return Bytecode{}
}

func compileProgram(mod Module, s *GlobalScope, prog *RootNode) Bytecode {
	blob := Bytecode{}
	for _, name := range s.GetLocalVariableNames() {
		symbol := s.GetLocalVariableReference(name)
		blob.write(InstrReserve{name, symbol})
	}

	blob.append(compileTopLevelStmts(mod, s, prog.Stmts))
	blob.write(InstrHalt{})
	return blob
}

func compileTopLevelStmts(mod Module, s *GlobalScope, stmts []Stmt) (blob Bytecode) {
	for _, stmt := range stmts {
		blob.append(compileTopLevelStmt(mod, s, stmt))
	}
	return blob
}

func compileTopLevelStmt(mod Module, s *GlobalScope, stmt Stmt) Bytecode {
	switch stmt := stmt.(type) {
	case *UseStmt:
		return compileUseStmt(mod, s, stmt)
	default:
		return compileStmt(s, stmt)
	}
}

func compileStmts(s Scope, stmts []Stmt) (blob Bytecode) {
	for _, stmt := range stmts {
		blob.append(compileStmt(s, stmt))
	}
	return blob
}

func compileStmt(s Scope, stmt Stmt) Bytecode {
	switch stmt := stmt.(type) {
	case *PubStmt:
		return compilePubStmt(s, stmt)
	case *IfStmt:
		return compileIfStmt(s, stmt)
	case *ReturnStmt:
		return compileReturnStmt(s, stmt)
	case *DeclarationStmt:
		return compileDeclarationStmt(s, stmt)
	case *ExprStmt:
		return compileExprStmt(s, stmt)
	default:
		panic(fmt.Sprintf("cannot compile %T", stmt))
	}
}

func compileUseStmt(mod Module, s *GlobalScope, stmt *UseStmt) Bytecode {
	name := stmt.Path.Val
	for _, imp := range mod.Imports() {
		if imp.Path() == name {
			if native, ok := imp.(*NativeModule); ok {
				lib := native.library
				blob := Bytecode{}
				blob.write(InstrPush{lib.toObject()})
				blob.write(InstrStore{name, s.GetVariableReference(name)})
				return blob
			}
		}
	}
	panic(fmt.Sprintf("cannot find library named '%s'", stmt.Path.Val))
}

func compilePubStmt(s Scope, stmt *PubStmt) Bytecode {
	return compileStmt(s, stmt.Stmt)
}

func compileIfStmt(s Scope, stmt *IfStmt) Bytecode {
	blob := compileExpr(s, stmt.Cond)
	jump := blob.write(InstrNOP{}) // Pending jump to end of clause
	done := blob.append(compileStmts(s, stmt.Clause.Stmts))
	blob.overwrite(jump, InstrJumpFalse{done})
	return blob
}

func compileReturnStmt(s Scope, stmt *ReturnStmt) (blob Bytecode) {
	if stmt.Expr == nil {
		blob.write(InstrPush{ObjectNone{}})
	} else {
		blob.append(compileExpr(s, stmt.Expr))
	}
	blob.write(InstrReturn{})
	return blob
}

func compileDeclarationStmt(s Scope, stmt *DeclarationStmt) Bytecode {
	blob := compileExpr(s, stmt.Expr)
	symbol := s.GetVariableReference(stmt.Name.Name)
	blob.write(InstrStore{stmt.Name.Name, symbol})
	return blob
}

func compileExprStmt(s Scope, stmt *ExprStmt) Bytecode {
	blob := compileExpr(s, stmt.Expr)
	blob.write(InstrPop{})
	return blob
}

func compileExpr(s Scope, expr Expr) Bytecode {
	switch expr := expr.(type) {
	case *FunctionExpr:
		return compileFunctionExpr(s, expr)
	case *DispatchExpr:
		return compileDispatchExpr(s, expr)
	case *AssignExpr:
		return compileAssignExpr(s, expr)
	case *BinaryExpr:
		return compileBinaryExpr(s, expr)
	case *SelfExpr:
		return compileSelfExpr(s, expr)
	case *IdentExpr:
		return compileIdentExpr(s, expr)
	case *NumberExpr:
		return compileNumberExpr(s, expr)
	case *StringExpr:
		return compileStringExpr(s, expr)
	case *BooleanExpr:
		return compileBoolExpr(s, expr)
	default:
		panic(fmt.Sprintf("cannot transform expression %T", expr))
	}
}

func compileFunctionExpr(s Scope, expr *FunctionExpr) (blob Bytecode) {
	local := s.GetChild(expr)
	var params []*UniqueSymbol
	for _, param := range expr.Params {
		name := param.Name.Name
		symbol := local.GetLocalVariableReference(name)
		params = append(params, symbol)
	}

	bodyBlob := Bytecode{}
	for _, name := range local.GetLocalVariableNames() {
		isParam := false
		for _, param := range expr.Params {
			if param.Name.Name == name {
				isParam = true
				break
			}
		}

		if isParam == false {
			symbol := local.GetLocalVariableReference(name)
			bodyBlob.write(InstrReserve{name, symbol})
		}
	}

	bodyBlob.append(compileStmts(local, expr.Block.Stmts))
	bodyBlob.write(InstrPush{ObjectNone{}})
	bodyBlob.write(InstrReturn{})

	function := ObjectFunction{
		params:   params,
		bytecode: bodyBlob,
	}

	blob.write(InstrPush{function})
	return blob
}

func compileDispatchExpr(s Scope, expr *DispatchExpr) (blob Bytecode) {
	for i := len(expr.Args) - 1; i >= 0; i-- {
		blob.append(compileExpr(s, expr.Args[i]))
	}
	blob.append(compileExpr(s, expr.Callee))
	blob.write(InstrDispatch{args: len(expr.Args)})
	return blob
}

func compileAssignExpr(s Scope, expr *AssignExpr) Bytecode {
	blob := compileExpr(s, expr.Right)
	symbol := s.GetVariableReference(expr.Left.Name)
	blob.write(InstrCopy{})
	blob.write(InstrStore{expr.Left.Name, symbol})
	return blob
}

func compileBinaryExpr(s Scope, expr *BinaryExpr) Bytecode {
	blob := compileExpr(s, expr.Left)
	blob.append(compileExpr(s, expr.Right))

	switch expr.Oper {
	case "+":
		blob.write(InstrAdd{})
	case "-":
		blob.write(InstrSub{})
	case "*":
		blob.write(InstrMul{})
	case "<":
		blob.write(InstrLT{})
	case "<=":
		blob.write(InstrLTEquals{})
	case ">":
		blob.write(InstrGT{})
	case ">=":
		blob.write(InstrGTEquals{})
	default:
		panic(fmt.Sprintf("cannot compile %T with '%s'", expr, expr.Oper))
	}

	return blob
}

func compileSelfExpr(s Scope, expr *SelfExpr) Bytecode {
	blob := Bytecode{}
	blob.write(InstrLoadSelf{})
	return blob
}

func compileIdentExpr(s Scope, expr *IdentExpr) Bytecode {
	blob := Bytecode{}
	symbol := s.GetVariableReference(expr.Name)

	if symbol == nil {
		panic("nil lookup")
	}

	blob.write(InstrLoad{expr.Name, symbol})
	return blob
}

func compileNumberExpr(s Scope, expr *NumberExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectInt{int64(expr.Val)}})
	return blob
}

func compileStringExpr(s Scope, expr *StringExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectStr{expr.Val}})
	return blob
}

func compileBoolExpr(s Scope, expr *BooleanExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectBool{expr.Val}})
	return blob
}
<commit_msg>compile access expression<commit_after>package lang

import "fmt"

func Compile(mod Module) Bytecode {
	if virt, ok := mod.(*VirtualModule); ok {
		main := compileProgram(mod, virt.Scope(), virt.ast)
		return main
	}

	return Bytecode{}
}

func compileProgram(mod Module, s *GlobalScope, prog *RootNode) Bytecode {
	blob := Bytecode{}
	for _, name := range s.GetLocalVariableNames() {
		symbol := s.GetLocalVariableReference(name)
		blob.write(InstrReserve{name, symbol})
	}

	blob.append(compileTopLevelStmts(mod, s, prog.Stmts))
	blob.write(InstrHalt{})
	return blob
}

func compileTopLevelStmts(mod Module, s *GlobalScope, stmts []Stmt) (blob Bytecode) {
	for _, stmt := range stmts {
		blob.append(compileTopLevelStmt(mod, s, stmt))
	}
	return blob
}

func compileTopLevelStmt(mod Module, s *GlobalScope, stmt Stmt) Bytecode {
	switch stmt := stmt.(type) {
	case *UseStmt:
		return compileUseStmt(mod, s, stmt)
	default:
		return compileStmt(s, stmt)
	}
}

func compileStmts(s Scope, stmts []Stmt) (blob Bytecode) {
	for _, stmt := range stmts {
		blob.append(compileStmt(s, stmt))
	}
	return blob
}

func compileStmt(s Scope, stmt Stmt) Bytecode {
	switch stmt := stmt.(type) {
	case *PubStmt:
		return compilePubStmt(s, stmt)
	case *IfStmt:
		return compileIfStmt(s, stmt)
	case *ReturnStmt:
		return compileReturnStmt(s, stmt)
	case *DeclarationStmt:
		return compileDeclarationStmt(s, stmt)
	case *ExprStmt:
		return compileExprStmt(s, stmt)
	default:
		panic(fmt.Sprintf("cannot compile %T", stmt))
	}
}

func compileUseStmt(mod Module, s *GlobalScope, stmt *UseStmt) Bytecode {
	name := stmt.Path.Val
	for _, imp := range mod.Imports() {
		if imp.Path() == name {
			if native, ok := imp.(*NativeModule); ok {
				lib := native.library
				blob := Bytecode{}
				blob.write(InstrPush{lib.toObject()})
				blob.write(InstrStore{name, s.GetVariableReference(name)})
				return blob
			}
		}
	}
	panic(fmt.Sprintf("cannot find library named '%s'", stmt.Path.Val))
}

func compilePubStmt(s Scope, stmt *PubStmt) Bytecode {
	return compileStmt(s, stmt.Stmt)
}

func compileIfStmt(s Scope, stmt *IfStmt) Bytecode {
	blob := compileExpr(s, stmt.Cond)
	jump := blob.write(InstrNOP{}) // Pending jump to end of clause
	done := blob.append(compileStmts(s, stmt.Clause.Stmts))
	blob.overwrite(jump, InstrJumpFalse{done})
	return blob
}

func compileReturnStmt(s Scope, stmt *ReturnStmt) (blob Bytecode) {
	if stmt.Expr == nil {
		blob.write(InstrPush{ObjectNone{}})
	} else {
		blob.append(compileExpr(s, stmt.Expr))
	}
	blob.write(InstrReturn{})
	return blob
}

func compileDeclarationStmt(s Scope, stmt *DeclarationStmt) Bytecode {
	blob := compileExpr(s, stmt.Expr)
	symbol := s.GetVariableReference(stmt.Name.Name)
	blob.write(InstrStore{stmt.Name.Name, symbol})
	return blob
}

func compileExprStmt(s Scope, stmt *ExprStmt) Bytecode {
	blob := compileExpr(s, stmt.Expr)
	blob.write(InstrPop{})
	return blob
}

func compileExpr(s Scope, expr Expr) Bytecode {
	switch expr := expr.(type) {
	case *FunctionExpr:
		return compileFunctionExpr(s, expr)
	case *DispatchExpr:
		return compileDispatchExpr(s, expr)
	case *AssignExpr:
		return compileAssignExpr(s, expr)
	case *BinaryExpr:
		return compileBinaryExpr(s, expr)
	case *AccessExpr:
		return compileAccessExpr(s, expr)
	case *SelfExpr:
		return compileSelfExpr(s, expr)
	case *IdentExpr:
		return compileIdentExpr(s, expr)
	case *NumberExpr:
		return compileNumberExpr(s, expr)
	case *StringExpr:
		return compileStringExpr(s, expr)
	case *BooleanExpr:
		return compileBoolExpr(s, expr)
	default:
		panic(fmt.Sprintf("cannot transform expression %T", expr))
	}
}

func compileFunctionExpr(s Scope, expr *FunctionExpr) (blob Bytecode) {
	local := s.GetChild(expr)
	var params []*UniqueSymbol
	for _, param := range expr.Params {
		name := param.Name.Name
		symbol := local.GetLocalVariableReference(name)
		params = append(params, symbol)
	}

	bodyBlob := Bytecode{}
	for _, name := range local.GetLocalVariableNames() {
		isParam := false
		for _, param := range expr.Params {
			if param.Name.Name == name {
				isParam = true
				break
			}
		}

		if isParam == false {
			symbol := local.GetLocalVariableReference(name)
			bodyBlob.write(InstrReserve{name, symbol})
		}
	}

	bodyBlob.append(compileStmts(local, expr.Block.Stmts))
	bodyBlob.write(InstrPush{ObjectNone{}})
	bodyBlob.write(InstrReturn{})

	function := ObjectFunction{
		params:   params,
		bytecode: bodyBlob,
	}

	blob.write(InstrPush{function})
	return blob
}

func compileDispatchExpr(s Scope, expr *DispatchExpr) (blob Bytecode) {
	for i := len(expr.Args) - 1; i >= 0; i-- {
		blob.append(compileExpr(s, expr.Args[i]))
	}
	blob.append(compileExpr(s, expr.Callee))
	blob.write(InstrDispatch{args: len(expr.Args)})
	return blob
}

func compileAccessExpr(s Scope, expr *AccessExpr) Bytecode {
	blob := compileExpr(s, expr.Left)
	blob.write(InstrLoadAttr{expr.Right.(*IdentExpr).Name})
	return blob
}

func compileAssignExpr(s Scope, expr *AssignExpr) Bytecode {
	blob := compileExpr(s, expr.Right)
	symbol := s.GetVariableReference(expr.Left.Name)
	blob.write(InstrCopy{})
	blob.write(InstrStore{expr.Left.Name, symbol})
	return blob
}

func compileBinaryExpr(s Scope, expr *BinaryExpr) Bytecode {
	blob := compileExpr(s, expr.Left)
	blob.append(compileExpr(s, expr.Right))

	switch expr.Oper {
	case "+":
		blob.write(InstrAdd{})
	case "-":
		blob.write(InstrSub{})
	case "*":
		blob.write(InstrMul{})
	case "<":
		blob.write(InstrLT{})
	case "<=":
		blob.write(InstrLTEquals{})
	case ">":
		blob.write(InstrGT{})
	case ">=":
		blob.write(InstrGTEquals{})
	default:
		panic(fmt.Sprintf("cannot compile %T with '%s'", expr, expr.Oper))
	}

	return blob
}

func compileSelfExpr(s Scope, expr *SelfExpr) Bytecode {
	blob := Bytecode{}
	blob.write(InstrLoadSelf{})
	return blob
}

func compileIdentExpr(s Scope, expr *IdentExpr) Bytecode {
	blob := Bytecode{}
	symbol := s.GetVariableReference(expr.Name)

	if symbol == nil {
		panic("nil lookup")
	}

	blob.write(InstrLoad{expr.Name, symbol})
	return blob
}

func compileNumberExpr(s Scope, expr *NumberExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectInt{int64(expr.Val)}})
	return blob
}

func compileStringExpr(s Scope, expr *StringExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectStr{expr.Val}})
	return blob
}

func compileBoolExpr(s Scope, expr *BooleanExpr) (blob Bytecode) {
	blob.write(InstrPush{ObjectBool{expr.Val}})
	return blob
}
<|endoftext|>


<commit_before>package redis

import (
	"bytes"
	"encoding/gob"
	"reflect"
	"time"

	"cloud.google.com/go/datastore"
	"github.com/acoshift/ds"
	"github.com/garyburd/redigo/redis"
)

// Cache implement Cache interface
type Cache struct {
	Pool      *redis.Pool
	Prefix    string
	TTL       time.Duration
	ExtendTTL bool
	Skip      func(*datastore.Key) bool
}

func encode(v interface{}) ([]byte, error) {
	w := &bytes.Buffer{}
	err := gob.NewEncoder(w).Encode(v)
	if err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}

func decode(b []byte, v interface{}) error {
	return gob.NewDecoder(bytes.NewReader(b)).Decode(v)
}

// Get gets data
func (cache *Cache) Get(key *datastore.Key, dst interface{}) error {
	if cache.Skip != nil && cache.Skip(key) {
		return ds.ErrCacheNotFound
	}

	db := cache.Pool.Get()
	defer db.Close()
	k := cache.Prefix + key.String()
	b, err := redis.Bytes(db.Do("GET", k))
	if err != nil {
		return err
	}
	if len(b) == 0 {
		return ds.ErrCacheNotFound
	}
	if cache.ExtendTTL {
		db.Do("EXPIRE", k, int(cache.TTL/time.Second))
	}
	return decode(b, dst)
}

// GetMulti gets multi data
func (cache *Cache) GetMulti(keys []*datastore.Key, dst interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	for _, key := range keys {
		db.Send("GET", cache.Prefix+key.String())
	}
	err := db.Flush()
	if err != nil {
		return err
	}
	for i := range keys {
		b, err := redis.Bytes(db.Receive())
		if err != nil {
			return err
		}
		if len(b) > 0 {
			decode(b, reflect.Indirect(reflect.ValueOf(dst)).Index(i).Interface())
		}
	}
	if cache.ExtendTTL {
		ttl := int(cache.TTL / time.Second)
		for _, key := range keys {
			db.Send("EXPIRE", cache.Prefix+key.String(), ttl)
		}
		db.Flush()
	}
	return nil
}

// Set sets data
func (cache *Cache) Set(key *datastore.Key, src interface{}) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := encode(src)
	if err != nil {
		return err
	}
	if cache.TTL > 0 {
		_, err = db.Do("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		return err
	}
	_, err = db.Do("SET", cache.Prefix+key.String(), b)
	return err
}

// SetMulti sets data
func (cache *Cache) SetMulti(keys []*datastore.Key, src interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	ttl := int(cache.TTL / time.Second)
	db.Send("MULTI")
	for i, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		b, err := encode(reflect.Indirect(reflect.ValueOf(src)).Index(i).Interface())
		if err != nil {
			return err
		}
		if cache.TTL > 0 {
			db.Send("SETEX", cache.Prefix+key.String(), ttl, b)
		}
		db.Send("SET", cache.Prefix+key.String(), b)
	}
	_, err := db.Do("EXEC")
	return err
}

// Del dels data
func (cache *Cache) Del(key *datastore.Key) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", cache.Prefix+key.String())
	return err
}

// DelMulti dels multi data
func (cache *Cache) DelMulti(keys []*datastore.Key) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for _, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		db.Send("DEL", cache.Prefix+key.String())
	}
	_, err := db.Do("EXEC")
	return err
}
<commit_msg>fix set cache for multi<commit_after>package redis

import (
	"bytes"
	"encoding/gob"
	"reflect"
	"time"

	"cloud.google.com/go/datastore"
	"github.com/acoshift/ds"
	"github.com/garyburd/redigo/redis"
)

// Cache implement Cache interface
type Cache struct {
	Pool      *redis.Pool
	Prefix    string
	TTL       time.Duration
	ExtendTTL bool
	Skip      func(*datastore.Key) bool
}

func encode(v interface{}) ([]byte, error) {
	w := &bytes.Buffer{}
	err := gob.NewEncoder(w).Encode(v)
	if err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}

func decode(b []byte, v interface{}) error {
	return gob.NewDecoder(bytes.NewReader(b)).Decode(v)
}

// Get gets data
func (cache *Cache) Get(key *datastore.Key, dst interface{}) error {
	if cache.Skip != nil && cache.Skip(key) {
		return ds.ErrCacheNotFound
	}

	db := cache.Pool.Get()
	defer db.Close()
	k := cache.Prefix + key.String()
	b, err := redis.Bytes(db.Do("GET", k))
	if err != nil {
		return err
	}
	if len(b) == 0 {
		return ds.ErrCacheNotFound
	}
	if cache.ExtendTTL {
		db.Do("EXPIRE", k, int(cache.TTL/time.Second))
	}
	return decode(b, dst)
}

// GetMulti gets multi data
func (cache *Cache) GetMulti(keys []*datastore.Key, dst interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	for _, key := range keys {
		db.Send("GET", cache.Prefix+key.String())
	}
	err := db.Flush()
	if err != nil {
		return err
	}
	for i := range keys {
		b, err := redis.Bytes(db.Receive())
		if err != nil {
			return err
		}
		if len(b) > 0 {
			decode(b, reflect.Indirect(reflect.ValueOf(dst)).Index(i).Interface())
		}
	}
	if cache.ExtendTTL {
		ttl := int(cache.TTL / time.Second)
		for _, key := range keys {
			db.Send("EXPIRE", cache.Prefix+key.String(), ttl)
		}
		db.Flush()
	}
	return nil
}

// Set sets data
func (cache *Cache) Set(key *datastore.Key, src interface{}) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	b, err := encode(src)
	if err != nil {
		return err
	}
	if cache.TTL > 0 {
		_, err = db.Do("SETEX", cache.Prefix+key.String(), int(cache.TTL/time.Second), b)
		return err
	}
	_, err = db.Do("SET", cache.Prefix+key.String(), b)
	return err
}

// SetMulti sets data
func (cache *Cache) SetMulti(keys []*datastore.Key, src interface{}) error {
	db := cache.Pool.Get()
	defer db.Close()
	ttl := int(cache.TTL / time.Second)
	db.Send("MULTI")
	for i, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		b, err := encode(reflect.Indirect(reflect.ValueOf(src)).Index(i).Interface())
		if err != nil {
			return err
		}
		if cache.TTL > 0 {
			db.Send("SETEX", cache.Prefix+key.String(), ttl, b)
		} else {
			db.Send("SET", cache.Prefix+key.String(), b)
		}
	}
	_, err := db.Do("EXEC")
	return err
}

// Del dels data
func (cache *Cache) Del(key *datastore.Key) error {
	if key == nil {
		return nil
	}
	if cache.Skip != nil && cache.Skip(key) {
		return nil
	}

	db := cache.Pool.Get()
	defer db.Close()
	_, err := db.Do("DEL", cache.Prefix+key.String())
	return err
}

// DelMulti dels multi data
func (cache *Cache) DelMulti(keys []*datastore.Key) error {
	db := cache.Pool.Get()
	defer db.Close()
	db.Send("MULTI")
	for _, key := range keys {
		if key == nil {
			continue
		}
		if cache.Skip != nil && cache.Skip(key) {
			continue
		}
		db.Send("DEL", cache.Prefix+key.String())
	}
	_, err := db.Do("EXEC")
	return err
}
<|endoftext|>


<commit_before>package generate

import (
	"errors"
	"fmt"

	"github.com/gobuffalo/buffalo/generators/resource"
	"github.com/gobuffalo/makr"
	"github.com/markbates/inflect"
	"github.com/spf13/cobra"
)

const resourceExamples = `$ buffalo g resource users
Generates:

- actions/users.go
- actions/users_test.go
- models/user.go
- models/user_test.go
- migrations/2016020216301234_create_users.up.fizz
- migrations/2016020216301234_create_users.down.fizz

$ buffalo g resource users --skip-migration
Generates:

- actions/users.go
- actions/users_test.go
- models/user.go
- models/user_test.go

$ buffalo g resource users --skip-model
Generates:

- actions/users.go
- actions/users_test.go

$ buffalo g resource users --use-model
Generates:

- actions/users.go
- actions/users_test.go`

// SkipResourceMigration allows to generate a resource without the migration.
var SkipResourceMigration = false

// SkipResourceModel allows to generate a resource without the model and Migration.
var SkipResourceModel = false

// UseResourceModel allows to generate a resource with a working model.
var UseResourceModel = ""

// ResourceCmd generates a new actions/resource file and a stub test.
var ResourceCmd = &cobra.Command{
	Use:     "resource [name]",
	Example: resourceExamples,
	Aliases: []string{"r"},
	Short:   "Generates a new actions/resource file",
	RunE: func(cmd *cobra.Command, args []string) error {
		var name, modelName string

		// Allow overwriting modelName with the --use-model flag
		// buffalo generate resource users --use-model people
		if UseResourceModel != "" {
			modelName = inflect.Pluralize(UseResourceModel)
		}

		if len(args) == 0 {
			if UseResourceModel == "" {
				return errors.New("you must specify a resource name")
			}
			// When there is no resource name given and --use-model flag is set
			name = UseResourceModel
		} else {
			// When resource name is specified
			name = inflect.Pluralize(args[0])
			// If there is no --use-model flag set use the resource to create the model
			if modelName == "" {
				modelName = name
			}
		}
		fmt.Printf("%#v\n\n", args)
		modelProps := getModelPropertiesFromArgs(args)

		data := makr.Data{
			"name":             name,
			"singular":         inflect.Singularize(name),
			"plural":           name,
			"camel":            inflect.Camelize(name),
			"under":            inflect.Underscore(name),
			"underSingular":    inflect.Singularize(inflect.Underscore(name)),
			"downFirstCap":     inflect.CamelizeDownFirst(name),
			"model":            inflect.Singularize(inflect.Camelize(modelName)),
			"modelPlural":      inflect.Camelize(modelName),
			"modelUnder":       inflect.Singularize(inflect.Underscore(modelName)),
			"modelPluralUnder": inflect.Underscore(modelName),
			"varPlural":        inflect.CamelizeDownFirst(modelName),
			"varSingular":      inflect.Singularize(inflect.CamelizeDownFirst(modelName)),
			"actions":          []string{"List", "Show", "New", "Create", "Edit", "Update", "Destroy"},
			"args":             args,
			"modelProps":       modelProps,

			// Flags
			"skipMigration": SkipResourceMigration,
			"skipModel":     SkipResourceModel,
			"useModel":      UseResourceModel,
		}
		fmt.Printf("%#v\n\n", args)
		g, err := resource.New(data)
		if err != nil {
			return err
		}
		fmt.Printf("%#v", args)
		return g.Run(".", data)
	},
}

func getModelPropertiesFromArgs(args []string) []string {
	var mProps []string
	for _, a := range args[1:] {
		mProps = append(mProps, inflect.Camelize(a))
	}
	return mProps
}
<commit_msg>removed debugging output<commit_after>package generate

import (
	"errors"

	"github.com/gobuffalo/buffalo/generators/resource"
	"github.com/gobuffalo/makr"
	"github.com/markbates/inflect"
	"github.com/spf13/cobra"
)

const resourceExamples = `$ buffalo g resource users
Generates:

- actions/users.go
- actions/users_test.go
- models/user.go
- models/user_test.go
- migrations/2016020216301234_create_users.up.fizz
- migrations/2016020216301234_create_users.down.fizz

$ buffalo g resource users --skip-migration
Generates:

- actions/users.go
- actions/users_test.go
- models/user.go
- models/user_test.go

$ buffalo g resource users --skip-model
Generates:

- actions/users.go
- actions/users_test.go

$ buffalo g resource users --use-model
Generates:

- actions/users.go
- actions/users_test.go`

// SkipResourceMigration allows to generate a resource without the migration.
var SkipResourceMigration = false

// SkipResourceModel allows to generate a resource without the model and Migration.
var SkipResourceModel = false

// UseResourceModel allows to generate a resource with a working model.
var UseResourceModel = ""

// ResourceCmd generates a new actions/resource file and a stub test.
var ResourceCmd = &cobra.Command{
	Use:     "resource [name]",
	Example: resourceExamples,
	Aliases: []string{"r"},
	Short:   "Generates a new actions/resource file",
	RunE: func(cmd *cobra.Command, args []string) error {
		var name, modelName string

		// Allow overwriting modelName with the --use-model flag
		// buffalo generate resource users --use-model people
		if UseResourceModel != "" {
			modelName = inflect.Pluralize(UseResourceModel)
		}

		if len(args) == 0 {
			if UseResourceModel == "" {
				return errors.New("you must specify a resource name")
			}
			// When there is no resource name given and --use-model flag is set
			name = UseResourceModel
		} else {
			// When resource name is specified
			name = inflect.Pluralize(args[0])
			// If there is no --use-model flag set use the resource to create the model
			if modelName == "" {
				modelName = name
			}
		}
		modelProps := getModelPropertiesFromArgs(args)

		data := makr.Data{
			"name":             name,
			"singular":         inflect.Singularize(name),
			"plural":           name,
			"camel":            inflect.Camelize(name),
			"under":            inflect.Underscore(name),
			"underSingular":    inflect.Singularize(inflect.Underscore(name)),
			"downFirstCap":     inflect.CamelizeDownFirst(name),
			"model":            inflect.Singularize(inflect.Camelize(modelName)),
			"modelPlural":      inflect.Camelize(modelName),
			"modelUnder":       inflect.Singularize(inflect.Underscore(modelName)),
			"modelPluralUnder": inflect.Underscore(modelName),
			"varPlural":        inflect.CamelizeDownFirst(modelName),
			"varSingular":      inflect.Singularize(inflect.CamelizeDownFirst(modelName)),
			"actions":          []string{"List", "Show", "New", "Create", "Edit", "Update", "Destroy"},
			"args":             args,
			"modelProps":       modelProps,

			// Flags
			"skipMigration": SkipResourceMigration,
			"skipModel":     SkipResourceModel,
			"useModel":      UseResourceModel,
		}
		g, err := resource.New(data)
		if err != nil {
			return err
		}
		return g.Run(".", data)
	},
}

func getModelPropertiesFromArgs(args []string) []string {
	var mProps []string
	for _, a := range args[1:] {
		mProps = append(mProps, inflect.Camelize(a))
	}
	return mProps
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"syscall"

	"github.com/docker/libchan"
	"github.com/docker/libchan/spdy"

	"frister.net/experiments/chanserver/crypto"
	"frister.net/experiments/chanserver/transport"
)

type RemoteCommand struct {
	Cmd        string
	Args       []string
	Stdin      io.Reader
	Stdout     io.WriteCloser
	Stderr     io.WriteCloser
	StatusChan libchan.Sender
}

type CommandResponse struct {
	Status int
}

func main() {
	crypto.Experiment()

	// cert := "certs/server.crt"
	// key := "certs/server.key"

	// keyPair, err := tls.LoadX509KeyPair(cert, key)
	keyPair, err := transport.GenerateX509KeyPair("server")
	if err != nil {
		fmt.Printf("GenerateX509KeyPair: ")
		log.Fatal(err)
	}

	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
		ClientAuth:         tls.RequireAnyClientCert,
		Certificates:       []tls.Certificate{*keyPair},
		MinVersion:         tls.VersionTLS10,
	}
	runRexecServer(tlsConfig)

}

func runRexecServer(tlsConfig *tls.Config) {
	var listener net.Listener

	listener, err := tls.Listen("tcp", "localhost:9323", tlsConfig)
	if err != nil {
		log.Fatal(err)
	}

	tl, err := spdy.NewTransportListener(listener, transport.TestAuthenticator)
	if err != nil {
		log.Fatal(err)
	}

	for {
		t, err := tl.AcceptTransport()
		if err != nil {
			log.Print(err)
			break
		}

		go func() {
			for {
				receiver, err := t.WaitReceiveChannel()
				if err != nil {
					log.Print(err)
					break
				}

				go func() {
					for {
						command := &RemoteCommand{}
						err := receiver.Receive(command)
						if err != nil {
							log.Print(err)
							break
						}

						cmd := exec.Command(command.Cmd, command.Args...)
						cmd.Stdout = command.Stdout
						cmd.Stderr = command.Stderr

						stdin, err := cmd.StdinPipe()
						if err != nil {
							log.Print(err)
							break
						}
						go func() {
							io.Copy(stdin, command.Stdin)
							stdin.Close()
						}()

						res := cmd.Run()
						command.Stdout.Close()
						command.Stderr.Close()
						returnResult := &CommandResponse{}
						if res != nil {
							if exiterr, ok := res.(*exec.ExitError); ok {
								returnResult.Status = exiterr.Sys().(syscall.WaitStatus).ExitStatus()
							} else {
								log.Print(res)
								returnResult.Status = 10
							}
						}

						err = command.StatusChan.Send(returnResult)
						if err != nil {
							log.Print(err)
						}
					}
				}()
			}
		}()
	}
}
<commit_msg>Add simple webserver parsing a handshake message<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os/exec"
	"syscall"

	"github.com/docker/libchan"
	"github.com/docker/libchan/spdy"

	"frister.net/experiments/chanserver/crypto"
	"frister.net/experiments/chanserver/transport"
)

type RemoteCommand struct {
	Cmd        string
	Args       []string
	Stdin      io.Reader
	Stdout     io.WriteCloser
	Stderr     io.WriteCloser
	StatusChan libchan.Sender
}

type CommandResponse struct {
	Status int
}

func main() {
	crypto.Experiment()

	keyPair, err := transport.GenerateX509KeyPair("server")
	if err != nil {
		fmt.Printf("GenerateX509KeyPair: ")
		log.Fatal(err)
	}

	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
		ClientAuth:         tls.RequireAnyClientCert,
		Certificates:       []tls.Certificate{*keyPair},
		MinVersion:         tls.VersionTLS10,
	}

	go runWebServer()
	runRexecServer(tlsConfig)

}

func handshakeHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	type HandshakeMessage struct {
		Nonce, SealedCertSignature []byte
	}

	dec := json.NewDecoder(r.Body)
	var m HandshakeMessage
	if err := dec.Decode(&m); err != nil {
		log.Printf("JSON decoding of message failed: %s", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	log.Printf("Got message: %v", m)
	log.Printf("Nonce: %s", m.Nonce)
	log.Printf("Sig: %s", m.SealedCertSignature)
	w.Write([]byte(":)"))
	// body := ioutil.ReadAll(r.Body)

}

func runWebServer() {
	http.HandleFunc("/api/v1/handshake", handshakeHandler)
	http.ListenAndServe("localhost:9322", nil)
}

func runRexecServer(tlsConfig *tls.Config) {
	var listener net.Listener

	listener, err := tls.Listen("tcp", "localhost:9323", tlsConfig)
	if err != nil {
		log.Fatal(err)
	}

	tl, err := spdy.NewTransportListener(listener, transport.TestAuthenticator)
	if err != nil {
		log.Fatal(err)
	}

	for {
		t, err := tl.AcceptTransport()
		if err != nil {
			log.Print(err)
			break
		}

		go func() {
			for {
				receiver, err := t.WaitReceiveChannel()
				if err != nil {
					log.Print(err)
					break
				}

				go func() {
					for {
						command := &RemoteCommand{}
						err := receiver.Receive(command)
						if err != nil {
							log.Print(err)
							break
						}

						cmd := exec.Command(command.Cmd, command.Args...)
						cmd.Stdout = command.Stdout
						cmd.Stderr = command.Stderr

						stdin, err := cmd.StdinPipe()
						if err != nil {
							log.Print(err)
							break
						}
						go func() {
							io.Copy(stdin, command.Stdin)
							stdin.Close()
						}()

						res := cmd.Run()
						command.Stdout.Close()
						command.Stderr.Close()
						returnResult := &CommandResponse{}
						if res != nil {
							if exiterr, ok := res.(*exec.ExitError); ok {
								returnResult.Status = exiterr.Sys().(syscall.WaitStatus).ExitStatus()
							} else {
								log.Print(res)
								returnResult.Status = 10
							}
						}

						err = command.StatusChan.Send(returnResult)
						if err != nil {
							log.Print(err)
						}
					}
				}()
			}
		}()
	}
}
<|endoftext|>


<commit_before>package checks

import (
	"encoding/json"
	"fmt"
)

// TODO:
// add mutex to handle concurrent read/writes

var GlobalSCollector map[Host]CurrentMetrics = make(map[Host]CurrentMetrics)

type Host string
type CurrentMetrics map[string]float64

type SCollector struct {
	Host string
}

func NewSCollector(host string) *SCollector {
	return &SCollector{host}
}

func (sc *SCollector) Check() (map[string]float64, error) {

	fmt.Println("SCollector Check")

	_, exists := GlobalSCollector[Host(sc.Host)]
	if !exists {
		GlobalSCollector[Host(sc.Host)] = make(map[string]float64)
	}

	jsonB, err := json.MarshalIndent(GlobalSCollector[Host(sc.Host)], "", "\t")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(jsonB))

	output := make(map[string]float64)
	for key, val := range GlobalSCollector[Host(sc.Host)] {
		output[key] = val
	}

	return output, nil
}

func (sc *SCollector) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (sc *SCollector) RedAlertMessage() string {
	return "Uhoh fail on " + sc.Host
}

func (sc *SCollector) GreenAlertMessage() string {
	return "Woo-hoo, successful check on " + sc.Host
}
<commit_msg>Remove debugging.<commit_after>package checks

// TODO:
// add mutex to handle concurrent read/writes

var GlobalSCollector map[Host]CurrentMetrics = make(map[Host]CurrentMetrics)

type Host string
type CurrentMetrics map[string]float64

type SCollector struct {
	Host string
}

func NewSCollector(host string) *SCollector {
	return &SCollector{host}
}

func (sc *SCollector) Check() (map[string]float64, error) {

	_, exists := GlobalSCollector[Host(sc.Host)]
	if !exists {
		GlobalSCollector[Host(sc.Host)] = make(map[string]float64)
	}

	output := make(map[string]float64)
	for key, val := range GlobalSCollector[Host(sc.Host)] {
		output[key] = val
	}

	return output, nil
}

func (sc *SCollector) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (sc *SCollector) RedAlertMessage() string {
	return "Uhoh fail on " + sc.Host
}

func (sc *SCollector) GreenAlertMessage() string {
	return "Woo-hoo, successful check on " + sc.Host
}
<|endoftext|>


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

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages. Use
// Config.Check to invoke the type checker for a package.
// Alternatively, create a new type checker with NewChecker
// and invoke it incrementally by calling Checker.Files.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (constant.Value)
// for every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
// For a tutorial, see https://golang.org/s/types-tutorial.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/constant"
	"go/token"
)

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An Importer resolves import paths to Packages.
//
// CAUTION: This interface does not support the import of locally
// vendored packages. See https://golang.org/s/go15vendor.
// If possible, external implementations should implement ImporterFrom.
type Importer interface {
	// Import returns the imported package for the given import path.
	// The semantics is like for ImporterFrom.ImportFrom except that
	// dir and mode are ignored (since they are not present).
	Import(path string) (*Package, error)
}

// ImportMode is reserved for future use.
type ImportMode int

// An ImporterFrom resolves import paths to packages; it
// supports vendoring per https://golang.org/s/go15vendor.
// Use go/importer to obtain an ImporterFrom implementation.
type ImporterFrom interface {
	// Importer is present for backward-compatibility. Calling
	// Import(path) is the same as calling ImportFrom(path, "", 0);
	// i.e., locally vendored packages may not be found.
	// The types package does not call Import if an ImporterFrom
	// is present.
	Importer

	// ImportFrom returns the imported package for the given import
	// path when imported by a package file located in dir.
	// If the import failed, besides returning an error, ImportFrom
	// is encouraged to cache and return a package anyway, if one
	// was created. This will reduce package inconsistencies and
	// follow-on type checker errors due to the missing package.
	// The mode value must be 0; it is reserved for future use.
	// Two calls to ImportFrom with the same path and dir must
	// return the same package.
	ImportFrom(path, dir string, mode ImportMode) (*Package, error)
}

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-on errors.
	//          Do not use casually!
	FakeImportC bool

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// An importer is used to import packages referred to from
	// import declarations.
	// If the installed importer implements ImporterFrom, the type
	// checker calls ImportFrom instead of Import.
	// The type checker reports an error if an importer is needed
	// but none was installed.
	Importer Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise SizesFor("gc", "amd64") is used instead.
	Sizes Sizes

	// If DisableUnusedImportCheck is set, packages are not checked
	// for unused imports.
	DisableUnusedImportCheck bool
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, also their values. Invalid expressions are
	// omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// The Types map does not record the type of every identifier,
	// only those that appear where an arbitrary expression is
	// permitted. For instance, the identifier f in a selector
	// expression x.f is found only in the Selections map, the
	// identifier z in a variable declaration 'var z int' is found
	// only in the Defs map, and identifiers denoting packages in
	// qualified identifiers are collected in the Uses map.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//     node               declared object
	//
	//     *ast.ImportSpec    *PkgName for imports without renames
	//     *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//     *ast.Field         anonymous parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//     *ast.File
	//     *ast.FuncType
	//     *ast.BlockStmt
	//     *ast.IfStmt
	//     *ast.SwitchStmt
	//     *ast.TypeSwitchStmt
	//     *ast.CaseClause
	//     *ast.CommClause
	//     *ast.ForStmt
	//     *ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, _ := e.(*ast.Ident); id != nil {
		if obj := info.ObjectOf(id); obj != nil {
			return obj.Type()
		}
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj := info.Defs[id]; obj != nil {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value constant.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant_, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (https://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the lhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object and
// the first error if any. Additionally, if info != nil, Check populates each
// of the non-nil maps in the Info struct.
//
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T, nil) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<commit_msg>go/types: fix lhs/rhs mixup in docs<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages. Use
// Config.Check to invoke the type checker for a package.
// Alternatively, create a new type checker with NewChecker
// and invoke it incrementally by calling Checker.Files.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (constant.Value)
// for every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
// For a tutorial, see https://golang.org/s/types-tutorial.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/constant"
	"go/token"
)

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An Importer resolves import paths to Packages.
//
// CAUTION: This interface does not support the import of locally
// vendored packages. See https://golang.org/s/go15vendor.
// If possible, external implementations should implement ImporterFrom.
type Importer interface {
	// Import returns the imported package for the given import path.
	// The semantics is like for ImporterFrom.ImportFrom except that
	// dir and mode are ignored (since they are not present).
	Import(path string) (*Package, error)
}

// ImportMode is reserved for future use.
type ImportMode int

// An ImporterFrom resolves import paths to packages; it
// supports vendoring per https://golang.org/s/go15vendor.
// Use go/importer to obtain an ImporterFrom implementation.
type ImporterFrom interface {
	// Importer is present for backward-compatibility. Calling
	// Import(path) is the same as calling ImportFrom(path, "", 0);
	// i.e., locally vendored packages may not be found.
	// The types package does not call Import if an ImporterFrom
	// is present.
	Importer

	// ImportFrom returns the imported package for the given import
	// path when imported by a package file located in dir.
	// If the import failed, besides returning an error, ImportFrom
	// is encouraged to cache and return a package anyway, if one
	// was created. This will reduce package inconsistencies and
	// follow-on type checker errors due to the missing package.
	// The mode value must be 0; it is reserved for future use.
	// Two calls to ImportFrom with the same path and dir must
	// return the same package.
	ImportFrom(path, dir string, mode ImportMode) (*Package, error)
}

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-on errors.
	//          Do not use casually!
	FakeImportC bool

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// An importer is used to import packages referred to from
	// import declarations.
	// If the installed importer implements ImporterFrom, the type
	// checker calls ImportFrom instead of Import.
	// The type checker reports an error if an importer is needed
	// but none was installed.
	Importer Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise SizesFor("gc", "amd64") is used instead.
	Sizes Sizes

	// If DisableUnusedImportCheck is set, packages are not checked
	// for unused imports.
	DisableUnusedImportCheck bool
}

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, also their values. Invalid expressions are
	// omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// The Types map does not record the type of every identifier,
	// only those that appear where an arbitrary expression is
	// permitted. For instance, the identifier f in a selector
	// expression x.f is found only in the Selections map, the
	// identifier z in a variable declaration 'var z int' is found
	// only in the Defs map, and identifiers denoting packages in
	// qualified identifiers are collected in the Uses map.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//     node               declared object
	//
	//     *ast.ImportSpec    *PkgName for imports without renames
	//     *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//     *ast.Field         anonymous parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//     *ast.File
	//     *ast.FuncType
	//     *ast.BlockStmt
	//     *ast.IfStmt
	//     *ast.SwitchStmt
	//     *ast.TypeSwitchStmt
	//     *ast.CaseClause
	//     *ast.CommClause
	//     *ast.ForStmt
	//     *ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, _ := e.(*ast.Ident); id != nil {
		if obj := info.ObjectOf(id); obj != nil {
			return obj.Type()
		}
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj := info.Defs[id]; obj != nil {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value constant.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant_, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (https://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the rhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object and
// the first error if any. Additionally, if info != nil, Check populates each
// of the non-nil maps in the Info struct.
//
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T, nil) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<|endoftext|>


<commit_before>package goat

import (
	"bencode"
	"fmt"
	"strconv"
)

// Tracker announce request
func TrackerAnnounce(user UserRecord, query map[string]string, resChan chan []byte) {
	// Store announce information in struct
	announce := MapToAnnounceLog(query)

	// Request to store announce
	go announce.Save()

	Static.LogChan <- fmt.Sprintf("announce: [ip: %s, port:%d]", announce.Ip, announce.Port)
	Static.LogChan <- fmt.Sprintf("announce: [info_hash: %s]", announce.InfoHash)

	// Only report announce when needed
	if announce.Event != "" {
		Static.LogChan <- fmt.Sprintf("announce: [event: %s]", announce.Event)
	}

	// Check for a matching file via info_hash
	file := new(FileRecord).Load(announce.InfoHash, "info_hash")
	if file == (FileRecord{}) {
		// Torrent is not currently registered
		resChan <- TrackerError("Unregistered torrent")

		// Create an entry in file table for this hash, but mark it as unverified
		file.InfoHash = announce.InfoHash
		file.Verified = false
		file.Leechers = 0
		file.Seeders = 0
		file.Completed = 0
		go file.Save()
		return
	}

	// Ensure file is verified, meaning we will permit tracking of it
	if !file.Verified {
		resChan <- TrackerError("Unverified torrent")
		return
	}

	// Check for existing record for this user with this file
	fileUser := new(FileUserRecord).Load(file.Id, user.Id)
	if fileUser == (FileUserRecord{}) {
		// Create new relationship
		fileUser.FileId = file.Id
		fileUser.UserId = user.Id
		fileUser.Active = true
		fileUser.Completed = false
		fileUser.Announced = 1
		fileUser.Uploaded = announce.Uploaded
		fileUser.Downloaded = announce.Downloaded
		fileUser.Left = announce.Left

		// Add a leecher to this file, UNLESS they have already completed it
		if announce.Left == 0 || announce.Event == "completed" {
			file.Seeders = file.Seeders + 1
		} else {
			file.Leechers = file.Leechers + 1
		}
	} else {
		// Else, pre-existing record, so update
		// Check for stopped status
		if announce.Event != "stopped" {
			fileUser.Active = true
		} else {
			fileUser.Active = false

			// Remove seeder if applicable
			if announce.Left == 0 && file.Seeders > 0 {
				file.Seeders = file.Seeders - 1
			}
		}

		// Check for completion
		if announce.Event == "completed" && announce.Left == 0 {
			fileUser.Completed = true

			// Mark file as completed by another user
			file.Completed = file.Completed + 1

			// Decrement leecher, add seeder
			if (file.Leechers > 0) {
				file.Leechers = file.Leechers - 1
			}
			file.Seeders = file.Seeders + 1
		} else {
			fileUser.Completed = false
		}

		// Add an announce
		fileUser.Announced = fileUser.Announced + 1

		// Store latest statistics, but do so in a sane way (no removing upload/download, no adding left)
		if (announce.Uploaded > fileUser.Uploaded) {
			fileUser.Uploaded = announce.Uploaded
		}
		if (announce.Downloaded > fileUser.Downloaded) {
			fileUser.Downloaded = announce.Downloaded
		}
		if (announce.Left < fileUser.Left) {
			fileUser.Left = announce.Left
		}
	}

	// Update File record
	go file.Save()

	// Update User record
	go user.Save()

	// Insert or update the FileUser record
	go fileUser.Save()

	// Check for numwant parameter, return up to that number of peers
	// Default is 50 per protocol
	numwant := 50
	if _, ok := query["numwant"]; ok {
		// Verify numwant is an integer
		num, err := strconv.Atoi(query["numwant"])
		if err == nil {
			numwant = num
		}
	}

	// Tracker announce response, with generated peerlist of length numwant, excluding this user
	resChan <- bencode.EncDictMap(map[string][]byte{
		"interval":     bencode.EncInt(RandRange(3200, 4000)),
		"min interval": bencode.EncInt(1800),
		"peers":        bencode.EncBytes(file.PeerList(query["ip"], numwant)),
	})
}

// Report a bencoded []byte response as specified by input string
func TrackerError(err string) []byte {
	return bencode.EncDictMap(map[string][]byte{
		"failure reason": bencode.EncString(err),
		"interval":       bencode.EncInt(RandRange(3200, 4000)),
		"min interval":   bencode.EncInt(1800),
	})
}
<commit_msg>Minor bugfixes: check for completion, and update user totals after updating files_users counts<commit_after>package goat

import (
	"bencode"
	"fmt"
	"strconv"
)

// Tracker announce request
func TrackerAnnounce(user UserRecord, query map[string]string, resChan chan []byte) {
	// Store announce information in struct
	announce := MapToAnnounceLog(query)

	// Request to store announce
	go announce.Save()

	Static.LogChan <- fmt.Sprintf("announce: [ip: %s, port:%d]", announce.Ip, announce.Port)
	Static.LogChan <- fmt.Sprintf("announce: [info_hash: %s]", announce.InfoHash)

	// Only report announce when needed
	if announce.Event != "" {
		Static.LogChan <- fmt.Sprintf("announce: [event: %s]", announce.Event)
	}

	// Check for a matching file via info_hash
	file := new(FileRecord).Load(announce.InfoHash, "info_hash")
	if file == (FileRecord{}) {
		// Torrent is not currently registered
		resChan <- TrackerError("Unregistered torrent")

		// Create an entry in file table for this hash, but mark it as unverified
		file.InfoHash = announce.InfoHash
		file.Verified = false
		file.Leechers = 0
		file.Seeders = 0
		file.Completed = 0
		go file.Save()
		return
	}

	// Ensure file is verified, meaning we will permit tracking of it
	if !file.Verified {
		resChan <- TrackerError("Unverified torrent")
		return
	}

	// Check for existing record for this user with this file
	fileUser := new(FileUserRecord).Load(file.Id, user.Id)
	if fileUser == (FileUserRecord{}) {
		// Create new relationship
		fileUser.FileId = file.Id
		fileUser.UserId = user.Id
		fileUser.Active = true
		fileUser.Completed = false
		fileUser.Announced = 1
		fileUser.Uploaded = announce.Uploaded
		fileUser.Downloaded = announce.Downloaded
		fileUser.Left = announce.Left

		// Add a leecher to this file, UNLESS they have already completed it
		if announce.Left == 0 || announce.Event == "completed" {
			file.Seeders = file.Seeders + 1
		} else {
			file.Leechers = file.Leechers + 1
		}
	} else {
		// Else, pre-existing record, so update
		// Check for stopped status
		if announce.Event != "stopped" {
			fileUser.Active = true
		} else {
			fileUser.Active = false

			// Remove seeder if applicable
			if announce.Left == 0 && file.Seeders > 0 {
				file.Seeders = file.Seeders - 1
			}
		}

		// Check for completion
		if announce.Event == "completed" || announce.Left == 0 {
			fileUser.Completed = true

			// Mark file as completed by another user
			file.Completed = file.Completed + 1

			// Decrement leecher, add seeder
			if (file.Leechers > 0) {
				file.Leechers = file.Leechers - 1
			}
			file.Seeders = file.Seeders + 1
		} else {
			fileUser.Completed = false
		}

		// Add an announce
		fileUser.Announced = fileUser.Announced + 1

		// Store latest statistics, but do so in a sane way (no removing upload/download, no adding left)
		if (announce.Uploaded > fileUser.Uploaded) {
			fileUser.Uploaded = announce.Uploaded
		}
		if (announce.Downloaded > fileUser.Downloaded) {
			fileUser.Downloaded = announce.Downloaded
		}
		if (announce.Left < fileUser.Left) {
			fileUser.Left = announce.Left
		}
	}

	// Update File record
	go file.Save()

	// Insert or update the FileUser record
	go fileUser.Save()

	// Update User record
	go user.Save()

	// Check for numwant parameter, return up to that number of peers
	// Default is 50 per protocol
	numwant := 50
	if _, ok := query["numwant"]; ok {
		// Verify numwant is an integer
		num, err := strconv.Atoi(query["numwant"])
		if err == nil {
			numwant = num
		}
	}

	// Tracker announce response, with generated peerlist of length numwant, excluding this user
	resChan <- bencode.EncDictMap(map[string][]byte{
		"interval":     bencode.EncInt(RandRange(3200, 4000)),
		"min interval": bencode.EncInt(1800),
		"peers":        bencode.EncBytes(file.PeerList(query["ip"], numwant)),
	})
}

// Report a bencoded []byte response as specified by input string
func TrackerError(err string) []byte {
	return bencode.EncDictMap(map[string][]byte{
		"failure reason": bencode.EncString(err),
		"interval":       bencode.EncInt(RandRange(3200, 4000)),
		"min interval":   bencode.EncInt(1800),
	})
}
<|endoftext|>