<commit_before>package crocker

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http/httputil"
	"os"
	"path"
	"path/filepath"
	. "polydawn.net/pogo/gosh"
	"strconv"
	"time"
)

const defaultDir = "/var/run" //Where a docker daemon will run by default
const localDir = "./dock"     //Where to start a local docker if desired

type Dock struct {
	/*
		Absolute path to the base dir for a docker daemon.

		'docker.sock' and 'docker.pid' are expected to exist immediately inside this path.
		The daemon's working dir may also be here.

		The last segment of the path is quite probably a symlink, and should be respected
		even if dangling (unless that means making more than one directory on the far
		side; if things are that dangling, give up).
	*/
	dir string

	/*
		True iff the daemon at this dock location was spawned by us.
		Basically used to determine if Slay() should actually fire teh lazors or not.
	*/
	isMine bool

	/*
		A socket connection to the docker for API calls
	*/
	sock *httputil.ClientConn
}

/*
	Produces a Dock struct referring to an active docker daemon.
	If an existing daemon can be found running, it is used; if not, one is started.
	@param dir path to dock dir.  May be relative.
*/
func NewDock(dir string) *Dock {
	dock := loadDock(dir)
	if dock == nil {
		dock = createDock(dir)
	}
	return dock
}

/*
	Launch a new docker daemon.
	You should try loadDock before this.  (Yes, there are inherently race conditions here.)
*/
func createDock(dir string) *Dock {
	dir, err := filepath.Abs(dir)
	if err != nil { panic(err); }

	dock := &Dock{
		dir:    dir,
		isMine: true,
	}
	Sh("mkdir")("-p")(DefaultIO)(dock.Dir())()
	dock.daemon().Start()
	dock.awaitSocket(250 * time.Millisecond)
	return dock
}

/*
	Check for what looks like an existing docker daemon setup, and return a Dock if one is found.
	We do a basic check if the pidfile and socket are present, and check if pid is stale, and that's it.
	No dialing or protocol negotiation is performed at this stage.
*/
func loadDock(dir string) *Dock {
	dir, err := filepath.Abs(dir)
	if err != nil { panic(err); }

	dock := &Dock{
		dir: dir,
		isMine: false,
	}

	// check pidfile presence.
	pidfileStat, err := os.Stat(dock.GetPidfilePath())
	if os.IsNotExist(err) { return nil; }
	if err != nil { panic(err); }
	if !pidfileStat.Mode().IsRegular() { return nil; }

	// check for process.
	pidfileBlob, err := ioutil.ReadFile(dock.GetPidfilePath())
	if os.IsNotExist(err) { return nil; }
	if err != nil { panic(err); }
	pid, err := strconv.Atoi(string(pidfileBlob))
	if err != nil { panic(err); }
	_, err = os.FindProcess(pid)
	if err != nil { panic(err); }

	// check for socket.
	if dock.awaitSocket(20 * time.Millisecond) != nil { return nil; }

	// alright, looks like a docker daemon.
	return dock
}

/*
	Check/wait for existence of docker.sock.
*/
func (dock *Dock) awaitSocket(patience time.Duration) error {
	timeout := time.Now().Add(patience)
	done := false
	for !done {
		done = time.Now().After(timeout)
		sockStat, err := os.Stat(dock.GetSockPath())
		if os.IsNotExist(err) {
			// continue
		} else if err != nil {
			panic(err)
		} else if (sockStat.Mode() & os.ModeSocket) != 0 {
			// still have to check if it's dialable; docker daemon doesn't even try to remove socket files when it's done.
			dial, err := net.Dial("unix", dock.GetSockPath())
			if err == nil {
				// success!
				dial.Close()
				return nil
			}
		} else {
			// file exists but isn't socket; do not want
			return fmt.Errorf("not a socket in place of docker socket")
		}
		if !done {
			time.Sleep(10 * time.Millisecond)
		}
	}
	return fmt.Errorf("timeout waiting for docker socket")
}

func (dock Dock) Dir() string {
	return dock.dir
}

func (dock Dock) IsChildProcess() bool {
	return dock.isMine
}

func (dock *Dock) cmd() Command {
	return Sh("docker")(DefaultIO)(
		"-H=" + fmt.Sprintf("unix://%s", dock.GetSockPath()),
	)
}

func (dock *Dock) Client() Command {
	return dock.cmd()
}

func (dock *Dock) GetPidfilePath() string {
	return path.Join(dock.Dir(), "docker.pid")
}

func (dock *Dock) GetSockPath() string {
	return path.Join(dock.Dir(), "docker.sock")
}

func (dock *Dock) daemon() Command {
	return dock.cmd()(
		"-d",
		"-g="+dock.Dir(),
		"-p="+dock.GetPidfilePath(),
	)(Opts{Cwd: dock.Dir()})
}

func (dock *Dock) Pull(image string) {
	dock.cmd()("pull", image)()
}

func (dock *Dock) Slay() {
	//Close the socket if it's open
	if dock.sock != nil {
		dock.sock.Close()
	}

	//Kill the daemon if docket started it
	if dock.isMine {
		Sh("bash")("-c")(DefaultIO)("kill `cat \""+dock.GetPidfilePath()+"\"`")()
	}
}

/*
	Import an image into repository, caching the expanded form so that it's
	ready to be used as a base filesystem for containers.
*/
func (dock *Dock) Import(reader io.Reader, name string, tag string) {
	fmt.Println("Importing", name + ":" + tag)
	dock.cmd()("import", "-", name, tag)(Opts{In: reader})()
}

func (dock *Dock) ImportFromFilename(path string, name string, tag string) {
	in, err := os.Open(path)
	if err != nil { panic(err) }
	dock.Import(in, name, tag)
}

/*
	Import an image from a docker-style image string, such as 'ubuntu:latest'
*/
func (dock *Dock) ImportFromFilenameTagstring(path, image string) {
	name, tag := SplitImageName(image)
	dock.ImportFromFilename(path, name, tag)
}
<commit_msg>Use filepath rather than generic path package<commit_after>package crocker

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http/httputil"
	"os"
	"path/filepath"
	. "polydawn.net/pogo/gosh"
	"strconv"
	"time"
)

const defaultDir = "/var/run" //Where a docker daemon will run by default
const localDir = "./dock"     //Where to start a local docker if desired

type Dock struct {
	/*
		Absolute path to the base dir for a docker daemon.

		'docker.sock' and 'docker.pid' are expected to exist immediately inside this path.
		The daemon's working dir may also be here.

		The last segment of the path is quite probably a symlink, and should be respected
		even if dangling (unless that means making more than one directory on the far
		side; if things are that dangling, give up).
	*/
	dir string

	/*
		True iff the daemon at this dock location was spawned by us.
		Basically used to determine if Slay() should actually fire teh lazors or not.
	*/
	isMine bool

	/*
		A socket connection to the docker for API calls
	*/
	sock *httputil.ClientConn
}

/*
	Produces a Dock struct referring to an active docker daemon.
	If an existing daemon can be found running, it is used; if not, one is started.
	@param dir path to dock dir.  May be relative.
*/
func NewDock(dir string) *Dock {
	dock := loadDock(dir)
	if dock == nil {
		dock = createDock(dir)
	}
	return dock
}

/*
	Launch a new docker daemon.
	You should try loadDock before this.  (Yes, there are inherently race conditions here.)
*/
func createDock(dir string) *Dock {
	dir, err := filepath.Abs(dir)
	if err != nil { panic(err); }

	dock := &Dock{
		dir:    dir,
		isMine: true,
	}
	Sh("mkdir")("-p")(DefaultIO)(dock.Dir())()
	dock.daemon().Start()
	dock.awaitSocket(250 * time.Millisecond)
	return dock
}

/*
	Check for what looks like an existing docker daemon setup, and return a Dock if one is found.
	We do a basic check if the pidfile and socket are present, and check if pid is stale, and that's it.
	No dialing or protocol negotiation is performed at this stage.
*/
func loadDock(dir string) *Dock {
	dir, err := filepath.Abs(dir)
	if err != nil { panic(err); }

	dock := &Dock{
		dir: dir,
		isMine: false,
	}

	// check pidfile presence.
	pidfileStat, err := os.Stat(dock.GetPidfilePath())
	if os.IsNotExist(err) { return nil; }
	if err != nil { panic(err); }
	if !pidfileStat.Mode().IsRegular() { return nil; }

	// check for process.
	pidfileBlob, err := ioutil.ReadFile(dock.GetPidfilePath())
	if os.IsNotExist(err) { return nil; }
	if err != nil { panic(err); }
	pid, err := strconv.Atoi(string(pidfileBlob))
	if err != nil { panic(err); }
	_, err = os.FindProcess(pid)
	if err != nil { panic(err); }

	// check for socket.
	if dock.awaitSocket(20 * time.Millisecond) != nil { return nil; }

	// alright, looks like a docker daemon.
	return dock
}

/*
	Check/wait for existence of docker.sock.
*/
func (dock *Dock) awaitSocket(patience time.Duration) error {
	timeout := time.Now().Add(patience)
	done := false
	for !done {
		done = time.Now().After(timeout)
		sockStat, err := os.Stat(dock.GetSockPath())
		if os.IsNotExist(err) {
			// continue
		} else if err != nil {
			panic(err)
		} else if (sockStat.Mode() & os.ModeSocket) != 0 {
			// still have to check if it's dialable; docker daemon doesn't even try to remove socket files when it's done.
			dial, err := net.Dial("unix", dock.GetSockPath())
			if err == nil {
				// success!
				dial.Close()
				return nil
			}
		} else {
			// file exists but isn't socket; do not want
			return fmt.Errorf("not a socket in place of docker socket")
		}
		if !done {
			time.Sleep(10 * time.Millisecond)
		}
	}
	return fmt.Errorf("timeout waiting for docker socket")
}

func (dock Dock) Dir() string {
	return dock.dir
}

func (dock Dock) IsChildProcess() bool {
	return dock.isMine
}

func (dock *Dock) cmd() Command {
	return Sh("docker")(DefaultIO)(
		"-H=" + fmt.Sprintf("unix://%s", dock.GetSockPath()),
	)
}

func (dock *Dock) Client() Command {
	return dock.cmd()
}

func (dock *Dock) GetPidfilePath() string {
	return filepath.Join(dock.Dir(), "docker.pid")
}

func (dock *Dock) GetSockPath() string {
	return filepath.Join(dock.Dir(), "docker.sock")
}

func (dock *Dock) daemon() Command {
	return dock.cmd()(
		"-d",
		"-g="+dock.Dir(),
		"-p="+dock.GetPidfilePath(),
	)(Opts{Cwd: dock.Dir()})
}

func (dock *Dock) Pull(image string) {
	dock.cmd()("pull", image)()
}

func (dock *Dock) Slay() {
	//Close the socket if it's open
	if dock.sock != nil {
		dock.sock.Close()
	}

	//Kill the daemon if docket started it
	if dock.isMine {
		Sh("bash")("-c")(DefaultIO)("kill `cat \""+dock.GetPidfilePath()+"\"`")()
	}
}

/*
	Import an image into repository, caching the expanded form so that it's
	ready to be used as a base filesystem for containers.
*/
func (dock *Dock) Import(reader io.Reader, name string, tag string) {
	fmt.Println("Importing", name + ":" + tag)
	dock.cmd()("import", "-", name, tag)(Opts{In: reader})()
}

func (dock *Dock) ImportFromFilename(path string, name string, tag string) {
	in, err := os.Open(path)
	if err != nil { panic(err) }
	dock.Import(in, name, tag)
}

/*
	Import an image from a docker-style image string, such as 'ubuntu:latest'
*/
func (dock *Dock) ImportFromFilenameTagstring(path, image string) {
	name, tag := SplitImageName(image)
	dock.ImportFromFilename(path, name, tag)
}
<|endoftext|>


<commit_before>package main

// Code responsible for handling an incoming event from github

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
)

// This function is called whenever an event happens on github.
func handleEvent(eventType string, document []byte) (err error) {

	// log.Println("Incoming request:", string(document))

	switch eventType {
	case "push":

		var event PushEvent
		err = json.Unmarshal(document, &event)
		if err != nil {
			return
		}

		log.Printf("Received PushEvent %#+v", event)

		if event.Deleted {
			// When a branch is deleted we get a "push" event we don't care
			// about (after = "0000")
			return
		}

		err = eventPush(event)
		if err != nil {
			return
		}

	default:
		log.Println("Unhandled event:", eventType)
	}

	return
}

// HTTP handler for /hook
// It is expecting a POST with a JSON payload according to
// http://developer.github.com/v3/activity/events/
func handleHook(w http.ResponseWriter, r *http.Request) {

	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Expected JSON POST payload.\n")
		return
	}

	request, err := ioutil.ReadAll(r.Body)
	check(err)

	var buf bytes.Buffer
	// r.Header.Write(&buf)
	// log.Println("Incoming request headers: ", string(buf.Bytes()))
	// buf.Reset()

	err = json.Indent(&buf, request, "", "  ")
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Expected valid JSON POST payload.\n")
		log.Println("Not a valid JSON payload. NOOP.")
		return
	}

	if len(r.Header["X-Github-Event"]) != 1 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Expected X-Github-Event header.\n")
		log.Println("No X-Github-Event header. NOOP")
		return
	}
	eventType := r.Header["X-Github-Event"][0]
	data := buf.Bytes()

	// Check to see if we have data from somewhere which is not github
	j, err := ParseJustNongithub(request)
	if !j.NonGithub.Wait {
		go func() {
			err := handleEvent(eventType, data)
			if err != nil {
				log.Printf("Error processing %v %v %q", eventType, string(data), err)
			}
		}()

		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "OK. Not waiting for build.\n")
		return
	}

	// Handle the event
	err = handleEvent(eventType, data)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error handling event: %q\n", err)
		log.Printf("Error handling event: %q", err)
		return
	}

	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "OK\n")
}

// Invoked when a respository we are watching changes
func runTang(repo, sha, repo_path, ref, logPath string) (err error) {

	// TODO(pwaller): do tee in go.
	// c := `./tang.hook |& tee $TANG_LOGPATH; exit ${PIPESTATUS[0]}`
	// cmd := Command(repo_path, "bash", "-c", c)
	cmd := Command(repo_path, "./tang.hook")

	tang_logfile, err := os.Open(logPath)
	if err != nil {
		return
	}
	defer tang_logfile.Close()

	cmd.Stdout = io.MultiWriter(os.Stdout, tang_logfile)
	cmd.Stderr = io.MultiWriter(os.Stderr, tang_logfile)

	cmd.Env = append(os.Environ(),
		"TANG_SHA="+sha, "TANG_REF="+ref, "TANG_LOGPATH="+logPath)
	err = cmd.Run()

	return
}

// Invoked when there is a push event to github.
func eventPush(event PushEvent) (err error) {
	if event.Repository.Name == "" {
		return ErrEmptyRepoName
	}

	if event.Repository.Organization == "" {
		return ErrEmptyRepoOrganization
	}

	if _, ok := allowedPushersSet[event.Pusher.Name]; !ok {
		log.Printf("Ignoring %q, not allowed", event.Pusher.Name)
		return ErrUserNotAllowed
	}

	gh_repo := path.Join(event.Repository.Organization, event.Repository.Name)

	log.Println("Push to", event.Repository.Url, event.Ref, "after", event.After)

	// The name of the subdirectory where the git
	// mirror is (or will appear, if it hasn't been
	// cloned yet).
	git_dir := path.Join(GIT_BASE_DIR, gh_repo)

	// Update our local mirror
	err = gitLocalMirror(event.Repository.Url, git_dir)
	if err != nil {
		return
	}

	// Check if we there is a tang hook
	tang_hook_present, err := gitHaveFile(git_dir, event.After, "tang.hook")
	if err != nil || !tang_hook_present || event.NonGithub.NoBuild {
		// Bail out, error, no tang.hook or instructed not to build it.
		return
	}

	// Dereference event.After, always. Not needed for github but useful for
	// `tang-event`, where we don't know the sha beforehand.
	sha, err := gitRevParse(git_dir, event.After)
	if err != nil {
		err = fmt.Errorf("gitRevParse: %q", err)
		return
	}

	// Only use 6 characters of sha for the name of the
	// directory checked out for this repository by tang.
	short_sha := sha[:6]
	checkout_dir := path.Join("checkout", short_sha)

	// Checkout the target sha
	err = gitCheckout(git_dir, checkout_dir, event.After)
	if err != nil {
		return
	}

	log.Println("Created", checkout_dir)

	pwd, err := os.Getwd()
	if err != nil {
		err = fmt.Errorf("runTang/getwd %q", err)
		return
	}

	logDir := path.Join("logs", short_sha)
	err = os.MkdirAll(logDir, 0777)
	if err != nil {
		err = fmt.Errorf("runTang/MkdirAll(%q): ", logDir, err)
		return
	}

	logPath := path.Join(logDir, "log.txt")
	fullLogPath := path.Join(pwd, logPath)

	// TODO(pwaller): One day this will have more information, e.g, QA link.
	infoURL := "http://services.scraperwiki.com/tang/" + logPath

	// Set the state of the commit to "in progress" (seen as yellow in
	// a github pull request)
	status := GithubStatus{"pending", infoURL, "Running"}
	updateStatus(gh_repo, event.After, status)

	// Run the tang script for the repository, if there is one.
	repo_workdir := path.Join(git_dir, checkout_dir)
	err = runTang(gh_repo, event.After, repo_workdir, event.Ref, fullLogPath)

	if err == nil {
		// All OK, send along a green
		s := GithubStatus{"success", infoURL, "Tests passed"}
		updateStatus(gh_repo, event.After, s)
		return
	}

	// Not OK, send along red.
	s := GithubStatus{"failure", infoURL, err.Error()}
	updateStatus(gh_repo, event.After, s)
	return
}
<commit_msg>Log incoming requests to json.log<commit_after>package main

// Code responsible for handling an incoming event from github

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
)

var jsonLogFile, _ = os.Create("logs/json.log")
var jsonLog = log.New(jsonLogFile, "", log.LstdFlags)

// This function is called whenever an event happens on github.
func handleEvent(eventType string, document []byte) (err error) {

	// log.Println("Incoming request:", string(document))
	jsonLog.Println("Incoming request:", string(document))

	switch eventType {
	case "push":

		var event PushEvent
		err = json.Unmarshal(document, &event)
		if err != nil {
			return
		}

		log.Printf("Received PushEvent %#+v", event)

		if event.Deleted {
			// When a branch is deleted we get a "push" event we don't care
			// about (after = "0000")
			return
		}

		err = eventPush(event)
		if err != nil {
			return
		}

	default:
		log.Println("Unhandled event:", eventType)
	}

	return
}

// HTTP handler for /hook
// It is expecting a POST with a JSON payload according to
// http://developer.github.com/v3/activity/events/
func handleHook(w http.ResponseWriter, r *http.Request) {

	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Expected JSON POST payload.\n")
		return
	}

	request, err := ioutil.ReadAll(r.Body)
	check(err)

	var buf bytes.Buffer
	// r.Header.Write(&buf)
	// log.Println("Incoming request headers: ", string(buf.Bytes()))
	// buf.Reset()

	err = json.Indent(&buf, request, "", "  ")
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Expected valid JSON POST payload.\n")
		log.Println("Not a valid JSON payload. NOOP.")
		return
	}

	if len(r.Header["X-Github-Event"]) != 1 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Expected X-Github-Event header.\n")
		log.Println("No X-Github-Event header. NOOP")
		return
	}
	eventType := r.Header["X-Github-Event"][0]
	data := buf.Bytes()

	// Check to see if we have data from somewhere which is not github
	j, err := ParseJustNongithub(request)
	if !j.NonGithub.Wait {
		go func() {
			err := handleEvent(eventType, data)
			if err != nil {
				log.Printf("Error processing %v %v %q", eventType, string(data), err)
			}
		}()

		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "OK. Not waiting for build.\n")
		return
	}

	// Handle the event
	err = handleEvent(eventType, data)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Error handling event: %q\n", err)
		log.Printf("Error handling event: %q", err)
		return
	}

	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, "OK\n")
}

// Invoked when a respository we are watching changes
func runTang(repo, sha, repo_path, ref, logPath string) (err error) {

	// TODO(pwaller): do tee in go.
	// c := `./tang.hook |& tee $TANG_LOGPATH; exit ${PIPESTATUS[0]}`
	// cmd := Command(repo_path, "bash", "-c", c)
	cmd := Command(repo_path, "./tang.hook")

	tang_logfile, err := os.Open(logPath)
	if err != nil {
		return
	}
	defer tang_logfile.Close()

	cmd.Stdout = io.MultiWriter(os.Stdout, tang_logfile)
	cmd.Stderr = io.MultiWriter(os.Stderr, tang_logfile)

	cmd.Env = append(os.Environ(),
		"TANG_SHA="+sha, "TANG_REF="+ref, "TANG_LOGPATH="+logPath)
	err = cmd.Run()

	return
}

// Invoked when there is a push event to github.
func eventPush(event PushEvent) (err error) {
	if event.Repository.Name == "" {
		return ErrEmptyRepoName
	}

	if event.Repository.Organization == "" {
		return ErrEmptyRepoOrganization
	}

	if _, ok := allowedPushersSet[event.Pusher.Name]; !ok {
		log.Printf("Ignoring %q, not allowed", event.Pusher.Name)
		return ErrUserNotAllowed
	}

	gh_repo := path.Join(event.Repository.Organization, event.Repository.Name)

	log.Println("Push to", event.Repository.Url, event.Ref, "after", event.After)

	// The name of the subdirectory where the git
	// mirror is (or will appear, if it hasn't been
	// cloned yet).
	git_dir := path.Join(GIT_BASE_DIR, gh_repo)

	// Update our local mirror
	err = gitLocalMirror(event.Repository.Url, git_dir)
	if err != nil {
		return
	}

	// Check if we there is a tang hook
	tang_hook_present, err := gitHaveFile(git_dir, event.After, "tang.hook")
	if err != nil || !tang_hook_present || event.NonGithub.NoBuild {
		// Bail out, error, no tang.hook or instructed not to build it.
		return
	}

	// Dereference event.After, always. Not needed for github but useful for
	// `tang-event`, where we don't know the sha beforehand.
	sha, err := gitRevParse(git_dir, event.After)
	if err != nil {
		err = fmt.Errorf("gitRevParse: %q", err)
		return
	}

	// Only use 6 characters of sha for the name of the
	// directory checked out for this repository by tang.
	short_sha := sha[:6]
	checkout_dir := path.Join("checkout", short_sha)

	// Checkout the target sha
	err = gitCheckout(git_dir, checkout_dir, event.After)
	if err != nil {
		return
	}

	log.Println("Created", checkout_dir)

	pwd, err := os.Getwd()
	if err != nil {
		err = fmt.Errorf("runTang/getwd %q", err)
		return
	}

	logDir := path.Join("logs", short_sha)
	err = os.MkdirAll(logDir, 0777)
	if err != nil {
		err = fmt.Errorf("runTang/MkdirAll(%q): ", logDir, err)
		return
	}

	logPath := path.Join(logDir, "log.txt")
	fullLogPath := path.Join(pwd, logPath)

	// TODO(pwaller): One day this will have more information, e.g, QA link.
	infoURL := "http://services.scraperwiki.com/tang/" + logPath

	// Set the state of the commit to "in progress" (seen as yellow in
	// a github pull request)
	status := GithubStatus{"pending", infoURL, "Running"}
	updateStatus(gh_repo, event.After, status)

	// Run the tang script for the repository, if there is one.
	repo_workdir := path.Join(git_dir, checkout_dir)
	err = runTang(gh_repo, event.After, repo_workdir, event.Ref, fullLogPath)

	if err == nil {
		// All OK, send along a green
		s := GithubStatus{"success", infoURL, "Tests passed"}
		updateStatus(gh_repo, event.After, s)
		return
	}

	// Not OK, send along red.
	s := GithubStatus{"failure", infoURL, err.Error()}
	updateStatus(gh_repo, event.After, s)
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 go-dockerclient 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 docker

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math"
	"net"
	"net/http"
	"net/http/httputil"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type APIEvents struct {
	Status string
	ID     string
	From   string
	Time   int64
}

type eventMonitoringState struct {
	sync.RWMutex
	sync.WaitGroup
	enabled   bool
	lastSeen  *int64
	C         chan *APIEvents
	errC      chan error
	listeners []chan *APIEvents
}

// event monitoring state is singleton
var eventMonitor eventMonitoringState

var maxMonitorConnRetries = 5
var retryInitialWaitTime = float64(10)

var ErrNoListeners = errors.New("No listeners present to recieve event")
var ErrListenerExists = errors.New("Listener already exists for docker events")

func (c *Client) AddEventListener(listener chan *APIEvents) error {
	var err error
	if !eventMonitor.isEnabled() {
		err = eventMonitor.enableEventMonitoring(c)
		if err != nil {
			return err
		}
	}
	err = eventMonitor.addListener(listener)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) RemoveEventListener(listener chan *APIEvents) error {
	err := eventMonitor.removeListener(listener)
	if err != nil {
		return err
	}

	if len(eventMonitor.listeners) == 0 {
		err = eventMonitor.disableEventMonitoring()
		if err != nil {
			return err
		}
	}

	return nil
}

func (eventState *eventMonitoringState) addListener(listener chan *APIEvents) error {

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// return error if listener is in pool
	if listenerExists(listener, &eventState.listeners) {
		return ErrListenerExists
	}

	// add to waitgroup for listeners
	eventState.Add(1)
	// add listener to list
	eventState.listeners = append(eventState.listeners, listener)
	return nil
}

func (eventState *eventMonitoringState) removeListener(listener chan *APIEvents) error {

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	if listenerExists(listener, &eventState.listeners) {
		// placeholder for new listener list
		var newListeners []chan *APIEvents

		// iterate on existing listeners, only adding non-matching listeners to new list
		for _, l := range eventState.listeners {
			if l != listener {
				newListeners = append(newListeners, l)
			}
		}

		// update listener list
		eventState.listeners = newListeners

		// release listener from waitgroup
		eventState.Add(-1)
	}
	return nil
}

func listenerExists(a chan *APIEvents, list *[]chan *APIEvents) bool {
	for _, b := range *list {
		if b == a {
			return true
		}
	}
	return false
}

func (eventState *eventMonitoringState) enableEventMonitoring(c *Client) error {
	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// if event monitoring is disabled, initialize it and start monitoring
	if !eventState.enabled {
		eventState.enabled = true
		var lastSeenDefault = int64(0)
		eventState.lastSeen = &lastSeenDefault
		eventState.C = make(chan *APIEvents, 100)
		eventState.errC = make(chan error, 1)
		go eventState.monitorEvents(c)
	}
	return nil
}

func (eventState *eventMonitoringState) disableEventMonitoring() error {

	// Wait until all sendEvents are finished
	eventState.Wait()

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// if event monitoring is enables, close the channels
	if eventState.enabled {
		eventState.enabled = false
		close(eventState.C)
		close(eventState.errC)
	}
	return nil
}

func (eventState *eventMonitoringState) monitorEvents(c *Client) {

	var err error

	// wait for first listener
	for eventState.noListeners() {
		time.Sleep(10 * time.Millisecond)
	}

	if err = eventState.connectWithRetry(c); err != nil {
		eventState.terminate(err)
	}

	for eventState.isEnabled() {
		timeout := time.After(100 * time.Millisecond)
		select {
		case ev := <-eventState.C:
			// send the event
			go eventState.sendEvent(ev)

			// update lastSeen
			go eventState.updateLastSeen(ev)

		case err = <-eventState.errC:
			if err == ErrNoListeners {
				// if there are no listeners, exit normally
				eventState.terminate(nil)
				return
			} else if err != nil {
				// otherwise, trigger a restart via the error channel
				defer func() { go eventState.monitorEvents(c) }()
				return
			}
		case <-timeout:
			continue
		}
	}
}

func (eventState *eventMonitoringState) connectWithRetry(c *Client) error {
	var retries int
	var err error
	for err = c.eventHijack(atomic.LoadInt64(eventState.lastSeen), eventState.C, eventState.errC); err != nil && retries < maxMonitorConnRetries; retries++ {
		waitTime := int64(retryInitialWaitTime * math.Pow(2, float64(retries)))
		time.Sleep(time.Duration(waitTime) * time.Millisecond)
		err = c.eventHijack(atomic.LoadInt64(eventState.lastSeen), eventState.C, eventState.errC)
	}
	return err
}

func (eventState *eventMonitoringState) noListeners() bool {
	eventState.RLock()
	defer eventState.RUnlock()
	return len(eventState.listeners) == 0
}

func (eventState *eventMonitoringState) isEnabled() bool {
	eventState.RLock()
	defer eventState.RUnlock()
	return eventState.enabled
}

func (eventState *eventMonitoringState) sendEvent(event *APIEvents) {

	// ensure the listener list doesn't change out from under us
	eventState.RLock()
	defer eventState.RUnlock()

	// add to waitgroup to make sure we don't close prematurely
	eventState.Add(1)
	defer eventState.Done()

	if eventState.isEnabled() {
		if eventState.noListeners() {
			eventState.errC <- ErrNoListeners
		}
		for _, listener := range eventState.listeners {
			listener <- event
		}
	}
}

func (eventState *eventMonitoringState) updateLastSeen(e *APIEvents) {
	eventState.Lock()
	defer eventState.Unlock()
	if atomic.LoadInt64(eventState.lastSeen) < e.Time {
		atomic.StoreInt64(eventState.lastSeen, e.Time)
	}
}

func (eventState *eventMonitoringState) terminate(err error) {
	eventState.disableEventMonitoring()
}

func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan chan error) error {

	uri := "/events"

	if startTime != 0 {
		uri += fmt.Sprintf("?since=%d", startTime)
	}

	req, err := http.NewRequest("GET", c.getURL(uri), nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "plain/text")
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol != "unix" {
		protocol = "tcp"
		address = c.endpointURL.Host
	}

	dial, err := net.Dial(protocol, address)
	if err != nil {
		return err
	}

	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)

	conn, rwc := clientconn.Hijack()
	if err != nil {
		return err
	}

	go func(rwc io.Reader) {

		defer clientconn.Close()
		defer conn.Close()

		scanner := bufio.NewScanner(rwc)
		for scanner.Scan() {
			line := scanner.Text()

			// Only pay attention to lines that start as json objects
			if strings.HasPrefix(line, "{") {
				var e APIEvents
				err = json.Unmarshal([]byte(line), &e)
				if err != nil {
					errChan <- err
				}
				eventChan <- &e
			}

		}
		if err := scanner.Err(); err != nil {
			errChan <- err
		}
	}(rwc)

	return nil
}
<commit_msg>caught closed chanel<commit_after>// Copyright 2013 go-dockerclient 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 docker

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math"
	"net"
	"net/http"
	"net/http/httputil"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type APIEvents struct {
	Status string
	ID     string
	From   string
	Time   int64
}

type eventMonitoringState struct {
	sync.RWMutex
	sync.WaitGroup
	enabled   bool
	lastSeen  *int64
	C         chan *APIEvents
	errC      chan error
	listeners []chan *APIEvents
}

// event monitoring state is singleton
var eventMonitor eventMonitoringState

var maxMonitorConnRetries = 5
var retryInitialWaitTime = float64(10)

var ErrNoListeners = errors.New("No listeners present to recieve event")
var ErrListenerExists = errors.New("Listener already exists for docker events")

func (c *Client) AddEventListener(listener chan *APIEvents) error {
	var err error
	if !eventMonitor.isEnabled() {
		err = eventMonitor.enableEventMonitoring(c)
		if err != nil {
			return err
		}
	}
	err = eventMonitor.addListener(listener)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) RemoveEventListener(listener chan *APIEvents) error {
	err := eventMonitor.removeListener(listener)
	if err != nil {
		return err
	}

	if len(eventMonitor.listeners) == 0 {
		err = eventMonitor.disableEventMonitoring()
		if err != nil {
			return err
		}
	}

	return nil
}

func (eventState *eventMonitoringState) addListener(listener chan *APIEvents) error {

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// return error if listener is in pool
	if listenerExists(listener, &eventState.listeners) {
		return ErrListenerExists
	}

	// add to waitgroup for listeners
	eventState.Add(1)
	// add listener to list
	eventState.listeners = append(eventState.listeners, listener)
	return nil
}

func (eventState *eventMonitoringState) removeListener(listener chan *APIEvents) error {

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	if listenerExists(listener, &eventState.listeners) {
		// placeholder for new listener list
		var newListeners []chan *APIEvents

		// iterate on existing listeners, only adding non-matching listeners to new list
		for _, l := range eventState.listeners {
			if l != listener {
				newListeners = append(newListeners, l)
			}
		}

		// update listener list
		eventState.listeners = newListeners

		// release listener from waitgroup
		eventState.Add(-1)
	}
	return nil
}

func listenerExists(a chan *APIEvents, list *[]chan *APIEvents) bool {
	for _, b := range *list {
		if b == a {
			return true
		}
	}
	return false
}

func (eventState *eventMonitoringState) enableEventMonitoring(c *Client) error {
	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// if event monitoring is disabled, initialize it and start monitoring
	if !eventState.enabled {
		eventState.enabled = true
		var lastSeenDefault = int64(0)
		eventState.lastSeen = &lastSeenDefault
		eventState.C = make(chan *APIEvents, 100)
		eventState.errC = make(chan error, 1)
		go eventState.monitorEvents(c)
	}
	return nil
}

func (eventState *eventMonitoringState) disableEventMonitoring() error {

	// Wait until all sendEvents are finished
	eventState.Wait()

	// lock to mutate internal state
	eventState.Lock()
	defer eventState.Unlock()

	// if event monitoring is enables, close the channels
	if eventState.enabled {
		eventState.enabled = false
		close(eventState.C)
		close(eventState.errC)
	}
	return nil
}

func (eventState *eventMonitoringState) monitorEvents(c *Client) {

	var err error

	// wait for first listener
	for eventState.noListeners() {
		time.Sleep(10 * time.Millisecond)
	}

	if err = eventState.connectWithRetry(c); err != nil {
		eventState.terminate(err)
	}

	for eventState.isEnabled() {
		timeout := time.After(100 * time.Millisecond)
		select {
		case ev, ok := <-eventState.C:
			if !ok {
				// channel has been closed, exiting
				return
			}
			// send the event
			go eventState.sendEvent(ev)

			// update lastSeen
			go eventState.updateLastSeen(ev)

		case err = <-eventState.errC:
			if err == ErrNoListeners {
				// if there are no listeners, exit normally
				eventState.terminate(nil)
				return
			} else if err != nil {
				// otherwise, trigger a restart via the error channel
				defer func() { go eventState.monitorEvents(c) }()
				return
			}
		case <-timeout:
			continue
		}
	}
}

func (eventState *eventMonitoringState) connectWithRetry(c *Client) error {
	var retries int
	var err error
	for err = c.eventHijack(atomic.LoadInt64(eventState.lastSeen), eventState.C, eventState.errC); err != nil && retries < maxMonitorConnRetries; retries++ {
		waitTime := int64(retryInitialWaitTime * math.Pow(2, float64(retries)))
		time.Sleep(time.Duration(waitTime) * time.Millisecond)
		err = c.eventHijack(atomic.LoadInt64(eventState.lastSeen), eventState.C, eventState.errC)
	}
	return err
}

func (eventState *eventMonitoringState) noListeners() bool {
	eventState.RLock()
	defer eventState.RUnlock()
	return len(eventState.listeners) == 0
}

func (eventState *eventMonitoringState) isEnabled() bool {
	eventState.RLock()
	defer eventState.RUnlock()
	return eventState.enabled
}

func (eventState *eventMonitoringState) sendEvent(event *APIEvents) {

	// ensure the listener list doesn't change out from under us
	eventState.RLock()
	defer eventState.RUnlock()

	// add to waitgroup to make sure we don't close prematurely
	eventState.Add(1)
	defer eventState.Done()

	if eventState.isEnabled() {
		if eventState.noListeners() {
			eventState.errC <- ErrNoListeners
		}
		for _, listener := range eventState.listeners {
			listener <- event
		}
	}
}

func (eventState *eventMonitoringState) updateLastSeen(e *APIEvents) {
	eventState.Lock()
	defer eventState.Unlock()
	if atomic.LoadInt64(eventState.lastSeen) < e.Time {
		atomic.StoreInt64(eventState.lastSeen, e.Time)
	}
}

func (eventState *eventMonitoringState) terminate(err error) {
	eventState.disableEventMonitoring()
}

func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan chan error) error {

	uri := "/events"

	if startTime != 0 {
		uri += fmt.Sprintf("?since=%d", startTime)
	}

	req, err := http.NewRequest("GET", c.getURL(uri), nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "plain/text")
	protocol := c.endpointURL.Scheme
	address := c.endpointURL.Path
	if protocol != "unix" {
		protocol = "tcp"
		address = c.endpointURL.Host
	}

	dial, err := net.Dial(protocol, address)
	if err != nil {
		return err
	}

	clientconn := httputil.NewClientConn(dial, nil)
	clientconn.Do(req)

	conn, rwc := clientconn.Hijack()
	if err != nil {
		return err
	}

	go func(rwc io.Reader) {

		defer clientconn.Close()
		defer conn.Close()

		scanner := bufio.NewScanner(rwc)
		for scanner.Scan() {
			line := scanner.Text()

			// Only pay attention to lines that start as json objects
			if strings.HasPrefix(line, "{") {
				var e APIEvents
				err = json.Unmarshal([]byte(line), &e)
				if err != nil {
					errChan <- err
				}
				eventChan <- &e
			}

		}
		if err := scanner.Err(); err != nil {
			errChan <- err
		}
	}(rwc)

	return nil
}
<|endoftext|>


<commit_before>package clw11

/*
#cgo windows linux LDFLAGS: -lOpenCL
#cgo darwin LDFLAGS: -framework OpenCL

#ifdef __APPLE__
#include "OpenCL/opencl.h"
#else
#include "CL/opencl.h"
#endif

extern void eventCallback(cl_event event, cl_int event_command_exec_status, void *user_data);

void callEventCallback(cl_event event, cl_int event_command_exec_status, void *user_data)
{
	eventCallback(event, event_command_exec_status, user_data);
}
*/
import "C"
import "unsafe"

type (
	Event                  C.cl_event
	EventInfo              C.cl_event_info
	ProfilingInfo          C.cl_profiling_info
	CommandType            C.cl_command_type
	CommandExecutionStatus C.cl_int
)

const (
	EventCommandQueue           EventInfo = C.CL_EVENT_COMMAND_QUEUE
	EventCommandType            EventInfo = C.CL_EVENT_COMMAND_TYPE
	EventReferenceCount         EventInfo = C.CL_EVENT_REFERENCE_COUNT
	EventCommandExecutionStatus EventInfo = C.CL_EVENT_COMMAND_EXECUTION_STATUS
	EventContext                EventInfo = C.CL_EVENT_CONTEXT
)

const (
	CommandNdrangeKernel        CommandType = C.CL_COMMAND_NDRANGE_KERNEL
	CommandTask                 CommandType = C.CL_COMMAND_TASK
	CommandNativeKernel         CommandType = C.CL_COMMAND_NATIVE_KERNEL
	CommandReadBuffer           CommandType = C.CL_COMMAND_READ_BUFFER
	CommandWriteBuffer          CommandType = C.CL_COMMAND_WRITE_BUFFER
	CommandCopyBuffer           CommandType = C.CL_COMMAND_COPY_BUFFER
	CommandReadImage            CommandType = C.CL_COMMAND_READ_IMAGE
	CommandWriteImage           CommandType = C.CL_COMMAND_WRITE_IMAGE
	CommandCopyImage            CommandType = C.CL_COMMAND_COPY_IMAGE
	CommandCopyImageToBuffer    CommandType = C.CL_COMMAND_COPY_IMAGE_TO_BUFFER
	CommandCopyBufferToImage    CommandType = C.CL_COMMAND_COPY_BUFFER_TO_IMAGE
	CommandMapBuffer            CommandType = C.CL_COMMAND_MAP_BUFFER
	CommandMapImage             CommandType = C.CL_COMMAND_MAP_IMAGE
	CommandUnmapMemoryObject    CommandType = C.CL_COMMAND_UNMAP_MEM_OBJECT
	CommandMarker               CommandType = C.CL_COMMAND_MARKER
	CommandAcquireGlObjects     CommandType = C.CL_COMMAND_ACQUIRE_GL_OBJECTS
	CommandReleaseGlObjects     CommandType = C.CL_COMMAND_RELEASE_GL_OBJECTS
	CommandReadBufferRectangle  CommandType = C.CL_COMMAND_READ_BUFFER_RECT
	CommandWriteBufferRectangle CommandType = C.CL_COMMAND_WRITE_BUFFER_RECT
	CommandCopyBufferRectangle  CommandType = C.CL_COMMAND_COPY_BUFFER_RECT
	CommandUser                 CommandType = C.CL_COMMAND_USER
)

const (
	Complete  CommandExecutionStatus = C.CL_COMPLETE
	Running   CommandExecutionStatus = C.CL_RUNNING
	Submitted CommandExecutionStatus = C.CL_SUBMITTED
	Queued    CommandExecutionStatus = C.CL_QUEUED
)

const (
	ProfilingCommandQueued ProfilingInfo = C.CL_PROFILING_COMMAND_QUEUED
	ProfilingCommandSubmit ProfilingInfo = C.CL_PROFILING_COMMAND_SUBMIT
	ProfilingCommandStart  ProfilingInfo = C.CL_PROFILING_COMMAND_START
	ProfilingCommandEnd    ProfilingInfo = C.CL_PROFILING_COMMAND_END
)

func toEventList(wait_list []Event) (event_wait_list *C.cl_event, num_events_in_wait_list C.cl_uint) {
	if wait_list != nil {
		event_wait_list = (*C.cl_event)(&wait_list[0])
		num_events_in_wait_list = C.cl_uint(len(wait_list))
	}
	return
}

func CreateUserEvent(context Context) (Event, error) {
	var err C.cl_int
	result := C.clCreateUserEvent(context, &err)
	return Event(result), toError(err)
}

func GetEventInfo(event Event, paramName EventInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventInfo(event, C.cl_event_info(paramName), C.size_t(paramValueSize), paramValue,
		(*C.size_t)(paramValueSizeRet)))
}

func GetEventProfilingInfo(event Event, paramName ProfilingInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventProfilingInfo(event, C.cl_profiling_info(paramName), C.size_t(paramValueSize),
		paramValue, (*C.size_t)(paramValueSizeRet)))
}

func SetEventCallback(event Event, command_exec_callback_type CommandExecutionStatus, callback eventCallbackGoFunction,
	user_data interface{}) error {

	key := eventCallbackMap.SetCallback(callback, user_data)

	err := toError(C.clSetEventCallback(event, C.cl_int(command_exec_callback_type), (*[0]byte)(C.callEventCallback),
		unsafe.Pointer(key)))

	if err != nil {
		// If the C side setting of the callback failed GetCallback will remove
		// the callback from the map preventing a memory leak.
		eventCallbackMap.GetCallback(key)
	}

	return err
}

func WaitForEvents(events []Event) error {
	event_list, num_events := toEventList(events)
	return toError(C.clWaitForEvents(num_events, event_list))
}
<commit_msg>Adjusted wait for events call.<commit_after>package clw11

/*
#cgo windows linux LDFLAGS: -lOpenCL
#cgo darwin LDFLAGS: -framework OpenCL

#ifdef __APPLE__
#include "OpenCL/opencl.h"
#else
#include "CL/opencl.h"
#endif

extern void eventCallback(cl_event event, cl_int event_command_exec_status, void *user_data);

void callEventCallback(cl_event event, cl_int event_command_exec_status, void *user_data)
{
	eventCallback(event, event_command_exec_status, user_data);
}
*/
import "C"
import "unsafe"

type (
	Event                  C.cl_event
	EventInfo              C.cl_event_info
	ProfilingInfo          C.cl_profiling_info
	CommandType            C.cl_command_type
	CommandExecutionStatus C.cl_int
)

const (
	EventCommandQueue           EventInfo = C.CL_EVENT_COMMAND_QUEUE
	EventCommandType            EventInfo = C.CL_EVENT_COMMAND_TYPE
	EventReferenceCount         EventInfo = C.CL_EVENT_REFERENCE_COUNT
	EventCommandExecutionStatus EventInfo = C.CL_EVENT_COMMAND_EXECUTION_STATUS
	EventContext                EventInfo = C.CL_EVENT_CONTEXT
)

const (
	CommandNdrangeKernel        CommandType = C.CL_COMMAND_NDRANGE_KERNEL
	CommandTask                 CommandType = C.CL_COMMAND_TASK
	CommandNativeKernel         CommandType = C.CL_COMMAND_NATIVE_KERNEL
	CommandReadBuffer           CommandType = C.CL_COMMAND_READ_BUFFER
	CommandWriteBuffer          CommandType = C.CL_COMMAND_WRITE_BUFFER
	CommandCopyBuffer           CommandType = C.CL_COMMAND_COPY_BUFFER
	CommandReadImage            CommandType = C.CL_COMMAND_READ_IMAGE
	CommandWriteImage           CommandType = C.CL_COMMAND_WRITE_IMAGE
	CommandCopyImage            CommandType = C.CL_COMMAND_COPY_IMAGE
	CommandCopyImageToBuffer    CommandType = C.CL_COMMAND_COPY_IMAGE_TO_BUFFER
	CommandCopyBufferToImage    CommandType = C.CL_COMMAND_COPY_BUFFER_TO_IMAGE
	CommandMapBuffer            CommandType = C.CL_COMMAND_MAP_BUFFER
	CommandMapImage             CommandType = C.CL_COMMAND_MAP_IMAGE
	CommandUnmapMemoryObject    CommandType = C.CL_COMMAND_UNMAP_MEM_OBJECT
	CommandMarker               CommandType = C.CL_COMMAND_MARKER
	CommandAcquireGlObjects     CommandType = C.CL_COMMAND_ACQUIRE_GL_OBJECTS
	CommandReleaseGlObjects     CommandType = C.CL_COMMAND_RELEASE_GL_OBJECTS
	CommandReadBufferRectangle  CommandType = C.CL_COMMAND_READ_BUFFER_RECT
	CommandWriteBufferRectangle CommandType = C.CL_COMMAND_WRITE_BUFFER_RECT
	CommandCopyBufferRectangle  CommandType = C.CL_COMMAND_COPY_BUFFER_RECT
	CommandUser                 CommandType = C.CL_COMMAND_USER
)

const (
	Complete  CommandExecutionStatus = C.CL_COMPLETE
	Running   CommandExecutionStatus = C.CL_RUNNING
	Submitted CommandExecutionStatus = C.CL_SUBMITTED
	Queued    CommandExecutionStatus = C.CL_QUEUED
)

const (
	ProfilingCommandQueued ProfilingInfo = C.CL_PROFILING_COMMAND_QUEUED
	ProfilingCommandSubmit ProfilingInfo = C.CL_PROFILING_COMMAND_SUBMIT
	ProfilingCommandStart  ProfilingInfo = C.CL_PROFILING_COMMAND_START
	ProfilingCommandEnd    ProfilingInfo = C.CL_PROFILING_COMMAND_END
)

func toEventList(wait_list []Event) (event_wait_list *C.cl_event, num_events_in_wait_list C.cl_uint) {
	if wait_list != nil {
		event_wait_list = (*C.cl_event)(&wait_list[0])
		num_events_in_wait_list = C.cl_uint(len(wait_list))
	}
	return
}

func CreateUserEvent(context Context) (Event, error) {
	var err C.cl_int
	result := C.clCreateUserEvent(context, &err)
	return Event(result), toError(err)
}

func GetEventInfo(event Event, paramName EventInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventInfo(event, C.cl_event_info(paramName), C.size_t(paramValueSize), paramValue,
		(*C.size_t)(paramValueSizeRet)))
}

func GetEventProfilingInfo(event Event, paramName ProfilingInfo, paramValueSize Size, paramValue unsafe.Pointer,
	paramValueSizeRet *Size) error {

	return toError(C.clGetEventProfilingInfo(event, C.cl_profiling_info(paramName), C.size_t(paramValueSize),
		paramValue, (*C.size_t)(paramValueSizeRet)))
}

func SetEventCallback(event Event, command_exec_callback_type CommandExecutionStatus, callback eventCallbackGoFunction,
	user_data interface{}) error {

	key := eventCallbackMap.SetCallback(callback, user_data)

	err := toError(C.clSetEventCallback(event, C.cl_int(command_exec_callback_type), (*[0]byte)(C.callEventCallback),
		unsafe.Pointer(key)))

	if err != nil {
		// If the C side setting of the callback failed GetCallback will remove
		// the callback from the map preventing a memory leak.
		eventCallbackMap.GetCallback(key)
	}

	return err
}

func WaitForEvents(num_events Uint, event_list *Event) error {
	return toError(C.clWaitForEvents(C.cl_uint(num_events), (*C.cl_event)(event_list)))
}
<|endoftext|>


<commit_before>package meter

import (
	"sync"
	"sync/atomic"
)

var nilDesc = &Desc{err: ErrNilDesc}

func NewEvent(desc *Desc) *Event {
	if desc == nil {
		desc = nilDesc
	}

	return &Event{
		desc: desc,
	}
}

type Event struct {
	desc     *Desc
	mu       sync.RWMutex
	counters []Counter
	index    map[uint64][]int
}

func (e *Event) Len() (n int) {
	e.mu.RLock()
	n = len(e.counters)
	e.mu.RUnlock()
	return
}

// Pack packs the event index dropping zero counters
func (e *Event) Pack() {
	e.mu.Lock()
	e.pack()
	e.mu.Unlock()
}

func (e *Event) add(n int64, h uint64, values []string) int64 {
	if e.index == nil {
		e.index = make(map[uint64][]int, 64)
	} else {
		for _, i := range e.index[h] {
			if 0 <= i && i < len(e.counters) {
				c := &e.counters[i]
				if c.Match(values) {
					e.mu.Unlock()
					return atomic.AddInt64(&c.n, n)
				}
			}
		}
	}
	i := len(e.counters)
	e.counters = append(e.counters, Counter{
		n:      n,
		values: values,
	})
	e.index[h] = append(e.index[h], i)
	return n
}

func (e *Event) Add(n int64, values ...string) int64 {
	h := valuesHash(values)
	e.mu.RLock()
	for _, i := range e.index[h] {
		if 0 <= i && i < len(e.counters) {
			c := &e.counters[i]
			if c.Match(values) {
				e.mu.RUnlock()
				return atomic.AddInt64(&c.n, n)

			}
		}
	}
	e.mu.RUnlock()
	e.mu.Lock()
	// Copy avoids allocation for variadic values.
	n = e.add(n, h, vcopy(values))
	e.mu.Unlock()
	return n
}

func (e *Event) Describe() *Desc {
	if e != nil {
		return e.desc
	}
	return nil
}

func (e *Event) Flush(s Snapshot) Snapshot {
	e.mu.RLock()
	for i := range e.counters {
		c := &e.counters[i]
		s = append(s, Counter{
			n:      atomic.SwapInt64(&c.n, 0),
			values: c.values,
		})
	}
	e.mu.RUnlock()
	return s
}

func (e *Event) Merge(s Snapshot) {
	for i := range s {
		c := &s[i]
		e.Add(c.n, c.values...)
	}
}

func (e *Event) get(i int) *Counter {
	if 0 <= i && i < len(e.counters) {
		return &e.counters[i]
	}
	return nil
}
func (e *Event) pack() {
	if len(e.counters) == 0 {
		return
	}
	counters := make([]Counter, len(e.counters))
	for h, idx := range e.index {
		var packed []int
		for _, i := range idx {
			c := e.get(i)
			if c.n != 0 {
				packed = append(packed, len(counters))
				counters = append(counters, Counter{
					n:      c.n,
					values: c.values,
				})
			}
		}
		if len(packed) == 0 {
			delete(e.index, h)
		} else {
			e.index[h] = packed
		}
	}
	e.counters = counters
}

func valuesHash(values []string) (h uint64) {
	h = hashNew()
	for _, v := range values {
		// if len(v) > maxValueSize {
		// 	v = v[:maxValueSize]
		// }
		// hashAddByte(h, byte(len(v)))
		for i := 0; 0 <= i && i < len(v); i++ {
			h = hashAddByte(h, v[i])
		}

	}
	return
}

func vcopy(values []string) []string {
	cp := make([]string, len(values))
	for i, v := range values {
		cp[i] = v
	}
	return cp
}

// func (e *Event) with(tag string) (c *CounterAtomic) {
// 	h := rawValuesHash(tag)
// 	e.mu.RLock()
// 	for _, c = range e.counters[h] {
// 		if c.values == tag {
// 			e.mu.RUnlock()
// 			return
// 		}
// 	}
// 	e.mu.RUnlock()
// 	e.mu.Lock()
// 	if e.counters == nil {
// 		e.counters = make(map[uint64][]*CounterAtomic, 64)
// 	} else {
// 		for _, cc := range e.counters[h] {
// 			if cc.values == tag {
// 				e.mu.Unlock()
// 				return c
// 			}
// 		}
// 	}
// 	c = new(CounterAtomic)
// 	c.values = tag
// 	e.counters[h] = append(e.counters[h], c)
// 	e.mu.Unlock()
// 	return c
// }

// func (e *Event) WithLabels(m map[string]string) Counter {
// 	if e == nil {
// 		return nil
// 	}
// 	desc := e.Describe()
// 	labels := desc.Labels()
// 	values := make([]string, len(labels))
// 	for i, label := range labels {
// 		values[i] = m[label]
// 	}
// 	return e.findOrCreate(values)
// }

// func (e *Event) WithLabelValues(values ...string) Counter {
// 	return e.findOrCreate(values)
// }
<commit_msg>Event.AddVolatile() for unsafe string values.<commit_after>package meter

import (
	"strings"
	"sync"
	"sync/atomic"
)

type Event struct {
	desc     *Desc
	mu       sync.RWMutex
	counters []Counter
	index    map[uint64][]int
}

var nilDesc = &Desc{err: ErrNilDesc}

const (
	defaultEventSize = 64
)

func NewEvent(desc *Desc) *Event {
	if desc == nil {
		desc = nilDesc
	}
	e := Event{
		desc:     desc,
		counters: make([]Counter, 0, defaultEventSize),
		index:    make(map[uint64][]int, defaultEventSize),
	}

	return &e
}

func (e *Event) Len() (n int) {
	e.mu.RLock()
	n = len(e.counters)
	e.mu.RUnlock()
	return
}

// Pack packs the event index dropping zero counters
func (e *Event) Pack() {
	e.mu.Lock()
	e.pack()
	e.mu.Unlock()
}

func (e *Event) add(n int64, h uint64, values []string) int64 {
	if e.index == nil {
		e.index = make(map[uint64][]int, 64)
	} else {
		if c := e.find(h, values); c != nil {
			return atomic.AddInt64(&c.n, n)
		}
	}
	i := len(e.counters)
	e.counters = append(e.counters, Counter{
		n:      n,
		values: values,
	})
	e.index[h] = append(e.index[h], i)
	return n
}

func (e *Event) find(h uint64, values []string) *Counter {
	for _, i := range e.index[h] {
		if 0 <= i && i < len(e.counters) {
			c := &e.counters[i]
			if c.Match(values) {
				return c
			}
		}
	}
	return nil
}

func (e *Event) AddVolatile(n int64, values ...string) int64 {
	h := vhash(values)
	e.mu.RLock()
	c := e.find(h, values)
	e.mu.RUnlock()
	if c != nil {
		return atomic.AddInt64(&c.n, n)
	}
	e.mu.Lock()
	// Copy avoids allocation for variadic values.
	n = e.add(n, h, vdeepcopy(values))
	e.mu.Unlock()
	return n
}

func (e *Event) Add(n int64, values ...string) int64 {
	h := vhash(values)
	e.mu.RLock()
	c := e.find(h, values)
	e.mu.RUnlock()
	if c != nil {
		return atomic.AddInt64(&c.n, n)
	}
	e.mu.Lock()
	// Copy avoids allocation for variadic values.
	n = e.add(n, h, vcopy(values))
	e.mu.Unlock()
	return n
}

func (e *Event) Describe() *Desc {
	if e != nil {
		return e.desc
	}
	return nil
}

func (e *Event) Flush(s Snapshot) Snapshot {
	e.mu.RLock()
	for i := range e.counters {
		c := &e.counters[i]
		s = append(s, Counter{
			n:      atomic.SwapInt64(&c.n, 0),
			values: c.values,
		})
	}
	e.mu.RUnlock()
	return s
}

func (e *Event) Merge(s Snapshot) {
	for i := range s {
		c := &s[i]
		e.Add(c.n, c.values...)
	}
}

func (e *Event) get(i int) *Counter {
	if 0 <= i && i < len(e.counters) {
		return &e.counters[i]
	}
	return nil
}
func (e *Event) pack() {
	if len(e.counters) == 0 {
		return
	}
	counters := make([]Counter, len(e.counters))
	for h, idx := range e.index {
		var packed []int
		for _, i := range idx {
			c := e.get(i)
			if c.n != 0 {
				packed = append(packed, len(counters))
				counters = append(counters, Counter{
					n:      c.n,
					values: c.values,
				})
			}
		}
		if len(packed) == 0 {
			delete(e.index, h)
		} else {
			e.index[h] = packed
		}
	}
	e.counters = counters
}

func vhash(values []string) (h uint64) {
	h = hashNew()
	for _, v := range values {
		for i := 0; 0 <= i && i < len(v); i++ {
			h = hashAddByte(h, v[i])
		}

	}
	return
}

func vdeepcopy(values []string) []string {
	s := strings.Builder{}
	n := 0
	for _, v := range values {
		n += len(v)
	}
	s.Grow(n)
	cp := make([]string, len(values))
	for i, v := range values {
		n = s.Len()
		s.WriteString(v)
		v = s.String()
		cp[i] = v[n:]
	}
	return cp

}
func vcopy(values []string) []string {
	cp := make([]string, len(values))
	for i, v := range values {
		cp[i] = v
	}
	return cp
}

// func (e *Event) with(tag string) (c *CounterAtomic) {
// 	h := rawValuesHash(tag)
// 	e.mu.RLock()
// 	for _, c = range e.counters[h] {
// 		if c.values == tag {
// 			e.mu.RUnlock()
// 			return
// 		}
// 	}
// 	e.mu.RUnlock()
// 	e.mu.Lock()
// 	if e.counters == nil {
// 		e.counters = make(map[uint64][]*CounterAtomic, 64)
// 	} else {
// 		for _, cc := range e.counters[h] {
// 			if cc.values == tag {
// 				e.mu.Unlock()
// 				return c
// 			}
// 		}
// 	}
// 	c = new(CounterAtomic)
// 	c.values = tag
// 	e.counters[h] = append(e.counters[h], c)
// 	e.mu.Unlock()
// 	return c
// }

// func (e *Event) WithLabels(m map[string]string) Counter {
// 	if e == nil {
// 		return nil
// 	}
// 	desc := e.Describe()
// 	labels := desc.Labels()
// 	values := make([]string, len(labels))
// 	for i, label := range labels {
// 		values[i] = m[label]
// 	}
// 	return e.findOrCreate(values)
// }

// func (e *Event) WithLabelValues(values ...string) Counter {
// 	return e.findOrCreate(values)
// }
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"

	"code.google.com/p/go.crypto/ssh"
	"github.com/flynn/go-shlex"
)

var host = flag.String("h", "", "host ip to listen on")
var port = flag.String("p", "22", "port to listen on")
var debug = flag.Bool("d", false, "debug mode displays handler output")
var env = flag.Bool("e", false, "pass environment to handlers")
var shell = flag.Bool("s", false, "run exec handler via SHELL")
var keys = flag.String("k", "", "pem file of private keys (read from SSH_PRIVATE_KEYS by default)")

var ErrUnauthorized = errors.New("execd: user is unauthorized")

type exitStatusMsg struct {
	Status uint32
}

func exitStatus(err error) (exitStatusMsg, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return exitStatusMsg{uint32(status.ExitStatus())}, nil
			}
		}
		return exitStatusMsg{0}, err
	}
	return exitStatusMsg{0}, nil
}

func attachCmd(cmd *exec.Cmd, stdout, stderr io.Writer, stdin io.Reader) (*sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	if stdin != nil {
		stdinIn, err := cmd.StdinPipe()
		if err != nil {
			return nil, err
		}
		go func() {
			io.Copy(stdinIn, stdin)
			stdinIn.Close()
		}()
	}

	stdoutOut, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stdout, stdoutOut)
		wg.Done()
	}()

	stderrOut, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stderr, stderrOut)
		wg.Done()
	}()

	return &wg, nil
}

func addKey(conf *ssh.ServerConfig, block *pem.Block) (err error) {
	var key interface{}
	switch block.Type {
	case "RSA PRIVATE KEY":
		key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	case "EC PRIVATE KEY":
		key, err = x509.ParseECPrivateKey(block.Bytes)
	case "DSA PRIVATE KEY":
		key, err = ssh.ParseDSAPrivateKey(block.Bytes)
	default:
		return fmt.Errorf("unsupported key type %q", block.Type)
	}
	if err != nil {
		return err
	}
	signer, err := ssh.NewSignerFromKey(key)
	if err != nil {
		return err
	}
	conf.AddHostKey(signer)
	return nil
}

func parseKeys(conf *ssh.ServerConfig, pemData []byte) error {
	var found bool
	for {
		var block *pem.Block
		block, pemData = pem.Decode(pemData)
		if block == nil {
			if !found {
				return errors.New("no private keys found")
			}
			return nil
		}
		if err := addKey(conf, block); err != nil {
			return err
		}
		found = true
	}
}

func handleAuth(handler []string, conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
	keydata := string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)))
	cmd := exec.Command(handler[0], append(handler[1:], conn.User(), keydata)...)
	var output bytes.Buffer
	done, err := attachCmd(cmd, &output, &output, nil)
	if err != nil {
		return nil, err
	}
	err = cmd.Run()
	done.Wait()
	status, err := exitStatus(err)
	if err != nil {
		return nil, err
	}
	if status.Status == 0 {
		return &ssh.Permissions{
			Extensions: map[string]string{
				"environ": strings.Trim(output.String(), "\n"),
				"user":    conn.User(),
			},
		}, nil
	} else {
		log.Println("auth-handler status:", status.Status)
	}
	return nil, ErrUnauthorized
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [options] <auth-handler> <exec-handler>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(64)
	}

	execHandler, err := shlex.Split(flag.Arg(1))
	if err != nil {
		log.Fatalln("Unable to parse receiver command:", err)
	}
	execHandler[0], err = filepath.Abs(execHandler[0])
	if err != nil {
		log.Fatalln("Invalid receiver path:", err)
	}

	authHandler, err := shlex.Split(flag.Arg(0))
	if err != nil {
		log.Fatalln("Unable to parse authchecker command:", err)
	}
	authHandler[0], err = filepath.Abs(authHandler[0])
	if err != nil {
		log.Fatalln("Invalid authchecker path:", err)
	}
	config := &ssh.ServerConfig{
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return handleAuth(authHandler, conn, key)
		},
	}

	if keyEnv := os.Getenv("SSH_PRIVATE_KEYS"); keyEnv != "" {
		if err := parseKeys(config, []byte(keyEnv)); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	} else {
		pemBytes, err := ioutil.ReadFile(*keys)
		if err != nil {
			log.Fatalln("Failed to load private keys:", err)
		}
		if err := parseKeys(config, pemBytes); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	}

	if p := os.Getenv("PORT"); p != "" && *port == "22" {
		*port = p
	}
	listener, err := net.Listen("tcp", *host+":"+*port)
	if err != nil {
		log.Fatalln("Failed to listen for connections:", err)
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("Failed to accept incoming connection:", err)
			continue
		}
		go handleConn(conn, config, execHandler)
	}
}

func handleConn(conn net.Conn, conf *ssh.ServerConfig, execHandler []string) {
	defer conn.Close()
	sshConn, chans, reqs, err := ssh.NewServerConn(conn, conf)
	if err != nil {
		log.Println("Failed to handshake:", err)
		return
	}

	go ssh.DiscardRequests(reqs)

	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		go handleChannel(sshConn, ch, execHandler)
	}
}

func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel, execHandler []string) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}
	defer ch.Close()
	for req := range reqs {
		switch req.Type {
		case "exec":
			assert := func(at string, err error) bool {
				if err != nil {
					log.Printf("%s failed: %s", at, err)
					ch.Stderr().Write([]byte("Internal error.\n"))
					return true
				}
				return false
			}

			if req.WantReply {
				req.Reply(true, nil)
			}

			cmdline := string(req.Payload[4:])
			var cmd *exec.Cmd
			if *shell {
				shellcmd := flag.Arg(1) + " " + cmdline
				cmd = exec.Command(os.Getenv("SHELL"), "-c", shellcmd)
			} else {
				cmdargs, err := shlex.Split(cmdline)
				if assert("shlex.Split", err) {
					return
				}
				cmd = exec.Command(execHandler[0], append(execHandler[1:], cmdargs...)...)
			}
			if !*env {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			cmd.Env = append(cmd.Env, "SSH_ORIGINAL_COMMAND="+cmdline)
			var stdout, stderr io.Writer
			if *debug {
				stdout = io.MultiWriter(ch, os.Stdout)
				stderr = io.MultiWriter(ch.Stderr(), os.Stdout)
			} else {
				stdout = ch
				stderr = ch.Stderr()
			}
			done, err := attachCmd(cmd, stdout, stderr, ch)
			if assert("attachCmd", err) {
				return
			}
			if assert("cmd.Start", cmd.Start()) {
				return
			}
			done.Wait()
			status, err := exitStatus(cmd.Wait())
			if assert("exitStatus", err) {
				return
			}
			_, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status))
			assert("sendExit", err)
			return
		case "env":
			if req.WantReply {
				req.Reply(true, nil)
			}
		default:
			return
		}
	}
}
<commit_msg>Add shell support. Very hacky, sorta-working prototype.<commit_after>package main

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"

	"code.google.com/p/go.crypto/ssh"
	"github.com/flynn/go-shlex"
	"github.com/kr/pty"
)

var host = flag.String("h", "", "host ip to listen on")
var port = flag.String("p", "22", "port to listen on")
var debug = flag.Bool("d", false, "debug mode displays handler output")
var env = flag.Bool("e", false, "pass environment to handlers")
var shell = flag.Bool("s", false, "run exec handler via SHELL")
var keys = flag.String("k", "", "pem file of private keys (read from SSH_PRIVATE_KEYS by default)")

var ErrUnauthorized = errors.New("execd: user is unauthorized")

type exitStatusMsg struct {
	Status uint32
}

func exitStatus(err error) (exitStatusMsg, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return exitStatusMsg{uint32(status.ExitStatus())}, nil
			}
		}
		return exitStatusMsg{0}, err
	}
	return exitStatusMsg{0}, nil
}

func attachCmd(cmd *exec.Cmd, stdout io.Writer, stderr io.Writer, stdin io.Reader) (*sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	if stdin != nil {
		stdinIn, err := cmd.StdinPipe()
		if err != nil {
			return nil, err
		}
		go func() {
			io.Copy(stdinIn, stdin)
			stdinIn.Close()
			// FIXME: Do we care that this is not part of the WaitGroup?
		}()
	}

	stdoutOut, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stdout, stdoutOut)
		wg.Done()
	}()

	stderrOut, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stderr, stderrOut)
		wg.Done()
	}()

	return &wg, nil
}

func attachShell(cmd *exec.Cmd, ch ssh.Channel) (*sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	// Note that pty merges stdout and stderr.
	cmdPty, err := pty.Start(cmd)
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(ch, cmdPty)
		wg.Done()
	}()
	go func() {
		io.Copy(cmdPty, ch)
		wg.Done()
	}()

	return &wg, nil
}

func addKey(conf *ssh.ServerConfig, block *pem.Block) (err error) {
	var key interface{}
	switch block.Type {
	case "RSA PRIVATE KEY":
		key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	case "EC PRIVATE KEY":
		key, err = x509.ParseECPrivateKey(block.Bytes)
	case "DSA PRIVATE KEY":
		key, err = ssh.ParseDSAPrivateKey(block.Bytes)
	default:
		return fmt.Errorf("unsupported key type %q", block.Type)
	}
	if err != nil {
		return err
	}
	signer, err := ssh.NewSignerFromKey(key)
	if err != nil {
		return err
	}
	conf.AddHostKey(signer)
	return nil
}

func parseKeys(conf *ssh.ServerConfig, pemData []byte) error {
	var found bool
	for {
		var block *pem.Block
		block, pemData = pem.Decode(pemData)
		if block == nil {
			if !found {
				return errors.New("no private keys found")
			}
			return nil
		}
		if err := addKey(conf, block); err != nil {
			return err
		}
		found = true
	}
}

func handleAuth(handler []string, conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
	keydata := string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)))
	cmd := exec.Command(handler[0], append(handler[1:], conn.User(), keydata)...)
	var output bytes.Buffer
	done, err := attachCmd(cmd, &output, &output, nil)
	if err != nil {
		return nil, err
	}
	err = cmd.Run()
	done.Wait()
	status, err := exitStatus(err)
	if err != nil {
		return nil, err
	}
	if status.Status == 0 {
		return &ssh.Permissions{
			Extensions: map[string]string{
				"environ": strings.Trim(output.String(), "\n"),
				"user":    conn.User(),
			},
		}, nil
	} else {
		log.Println("auth-handler status:", status.Status)
	}
	return nil, ErrUnauthorized
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [options] <auth-handler> <exec-handler>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(64)
	}

	execHandler, err := shlex.Split(flag.Arg(1))
	if err != nil {
		log.Fatalln("Unable to parse receiver command:", err)
	}
	execHandler[0], err = filepath.Abs(execHandler[0])
	if err != nil {
		log.Fatalln("Invalid receiver path:", err)
	}

	authHandler, err := shlex.Split(flag.Arg(0))
	if err != nil {
		log.Fatalln("Unable to parse authchecker command:", err)
	}
	authHandler[0], err = filepath.Abs(authHandler[0])
	if err != nil {
		log.Fatalln("Invalid authchecker path:", err)
	}
	config := &ssh.ServerConfig{
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return handleAuth(authHandler, conn, key)
		},
	}

	if keyEnv := os.Getenv("SSH_PRIVATE_KEYS"); keyEnv != "" {
		if err := parseKeys(config, []byte(keyEnv)); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	} else {
		pemBytes, err := ioutil.ReadFile(*keys)
		if err != nil {
			log.Fatalln("Failed to load private keys:", err)
		}
		if err := parseKeys(config, pemBytes); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	}

	if p := os.Getenv("PORT"); p != "" && *port == "22" {
		*port = p
	}
	listener, err := net.Listen("tcp", *host+":"+*port)
	if err != nil {
		log.Fatalln("Failed to listen for connections:", err)
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("Failed to accept incoming connection:", err)
			continue
		}
		go handleConn(conn, config, execHandler)
	}
}

func handleConn(conn net.Conn, conf *ssh.ServerConfig, execHandler []string) {
	defer conn.Close()
	sshConn, chans, reqs, err := ssh.NewServerConn(conn, conf)
	if err != nil {
		log.Println("Failed to handshake:", err)
		return
	}

	go ssh.DiscardRequests(reqs)

	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		go handleChannel(sshConn, ch, execHandler)
	}
}

func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel, execHandler []string) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}
	defer ch.Close()

	assert := func(at string, err error) bool {
		if err != nil {
			log.Printf("%s failed: %s", at, err)
			ch.Stderr().Write([]byte("Internal error.\n"))
			return true
		}
		return false
	}

	var stdout, stderr io.Writer
	if *debug {
		stdout = io.MultiWriter(ch, os.Stdout)
		stderr = io.MultiWriter(ch.Stderr(), os.Stdout)
	} else {
		stdout = ch
		stderr = ch.Stderr()
	}

	// FIXME: We currently bail out as soon as a req is matched. Technically ssh
	// can send multiple requests out of band, which we might want to handle?
	for req := range reqs {
		switch req.Type {
		case "exec":
			if req.WantReply {
				req.Reply(true, nil)
			}

			cmdline := string(req.Payload[4:])
			var cmd *exec.Cmd
			if *shell {
				shellcmd := flag.Arg(1) + " " + cmdline
				cmd = exec.Command(os.Getenv("SHELL"), "-c", shellcmd)
			} else {
				cmdargs, err := shlex.Split(cmdline)
				if assert("shlex.Split", err) {
					return
				}
				cmd = exec.Command(execHandler[0], append(execHandler[1:], cmdargs...)...)
			}
			if !*env {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			cmd.Env = append(cmd.Env, "SSH_ORIGINAL_COMMAND="+cmdline)
			done, err := attachCmd(cmd, stdout, stderr, ch)
			if assert("attachCmd", err) {
				return
			}
			if assert("cmd.Start", cmd.Start()) {
				return
			}
			done.Wait()
			status, err := exitStatus(cmd.Wait())
			if assert("exitStatus", err) {
				return
			}
			_, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status))
			assert("sendExit", err)
			return
		case "pty-req":
			// TODO: Handle "shell" which technically comes after "pty-req".
			// TODO: Handle "window-change" for pty
			// TODO: Parse payload to set initial window dimensions
			// XXX: Obey handler
			cmd := exec.Command("/usr/local/bin/bash")
			if !*env {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			// TODO: Pass in stdout/stdin to support our mitm'ing above
			done, err := attachShell(cmd, ch)
			if assert("attachShell", err) {
				return
			}
			done.Wait()
			_, err = exitStatus(cmd.Wait())
			if assert("exitStatus", err) {
				return
			}
			// FIXME: Do we want to send anything back before closing?
			return
		}

		if req.WantReply {
			req.Reply(true, nil)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package device

type efh_toolDevice struct{}

func NewEfh_toolDevice() (dev *efh_toolDevice, err error) {
	// TODO
	return
}

func (_ *efh_toolDevice) ReadRegister(bar int, addr uint64, size int) (value uint64, err error) {
	// TODO
	return
}
<commit_msg>inspect:device: implement efh_toolDevice<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package device

import (
	"fmt"
	"os/exec"

	"github.com/ikravets/errs"
)

type efh_toolDevice struct{}

func NewEfh_toolDevice() (dev *efh_toolDevice, err error) {
	return &efh_toolDevice{}, nil
}

func (_ *efh_toolDevice) ReadRegister(bar int, addr uint64, size int) (value uint64, err error) {
	errs.PassE(&err)
	v, err := (exec.Command("efh_tool", "read", fmt.Sprint(bar), fmt.Sprintf("%0#16x", addr), fmt.Sprint(size))).Output()
	errs.CheckE(err)
	_, err = fmt.Sscan(string(v), &value)
	return
}
<|endoftext|>


<commit_before>// Copyright 2021 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 vulncheck

import (
	"context"
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/vuln/client"
)

// modKey creates a unique string identifier for mod.
func modKey(mod *Module) string {
	if mod == nil {
		return ""
	}
	return fmt.Sprintf("%s@%s", mod.Path, mod.Version)
}

// extractModules collects modules in `pkgs` up to uniqueness of
// module path and version.
func extractModules(pkgs []*Package) []*Module {
	modMap := map[string]*Module{}

	seen := map[*Package]bool{}
	var extract func(*Package, map[string]*Module)
	extract = func(pkg *Package, modMap map[string]*Module) {
		if pkg == nil || seen[pkg] {
			return
		}
		if pkg.Module != nil {
			if pkg.Module.Replace != nil {
				modMap[modKey(pkg.Module.Replace)] = pkg.Module
			} else {
				modMap[modKey(pkg.Module)] = pkg.Module
			}
		}
		seen[pkg] = true
		for _, imp := range pkg.Imports {
			extract(imp, modMap)
		}
	}
	for _, pkg := range pkgs {
		extract(pkg, modMap)
	}

	modules := []*Module{}
	for _, mod := range modMap {
		modules = append(modules, mod)
	}
	return modules
}

// fetchVulnerabilities fetches vulnerabilities that affect the supplied modules.
func fetchVulnerabilities(ctx context.Context, client client.Client, modules []*Module) (moduleVulnerabilities, error) {
	mv := moduleVulnerabilities{}
	for _, mod := range modules {
		modPath := mod.Path
		if mod.Replace != nil {
			modPath = mod.Replace.Path
		}

		// skip loading vulns for local imports
		if isLocal(mod) {
			// TODO: what if client has its own db
			// with local vulns?
			continue
		}
		vulns, err := client.GetByModule(ctx, modPath)
		if err != nil {
			return nil, err
		}
		if len(vulns) == 0 {
			continue
		}
		mv = append(mv, modVulns{
			mod:   mod,
			vulns: vulns,
		})
	}
	return mv, nil
}

// fetchingInTesting is a flag used to avoid skipping
// loading local vulnerabilities in testing.
var fetchingInTesting bool = false

func isLocal(mod *Module) bool {
	if fetchingInTesting {
		return false
	}
	modDir := mod.Dir
	if mod.Replace != nil {
		modDir = mod.Replace.Dir
	}
	return !strings.HasPrefix(modDir, modCacheDirectory())
}
func modCacheDirectory() string {
	var modCacheDir string
	// TODO: define modCacheDir using something similar to cmd/go/internal/cfg.GOMODCACHE?
	if modCacheDir = os.Getenv("GOMODCACHE"); modCacheDir == "" {
		if modCacheDir = os.Getenv("GOPATH"); modCacheDir == "" {
			modCacheDir = build.Default.GOPATH
		}
		modCacheDir = filepath.Join(modCacheDir, "pkg", "mod")
	}
	return modCacheDir
}
<commit_msg>vulncheck: fix skipping load of local packages<commit_after>// Copyright 2021 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 vulncheck

import (
	"context"
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/vuln/client"
)

// modKey creates a unique string identifier for mod.
func modKey(mod *Module) string {
	if mod == nil {
		return ""
	}
	return fmt.Sprintf("%s@%s", mod.Path, mod.Version)
}

// extractModules collects modules in `pkgs` up to uniqueness of
// module path and version.
func extractModules(pkgs []*Package) []*Module {
	modMap := map[string]*Module{}

	seen := map[*Package]bool{}
	var extract func(*Package, map[string]*Module)
	extract = func(pkg *Package, modMap map[string]*Module) {
		if pkg == nil || seen[pkg] {
			return
		}
		if pkg.Module != nil {
			if pkg.Module.Replace != nil {
				modMap[modKey(pkg.Module.Replace)] = pkg.Module
			} else {
				modMap[modKey(pkg.Module)] = pkg.Module
			}
		}
		seen[pkg] = true
		for _, imp := range pkg.Imports {
			extract(imp, modMap)
		}
	}
	for _, pkg := range pkgs {
		extract(pkg, modMap)
	}

	modules := []*Module{}
	for _, mod := range modMap {
		modules = append(modules, mod)
	}
	return modules
}

// fetchVulnerabilities fetches vulnerabilities that affect the supplied modules.
func fetchVulnerabilities(ctx context.Context, client client.Client, modules []*Module) (moduleVulnerabilities, error) {
	mv := moduleVulnerabilities{}
	for _, mod := range modules {
		modPath := mod.Path
		if mod.Replace != nil {
			modPath = mod.Replace.Path
		}

		// skip loading vulns for local imports
		if isLocal(mod) {
			// TODO: what if client has its own db
			// with local vulns?
			continue
		}
		vulns, err := client.GetByModule(ctx, modPath)
		if err != nil {
			return nil, err
		}
		if len(vulns) == 0 {
			continue
		}
		mv = append(mv, modVulns{
			mod:   mod,
			vulns: vulns,
		})
	}
	return mv, nil
}

// fetchingInTesting is a flag used to avoid skipping
// loading local vulnerabilities in testing.
var fetchingInTesting bool = false

func isLocal(mod *Module) bool {
	if fetchingInTesting {
		return false
	}
	modDir := mod.Dir
	if mod.Replace != nil {
		modDir = mod.Replace.Dir
	}
	return modDir != "" && !strings.HasPrefix(modDir, modCacheDirectory())
}
func modCacheDirectory() string {
	var modCacheDir string
	// TODO: define modCacheDir using something similar to cmd/go/internal/cfg.GOMODCACHE?
	if modCacheDir = os.Getenv("GOMODCACHE"); modCacheDir == "" {
		if modCacheDir = os.Getenv("GOPATH"); modCacheDir == "" {
			modCacheDir = build.Default.GOPATH
		}
		modCacheDir = filepath.Join(modCacheDir, "pkg", "mod")
	}
	return modCacheDir
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"

	"github.com/krasoffski/gomill/htcmap"
)

const (
	width      = 600
	height     = 300
	cells      = 100
	xyrange    = 30.0
	xyscale    = width / 2 / xyrange
	multiplier = 0.4
	zscale     = height * multiplier
	angle      = math.Pi / 6
)

var (
	sin30 = math.Sin(angle)
	cos30 = math.Cos(angle)
)

// Point represents dot on three dimensional system of coordinates
type Point struct {
	X, Y, Z float64
}

func (p *Point) Isom() (float64, float64) {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return sx, sy
}

// NewPoint transform given cells i and j to coordinates and executes given
// function of two variables using created coordinates. If successful, a pointer
// to new Point returned or error in case when function returns non-real value.
func NewPoint(i, j int, f func(float64, float64) float64) (*Point, error) {
	// Transforming cell indexes to coordinates.
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	z := f(x, y)
	if math.IsNaN(z) || math.IsInf(z, +1) || math.IsInf(z, -1) {
		return nil, fmt.Errorf("error: function returned non real number")
	}
	return &Point{x, y, z}, nil
}

type Isometric struct {
	Sx, Sy float64
}

func NewIsometric(p Point) *Isometric {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return &Isometric{Sx: sx, Sy: sy}
}

type IsometricPolygon struct {
	A, B, C, D Isometric
	Color      string
}

func (p *IsometricPolygon) String() string {
	return fmt.Sprintf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
		"style='stroke:green; fill:%s; stroke-width:0.7'/>\n",
		p.A.Sx, p.A.Sy, p.B.Sx, p.B.Sy, p.C.Sx, p.C.Sy, p.D.Sx, p.D.Sy, p.Color)
}

func main() {

	cellPoints := make([][4]*Point, 0, cells*cells)
	var min, max float64

	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			// TODO: Rework ugly solution and find better names.
			var coords [4]*Point
			var aErr, bErr, cErr, dErr error
			coords[0], aErr = NewPoint(i+1, j, f1)
			coords[1], bErr = NewPoint(i, j, f1)
			coords[2], cErr = NewPoint(i, j+1, f1)
			coords[3], dErr = NewPoint(i+1, j+1, f1)

			// Skipping cell with non real points.
			if aErr != nil || bErr != nil || cErr != nil || dErr != nil {
				continue
			}
			for _, p := range coords {
				// fmt.Println(p.Z)
				min = math.Min(min, p.Z)
				max = math.Max(max, p.Z)
			}
			cellPoints = append(cellPoints, coords)
			// fmt.Printf("%v %v %v %v\n", aErr, bErr, cErr, dErr)

			// color := htcmap.AsStr((bz+dz)/2, -0.13, +0.13)

		}

	}
	fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
		"width='%d' height='%d'>\n", width, height)

	for _, arr := range cellPoints {
		c := htcmap.AsStr(arr[1].Z, min, max)
		ax, ay := arr[0].Isom()
		bx, by := arr[1].Isom()
		cx, cy := arr[2].Isom()
		dx, dy := arr[3].Isom()
		fmt.Printf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
			"style='stroke:green; fill:%s; stroke-width:0.7'/>\n",
			ax, ay, bx, by, cx, cy, dx, dy, c)

	}

	// fmt.Printf("Min: %g, Max: %g\n", min, max)

	fmt.Println("</svg>")
}

func f1(x, y float64) float64 {
	r := math.Hypot(x, y)
	return math.Sin(r) / r
}

func f2(x, y float64) float64 {
	return x * math.Exp(-x*x-y*y)
}
<commit_msg>Solving issue with wrong coloring (in progress).<commit_after>package main

import (
	"fmt"
	"math"
	"os"

	"github.com/krasoffski/gomill/htcmap"
)

const (
	width   = 600
	height  = 320
	cells   = 100
	xyrange = 30.0
	xyscale = width / 2 / xyrange
	zscale  = height * 0.4
	angle   = math.Pi / 6
)

var (
	sin30 = math.Sin(angle)
	cos30 = math.Cos(angle)
)

// Point represents dot on three dimensional system of coordinates
type Point struct {
	X, Y, Z float64
}

// Isom transforms Point from 3 dimensional system to isometric.
func (p *Point) Isom() (float64, float64) {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return sx, sy
}

// NewPoint transform given cells i and j to coordinates and executes given
// function of two variables using created coordinates. If successful, a pointer
// to new Point returned or error in case when function returns non-real value.
func NewPoint(i, j int, f func(float64, float64) float64) (*Point, error) {
	// Transforming cell indexes to coordinates.
	x := xyrange * (float64(i)/cells - 0.5)
	y := xyrange * (float64(j)/cells - 0.5)
	z := f(x, y)
	if math.IsNaN(z) || math.IsInf(z, +1) || math.IsInf(z, -1) {
		return nil, fmt.Errorf("error: function returned non real number")
	}
	return &Point{x, y, z}, nil
}

type Isometric struct {
	Sx, Sy float64
}

func NewIsometric(p Point) *Isometric {
	sx := width/2 + (p.X-p.Y)*cos30*xyscale
	sy := height/2 + (p.X+p.Y)*sin30*xyscale - p.Z*zscale
	return &Isometric{Sx: sx, Sy: sy}
}

type IsometricPolygon struct {
	A, B, C, D Isometric
	Color      string
}

func (p *IsometricPolygon) String() string {
	return fmt.Sprintf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
		"style='stroke:green; fill:%s; stroke-width:0.7'/>\n",
		p.A.Sx, p.A.Sy, p.B.Sx, p.B.Sy, p.C.Sx, p.C.Sy, p.D.Sx, p.D.Sy, p.Color)
}

func main() {

	cellPoints := make([][4]*Point, 0, cells*cells)

	for i := 0; i < cells; i++ {
		for j := 0; j < cells; j++ {
			var coords [4]*Point
			var aErr, bErr, cErr, dErr error
			coords[0], aErr = NewPoint(i+1, j, f1)
			coords[1], bErr = NewPoint(i, j, f1)
			coords[2], cErr = NewPoint(i, j+1, f1)
			coords[3], dErr = NewPoint(i+1, j+1, f1)

			// Skipping cell with non-real points.
			if aErr != nil || bErr != nil || cErr != nil || dErr != nil {
				continue
			}

			// for _, p := range coords {
			// 	// fmt.Println(p.Z)
			// 	min = math.Min(min, p.Z)
			// 	max = math.Max(max, p.Z)
			// }
			cellPoints = append(cellPoints, coords)
		}

	}
	if len(cellPoints) == 0 {
		fmt.Fprintln(os.Stderr, "error: no real points are exist")
		os.Exit(1)
	}
	min, max := cellPoints[0][0].Z, cellPoints[0][0].Z
	for _, cell := range cellPoints {
		min = math.Min(min, cell[3].Z)
		max = math.Max(max, cell[1].Z)
	}
	fmt.Printf("<svg xmlns='http://www.w3.org/2000/svg' "+
		"width='%d' height='%d'>\n", width, height)

	for _, arr := range cellPoints {

		ax, ay := arr[0].Isom()
		bx, by := arr[1].Isom()
		cx, cy := arr[2].Isom()
		dx, dy := arr[3].Isom()

		avg := (arr[1].Z + arr[3].Z) / 2
		c := htcmap.AsStr(avg, min, max)

		fmt.Printf("<polygon points='%g,%g %g,%g %g,%g %g,%g' "+
			"style='stroke:green; fill:%s; stroke-width:0.7'>%g</polygon>\n",
			ax, ay, bx, by, cx, cy, dx, dy, c, avg)
	}

	fmt.Fprintf(os.Stderr, "Min: %g, Max: %g\n", min, max)

	fmt.Println("</svg>")
}

func f1(x, y float64) float64 {
	r := math.Hypot(x, y)
	return math.Sin(r) / r
}

func f2(x, y float64) float64 {
	return x * math.Exp(-x*x-y*y)
}
<|endoftext|>


<commit_before>package apachelog

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

// Using a variant of apache common log format used in Ruby's Rack::CommonLogger which includes response time
// in seconds at the the end of the log line.
const apacheFormatPattern = "%s - - [%s] \"%s %s %s\" %d %d %0.4f\n"

// A wrapper around a ResponseWriter that carries other metadata needed to write a log line.
type Record struct {
	http.ResponseWriter

	ip                    string
	time                  time.Time
	method, uri, protocol string
	status                int
	responseBytes         int64
	elapsedTime           time.Duration
}

// Write the Record out as a single log line to out.
func (r *Record) Log(out io.Writer) {
	timeFormatted := r.time.Format("02/Jan/2006 15:04:05")
	fmt.Fprintf(out, apacheFormatPattern, r.ip, timeFormatted, r.method, r.uri, r.protocol, r.status,
		r.responseBytes, r.elapsedTime.Seconds())
}

// This proxies to the underlying ResponseWriter.Write method while recording response size.
func (r *Record) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

// This proxies to the underlying ResponseWriter.WriteHeader method while recording response status.
func (r *Record) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// This is an http.Handler that logs each response.
type Handler struct {
	handler http.Handler
	out     io.Writer
}

// Create a new Handler, given some underlying http.Handler to wrap and an output stream (typically
// os.Stderr).
func NewHandler(handler http.Handler, out io.Writer) http.Handler {
	return &Handler{
		handler: handler,
		out:     out,
	}
}

// This delegates to the underlying handler's ServeHTTP method and writes one log line for every call.
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	clientIP := r.RemoteAddr
	if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
		clientIP = clientIP[:colon]
	}

	record := &Record{
		ResponseWriter: rw,
		ip:             clientIP,
		time:           time.Time{},
		method:         r.Method,
		uri:            r.RequestURI,
		protocol:       r.Proto,
		status:         http.StatusOK,
		elapsedTime:    time.Duration(0),
	}

	startTime := time.Now()
	h.handler.ServeHTTP(record, r)
	finishTime := time.Now()

	record.time = finishTime
	record.elapsedTime = finishTime.Sub(startTime)

	record.Log(h.out)
}
<commit_msg>Add documentation header.<commit_after>/*
apachelog is a library for logging the responses of an http.Handler in the Apache Common Log Format. It uses a
variant of this log format (http://httpd.apache.org/docs/1.3/logs.html#common) also used by Rack::CommonLogger
in Ruby. The format has an additional field at the end for the response time in seconds.

Using apachelog is typically very simple. You'll need to create an http.Handler and set up your request
routing first. In a simple web application, for example, you might just use http.DefaultServeMux. Next, wrap
the http.Handler in an apachelog.Handler using NewHandler, create an http.Server with this handler, and you're
good to go.

Example:

		mux := http.DefaultServeMux
		mux.HandleFunc("/", handler)
		loggingHandler := apachelog.NewHandler(mux, os.Stderr)
		server := &http.Server{
			Addr: ":8899",
			Handler: loggingHandler,
		}
		server.ListenAndServe()
*/
package apachelog

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

// Using a variant of apache common log format used in Ruby's Rack::CommonLogger which includes response time
// in seconds at the the end of the log line.
const apacheFormatPattern = "%s - - [%s] \"%s %s %s\" %d %d %0.4f\n"

// A wrapper around a ResponseWriter that carries other metadata needed to write a log line.
type Record struct {
	http.ResponseWriter

	ip                    string
	time                  time.Time
	method, uri, protocol string
	status                int
	responseBytes         int64
	elapsedTime           time.Duration
}

// Write the Record out as a single log line to out.
func (r *Record) Log(out io.Writer) {
	timeFormatted := r.time.Format("02/Jan/2006 15:04:05")
	fmt.Fprintf(out, apacheFormatPattern, r.ip, timeFormatted, r.method, r.uri, r.protocol, r.status,
		r.responseBytes, r.elapsedTime.Seconds())
}

// This proxies to the underlying ResponseWriter.Write method while recording response size.
func (r *Record) Write(p []byte) (int, error) {
	written, err := r.ResponseWriter.Write(p)
	r.responseBytes += int64(written)
	return written, err
}

// This proxies to the underlying ResponseWriter.WriteHeader method while recording response status.
func (r *Record) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

// This is an http.Handler that logs each response.
type Handler struct {
	handler http.Handler
	out     io.Writer
}

// Create a new Handler, given some underlying http.Handler to wrap and an output stream (typically
// os.Stderr).
func NewHandler(handler http.Handler, out io.Writer) http.Handler {
	return &Handler{
		handler: handler,
		out:     out,
	}
}

// This delegates to the underlying handler's ServeHTTP method and writes one log line for every call.
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	clientIP := r.RemoteAddr
	if colon := strings.LastIndex(clientIP, ":"); colon != -1 {
		clientIP = clientIP[:colon]
	}

	record := &Record{
		ResponseWriter: rw,
		ip:             clientIP,
		time:           time.Time{},
		method:         r.Method,
		uri:            r.RequestURI,
		protocol:       r.Proto,
		status:         http.StatusOK,
		elapsedTime:    time.Duration(0),
	}

	startTime := time.Now()
	h.handler.ServeHTTP(record, r)
	finishTime := time.Now()

	record.time = finishTime
	record.elapsedTime = finishTime.Sub(startTime)

	record.Log(h.out)
}
<|endoftext|>