<commit_before>package integration_test

import (
	"os/exec"
	"path/filepath"

	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CF NodeJS Buildpack", func() {
	var app *cutlass.App
	var createdServices []string

	BeforeEach(func() {
		app = cutlass.New(filepath.Join(bpDir, "fixtures", "logenv"))
		app.SetEnv("BP_DEBUG", "true")
		PushAppAndConfirm(app)

		createdServices = make([]string, 0)
	})

	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil

		for _, service := range createdServices {
			command := exec.Command("cf", "delete-service", "-f", service)
			_, err := command.Output()
			Expect(err).To(BeNil())
		}
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)

			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with two credentials services", func() {
		It("checks if detection of second service with credentials works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			duplicateCredentialsServiceName := "dynatrace-dupe-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", duplicateCredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, duplicateCredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "bind-service", app.Name, duplicateCredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.Stdout.String()).To(ContainSubstring("More than one matching service found!"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with failing agent download and ignoring errors", func() {
		It("checks if skipping download errors works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paasFAILING/manifest\",\"environmentid\":\"envid\",\"skiperrors\":\"true\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.Stdout.String()).To(ContainSubstring("Download returned with status 404"))
			Expect(app.Stdout.String()).To(ContainSubstring("Error during installer download, skipping installation"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with two dynatrace services", func() {
		It("check if service detection isn't disturbed by a service with tags", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			tagsServiceName := "dynatrace-tags-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", tagsServiceName, "-p", "'{\"tag:dttest\":\"dynatrace_test\"}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, tagsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "bind-service", app.Name, tagsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service and without manifest.json", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)

			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with failing agent download and checking retry", func() {
		It("checks if retrying downloads works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paasFAILING/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.CombinedOutput()

			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 4s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 5s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 7s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Download returned with status 404"))

			Eventually(app.Stdout.String).Should(ContainSubstring("Failed to compile droplet"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service and a redis service", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)
			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			redisServiceName := "redis-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", redisServiceName, "-p", "'{\"name\":\"redis\", \"credentials\":{\"db_type\":\"redis\", \"instance_administration_api\":{\"deployment_id\":\"12345asdf\", \"instance_id\":\"12345asdf\", \"root\":\"https://doesnotexi.st\"}}}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, redisServiceName)
			command = exec.Command("cf", "bind-service", app.Name, redisServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})
})
<commit_msg>Removes executable mode from test file<commit_after>package integration_test

import (
	"os/exec"
	"path/filepath"

	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CF NodeJS Buildpack", func() {
	var app *cutlass.App
	var createdServices []string

	BeforeEach(func() {
		app = cutlass.New(filepath.Join(bpDir, "fixtures", "logenv"))
		app.SetEnv("BP_DEBUG", "true")
		PushAppAndConfirm(app)

		createdServices = make([]string, 0)
	})

	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil

		for _, service := range createdServices {
			command := exec.Command("cf", "delete-service", "-f", service)
			_, err := command.Output()
			Expect(err).To(BeNil())
		}
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)

			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with two credentials services", func() {
		It("checks if detection of second service with credentials works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			duplicateCredentialsServiceName := "dynatrace-dupe-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", duplicateCredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, duplicateCredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "bind-service", app.Name, duplicateCredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.Stdout.String()).To(ContainSubstring("More than one matching service found!"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with failing agent download and ignoring errors", func() {
		It("checks if skipping download errors works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paasFAILING/manifest\",\"environmentid\":\"envid\",\"skiperrors\":\"true\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.Stdout.String()).To(ContainSubstring("Download returned with status 404"))
			Expect(app.Stdout.String()).To(ContainSubstring("Error during installer download, skipping installation"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with two dynatrace services", func() {
		It("check if service detection isn't disturbed by a service with tags", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			tagsServiceName := "dynatrace-tags-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", tagsServiceName, "-p", "'{\"tag:dttest\":\"dynatrace_test\"}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, tagsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "bind-service", app.Name, tagsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service and without manifest.json", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)

			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with failing agent download and checking retry", func() {
		It("checks if retrying downloads works", func() {
			CredentialsServiceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", CredentialsServiceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paasFAILING/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, CredentialsServiceName)

			command = exec.Command("cf", "bind-service", app.Name, CredentialsServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.CombinedOutput()

			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 4s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 5s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Error during installer download, retrying in 7s"))
			Eventually(app.Stdout.String).Should(ContainSubstring("Download returned with status 404"))

			Eventually(app.Stdout.String).Should(ContainSubstring("Failed to compile droplet"))
		})
	})

	Context("deploying a NodeJS app with Dynatrace agent with single credentials service and a redis service", func() {
		It("checks if Dynatrace injection was successful", func() {
			serviceName := "dynatrace-" + cutlass.RandStringRunes(20) + "-service"
			command := exec.Command("cf", "cups", serviceName, "-p", "'{\"apitoken\":\"secretpaastoken\",\"apiurl\":\"https://s3.amazonaws.com/dt-paas/manifest\",\"environmentid\":\"envid\"}'")
			_, err := command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, serviceName)
			command = exec.Command("cf", "bind-service", app.Name, serviceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			redisServiceName := "redis-" + cutlass.RandStringRunes(20) + "-service"
			command = exec.Command("cf", "cups", redisServiceName, "-p", "'{\"name\":\"redis\", \"credentials\":{\"db_type\":\"redis\", \"instance_administration_api\":{\"deployment_id\":\"12345asdf\", \"instance_id\":\"12345asdf\", \"root\":\"https://doesnotexi.st\"}}}'")
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())
			createdServices = append(createdServices, redisServiceName)
			command = exec.Command("cf", "bind-service", app.Name, redisServiceName)
			_, err = command.CombinedOutput()
			Expect(err).To(BeNil())

			command = exec.Command("cf", "restage", app.Name)
			_, err = command.Output()
			Expect(err).To(BeNil())

			Expect(app.ConfirmBuildpack(buildpackVersion)).To(Succeed())
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace service credentials found. Setting up Dynatrace PaaS agent."))
			Expect(app.Stdout.String()).To(ContainSubstring("Starting Dynatrace PaaS agent installer"))
			Expect(app.Stdout.String()).To(ContainSubstring("Copy dynatrace-env.sh"))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent installed."))
			Expect(app.Stdout.String()).To(ContainSubstring("Dynatrace PaaS agent injection is set up."))
		})
	})
})
<|endoftext|>


<commit_before>package fuse

// Written with a look to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html
import (
	"exec"
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"unsafe"
)

var fusermountBinary string
var umountBinary string

func Socketpair(network string) (l, r *os.File, err os.Error) {
	var domain int
	var typ int
	switch network {
	case "unix":
		domain = syscall.AF_UNIX
		typ = syscall.SOCK_STREAM
	case "unixgram":
		domain = syscall.AF_UNIX
		typ = syscall.SOCK_SEQPACKET
	default:
		panic("unknown network " + network)
	}
	fd, errno := syscall.Socketpair(domain, typ, 0)
	if errno != 0 {
		return nil, nil, os.NewSyscallError("socketpair", errno)
	}
	l = os.NewFile(fd[0], "socketpair-half1")
	r = os.NewFile(fd[1], "socketpair-half2")
	return
}

// Create a FUSE FS on the specified mount point.  The returned
// mount point is always absolute.
func mount(mountPoint string, options string) (f *os.File, finalMountPoint string, err os.Error) {
	local, remote, err := Socketpair("unixgram")
	if err != nil {
		return
	}

	defer local.Close()
	defer remote.Close()

	mountPoint = filepath.Clean(mountPoint)
	if !filepath.IsAbs(mountPoint) {
		cwd := ""
		cwd, err = os.Getwd()
		if err != nil {
			return
		}
		mountPoint = filepath.Clean(filepath.Join(cwd, mountPoint))
	}

	cmd := []string{fusermountBinary, mountPoint}
	if options != "" {
		cmd = append(cmd, "-o")
		cmd = append(cmd, options)
	}

	proc, err := os.StartProcess(fusermountBinary,
		cmd,
		&os.ProcAttr{
			Env:   []string{"_FUSE_COMMFD=3"},
			Files: []*os.File{os.Stdin, os.Stdout, os.Stderr, remote}})

	if err != nil {
		return
	}
	w, err := os.Wait(proc.Pid, 0)
	if err != nil {
		return
	}
	if w.ExitStatus() != 0 {
		err = os.NewError(fmt.Sprintf("fusermount exited with code %d\n", w.ExitStatus()))
		return
	}

	f, err = getConnection(local)
	finalMountPoint = mountPoint
	return
}

func privilegedUnmount(mountPoint string) os.Error {
	dir, _ := filepath.Split(mountPoint)
	proc, err := os.StartProcess(umountBinary,
		[]string{umountBinary, mountPoint},
		&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
	if err != nil {
		return err
	}
	w, err := os.Wait(proc.Pid, 0)
	if w.ExitStatus() != 0 {
		return os.NewError(fmt.Sprintf("umount exited with code %d\n", w.ExitStatus()))
	}
	return err
}

func unmount(mountPoint string) (err os.Error) {
	if os.Geteuid() == 0 {
		return privilegedUnmount(mountPoint)
	}
	dir, _ := filepath.Split(mountPoint)
	proc, err := os.StartProcess(fusermountBinary,
		[]string{fusermountBinary, "-u", mountPoint},
		&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
	if err != nil {
		return
	}
	w, err := os.Wait(proc.Pid, 0)
	if err != nil {
		return
	}
	if w.ExitStatus() != 0 {
		return os.NewError(fmt.Sprintf("fusermount -u exited with code %d\n", w.ExitStatus()))
	}
	return
}

func getConnection(local *os.File) (f *os.File, err os.Error) {
	var data [4]byte
	control := make([]byte, 4*256)

	// n, oobn, recvflags, from, errno  - todo: error checking.
	_, oobn, _, _,
		errno := syscall.Recvmsg(
		local.Fd(), data[:], control[:], 0)
	if errno != 0 {
		return
	}

	message := *(*syscall.Cmsghdr)(unsafe.Pointer(&control[0]))
	fd := *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&control[0])) + syscall.SizeofCmsghdr))

	if message.Type != 1 {
		err = os.NewError(fmt.Sprintf("getConnection: recvmsg returned wrong control type: %d", message.Type))
		return
	}
	if oobn <= syscall.SizeofCmsghdr {
		err = os.NewError(fmt.Sprintf("getConnection: too short control message. Length: %d", oobn))
		return
	}
	if fd < 0 {
		err = os.NewError(fmt.Sprintf("getConnection: fd < 0: %d", fd))
		return
	}
	f = os.NewFile(int(fd), "<fuseConnection>")
	return
}

func init() {
	fusermountBinary, _ = exec.LookPath("fusermount")
	umountBinary, _ = exec.LookPath("umount")
}
<commit_msg>Exit early if fusermount not found.<commit_after>package fuse

// Written with a look to http://ptspts.blogspot.com/2009/11/fuse-protocol-tutorial-for-linux-26.html
import (
	"exec"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"syscall"
	"unsafe"
)

var fusermountBinary string
var umountBinary string

func Socketpair(network string) (l, r *os.File, err os.Error) {
	var domain int
	var typ int
	switch network {
	case "unix":
		domain = syscall.AF_UNIX
		typ = syscall.SOCK_STREAM
	case "unixgram":
		domain = syscall.AF_UNIX
		typ = syscall.SOCK_SEQPACKET
	default:
		panic("unknown network " + network)
	}
	fd, errno := syscall.Socketpair(domain, typ, 0)
	if errno != 0 {
		return nil, nil, os.NewSyscallError("socketpair", errno)
	}
	l = os.NewFile(fd[0], "socketpair-half1")
	r = os.NewFile(fd[1], "socketpair-half2")
	return
}

// Create a FUSE FS on the specified mount point.  The returned
// mount point is always absolute.
func mount(mountPoint string, options string) (f *os.File, finalMountPoint string, err os.Error) {
	local, remote, err := Socketpair("unixgram")
	if err != nil {
		return
	}

	defer local.Close()
	defer remote.Close()

	mountPoint = filepath.Clean(mountPoint)
	if !filepath.IsAbs(mountPoint) {
		cwd := ""
		cwd, err = os.Getwd()
		if err != nil {
			return
		}
		mountPoint = filepath.Clean(filepath.Join(cwd, mountPoint))
	}

	cmd := []string{fusermountBinary, mountPoint}
	if options != "" {
		cmd = append(cmd, "-o")
		cmd = append(cmd, options)
	}

	proc, err := os.StartProcess(fusermountBinary,
		cmd,
		&os.ProcAttr{
			Env:   []string{"_FUSE_COMMFD=3"},
			Files: []*os.File{os.Stdin, os.Stdout, os.Stderr, remote}})

	if err != nil {
		return
	}
	w, err := os.Wait(proc.Pid, 0)
	if err != nil {
		return
	}
	if w.ExitStatus() != 0 {
		err = os.NewError(fmt.Sprintf("fusermount exited with code %d\n", w.ExitStatus()))
		return
	}

	f, err = getConnection(local)
	finalMountPoint = mountPoint
	return
}

func privilegedUnmount(mountPoint string) os.Error {
	dir, _ := filepath.Split(mountPoint)
	proc, err := os.StartProcess(umountBinary,
		[]string{umountBinary, mountPoint},
		&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
	if err != nil {
		return err
	}
	w, err := os.Wait(proc.Pid, 0)
	if w.ExitStatus() != 0 {
		return os.NewError(fmt.Sprintf("umount exited with code %d\n", w.ExitStatus()))
	}
	return err
}

func unmount(mountPoint string) (err os.Error) {
	if os.Geteuid() == 0 {
		return privilegedUnmount(mountPoint)
	}
	dir, _ := filepath.Split(mountPoint)
	proc, err := os.StartProcess(fusermountBinary,
		[]string{fusermountBinary, "-u", mountPoint},
		&os.ProcAttr{Dir: dir, Files: []*os.File{nil, nil, os.Stderr}})
	if err != nil {
		return
	}
	w, err := os.Wait(proc.Pid, 0)
	if err != nil {
		return
	}
	if w.ExitStatus() != 0 {
		return os.NewError(fmt.Sprintf("fusermount -u exited with code %d\n", w.ExitStatus()))
	}
	return
}

func getConnection(local *os.File) (f *os.File, err os.Error) {
	var data [4]byte
	control := make([]byte, 4*256)

	// n, oobn, recvflags, from, errno  - todo: error checking.
	_, oobn, _, _,
		errno := syscall.Recvmsg(
		local.Fd(), data[:], control[:], 0)
	if errno != 0 {
		return
	}

	message := *(*syscall.Cmsghdr)(unsafe.Pointer(&control[0]))
	fd := *(*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&control[0])) + syscall.SizeofCmsghdr))

	if message.Type != 1 {
		err = os.NewError(fmt.Sprintf("getConnection: recvmsg returned wrong control type: %d", message.Type))
		return
	}
	if oobn <= syscall.SizeofCmsghdr {
		err = os.NewError(fmt.Sprintf("getConnection: too short control message. Length: %d", oobn))
		return
	}
	if fd < 0 {
		err = os.NewError(fmt.Sprintf("getConnection: fd < 0: %d", fd))
		return
	}
	f = os.NewFile(int(fd), "<fuseConnection>")
	return
}

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


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

type pattern struct {
	Name    string
	Notes   []int
	Weights []float64
}

func loadJSON(filename string) (map[string]interface{}, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	jsonMap := make(map[string]interface{})
	err = json.Unmarshal(data, &jsonMap)
	if err != nil {
		return nil, err
	}

	return jsonMap, nil
}

func extractMap(jsonMap map[string]interface{}) ([]pattern, error) {
	resultSlice := make([]pattern, 0)
	for _, jmValue := range jsonMap {
		valueSlice := jmValue.([]interface{})
		for _, patternMap := range valueSlice {

			mapv := patternMap.(map[string]interface{})

			patternName := mapv["name"].(string)
			notes := make([]int, 0)
			for _, mv := range mapv["notes"].([]interface{}) {
				notes = append(notes, int(mv.(float64)))
			}
			weights := make([]float64, 0)
			for _, weight := range mapv["weights"].([]interface{}) {
				weights = append(weights, weight.(float64))
			}

			resultSlice = append(resultSlice, pattern{Name: patternName, Notes: notes, Weights: weights})
		}
	}

	return resultSlice, nil
}

func loadPatternMap(filename string) ([]pattern, error) {
	var err error

	jsonMap, err := loadJSON(filename)

	if err != nil {
		return nil, err
	}

	chordPatterns, err := extractMap(jsonMap)

	if err != nil {
		return nil, err
	}
	return chordPatterns, nil
}

//type Chord struct {
//	root int
//	patternName string
//	notes []int
//}
//
//type ChordPattern struct {
//	name string
//	notes []int
//}

func main() {
	patterns, _ := loadPatternMap("../resources/chords.json")
	//chordMap = make(map[int][]int)
	chrom := []string{"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"}
	chords := make(map[string][]float64)
	for _, pattern := range patterns {
		for noteValue, noteName := range chrom {
			chord := make([]float64, 12)
			for noteIndex, patternEntry := range pattern.Notes {
				w := pattern.Weights[noteIndex]
				newNoteValue := (noteValue + patternEntry) % 12
				//chord = append(chord, float64((noteValue + patternEntry) % 12) * w)

				chord[newNoteValue] = pattern.Weights[noteIndex] * w
			}
			chordName := fmt.Sprintf("%s %s", noteName, pattern.Name)
			chords[chordName] = chord
		}
	}
	/*
		for patternName, pattern := range patternMap {
			for noteValue, noteName := range chrom {
				chord := make([]int, 0)
				for _, patternEntry := range pattern {
					chord = append(chord, ((noteValue + patternEntry) % 12))
				}
				chordName := fmt.Sprintf("%s %s", noteName, patternName)
				chords[chordName] = chord
			}
		}
		// Apply generic weights
		weights := []float64{
			1.0, // 0
			0.5, // 3
			0.5, // 5
			0.5, // 7
			0.5, // 2
			0.5, // 4
			0.5, // 6
			0.5, // ?
			0.5, // ?
			0.5, // ?
			0.5, // ?
			0.5} // ?

		wChords := make(map[string][]float64)
		for chordName, chord := range chords {
			wChord := make([]float64, 12)
			for i, note := range chord {
				wChord[note] = weights[i]
			}
			wChords[chordName] = wChord
		}
	*/

	// Format as csv
	csvLines := ""
	for name, chord := range chords {
		csvLine := name
		for _, note := range chord {
			csvLine = csvLine + fmt.Sprintf(",%.1f", note)
		}
		csvLine += "\n"
		csvLines += csvLine
	}
	ioutil.WriteFile("out.csv", []byte(csvLines), 0644)
	// Output csv lines, with weigthed notes and chord name
}
<commit_msg>Removed old comments<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

type pattern struct {
	Name    string
	Notes   []int
	Weights []float64
}

func loadJSON(filename string) (map[string]interface{}, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	jsonMap := make(map[string]interface{})
	err = json.Unmarshal(data, &jsonMap)
	if err != nil {
		return nil, err
	}

	return jsonMap, nil
}

func extractMap(jsonMap map[string]interface{}) ([]pattern, error) {
	resultSlice := make([]pattern, 0)
	for _, jmValue := range jsonMap {
		valueSlice := jmValue.([]interface{})
		for _, patternMap := range valueSlice {

			mapv := patternMap.(map[string]interface{})

			patternName := mapv["name"].(string)
			notes := make([]int, 0)
			for _, mv := range mapv["notes"].([]interface{}) {
				notes = append(notes, int(mv.(float64)))
			}
			weights := make([]float64, 0)
			for _, weight := range mapv["weights"].([]interface{}) {
				weights = append(weights, weight.(float64))
			}

			resultSlice = append(resultSlice, pattern{Name: patternName, Notes: notes, Weights: weights})
		}
	}

	return resultSlice, nil
}

func loadPatternMap(filename string) ([]pattern, error) {
	var err error

	jsonMap, err := loadJSON(filename)

	if err != nil {
		return nil, err
	}

	chordPatterns, err := extractMap(jsonMap)

	if err != nil {
		return nil, err
	}
	return chordPatterns, nil
}

func main() {
	patterns, _ := loadPatternMap("../resources/chords.json")
	chrom := []string{"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"}
	chords := make(map[string][]float64)
	for _, pattern := range patterns {
		for noteValue, noteName := range chrom {
			chord := make([]float64, 12)
			for noteIndex, patternEntry := range pattern.Notes {
				w := pattern.Weights[noteIndex]
				newNoteValue := (noteValue + patternEntry) % 12
				chord[newNoteValue] = pattern.Weights[noteIndex] * w
			}
			chordName := fmt.Sprintf("%s %s", noteName, pattern.Name)
			chords[chordName] = chord
		}
	}

	csvLines := ""
	for name, chord := range chords {
		csvLine := name
		for _, note := range chord {
			csvLine = csvLine + fmt.Sprintf(",%.1f", note)
		}
		csvLine += "\n"
		csvLines += csvLine
	}
	ioutil.WriteFile("out.csv", []byte(csvLines), 0644)
}
<|endoftext|>


<commit_before>package checkerlution

import (
	"github.com/couchbaselabs/go.assert"
	cbot "github.com/tleyden/checkers-bot"
	"testing"
)

func TestLookupFitnessHistory(t *testing.T) {

	checkerlution := &Checkerlution{}
	checkerlution.ourTeamId = cbot.RED_TEAM
	checkerlution.CreateNeurgoCortex()
	cortex := checkerlution.cortex

	checkerlutionOpponent := &Checkerlution{}
	checkerlutionOpponent.ourTeamId = cbot.BLUE_TEAM

	checkerlutionOpponent.CreateNeurgoCortex()
	opponentCortex := checkerlutionOpponent.cortex

	scape := &CheckerlutionScape{}

	fitness := 10.0
	fitnessOpponent := -10.0

	scape.recordFitness(cortex, fitness, opponentCortex, fitnessOpponent)
	retrievedFitness, isPresent := scape.lookupFitnessHistory(opponentCortex, cortex)
	assert.True(t, isPresent)
	assert.Equals(t, retrievedFitness, -10.0)

}
<commit_msg>fix broken unit test<commit_after>package checkerlution

import (
	"github.com/couchbaselabs/go.assert"
	cbot "github.com/tleyden/checkers-bot"
	"testing"
)

func TestLookupFitnessHistory(t *testing.T) {

	checkerlution := &Checkerlution{}
	checkerlution.ourTeamId = cbot.RED_TEAM
	checkerlution.CreateNeurgoCortex()
	cortex := checkerlution.cortex

	checkerlutionOpponent := &Checkerlution{}
	checkerlutionOpponent.ourTeamId = cbot.BLUE_TEAM

	checkerlutionOpponent.CreateNeurgoCortex()
	opponentCortex := checkerlutionOpponent.cortex

	scape := &CheckerlutionScape{}

	fitness := 10.0
	fitnessOpponent := -10.0

	scape.recordFitness(cortex, fitness, opponentCortex, fitnessOpponent)
	retrievedFitness, isPresent := scape.lookupFitnessHistory(cortex, opponentCortex)
	assert.True(t, isPresent)
	assert.Equals(t, retrievedFitness, 10.0)

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mattn/go-encoding"
	"github.com/mattn/go-zglob"
	enc "golang.org/x/text/encoding"
)

type logOpts struct {
	LogFile             string  `short:"f" long:"file" value-name:"FILE" description:"Path to log file"`
	Pattern             string  `short:"p" long:"pattern" required:"true" value-name:"PAT" description:"Pattern to search for"`
	Exclude             string  `short:"E" long:"exclude" value-name:"PAT" description:"Pattern to exclude from matching"`
	WarnOver            int64   `short:"w" long:"warning-over" description:"Trigger a warning if matched lines is over a number"`
	CritOver            int64   `short:"c" long:"critical-over" description:"Trigger a critical if matched lines is over a number"`
	WarnLevel           float64 `long:"warning-level" value-name:"N" description:"Warning level if pattern has a group"`
	CritLevel           float64 `long:"critical-level" value-name:"N" description:"Critical level if pattern has a group"`
	ReturnContent       bool    `short:"r" long:"return" description:"Return matched line"`
	FilePattern         string  `short:"F" long:"file-pattern" value-name:"FILE" description:"Check a pattern of files, instead of one file"`
	CaseInsensitive     bool    `short:"i" long:"icase" description:"Run a case insensitive match"`
	StateDir            string  `short:"s" long:"state-dir" value-name:"DIR" description:"Dir to keep state files under"`
	NoState             bool    `long:"no-state" description:"Don't use state file and read whole logs"`
	Encoding            string  `long:"encoding" description:"Encoding of log file"`
	Missing             string  `long:"missing" default:"UNKNOWN" value-name:"(CRITICAL|WARNING|OK|UNKNOWN)" description:"Exit status when log files missing"`
	patternReg          *regexp.Regexp
	excludeReg          *regexp.Regexp
	fileListFromGlob    []string
	fileListFromPattern []string
	origArgs            []string
	decoder             *enc.Decoder
}

func (opts *logOpts) prepare() error {
	if opts.LogFile == "" && opts.FilePattern == "" {
		return fmt.Errorf("No log file specified")
	}

	var err error
	if opts.patternReg, err = regCompileWithCase(opts.Pattern, opts.CaseInsensitive); err != nil {
		return fmt.Errorf("pattern is invalid")
	}

	if opts.Exclude != "" {
		opts.excludeReg, err = regCompileWithCase(opts.Exclude, opts.CaseInsensitive)
		if err != nil {
			return fmt.Errorf("exclude pattern is invalid")
		}
	}

	if opts.LogFile != "" {
		files, err := zglob.Glob(opts.LogFile)
		// unless --missing specified, we should ignore file not found error
		if err != nil && err != os.ErrNotExist {
			return fmt.Errorf("invalid glob for --file")
		}

		for _, file := range files {
			opts.fileListFromGlob = append(opts.fileListFromGlob, file)
		}
	}

	if opts.FilePattern != "" {
		dirStr := filepath.Dir(opts.FilePattern)
		filePat := filepath.Base(opts.FilePattern)
		reg, err := regCompileWithCase(filePat, opts.CaseInsensitive)
		if err != nil {
			return fmt.Errorf("file-pattern is invalid")
		}

		fileInfos, err := ioutil.ReadDir(dirStr)
		if err != nil {
			return fmt.Errorf("cannot read the directory:" + err.Error())
		}

		for _, fileInfo := range fileInfos {
			if fileInfo.IsDir() {
				continue
			}
			fname := fileInfo.Name()
			if reg.MatchString(fname) {
				opts.fileListFromPattern = append(opts.fileListFromPattern, dirStr+string(filepath.Separator)+fileInfo.Name())
			}
		}
	}
	if !validateMissing(opts.Missing) {
		return fmt.Errorf("missing option is invalid")
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "LOG"
	ckr.Exit()
}

func regCompileWithCase(ptn string, caseInsensitive bool) (*regexp.Regexp, error) {
	if caseInsensitive {
		ptn = "(?i)" + ptn
	}
	return regexp.Compile(ptn)
}

func validateMissing(missing string) bool {
	switch missing {
	case "CRITICAL", "WARNING", "OK", "UNKNOWN", "":
		return true
	default:
		return false
	}
}

func parseArgs(args []string) (*logOpts, error) {
	origArgs := make([]string, len(args))
	copy(origArgs, args)
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	opts.origArgs = origArgs
	if opts.StateDir == "" {
		workdir := os.Getenv("MACKEREL_PLUGIN_WORKDIR")
		if workdir == "" {
			workdir = os.TempDir()
		}
		opts.StateDir = filepath.Join(workdir, "check-log")
	}
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	warnNum := int64(0)
	critNum := int64(0)
	var missingFiles []string
	errorOverall := ""

	if opts.LogFile != "" && len(opts.fileListFromGlob) == 0 {
		missingFiles = append(missingFiles, opts.LogFile)
	}

	for _, f := range append(opts.fileListFromGlob, opts.fileListFromPattern...) {
		_, err := os.Stat(f)
		if err != nil {
			missingFiles = append(missingFiles, f)
			continue
		}
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}

	msg := fmt.Sprintf("%d warnings, %d criticals for pattern /%s/.", warnNum, critNum, opts.Pattern)
	if errorOverall != "" {
		msg += "\n" + errorOverall
	}
	checkSt := checkers.OK
	if len(missingFiles) > 0 {
		switch opts.Missing {
		case "OK":
		case "WARNING":
			checkSt = checkers.WARNING
		case "CRITICAL":
			checkSt = checkers.CRITICAL
		default:
			checkSt = checkers.UNKNOWN
		}
		msg += "\n" + fmt.Sprintf("The following %d files are missing.", len(missingFiles))
		for _, f := range missingFiles {
			msg += "\n" + f
		}
	}
	if warnNum > opts.WarnOver {
		checkSt = checkers.WARNING
	}
	if critNum > opts.CritOver {
		checkSt = checkers.CRITICAL
	}
	return checkers.NewChecker(checkSt, msg)
}

func (opts *logOpts) searchLog(logFile string) (int64, int64, string, error) {
	stateFile := getStateFile(opts.StateDir, logFile, opts.origArgs)
	skipBytes := int64(0)
	if !opts.NoState {
		s, err := getBytesToSkip(stateFile)
		if err != nil {
			return 0, 0, "", err
		}
		skipBytes = s
	}

	f, err := os.Open(logFile)
	if err != nil {
		return 0, 0, "", err
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		return 0, 0, "", err
	}

	rotated := false
	if stat.Size() < skipBytes {
		rotated = true
	} else if skipBytes > 0 {
		f.Seek(skipBytes, 0)
	}

	var r io.Reader = f
	if opts.Encoding != "" {
		e := encoding.GetEncoding(opts.Encoding)
		if e == nil {
			return 0, 0, "", fmt.Errorf("unknown encoding:" + opts.Encoding)
		}
		opts.decoder = e.NewDecoder()
	}

	warnNum, critNum, readBytes, errLines, err := opts.searchReader(r)
	if err != nil {
		return warnNum, critNum, errLines, err
	}

	if rotated {
		skipBytes = readBytes
	} else {
		skipBytes += readBytes
	}

	if !opts.NoState {
		err = writeBytesToSkip(stateFile, skipBytes)
		if err != nil {
			log.Printf("writeByteToSkip failed: %s\n", err.Error())
		}
	}
	return warnNum, critNum, errLines, nil
}

func (opts *logOpts) searchReader(rdr io.Reader) (warnNum, critNum, readBytes int64, errLines string, err error) {
	r := bufio.NewReader(rdr)
	for {
		lineBytes, rErr := r.ReadBytes('\n')
		if rErr != nil {
			if rErr != io.EOF {
				err = rErr
			}
			break
		}
		readBytes += int64(len(lineBytes))

		if opts.decoder != nil {
			lineBytes, err = opts.decoder.Bytes(lineBytes)
			if err != nil {
				break
			}
		}
		line := strings.Trim(string(lineBytes), "\r\n")
		if matched, matches := opts.match(line); matched {
			if len(matches) > 1 && (opts.WarnLevel > 0 || opts.CritLevel > 0) {
				level, err := strconv.ParseFloat(matches[1], 64)
				if err != nil {
					warnNum++
					critNum++
					errLines += line + "\n"
				} else {
					levelOver := false
					if level > opts.WarnLevel {
						levelOver = true
						warnNum++
					}
					if level > opts.CritLevel {
						levelOver = true
						critNum++
					}
					if levelOver {
						errLines += line + "\n"
					}
				}
			} else {
				warnNum++
				critNum++
				errLines += line + "\n"
			}
		}
	}
	return
}

func (opts *logOpts) match(line string) (bool, []string) {
	pReg := opts.patternReg
	eReg := opts.excludeReg

	matches := pReg.FindStringSubmatch(line)
	matched := len(matches) > 0 && (eReg == nil || !eReg.MatchString(line))
	return matched, matches
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string, args []string) string {
	return filepath.Join(
		stateDir,
		fmt.Sprintf(
			"%s-%x",
			stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator)),
			md5.Sum([]byte(strings.Join(args, " "))),
		),
	)
}

func getBytesToSkip(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, nil
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		log.Printf("failed to getBytesToSkip (ignoring): %s", err)
	}
	return i, nil
}

func writeBytesToSkip(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return writeFileAtomically(f, []byte(fmt.Sprintf("%d", num)))
}

func writeFileAtomically(f string, contents []byte) error {
	tmpf, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	defer os.Remove(tmpf.Name())
	_, err = tmpf.Write(contents)
	if err != nil {
		return err
	}
	tmpf.Close()
	return os.Rename(tmpf.Name(), f)
}
<commit_msg>Simplify<commit_after>package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mattn/go-encoding"
	"github.com/mattn/go-zglob"
	enc "golang.org/x/text/encoding"
)

type logOpts struct {
	LogFile             string  `short:"f" long:"file" value-name:"FILE" description:"Path to log file"`
	Pattern             string  `short:"p" long:"pattern" required:"true" value-name:"PAT" description:"Pattern to search for"`
	Exclude             string  `short:"E" long:"exclude" value-name:"PAT" description:"Pattern to exclude from matching"`
	WarnOver            int64   `short:"w" long:"warning-over" description:"Trigger a warning if matched lines is over a number"`
	CritOver            int64   `short:"c" long:"critical-over" description:"Trigger a critical if matched lines is over a number"`
	WarnLevel           float64 `long:"warning-level" value-name:"N" description:"Warning level if pattern has a group"`
	CritLevel           float64 `long:"critical-level" value-name:"N" description:"Critical level if pattern has a group"`
	ReturnContent       bool    `short:"r" long:"return" description:"Return matched line"`
	FilePattern         string  `short:"F" long:"file-pattern" value-name:"FILE" description:"Check a pattern of files, instead of one file"`
	CaseInsensitive     bool    `short:"i" long:"icase" description:"Run a case insensitive match"`
	StateDir            string  `short:"s" long:"state-dir" value-name:"DIR" description:"Dir to keep state files under"`
	NoState             bool    `long:"no-state" description:"Don't use state file and read whole logs"`
	Encoding            string  `long:"encoding" description:"Encoding of log file"`
	Missing             string  `long:"missing" default:"UNKNOWN" value-name:"(CRITICAL|WARNING|OK|UNKNOWN)" description:"Exit status when log files missing"`
	patternReg          *regexp.Regexp
	excludeReg          *regexp.Regexp
	fileListFromGlob    []string
	fileListFromPattern []string
	origArgs            []string
	decoder             *enc.Decoder
}

func (opts *logOpts) prepare() error {
	if opts.LogFile == "" && opts.FilePattern == "" {
		return fmt.Errorf("No log file specified")
	}

	var err error
	if opts.patternReg, err = regCompileWithCase(opts.Pattern, opts.CaseInsensitive); err != nil {
		return fmt.Errorf("pattern is invalid")
	}

	if opts.Exclude != "" {
		opts.excludeReg, err = regCompileWithCase(opts.Exclude, opts.CaseInsensitive)
		if err != nil {
			return fmt.Errorf("exclude pattern is invalid")
		}
	}

	if opts.LogFile != "" {
		opts.fileListFromGlob, err = zglob.Glob(opts.LogFile)
		// unless --missing specified, we should ignore file not found error
		if err != nil && err != os.ErrNotExist {
			return fmt.Errorf("invalid glob for --file")
		}
	}

	if opts.FilePattern != "" {
		dirStr := filepath.Dir(opts.FilePattern)
		filePat := filepath.Base(opts.FilePattern)
		reg, err := regCompileWithCase(filePat, opts.CaseInsensitive)
		if err != nil {
			return fmt.Errorf("file-pattern is invalid")
		}

		fileInfos, err := ioutil.ReadDir(dirStr)
		if err != nil {
			return fmt.Errorf("cannot read the directory:" + err.Error())
		}

		for _, fileInfo := range fileInfos {
			if fileInfo.IsDir() {
				continue
			}
			fname := fileInfo.Name()
			if reg.MatchString(fname) {
				opts.fileListFromPattern = append(opts.fileListFromPattern, dirStr+string(filepath.Separator)+fileInfo.Name())
			}
		}
	}
	if !validateMissing(opts.Missing) {
		return fmt.Errorf("missing option is invalid")
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "LOG"
	ckr.Exit()
}

func regCompileWithCase(ptn string, caseInsensitive bool) (*regexp.Regexp, error) {
	if caseInsensitive {
		ptn = "(?i)" + ptn
	}
	return regexp.Compile(ptn)
}

func validateMissing(missing string) bool {
	switch missing {
	case "CRITICAL", "WARNING", "OK", "UNKNOWN", "":
		return true
	default:
		return false
	}
}

func parseArgs(args []string) (*logOpts, error) {
	origArgs := make([]string, len(args))
	copy(origArgs, args)
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	opts.origArgs = origArgs
	if opts.StateDir == "" {
		workdir := os.Getenv("MACKEREL_PLUGIN_WORKDIR")
		if workdir == "" {
			workdir = os.TempDir()
		}
		opts.StateDir = filepath.Join(workdir, "check-log")
	}
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	warnNum := int64(0)
	critNum := int64(0)
	var missingFiles []string
	errorOverall := ""

	if opts.LogFile != "" && len(opts.fileListFromGlob) == 0 {
		missingFiles = append(missingFiles, opts.LogFile)
	}

	for _, f := range append(opts.fileListFromGlob, opts.fileListFromPattern...) {
		_, err := os.Stat(f)
		if err != nil {
			missingFiles = append(missingFiles, f)
			continue
		}
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}

	msg := fmt.Sprintf("%d warnings, %d criticals for pattern /%s/.", warnNum, critNum, opts.Pattern)
	if errorOverall != "" {
		msg += "\n" + errorOverall
	}
	checkSt := checkers.OK
	if len(missingFiles) > 0 {
		switch opts.Missing {
		case "OK":
		case "WARNING":
			checkSt = checkers.WARNING
		case "CRITICAL":
			checkSt = checkers.CRITICAL
		default:
			checkSt = checkers.UNKNOWN
		}
		msg += "\n" + fmt.Sprintf("The following %d files are missing.", len(missingFiles))
		for _, f := range missingFiles {
			msg += "\n" + f
		}
	}
	if warnNum > opts.WarnOver {
		checkSt = checkers.WARNING
	}
	if critNum > opts.CritOver {
		checkSt = checkers.CRITICAL
	}
	return checkers.NewChecker(checkSt, msg)
}

func (opts *logOpts) searchLog(logFile string) (int64, int64, string, error) {
	stateFile := getStateFile(opts.StateDir, logFile, opts.origArgs)
	skipBytes := int64(0)
	if !opts.NoState {
		s, err := getBytesToSkip(stateFile)
		if err != nil {
			return 0, 0, "", err
		}
		skipBytes = s
	}

	f, err := os.Open(logFile)
	if err != nil {
		return 0, 0, "", err
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		return 0, 0, "", err
	}

	rotated := false
	if stat.Size() < skipBytes {
		rotated = true
	} else if skipBytes > 0 {
		f.Seek(skipBytes, 0)
	}

	var r io.Reader = f
	if opts.Encoding != "" {
		e := encoding.GetEncoding(opts.Encoding)
		if e == nil {
			return 0, 0, "", fmt.Errorf("unknown encoding:" + opts.Encoding)
		}
		opts.decoder = e.NewDecoder()
	}

	warnNum, critNum, readBytes, errLines, err := opts.searchReader(r)
	if err != nil {
		return warnNum, critNum, errLines, err
	}

	if rotated {
		skipBytes = readBytes
	} else {
		skipBytes += readBytes
	}

	if !opts.NoState {
		err = writeBytesToSkip(stateFile, skipBytes)
		if err != nil {
			log.Printf("writeByteToSkip failed: %s\n", err.Error())
		}
	}
	return warnNum, critNum, errLines, nil
}

func (opts *logOpts) searchReader(rdr io.Reader) (warnNum, critNum, readBytes int64, errLines string, err error) {
	r := bufio.NewReader(rdr)
	for {
		lineBytes, rErr := r.ReadBytes('\n')
		if rErr != nil {
			if rErr != io.EOF {
				err = rErr
			}
			break
		}
		readBytes += int64(len(lineBytes))

		if opts.decoder != nil {
			lineBytes, err = opts.decoder.Bytes(lineBytes)
			if err != nil {
				break
			}
		}
		line := strings.Trim(string(lineBytes), "\r\n")
		if matched, matches := opts.match(line); matched {
			if len(matches) > 1 && (opts.WarnLevel > 0 || opts.CritLevel > 0) {
				level, err := strconv.ParseFloat(matches[1], 64)
				if err != nil {
					warnNum++
					critNum++
					errLines += line + "\n"
				} else {
					levelOver := false
					if level > opts.WarnLevel {
						levelOver = true
						warnNum++
					}
					if level > opts.CritLevel {
						levelOver = true
						critNum++
					}
					if levelOver {
						errLines += line + "\n"
					}
				}
			} else {
				warnNum++
				critNum++
				errLines += line + "\n"
			}
		}
	}
	return
}

func (opts *logOpts) match(line string) (bool, []string) {
	pReg := opts.patternReg
	eReg := opts.excludeReg

	matches := pReg.FindStringSubmatch(line)
	matched := len(matches) > 0 && (eReg == nil || !eReg.MatchString(line))
	return matched, matches
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string, args []string) string {
	return filepath.Join(
		stateDir,
		fmt.Sprintf(
			"%s-%x",
			stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator)),
			md5.Sum([]byte(strings.Join(args, " "))),
		),
	)
}

func getBytesToSkip(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, nil
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		log.Printf("failed to getBytesToSkip (ignoring): %s", err)
	}
	return i, nil
}

func writeBytesToSkip(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return writeFileAtomically(f, []byte(fmt.Sprintf("%d", num)))
}

func writeFileAtomically(f string, contents []byte) error {
	tmpf, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	defer os.Remove(tmpf.Name())
	_, err = tmpf.Write(contents)
	if err != nil {
		return err
	}
	tmpf.Close()
	return os.Rename(tmpf.Name(), f)
}
<|endoftext|>


<commit_before>package fs

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

func (fs *Filesystem) resolvePath(p string) ([]string, error) {
	p, err := fs.resolveVars(p)
	if err != nil {
		return nil, err
	}
	return fs.resolveGlob(p)
}

func (fs *Filesystem) resolveVars(p string) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		resolved, err := exec.LookPath(p[len(pathVar):])
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		return path.Join(fs.user.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		return strings.Replace(p, uidVar, fs.user.Uid, -1), nil

	case strings.Contains(p, userVar):
		return strings.Replace(p, userVar, fs.user.Username, -1), nil
	}
	return p, nil
}

func (fs *Filesystem) resolveGlob(p string) ([]string, error) {
	if !strings.Contains(p, "*") {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<commit_msg>Fixed panic<commit_after>package fs

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

func (fs *Filesystem) resolvePath(p string) ([]string, error) {
	p, err := fs.resolveVars(p)
	if err != nil {
		return nil, err
	}
	return fs.resolveGlob(p)
}

func (fs *Filesystem) resolveVars(p string) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		resolved, err := exec.LookPath(p[len(pathVar):])
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		if fs.user == nil {
			return p, nil
		}
		return path.Join(fs.user.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		if fs.user == nil {
			return p, nil
		}
		return strings.Replace(p, uidVar, fs.user.Uid, -1), nil

	case strings.Contains(p, userVar):
		if fs.user == nil {
			return p, nil
		}
		return strings.Replace(p, userVar, fs.user.Username, -1), nil
	}
	return p, nil
}

func (fs *Filesystem) resolveGlob(p string) ([]string, error) {
	if !strings.Contains(p, "*") {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<|endoftext|>


<commit_before>package fs

import (
	"fmt"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"os"
)

func resolvePath(p string, u *user.User) ([]string, error) {
	p, err := resolveVars(p, u)
	if err != nil {
		return nil, err
	}
	return resolveGlob(p)
}

func resolveVars(p string, u *user.User) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		emptyPath := false
		if os.Getenv("PATH") == "" {
			emptyPath = true
			os.Setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin")
		}
		resolved, err := exec.LookPath(p[len(pathVar):])
		if emptyPath {
			os.Unsetenv("PATH")
		}
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		if u == nil {
			return p, nil
		}
		return path.Join(u.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, uidVar, u.Uid, -1), nil

	case strings.Contains(p, userVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, userVar, u.Username, -1), nil
	}
	return p, nil
}

func isGlobbed(p string) bool {
	return strings.Contains(p, "*")
}

func resolveGlob(p string) ([]string, error) {
	if !isGlobbed(p) {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<commit_msg>Unsetenv > Setenv "" as the former is unavailable in golang 1.3<commit_after>package fs

import (
	"fmt"
	"os/exec"
	"os/user"
	"path"
	"path/filepath"
	"strings"
	"os"
)

func resolvePath(p string, u *user.User) ([]string, error) {
	p, err := resolveVars(p, u)
	if err != nil {
		return nil, err
	}
	return resolveGlob(p)
}

func resolveVars(p string, u *user.User) (string, error) {
	const pathVar = "${PATH}/"
	const homeVar = "${HOME}"
	const uidVar = "${UID}"
	const userVar = "${USER}"

	switch {
	case strings.HasPrefix(p, pathVar):
		emptyPath := false
		if os.Getenv("PATH") == "" {
			emptyPath = true
			os.Setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin")
		}
		resolved, err := exec.LookPath(p[len(pathVar):])
		if emptyPath {
			os.Setenv("PATH", "") // Do not use Unsetenv, incompatible with golang 1.3
		}
		if err != nil {
			return "", fmt.Errorf("failed to resolve %s", p)
		}
		return resolved, nil

	case strings.HasPrefix(p, homeVar):
		if u == nil {
			return p, nil
		}
		return path.Join(u.HomeDir, p[len(homeVar):]), nil

	case strings.Contains(p, uidVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, uidVar, u.Uid, -1), nil

	case strings.Contains(p, userVar):
		if u == nil {
			return p, nil
		}
		return strings.Replace(p, userVar, u.Username, -1), nil
	}
	return p, nil
}

func isGlobbed(p string) bool {
	return strings.Contains(p, "*")
}

func resolveGlob(p string) ([]string, error) {
	if !isGlobbed(p) {
		return []string{p}, nil
	}
	list, err := filepath.Glob(p)
	if err != nil {
		return nil, fmt.Errorf("failed to glob resolve %s: %v", p, err)
	}
	return list, nil
}
<|endoftext|>


<commit_before>package eval

import "reflect"

// Type ConstType can annotate information needed for evaluating const
// expressions. It should not be used with the reflect package.
type ConstType interface {
	reflect.Type
	IsIntegral() bool
	IsReal() bool
	IsNumeric() bool

	// Format for "something bad X (type X.ErrorType())"
	ErrorType() string

	// The go type the ConstType is promoted to by default
	DefaultPromotion() reflect.Type
}

type ConstIntType struct { reflect.Type }
type ConstShiftedIntType struct { reflect.Type }
type ConstRuneType struct { reflect.Type }
type ConstFloatType struct { reflect.Type }
type ConstComplexType struct { reflect.Type }
type ConstStringType struct { reflect.Type }
type ConstNilType struct { reflect.Type }
type ConstBoolType struct { reflect.Type }

var (
	ConstInt = ConstIntType { reflect.TypeOf(0) }
	ConstShiftedInt = ConstShiftedIntType { reflect.TypeOf(0) }
	ConstRune = ConstRuneType { reflect.TypeOf('\000') }
	ConstFloat = ConstFloatType { reflect.TypeOf(0.0) }
	ConstComplex = ConstComplexType { reflect.TypeOf(0i) }
	ConstString = ConstStringType { reflect.TypeOf("") }
	ConstNil = ConstNilType { nil }
	ConstBool = ConstBoolType { reflect.TypeOf(false) }
)

// These are actually the names of the default const promotions
func (ConstIntType) String() string { return "int" }
func (ConstShiftedIntType) String() string { return "shifted_int" }
func (ConstRuneType) String() string { return "rune" }
func (ConstFloatType) String() string { return "float64" }
func (ConstComplexType) String() string { return "complex128" }
func (ConstStringType) String() string { return "string" }
func (ConstNilType) String() string { return "<T>" }
func (ConstBoolType) String() string { return "bool" }

func (ConstIntType) ErrorType() string { return "untyped number" }
func (ConstShiftedIntType) ErrorType() string { return "untyped number" }
func (ConstRuneType) ErrorType() string { return "untyped number" }
func (ConstFloatType) ErrorType() string { return "untyped number" }
func (ConstComplexType) ErrorType() string { return "untyped number" }
func (ConstStringType) ErrorType() string { return "untyped string" }
func (ConstNilType) ErrorType() string { return "nil" }
func (ConstBoolType) ErrorType() string { return "untyped bool" }

func (c ConstIntType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstShiftedIntType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstRuneType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstFloatType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstComplexType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstStringType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstNilType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstBoolType) DefaultPromotion() reflect.Type { return c.Type }

func (ConstIntType) IsIntegral() bool { return true }
func (ConstShiftedIntType) IsIntegral() bool { return true }
func (ConstRuneType) IsIntegral() bool { return true }
func (ConstFloatType) IsIntegral() bool { return false }
func (ConstComplexType) IsIntegral() bool { return false }
func (ConstStringType) IsIntegral() bool { return false }
func (ConstNilType) IsIntegral() bool { return false }
func (ConstBoolType) IsIntegral() bool { return false }

func (ConstIntType) IsReal() bool { return true }
func (ConstShiftedIntType) IsReal() bool { return true }
func (ConstRuneType) IsReal() bool { return true }
func (ConstFloatType) IsReal() bool { return true }
func (ConstComplexType) IsReal() bool { return false }
func (ConstStringType) IsReal() bool { return false }
func (ConstNilType) IsReal() bool { return false }
func (ConstBoolType) IsReal() bool { return false }

func (ConstIntType) IsNumeric() bool { return true }
func (ConstShiftedIntType) IsNumeric() bool { return true }
func (ConstRuneType) IsNumeric() bool { return true }
func (ConstFloatType) IsNumeric() bool { return true }
func (ConstComplexType) IsNumeric() bool { return true }
func (ConstStringType) IsNumeric() bool { return false }
func (ConstNilType) IsNumeric() bool { return false }
func (ConstBoolType) IsNumeric() bool { return false }

// promoteConsts returns the ConstType of a binary, a non-boolean,
// expression involving const types of x and y.  Errors match those
// produced by gc and are as follows:
func promoteConsts(x, y ConstType, xexpr, yexpr Expr, xval, yval reflect.Value) (ConstType, []error) {
	switch x.(type) {
	case ConstShiftedIntType:
		switch y.(type) {
		case ConstIntType, ConstRuneType:
			return ConstShiftedInt, nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstIntType, ConstRuneType:
		switch y.(type) {
		case ConstShiftedIntType:
			return ConstShiftedInt, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return promoteConstNumbers(x, y), nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstFloatType, ConstComplexType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return promoteConstNumbers(x, y), nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstStringType:
		switch y.(type) {
		case ConstStringType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return nil, []error{ErrBadConstConversion{xexpr, x, y}}
		default:
			return nil, []error{
				ErrBadConstConversion{xexpr, x, ConstInt},
				ErrBadConstConversion{yexpr, y, ConstInt},
			}
		}
	case ConstNilType:
		switch y.(type) {
		case ConstNilType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return nil, []error{ErrBadConstConversion{xexpr, x, y}}
		default:
			return nil, []error{
				ErrBadConstConversion{xexpr, x, ConstInt},
				ErrBadConstConversion{yexpr, y, ConstInt},
			}
		}
	case ConstBoolType:
		switch y.(type) {
		case ConstBoolType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType, ConstStringType, ConstNilType:
			return nil, []error{ErrBadConstConversion{yexpr, y, x}}
		}
	}
	panic("go-interactive: impossible")
}

// promoteConstNumbers can't fail, but panics if x or y are not
// Const(Int|Rune|Float|Complex)Type
func promoteConstNumbers(x, y ConstType) ConstType {
	switch x.(type) {
	case ConstIntType:
		switch y.(type) {
		case ConstIntType:
			return x
		case ConstRuneType, ConstFloatType, ConstComplexType:
			return y
		}
	case ConstRuneType:
		switch y.(type) {
		case ConstIntType, ConstRuneType:
			return x
		case ConstFloatType, ConstComplexType:
			return y
		}
	case ConstFloatType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType:
			return x
		case ConstComplexType:
			return y
		}
	case ConstComplexType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return x
		}
	}
	panic("go-interactive: promoteConstNumbers called with non-numbers")
}

// Convert an untyped constant to a typed constant, where it would be
// legal to do using a type cast.
func castConstToTyped(from ConstType, c constValue, to reflect.Type, expr Expr) (
	constValue, []error) {
        return convertConstToTyped(from, c, to, true, expr)
}

// Convert an untyped constant to a typed constant, where it would be
// legal to do so automatically in a binary expression.
func promoteConstToTyped(from ConstType, c constValue, to reflect.Type, expr Expr) (
	constValue, []error) {
        return convertConstToTyped(from, c, to, false, expr)
}

// Convert an untyped constant to a typed constant. If the types from and to are
// incompatible, ErrBadConstConversion is returned along with an invalid value.
// If the types were compatible but other errors are present, such as integer
// overflows or floating truncations, the conversion will continue and a valid
// value will be returned. Therefore, if a valid value is returned, the const
// type is assignable to the reflect.Type. This can be checked using
//
//  reflect.Value(constValue).IsValid()
//
func convertConstToTyped(from ConstType, c constValue, to reflect.Type, isTypeCast bool, expr Expr) (
	constValue, []error) {
	v := hackedNew(to).Elem()

	switch from.(type) {
	case ConstShiftedIntType:
		switch to.Kind() {
			case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
				// TODO shift used as float
				return constValue{}, []error{ErrBadConstConversion{expr, from, to}}
		}
		return convertConstToTyped(ConstInt, c, to, isTypeCast, expr)
	case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
		underlying := reflect.Value(c).Interface().(*ConstNumber)
		switch to.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			var errs []error
			i, truncation, overflow := underlying.Value.Int(to.Bits())
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstInt, underlying})
			}
			if overflow {
				errs = append(errs, ErrOverflowedConstant{expr, from, to, underlying})
			}
			// For some reason, the errors produced are "complex -> int" then "complex -> real"
			_, truncation = underlying.Value.Real()
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstFloat, underlying})
			}
			v.SetInt(i)
			return constValue(v), errs

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			var errs []error
			u, truncation, overflow := underlying.Value.Uint(to.Bits())
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstInt, underlying})
			}
			if overflow {
				errs = append(errs, ErrOverflowedConstant{expr, from, to, underlying})
			}
			// For some reason, the erros produced are "complex -> int" then "complex -> real"
			_, truncation = underlying.Value.Real()
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstFloat, underlying})
			}
			v.SetUint(u)
			return constValue(v), errs

		case reflect.Float32, reflect.Float64:
			var errs []error
			f, truncation, _ := underlying.Value.Float64()
			if truncation {
				errs = []error{ErrTruncatedConstant{expr, ConstFloat, underlying}}
			}
			v.SetFloat(f)
			return constValue(v), errs

		case reflect.Complex64, reflect.Complex128:
			cmplx, _ := underlying.Value.Complex128()
			v.SetComplex(cmplx)
			return constValue(v), nil

		// string(97) is legal, equivalent of string('a'), but this
                // conversion is not automatic. "abc" + 10 is illegal.
		case reflect.String:
			if isTypeCast && from.IsIntegral() {
				i, _, overflow := underlying.Value.Int(32)
				if overflow {
					err := ErrOverflowedConstant{expr, from, ConstString, underlying}
					return constValue{}, []error{err}
				}
				v.SetString(string(i))
				return constValue(v), nil
			}

		// consts can satisfy the empty interface only
		case reflect.Interface:
			if to == emptyInterface {
				to = underlying.Type.DefaultPromotion()
				cv, _ := convertConstToTyped(from, c, to, isTypeCast, expr)
				v.Set(reflect.Value(cv).Convert(emptyInterface))
				return constValue(v), nil
			}
		}

	case ConstStringType:
		if to.Kind() == reflect.String {
			v.SetString(reflect.Value(c).String())
			return constValue(v), nil
		} else if to == emptyInterface {
			v.Set(reflect.Value(c).Convert(emptyInterface))
			return constValue(v), nil
		} else if isTypeCast && to == byteSlice || to == runeSlice {
			v = reflect.Value(c).Convert(to)
			return constValue(v), nil
		}

	case ConstBoolType:
		if to.Kind() == reflect.Bool {
			v.SetBool(reflect.Value(c).Bool())
			return constValue(v), nil
		} else if to == emptyInterface {
			v.Set(reflect.Value(c).Convert(emptyInterface))
			return constValue(v), nil
		}

	case ConstNilType:
		// Unfortunately there is no reflect.Type.CanNil()
		if isNillable(to) {
			// v is already nil
			return constValue(v), nil
		}
	}

	return constValue{}, []error{ErrBadConstConversion{expr, from, to}}
}

// Convert a typed numeric value to a const number. Ok is false if v is not numeric
// Because overflowing constants would result in loss of precision in error messages,
// the Expr.Const() method of nodes containing such errors return a *ConstNumber
// instead of the typed value. Because of this, if v is a *ConstNumber, the
// underlying const number will be returned. When working with a successfully type
// checked tree a typed node's Expr.Const() method will never return a *ConstNumber.
func convertTypedToConstNumber(v reflect.Value) (_ *ConstNumber, ok bool) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return NewConstInt64(v.Int()), true

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return NewConstUint64(v.Uint()), true

	case reflect.Float32, reflect.Float64:
		return NewConstFloat64(v.Float()), true

	case reflect.Complex64, reflect.Complex128:
		return NewConstComplex128(v.Complex()), true

	default:
                if n, ok := v.Interface().(*ConstNumber); ok {
                        return n, true
                } else {
		        return nil, false
                }
	}
}

<commit_msg>Removed todo<commit_after>package eval

import "reflect"

// Type ConstType can annotate information needed for evaluating const
// expressions. It should not be used with the reflect package.
type ConstType interface {
	reflect.Type
	IsIntegral() bool
	IsReal() bool
	IsNumeric() bool

	// Format for "something bad X (type X.ErrorType())"
	ErrorType() string

	// The go type the ConstType is promoted to by default
	DefaultPromotion() reflect.Type
}

type ConstIntType struct { reflect.Type }
type ConstShiftedIntType struct { reflect.Type }
type ConstRuneType struct { reflect.Type }
type ConstFloatType struct { reflect.Type }
type ConstComplexType struct { reflect.Type }
type ConstStringType struct { reflect.Type }
type ConstNilType struct { reflect.Type }
type ConstBoolType struct { reflect.Type }

var (
	ConstInt = ConstIntType { reflect.TypeOf(0) }
	ConstShiftedInt = ConstShiftedIntType { reflect.TypeOf(0) }
	ConstRune = ConstRuneType { reflect.TypeOf('\000') }
	ConstFloat = ConstFloatType { reflect.TypeOf(0.0) }
	ConstComplex = ConstComplexType { reflect.TypeOf(0i) }
	ConstString = ConstStringType { reflect.TypeOf("") }
	ConstNil = ConstNilType { nil }
	ConstBool = ConstBoolType { reflect.TypeOf(false) }
)

// These are actually the names of the default const promotions
func (ConstIntType) String() string { return "int" }
func (ConstShiftedIntType) String() string { return "shifted_int" }
func (ConstRuneType) String() string { return "rune" }
func (ConstFloatType) String() string { return "float64" }
func (ConstComplexType) String() string { return "complex128" }
func (ConstStringType) String() string { return "string" }
func (ConstNilType) String() string { return "<T>" }
func (ConstBoolType) String() string { return "bool" }

func (ConstIntType) ErrorType() string { return "untyped number" }
func (ConstShiftedIntType) ErrorType() string { return "untyped number" }
func (ConstRuneType) ErrorType() string { return "untyped number" }
func (ConstFloatType) ErrorType() string { return "untyped number" }
func (ConstComplexType) ErrorType() string { return "untyped number" }
func (ConstStringType) ErrorType() string { return "untyped string" }
func (ConstNilType) ErrorType() string { return "nil" }
func (ConstBoolType) ErrorType() string { return "untyped bool" }

func (c ConstIntType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstShiftedIntType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstRuneType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstFloatType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstComplexType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstStringType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstNilType) DefaultPromotion() reflect.Type { return c.Type }
func (c ConstBoolType) DefaultPromotion() reflect.Type { return c.Type }

func (ConstIntType) IsIntegral() bool { return true }
func (ConstShiftedIntType) IsIntegral() bool { return true }
func (ConstRuneType) IsIntegral() bool { return true }
func (ConstFloatType) IsIntegral() bool { return false }
func (ConstComplexType) IsIntegral() bool { return false }
func (ConstStringType) IsIntegral() bool { return false }
func (ConstNilType) IsIntegral() bool { return false }
func (ConstBoolType) IsIntegral() bool { return false }

func (ConstIntType) IsReal() bool { return true }
func (ConstShiftedIntType) IsReal() bool { return true }
func (ConstRuneType) IsReal() bool { return true }
func (ConstFloatType) IsReal() bool { return true }
func (ConstComplexType) IsReal() bool { return false }
func (ConstStringType) IsReal() bool { return false }
func (ConstNilType) IsReal() bool { return false }
func (ConstBoolType) IsReal() bool { return false }

func (ConstIntType) IsNumeric() bool { return true }
func (ConstShiftedIntType) IsNumeric() bool { return true }
func (ConstRuneType) IsNumeric() bool { return true }
func (ConstFloatType) IsNumeric() bool { return true }
func (ConstComplexType) IsNumeric() bool { return true }
func (ConstStringType) IsNumeric() bool { return false }
func (ConstNilType) IsNumeric() bool { return false }
func (ConstBoolType) IsNumeric() bool { return false }

// promoteConsts returns the ConstType of a binary, a non-boolean,
// expression involving const types of x and y.  Errors match those
// produced by gc and are as follows:
func promoteConsts(x, y ConstType, xexpr, yexpr Expr, xval, yval reflect.Value) (ConstType, []error) {
	switch x.(type) {
	case ConstShiftedIntType:
		switch y.(type) {
		case ConstIntType, ConstRuneType:
			return ConstShiftedInt, nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstIntType, ConstRuneType:
		switch y.(type) {
		case ConstShiftedIntType:
			return ConstShiftedInt, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return promoteConstNumbers(x, y), nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstFloatType, ConstComplexType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return promoteConstNumbers(x, y), nil
		}
		return nil, []error{ErrBadConstConversion{yexpr, y, x}}
	case ConstStringType:
		switch y.(type) {
		case ConstStringType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return nil, []error{ErrBadConstConversion{xexpr, x, y}}
		default:
			return nil, []error{
				ErrBadConstConversion{xexpr, x, ConstInt},
				ErrBadConstConversion{yexpr, y, ConstInt},
			}
		}
	case ConstNilType:
		switch y.(type) {
		case ConstNilType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return nil, []error{ErrBadConstConversion{xexpr, x, y}}
		default:
			return nil, []error{
				ErrBadConstConversion{xexpr, x, ConstInt},
				ErrBadConstConversion{yexpr, y, ConstInt},
			}
		}
	case ConstBoolType:
		switch y.(type) {
		case ConstBoolType:
			return x, nil
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType, ConstStringType, ConstNilType:
			return nil, []error{ErrBadConstConversion{yexpr, y, x}}
		}
	}
	panic("go-interactive: impossible")
}

// promoteConstNumbers can't fail, but panics if x or y are not
// Const(Int|Rune|Float|Complex)Type
func promoteConstNumbers(x, y ConstType) ConstType {
	switch x.(type) {
	case ConstIntType:
		switch y.(type) {
		case ConstIntType:
			return x
		case ConstRuneType, ConstFloatType, ConstComplexType:
			return y
		}
	case ConstRuneType:
		switch y.(type) {
		case ConstIntType, ConstRuneType:
			return x
		case ConstFloatType, ConstComplexType:
			return y
		}
	case ConstFloatType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType:
			return x
		case ConstComplexType:
			return y
		}
	case ConstComplexType:
		switch y.(type) {
		case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
			return x
		}
	}
	panic("go-interactive: promoteConstNumbers called with non-numbers")
}

// Convert an untyped constant to a typed constant, where it would be
// legal to do using a type cast.
func castConstToTyped(from ConstType, c constValue, to reflect.Type, expr Expr) (
	constValue, []error) {
        return convertConstToTyped(from, c, to, true, expr)
}

// Convert an untyped constant to a typed constant, where it would be
// legal to do so automatically in a binary expression.
func promoteConstToTyped(from ConstType, c constValue, to reflect.Type, expr Expr) (
	constValue, []error) {
        return convertConstToTyped(from, c, to, false, expr)
}

// Convert an untyped constant to a typed constant. If the types from and to are
// incompatible, ErrBadConstConversion is returned along with an invalid value.
// If the types were compatible but other errors are present, such as integer
// overflows or floating truncations, the conversion will continue and a valid
// value will be returned. Therefore, if a valid value is returned, the const
// type is assignable to the reflect.Type. This can be checked using
//
//  reflect.Value(constValue).IsValid()
//
func convertConstToTyped(from ConstType, c constValue, to reflect.Type, isTypeCast bool, expr Expr) (
	constValue, []error) {
	v := hackedNew(to).Elem()

	switch from.(type) {
	case ConstShiftedIntType:
		switch to.Kind() {
			case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
				return constValue{}, []error{ErrBadConstConversion{expr, from, to}}
		}
		return convertConstToTyped(ConstInt, c, to, isTypeCast, expr)
	case ConstIntType, ConstRuneType, ConstFloatType, ConstComplexType:
		underlying := reflect.Value(c).Interface().(*ConstNumber)
		switch to.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			var errs []error
			i, truncation, overflow := underlying.Value.Int(to.Bits())
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstInt, underlying})
			}
			if overflow {
				errs = append(errs, ErrOverflowedConstant{expr, from, to, underlying})
			}
			// For some reason, the errors produced are "complex -> int" then "complex -> real"
			_, truncation = underlying.Value.Real()
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstFloat, underlying})
			}
			v.SetInt(i)
			return constValue(v), errs

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			var errs []error
			u, truncation, overflow := underlying.Value.Uint(to.Bits())
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstInt, underlying})
			}
			if overflow {
				errs = append(errs, ErrOverflowedConstant{expr, from, to, underlying})
			}
			// For some reason, the erros produced are "complex -> int" then "complex -> real"
			_, truncation = underlying.Value.Real()
			if truncation {
				errs = append(errs, ErrTruncatedConstant{expr, ConstFloat, underlying})
			}
			v.SetUint(u)
			return constValue(v), errs

		case reflect.Float32, reflect.Float64:
			var errs []error
			f, truncation, _ := underlying.Value.Float64()
			if truncation {
				errs = []error{ErrTruncatedConstant{expr, ConstFloat, underlying}}
			}
			v.SetFloat(f)
			return constValue(v), errs

		case reflect.Complex64, reflect.Complex128:
			cmplx, _ := underlying.Value.Complex128()
			v.SetComplex(cmplx)
			return constValue(v), nil

		// string(97) is legal, equivalent of string('a'), but this
                // conversion is not automatic. "abc" + 10 is illegal.
		case reflect.String:
			if isTypeCast && from.IsIntegral() {
				i, _, overflow := underlying.Value.Int(32)
				if overflow {
					err := ErrOverflowedConstant{expr, from, ConstString, underlying}
					return constValue{}, []error{err}
				}
				v.SetString(string(i))
				return constValue(v), nil
			}

		// consts can satisfy the empty interface only
		case reflect.Interface:
			if to == emptyInterface {
				to = underlying.Type.DefaultPromotion()
				cv, _ := convertConstToTyped(from, c, to, isTypeCast, expr)
				v.Set(reflect.Value(cv).Convert(emptyInterface))
				return constValue(v), nil
			}
		}

	case ConstStringType:
		if to.Kind() == reflect.String {
			v.SetString(reflect.Value(c).String())
			return constValue(v), nil
		} else if to == emptyInterface {
			v.Set(reflect.Value(c).Convert(emptyInterface))
			return constValue(v), nil
		} else if isTypeCast && to == byteSlice || to == runeSlice {
			v = reflect.Value(c).Convert(to)
			return constValue(v), nil
		}

	case ConstBoolType:
		if to.Kind() == reflect.Bool {
			v.SetBool(reflect.Value(c).Bool())
			return constValue(v), nil
		} else if to == emptyInterface {
			v.Set(reflect.Value(c).Convert(emptyInterface))
			return constValue(v), nil
		}

	case ConstNilType:
		// Unfortunately there is no reflect.Type.CanNil()
		if isNillable(to) {
			// v is already nil
			return constValue(v), nil
		}
	}

	return constValue{}, []error{ErrBadConstConversion{expr, from, to}}
}

// Convert a typed numeric value to a const number. Ok is false if v is not numeric
// Because overflowing constants would result in loss of precision in error messages,
// the Expr.Const() method of nodes containing such errors return a *ConstNumber
// instead of the typed value. Because of this, if v is a *ConstNumber, the
// underlying const number will be returned. When working with a successfully type
// checked tree a typed node's Expr.Const() method will never return a *ConstNumber.
func convertTypedToConstNumber(v reflect.Value) (_ *ConstNumber, ok bool) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return NewConstInt64(v.Int()), true

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return NewConstUint64(v.Uint()), true

	case reflect.Float32, reflect.Float64:
		return NewConstFloat64(v.Float()), true

	case reflect.Complex64, reflect.Complex128:
		return NewConstComplex128(v.Complex()), true

	default:
                if n, ok := v.Interface().(*ConstNumber); ok {
                        return n, true
                } else {
		        return nil, false
                }
	}
}

<|endoftext|>