<commit_before>package lfs

import (
	"bytes"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"strings"
)

// getCreds gets the credentials for the given request's URL, and sets its
// Authorization header with them using Basic Authentication. This is like
// getCredsForAPI(), but skips checking the LFS url or git remote.
func getCreds(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	creds, err := fillCredentials(req.URL)
	if err != nil {
		return nil, Error(err)
	}

	setRequestAuth(req, creds["username"], creds["password"])
	return creds, nil
}

// getCredsForAPI gets the credentials for LFS API requests and sets the given
// request's Authorization header with them using Basic Authentication.
// 1. Check the LFS URL for authentication. Ex: http://user:pass@example.com
// 2. Check the Git remote URL for authentication IF it's the same scheme and
//    host of the LFS URL.
// 3. Ask 'git credential' to fill in the password from one of the above URLs.
//
// This prefers the Git remote URL for checking credentials so that users only
// have to enter their passwords once for Git and Git LFS. It uses the same
// URL path that Git does, in case 'useHttpPath' is enabled in the Git config.
func getCredsForAPI(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	credsUrl, err := getCredURLForAPI(req)
	if err != nil {
		return nil, Error(err)
	}

	if credsUrl == nil {
		return nil, nil
	}

	creds, err := fillCredentials(credsUrl)
	if err != nil {
		return nil, Error(err)
	}

	if creds != nil {
		setRequestAuth(req, creds["username"], creds["password"])
	}

	return creds, nil
}

func getCredURLForAPI(req *http.Request) (*url.URL, error) {
	apiUrl, err := Config.ObjectUrl("")
	if err != nil {
		return nil, err
	}

	// if the LFS request doesn't match the current LFS url, don't bother
	// attempting to set the Authorization header from the LFS or Git remote URLs.
	if req.URL.Scheme != apiUrl.Scheme ||
		req.URL.Host != apiUrl.Host {
		return req.URL, nil
	}

	if setRequestAuthFromUrl(req, apiUrl) {
		return nil, nil
	}

	credsUrl := apiUrl
	if len(Config.CurrentRemote) > 0 {
		if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
			gitRemoteUrl, err := url.Parse(u)
			if err != nil {
				return nil, err
			}

			if gitRemoteUrl.Scheme == apiUrl.Scheme &&
				gitRemoteUrl.Host == apiUrl.Host {

				if setRequestAuthFromUrl(req, gitRemoteUrl) {
					return nil, nil
				}

				credsUrl = gitRemoteUrl
			}
		}
	}

	return credsUrl, nil
}

func fillCredentials(u *url.URL) (Creds, error) {
	path := strings.TrimPrefix(u.Path, "/")
	creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
	return execCreds(creds, "fill")
}

func saveCredentials(creds Creds, res *http.Response) {
	if creds == nil {
		return
	}

	switch res.StatusCode {
	case 401, 403:
		execCreds(creds, "reject")
	default:
		if res.StatusCode < 300 {
			execCreds(creds, "approve")
		}
	}
}

type Creds map[string]string

func (c Creds) Buffer() *bytes.Buffer {
	buf := new(bytes.Buffer)

	for k, v := range c {
		buf.Write([]byte(k))
		buf.Write([]byte("="))
		buf.Write([]byte(v))
		buf.Write([]byte("\n"))
	}

	return buf
}

type credentialFunc func(Creds, string) (Creds, error)

func execCredsCommand(input Creds, subCommand string) (Creds, error) {
	output := new(bytes.Buffer)
	cmd := exec.Command("git", "credential", subCommand)
	cmd.Stdin = input.Buffer()
	cmd.Stdout = output
	/*
		There is a reason we don't hook up stderr here:
		Git's credential cache daemon helper does not close its stderr, so if this
		process is the process that fires up the daemon, it will wait forever
		(until the daemon exits, really) trying to read from stderr.

		See https://github.com/github/git-lfs/issues/117 for more details.
	*/

	err := cmd.Start()
	if err == nil {
		err = cmd.Wait()
	}

	if _, ok := err.(*exec.ExitError); ok {
		if !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
			return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
				input["protocol"], input["host"])
		}

		// 'git credential' exits with 128 if the helper doesn't fill the username
		// and password values.
		if subCommand == "fill" && err.Error() == "exit status 128" {
			return input, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("'git credential %s' error: %s\n", subCommand, err.Error())
	}

	creds := make(Creds)
	for _, line := range strings.Split(output.String(), "\n") {
		pieces := strings.SplitN(line, "=", 2)
		if len(pieces) < 2 {
			continue
		}
		creds[pieces[0]] = pieces[1]
	}

	return creds, nil
}

var execCreds credentialFunc = execCredsCommand
<commit_msg>Include the username in the creds call if present<commit_after>package lfs

import (
	"bytes"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"strings"
)

// getCreds gets the credentials for the given request's URL, and sets its
// Authorization header with them using Basic Authentication. This is like
// getCredsForAPI(), but skips checking the LFS url or git remote.
func getCreds(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	creds, err := fillCredentials(req.URL)
	if err != nil {
		return nil, Error(err)
	}

	setRequestAuth(req, creds["username"], creds["password"])
	return creds, nil
}

// getCredsForAPI gets the credentials for LFS API requests and sets the given
// request's Authorization header with them using Basic Authentication.
// 1. Check the LFS URL for authentication. Ex: http://user:pass@example.com
// 2. Check the Git remote URL for authentication IF it's the same scheme and
//    host of the LFS URL.
// 3. Ask 'git credential' to fill in the password from one of the above URLs.
//
// This prefers the Git remote URL for checking credentials so that users only
// have to enter their passwords once for Git and Git LFS. It uses the same
// URL path that Git does, in case 'useHttpPath' is enabled in the Git config.
func getCredsForAPI(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	credsUrl, err := getCredURLForAPI(req)
	if err != nil {
		return nil, Error(err)
	}

	if credsUrl == nil {
		return nil, nil
	}

	creds, err := fillCredentials(credsUrl)
	if err != nil {
		return nil, Error(err)
	}

	if creds != nil {
		setRequestAuth(req, creds["username"], creds["password"])
	}

	return creds, nil
}

func getCredURLForAPI(req *http.Request) (*url.URL, error) {
	apiUrl, err := Config.ObjectUrl("")
	if err != nil {
		return nil, err
	}

	// if the LFS request doesn't match the current LFS url, don't bother
	// attempting to set the Authorization header from the LFS or Git remote URLs.
	if req.URL.Scheme != apiUrl.Scheme ||
		req.URL.Host != apiUrl.Host {
		return req.URL, nil
	}

	if setRequestAuthFromUrl(req, apiUrl) {
		return nil, nil
	}

	credsUrl := apiUrl
	if len(Config.CurrentRemote) > 0 {
		if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
			gitRemoteUrl, err := url.Parse(u)
			if err != nil {
				return nil, err
			}

			if gitRemoteUrl.Scheme == apiUrl.Scheme &&
				gitRemoteUrl.Host == apiUrl.Host {

				if setRequestAuthFromUrl(req, gitRemoteUrl) {
					return nil, nil
				}

				credsUrl = gitRemoteUrl
			}
		}
	}

	return credsUrl, nil
}

func fillCredentials(u *url.URL) (Creds, error) {
	path := strings.TrimPrefix(u.Path, "/")
	creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
	if u.User != nil && u.User.Username() != "" {
		creds["username"] = u.User.Username()
	}
	return execCreds(creds, "fill")
}

func saveCredentials(creds Creds, res *http.Response) {
	if creds == nil {
		return
	}

	switch res.StatusCode {
	case 401, 403:
		execCreds(creds, "reject")
	default:
		if res.StatusCode < 300 {
			execCreds(creds, "approve")
		}
	}
}

type Creds map[string]string

func (c Creds) Buffer() *bytes.Buffer {
	buf := new(bytes.Buffer)

	for k, v := range c {
		buf.Write([]byte(k))
		buf.Write([]byte("="))
		buf.Write([]byte(v))
		buf.Write([]byte("\n"))
	}

	return buf
}

type credentialFunc func(Creds, string) (Creds, error)

func execCredsCommand(input Creds, subCommand string) (Creds, error) {
	output := new(bytes.Buffer)
	cmd := exec.Command("git", "credential", subCommand)
	cmd.Stdin = input.Buffer()
	cmd.Stdout = output
	/*
		There is a reason we don't hook up stderr here:
		Git's credential cache daemon helper does not close its stderr, so if this
		process is the process that fires up the daemon, it will wait forever
		(until the daemon exits, really) trying to read from stderr.

		See https://github.com/github/git-lfs/issues/117 for more details.
	*/

	err := cmd.Start()
	if err == nil {
		err = cmd.Wait()
	}

	if _, ok := err.(*exec.ExitError); ok {
		if !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
			return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
				input["protocol"], input["host"])
		}

		// 'git credential' exits with 128 if the helper doesn't fill the username
		// and password values.
		if subCommand == "fill" && err.Error() == "exit status 128" {
			return input, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("'git credential %s' error: %s\n", subCommand, err.Error())
	}

	creds := make(Creds)
	for _, line := range strings.Split(output.String(), "\n") {
		pieces := strings.SplitN(line, "=", 2)
		if len(pieces) < 2 {
			continue
		}
		creds[pieces[0]] = pieces[1]
	}

	return creds, nil
}

var execCreds credentialFunc = execCredsCommand
<|endoftext|>


<commit_before>/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import "flag"
import "fmt"
import "io"
import "io/ioutil"
import "log"
import "os"
import "os/exec"
import "path"
import "runtime"

import "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/compiler/go/cfc"

var packageName string = "git-wip-us.apache.org/repos/asf/lucy.git/go/lucy"
var cfPackageName string = "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish"
var charmonizerC string = "../common/charmonizer.c"
var charmonizerEXE string = "charmonizer"
var charmonyH string = "charmony.h"
var buildDir string
var hostSrcDir string
var buildGO string
var configGO string
var installedLibPath string

func init() {
	_, buildGO, _, _ = runtime.Caller(1)
	buildDir = path.Dir(buildGO)
	hostSrcDir = path.Join(buildDir, "../c/src")
	configGO = path.Join(buildDir, "lucy", "config.go")
	var err error
	installedLibPath, err = cfc.InstalledLibPath(packageName)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	os.Chdir(buildDir)
	flag.Parse()
	action := "build"
	args := flag.Args()
	if len(args) > 0 {
		action = args[0]
	}
	switch action {
	case "build":
		build()
	case "clean":
		clean()
	case "test":
		test()
	case "install":
		install()
	default:
		log.Fatalf("Unrecognized action specified: %s", action)
	}
}

func current(orig, dest string) bool {

	destInfo, err := os.Stat(dest)
	if err != nil {
		if os.IsNotExist(err) {
			// If dest doesn't exist, we're not current.
			return false
		} else {
			log.Fatalf("Unexpected stat err: %s", err)
		}
	}

	// If source is newer than dest, we're not current.
	origInfo, err := os.Stat(orig)
	if err != nil {
		log.Fatalf("Unexpected: %s", err)
	}
	return origInfo.ModTime().Before(destInfo.ModTime())
}

func runCommand(name string, args ...string) {
	command := exec.Command(name, args...)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	err := command.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func configure() {
	if !current(charmonizerC, charmonizerEXE) {
		runCommand("cc", "-o", charmonizerEXE, charmonizerC)
	}
	if !current(charmonizerEXE, charmonyH) {
		runCommand("./charmonizer", "--cc=cc", "--enable-c", "--enable-go",
			"--enable-makefile", "--host=go", "--", "-std=gnu99", "-O2")
	}
}

func runCFC() {
	hierarchy := cfc.NewHierarchy("autogen")
	hierarchy.AddSourceDir("../core")
	hierarchy.Build()
	autogenHeader := "Auto-generated by build.go."
	coreBinding := cfc.NewBindCore(hierarchy, autogenHeader, "")
	modified := coreBinding.WriteAllModified(false)
	if modified {
		cBinding := cfc.NewBindC(hierarchy, autogenHeader, "")
		cBinding.WriteCallbacks()
		cBinding.WriteHostDefs()
		hierarchy.WriteLog()
	}
}

func build() {
	configure()
	runCFC()
	runCommand("make", "-j", "static")
	writeConfigGO()
	runCommand("go", "build", packageName)
}

func test() {
	build()
	runCommand("go", "test", packageName)
}

func copyFile(source, dest string) {
	sourceFH, err := os.Open(source)
	if err != nil {
		log.Fatal(err)
	}
	defer sourceFH.Close()
	destFH, err := os.Create(dest)
	if err != nil {
		log.Fatal(err)
	}
	defer destFH.Close()
	_, err = io.Copy(destFH, sourceFH)
	if err != nil {
		log.Fatalf("io.Copy from %s to %s failed: %s", source, dest, err)
	}
}

func installStaticLib() {
	tempLibPath := path.Join(buildDir, "liblucy.a")
	destDir := path.Dir(installedLibPath)
	if _, err := os.Stat(destDir); os.IsNotExist(err) {
		err = os.MkdirAll(destDir, 0755)
		if err != nil {
			log.Fatalf("Can't create dir '%s': %s", destDir, err)
		}
	}
	os.Remove(installedLibPath)
	copyFile(tempLibPath, installedLibPath)
}

func install() {
	build()
	runCommand("go", "install", packageName)
	installStaticLib()
}

func writeConfigGO() {
	if current(buildGO, configGO) {
		return
	}
	installedLibDir := path.Dir(installedLibPath)
	cfLibPath, err := cfc.InstalledLibPath(cfPackageName)
	if err != nil {
		log.Fatal(err)
	}
	cfLibDir := path.Dir(cfLibPath)
	content := fmt.Sprintf(
		"// Auto-generated by build.go, specifying absolute path to static lib.\n"+
			"package lucy\n"+
			"// #cgo CFLAGS: -I%s/../core\n"+
			"// #cgo CFLAGS: -I%s\n"+
			"// #cgo CFLAGS: -I%s/autogen/include\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -llucy\n"+
			"// #cgo LDFLAGS: -lclownfish\n"+
			"import \"C\"\n",
		buildDir, buildDir, buildDir, buildDir, installedLibDir, cfLibDir)
	ioutil.WriteFile(configGO, []byte(content), 0666)
}

func clean() {
	fmt.Println("Cleaning")
	if _, err := os.Stat("Makefile"); !os.IsNotExist(err) {
		runCommand("make", "clean")
	}
	files := []string{charmonizerEXE, "charmony.h", "Makefile", configGO}
	for _, file := range files {
		err := os.Remove(file)
		if err == nil {
			fmt.Println("Removing", file)
		} else if !os.IsNotExist(err) {
			log.Fatal(err)
		}
	}
}
<commit_msg>Adapt build.go for autogen changes.<commit_after>/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import "flag"
import "fmt"
import "io"
import "io/ioutil"
import "log"
import "os"
import "os/exec"
import "path"
import "runtime"

import "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/compiler/go/cfc"

var packageName string = "git-wip-us.apache.org/repos/asf/lucy.git/go/lucy"
var cfPackageName string = "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish"
var charmonizerC string = "../common/charmonizer.c"
var charmonizerEXE string = "charmonizer"
var charmonyH string = "charmony.h"
var buildDir string
var hostSrcDir string
var buildGO string
var configGO string
var cfbindGO string
var installedLibPath string

func init() {
	_, buildGO, _, _ = runtime.Caller(1)
	buildDir = path.Dir(buildGO)
	hostSrcDir = path.Join(buildDir, "../c/src")
	configGO = path.Join(buildDir, "lucy", "config.go")
	cfbindGO = path.Join(buildDir, "lucy", "cfbind.go")
	var err error
	installedLibPath, err = cfc.InstalledLibPath(packageName)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	os.Chdir(buildDir)
	flag.Parse()
	action := "build"
	args := flag.Args()
	if len(args) > 0 {
		action = args[0]
	}
	switch action {
	case "build":
		build()
	case "clean":
		clean()
	case "test":
		test()
	case "install":
		install()
	default:
		log.Fatalf("Unrecognized action specified: %s", action)
	}
}

func current(orig, dest string) bool {

	destInfo, err := os.Stat(dest)
	if err != nil {
		if os.IsNotExist(err) {
			// If dest doesn't exist, we're not current.
			return false
		} else {
			log.Fatalf("Unexpected stat err: %s", err)
		}
	}

	// If source is newer than dest, we're not current.
	origInfo, err := os.Stat(orig)
	if err != nil {
		log.Fatalf("Unexpected: %s", err)
	}
	return origInfo.ModTime().Before(destInfo.ModTime())
}

func runCommand(name string, args ...string) {
	command := exec.Command(name, args...)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	err := command.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func configure() {
	if !current(charmonizerC, charmonizerEXE) {
		runCommand("cc", "-o", charmonizerEXE, charmonizerC)
	}
	if !current(charmonizerEXE, charmonyH) {
		runCommand("./charmonizer", "--cc=cc", "--enable-c", "--enable-go",
			"--enable-makefile", "--host=go", "--", "-std=gnu99", "-O2")
	}
}

func runCFC() {
	hierarchy := cfc.NewHierarchy("autogen")
	hierarchy.AddSourceDir("../core")
	hierarchy.Build()
	autogenHeader := "Auto-generated by build.go.\n"
	coreBinding := cfc.NewBindCore(hierarchy, autogenHeader, "")
	modified := coreBinding.WriteAllModified(false)
	if modified {
		cfc.RegisterParcelPackage("Clownfish", cfPackageName)
		goBinding := cfc.NewBindGo(hierarchy)
		goBinding.SetHeader(autogenHeader)
		goBinding.SetSuppressInit(true)
		parcel := cfc.FetchParcel("Lucy")
		packageDir := path.Join(buildDir, "lucy")
		goBinding.WriteBindings(parcel, packageDir)
		hierarchy.WriteLog()
	}
}

func build() {
	configure()
	runCFC()
	runCommand("make", "-j", "static")
	writeConfigGO()
	runCommand("go", "build", packageName)
}

func test() {
	build()
	runCommand("go", "test", packageName)
}

func copyFile(source, dest string) {
	sourceFH, err := os.Open(source)
	if err != nil {
		log.Fatal(err)
	}
	defer sourceFH.Close()
	destFH, err := os.Create(dest)
	if err != nil {
		log.Fatal(err)
	}
	defer destFH.Close()
	_, err = io.Copy(destFH, sourceFH)
	if err != nil {
		log.Fatalf("io.Copy from %s to %s failed: %s", source, dest, err)
	}
}

func installStaticLib() {
	tempLibPath := path.Join(buildDir, "liblucy.a")
	destDir := path.Dir(installedLibPath)
	if _, err := os.Stat(destDir); os.IsNotExist(err) {
		err = os.MkdirAll(destDir, 0755)
		if err != nil {
			log.Fatalf("Can't create dir '%s': %s", destDir, err)
		}
	}
	os.Remove(installedLibPath)
	copyFile(tempLibPath, installedLibPath)
}

func install() {
	build()
	runCommand("go", "install", packageName)
	installStaticLib()
}

func writeConfigGO() {
	if current(buildGO, configGO) {
		return
	}
	installedLibDir := path.Dir(installedLibPath)
	cfLibPath, err := cfc.InstalledLibPath(cfPackageName)
	if err != nil {
		log.Fatal(err)
	}
	cfLibDir := path.Dir(cfLibPath)
	content := fmt.Sprintf(
		"// Auto-generated by build.go, specifying absolute path to static lib.\n"+
			"package lucy\n"+
			"// #cgo CFLAGS: -I%s/../core\n"+
			"// #cgo CFLAGS: -I%s\n"+
			"// #cgo CFLAGS: -I%s/autogen/include\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -L%s\n"+
			"// #cgo LDFLAGS: -llucy\n"+
			"// #cgo LDFLAGS: -lclownfish\n"+
			"import \"C\"\n",
		buildDir, buildDir, buildDir, buildDir, installedLibDir, cfLibDir)
	ioutil.WriteFile(configGO, []byte(content), 0666)
}

func clean() {
	fmt.Println("Cleaning")
	if _, err := os.Stat("Makefile"); !os.IsNotExist(err) {
		runCommand("make", "clean")
	}
	files := []string{charmonizerEXE, "charmony.h", "Makefile", configGO, cfbindGO}
	for _, file := range files {
		err := os.Remove(file)
		if err == nil {
			fmt.Println("Removing", file)
		} else if !os.IsNotExist(err) {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strings"
	"text/template"
)

const (
	version = "1.1.1"

	// gotest regular expressions

	// === RUN TestAdd
	gt_startRE = "^=== RUN:? ([a-zA-Z_][^[:space:]]*)"

	// --- PASS: TestSub (0.00 seconds)
	// --- FAIL: TestSubFail (0.00 seconds)
	// --- SKIP: TestSubSkip (0.00 seconds)
	gt_endRE = "^--- (PASS|FAIL|SKIP): ([a-zA-Z_][^[:space:]]*) \\((\\d+(.\\d+)?)"

	// FAIL	_/home/miki/Projects/goroot/src/xunit	0.004s
	// ok  	_/home/miki/Projects/goroot/src/anotherTest	0.000s
	gt_suiteRE = "^(ok|FAIL)[ \t]+([^ \t]+)[ \t]+(\\d+.\\d+)"

	// ?       alipay  [no test files]
	gt_noFiles = "^\\?.*\\[no test files\\]$"
	// FAIL    node/config [build failed]
	gt_buildFailed = `^FAIL.*\[(build|setup) failed\]$`

	// gocheck regular expressions

	// START: mmath_test.go:16: MySuite.TestAdd
	gc_startRE = "START: [^:]+:[^:]+: ([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)"
	// PASS: mmath_test.go:16: MySuite.TestAdd	0.000s
	// FAIL: mmath_test.go:35: MySuite.TestDiv
	gc_endRE = "(PASS|FAIL): [^:]+:[^:]+: ([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)([[:space:]]+([0-9]+.[0-9]+))?"
)

var (
	failOnRace = false
)

type Test struct {
	Name, Time, Message string
	Failed              bool
	Skipped             bool
}

type Suite struct {
	Name   string
	Time   string
	Status string
	Tests  []*Test
}

type SuiteStack struct {
	nodes []*Suite
	count int
}

// Push adds a node to the stack.
func (s *SuiteStack) Push(n *Suite) {
	s.nodes = append(s.nodes[:s.count], n)
	s.count++
}

// Pop removes and returns a node from the stack in last to first order.
func (s *SuiteStack) Pop() *Suite {
	if s.count == 0 {
		return nil
	}
	s.count--
	return s.nodes[s.count]
}

type TestResults struct {
	Suites []*Suite
	Multi  bool
}

func (suite *Suite) NumFailed() int {
	count := 0
	for _, test := range suite.Tests {
		if test.Failed {
			count++
		}
	}

	return count
}

func (suite *Suite) NumSkipped() int {
	count := 0
	for _, test := range suite.Tests {
		if test.Skipped {
			count++
		}
	}

	return count
}

func (suite *Suite) Count() int {
	return len(suite.Tests)
}

func hasDatarace(lines []string) bool {
	has_datarace := regexp.MustCompile("^WARNING: DATA RACE$").MatchString
	for _, line := range lines {
		if has_datarace(line) {
			return true
		}
	}
	return false
}

func gt_Parse(rd io.Reader) ([]*Suite, error) {
	find_start := regexp.MustCompile(gt_startRE).FindStringSubmatch
	find_end := regexp.MustCompile(gt_endRE).FindStringSubmatch
	find_suite := regexp.MustCompile(gt_suiteRE).FindStringSubmatch
	is_nofiles := regexp.MustCompile(gt_noFiles).MatchString
	is_buildFailed := regexp.MustCompile(gt_buildFailed).MatchString
	is_exit := regexp.MustCompile("^exit status -?\\d+").MatchString

	suites := []*Suite{}
	var curTest *Test
	var curSuite *Suite
	var out []string
	suiteStack := SuiteStack{}
	// Handles a test that ended with a panic.
	handlePanic := func() {
		curTest.Failed = true
		curTest.Skipped = false
		curTest.Time = "N/A"
		curSuite.Tests = append(curSuite.Tests, curTest)
		curTest = nil
	}

	// Appends output to the last test.
	appendError := func() error {
		if len(out) > 0 && curSuite != nil && len(curSuite.Tests) > 0 {
			message := strings.Join(out, "\n")
			if curSuite.Tests[len(curSuite.Tests)-1].Message == "" {
				curSuite.Tests[len(curSuite.Tests)-1].Message = message
			} else {
				curSuite.Tests[len(curSuite.Tests)-1].Message += "\n" + message
			}
		}
		out = []string{}
		return nil
	}

	scanner := bufio.NewScanner(rd)
	for lnum := 1; scanner.Scan(); lnum++ {
		line := scanner.Text()

		// TODO: Only outside a suite/test, report as empty suite?
		if is_nofiles(line) {
			continue
		}

		if is_buildFailed(line) {
			return nil, fmt.Errorf("%d: package build failed: %s", lnum, line)
		}

		if curSuite == nil {
			curSuite = &Suite{}
		}

		tokens := find_start(line)
		if tokens != nil {
			if curTest != nil {
				// This occurs when the last test ended with a panic.
				if suiteStack.count == 0 {
					suiteStack.Push(curSuite)
					curSuite = &Suite{Name: curTest.Name}
				} else {
					handlePanic()
				}
			}
			if e := appendError(); e != nil {
				return nil, e
			}
			curTest = &Test{
				Name: tokens[1],
			}
			continue
		}

		tokens = find_end(line)
		if tokens != nil {
			if curTest == nil {
				if suiteStack.count > 0 {
					prevSuite := suiteStack.Pop()
					suites = append(suites, curSuite)
					curSuite = prevSuite
					continue
				} else {
					return nil, fmt.Errorf("%d: orphan end test", lnum)
				}
			}
			if tokens[2] != curTest.Name {
				err := fmt.Errorf("%d: name mismatch (try disabling parallel mode)", lnum)
				return nil, err
			}
			curTest.Failed = (tokens[1] == "FAIL") || (failOnRace && hasDatarace(out))
			curTest.Skipped = (tokens[1] == "SKIP")
			curTest.Time = tokens[3]
			curTest.Message = strings.Join(out, "\n")
			curSuite.Tests = append(curSuite.Tests, curTest)
			curTest = nil
			out = []string{}
			continue
		}

		tokens = find_suite(line)
		if tokens != nil {
			if curTest != nil {
				// This occurs when the last test ended with a panic.
				handlePanic()
			}
			if e := appendError(); e != nil {
				return nil, e
			}
			curSuite.Name = tokens[2]
			curSuite.Time = tokens[3]
			suites = append(suites, curSuite)
			curSuite = nil
			continue
		}

		if is_exit(line) || (line == "FAIL") || (line == "PASS") {
			continue
		}

		out = append(out, line)
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return suites, nil
}

func map2arr(m map[string]*Suite) []*Suite {
	arr := make([]*Suite, 0, len(m))
	for _, suite := range m {
		/* FIXME:
		suite.Status =
		suite.Time =
		*/
		arr = append(arr, suite)
	}

	return arr
}

// gc_Parse parses output of "go test -gocheck.vv", returns a list of tests
// See data/gocheck.out for an example
func gc_Parse(rd io.Reader) ([]*Suite, error) {
	find_start := regexp.MustCompile(gc_startRE).FindStringSubmatch
	find_end := regexp.MustCompile(gc_endRE).FindStringSubmatch

	scanner := bufio.NewScanner(rd)
	var test *Test
	var suites = make(map[string]*Suite)
	var suiteName string
	var out []string

	for lnum := 1; scanner.Scan(); lnum++ {
		line := scanner.Text()
		tokens := find_start(line)
		if len(tokens) > 0 {
			if test != nil {
				return nil, fmt.Errorf("%d: start in middle\n", lnum)
			}
			suiteName = tokens[1]
			test = &Test{Name: tokens[2]}
			out = []string{}
			continue
		}

		tokens = find_end(line)
		if len(tokens) > 0 {
			if test == nil {
				return nil, fmt.Errorf("%d: orphan end", lnum)
			}
			if (tokens[2] != suiteName) || (tokens[3] != test.Name) {
				return nil, fmt.Errorf("%d: suite/name mismatch", lnum)
			}
			test.Message = strings.Join(out, "\n")
			test.Time = tokens[4]
			test.Failed = (tokens[1] == "FAIL")

			suite, ok := suites[suiteName]
			if !ok {
				suite = &Suite{Name: suiteName}
			}
			suite.Tests = append(suite.Tests, test)
			suites[suiteName] = suite

			test = nil
			suiteName = ""
			out = []string{}

			continue
		}

		if test != nil {
			out = append(out, line)
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return map2arr(suites), nil
}

func hasFailures(suites []*Suite) bool {
	for _, suite := range suites {
		if suite.NumFailed() > 0 {
			return true
		}
	}
	return false
}

var xmlTemplate string = `<?xml version="1.0" encoding="utf-8"?>
{{if .Multi}}<testsuites>{{end}}
{{range $suite := .Suites}}  <testsuite name="{{.Name}}" tests="{{.Count}}" errors="0" failures="{{.NumFailed}}" skip="{{.NumSkipped}}">
{{range  $test := $suite.Tests}}    <testcase classname="{{$suite.Name}}" name="{{$test.Name}}" time="{{$test.Time}}">
{{if $test.Skipped }}      <skipped/> {{end}}
{{if $test.Failed }}      <failure type="go.error" message="error">
        <![CDATA[{{$test.Message}}]]>
      </failure>{{end}}    </testcase>
{{end}}  </testsuite>
{{end}}{{if .Multi}}</testsuites>{{end}}
`

// writeXML exits xunit XML of tests to out
func writeXML(suites []*Suite, out io.Writer, bamboo bool) {
	testsResult := TestResults{
		Suites: suites,
		Multi:  bamboo || (len(suites) > 1),
	}
	t := template.New("test template")
	t, err := t.Parse(xmlTemplate)
	if err != nil {
		fmt.Printf("Error in parse %v\n", err)
		return
	}
	err = t.Execute(out, testsResult)
	if err != nil {
		fmt.Printf("Error in execute %v\n", err)
		return
	}
}

// getInput return input io.Reader from file name, if file name is - it will
// return os.Stdin
func getInput(filename string) (io.Reader, error) {
	if filename == "-" || filename == "" {
		return os.Stdin, nil
	}

	return os.Open(filename)
}

// getInput return output io.Writer from file name, if file name is - it will
// return os.Stdout
func getOutput(filename string) (io.Writer, error) {
	if filename == "-" || filename == "" {
		return os.Stdout, nil
	}

	return os.Create(filename)
}

// getIO returns input and output streams from file names
func getIO(inputFile, outputFile string) (io.Reader, io.Writer, error) {
	input, err := getInput(inputFile)
	if err != nil {
		return nil, nil, fmt.Errorf("can't open %s for reading: %s", inputFile, err)
	}

	output, err := getOutput(outputFile)
	if err != nil {
		return nil, nil, fmt.Errorf("can't open %s for writing: %s", outputFile, err)
	}

	return input, output, nil
}

func main() {
	inputFile := flag.String("input", "", "input file (default to stdin)")
	outputFile := flag.String("output", "", "output file (default to stdout)")
	fail := flag.Bool("fail", false, "fail (non zero exit) if any test failed")
	showVersion := flag.Bool("version", false, "print version and exit")
	bamboo := flag.Bool("bamboo", false, "xml compatible with Atlassian's Bamboo")
	is_gocheck := flag.Bool("gocheck", false, "parse gocheck output")
	flag.BoolVar(&failOnRace, "fail-on-race", false, "mark test as failing if it exposes a data race")
	flag.Parse()

	if *showVersion {
		fmt.Printf("go2xunit %s\n", version)
		os.Exit(0)
	}

	// No time ... prefix for error messages
	log.SetFlags(0)

	if flag.NArg() > 0 {
		log.Fatalf("error: %s does not take parameters (did you mean -input?)", os.Args[0])
	}

	input, output, err := getIO(*inputFile, *outputFile)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	var parse func(rd io.Reader) ([]*Suite, error)

	if *is_gocheck {
		parse = gc_Parse
	} else {
		parse = gt_Parse
	}

	suites, err := parse(input)
	if err != nil {
		log.Fatalf("error: %s", err)
	}
	if len(suites) == 0 {
		log.Fatalf("error: no tests found")
		os.Exit(1)
	}

	writeXML(suites, output, *bamboo)
	if *fail && hasFailures(suites) {
		os.Exit(1)
	}
}
<commit_msg>Refactored to only support bamboo-compatible output.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"regexp"
	"strings"
	"text/template"
)

const (
	version = "1.1.1"

	// gotest regular expressions

	// === RUN TestAdd
	gt_startRE = "^=== RUN:? ([a-zA-Z_][^[:space:]]*)"

	// --- PASS: TestSub (0.00 seconds)
	// --- FAIL: TestSubFail (0.00 seconds)
	// --- SKIP: TestSubSkip (0.00 seconds)
	gt_endRE = "^--- (PASS|FAIL|SKIP): ([a-zA-Z_][^[:space:]]*) \\((\\d+(.\\d+)?)"

	// FAIL	_/home/miki/Projects/goroot/src/xunit	0.004s
	// ok  	_/home/miki/Projects/goroot/src/anotherTest	0.000s
	gt_suiteRE = "^(ok|FAIL)[ \t]+([^ \t]+)[ \t]+(\\d+.\\d+)"

	// ?       alipay  [no test files]
	gt_noFiles = "^\\?.*\\[no test files\\]$"
	// FAIL    node/config [build failed]
	gt_buildFailed = `^FAIL.*\[(build|setup) failed\]$`

	// gocheck regular expressions

	// START: mmath_test.go:16: MySuite.TestAdd
	gc_startRE = "START: [^:]+:[^:]+: ([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)"
	// PASS: mmath_test.go:16: MySuite.TestAdd	0.000s
	// FAIL: mmath_test.go:35: MySuite.TestDiv
	gc_endRE = "(PASS|FAIL): [^:]+:[^:]+: ([A-Za-z_][[:word:]]*).([A-Za-z_][[:word:]]*)([[:space:]]+([0-9]+.[0-9]+))?"
)

var (
	failOnRace = false
)

type Test struct {
	Name, Time, Message string
	Failed              bool
	Skipped             bool
}

type Suite struct {
	Name   string
	Time   string
	Status string
	Tests  []*Test
}

type SuiteStack struct {
	nodes []*Suite
	count int
}

// Push adds a node to the stack.
func (s *SuiteStack) Push(n *Suite) {
	s.nodes = append(s.nodes[:s.count], n)
	s.count++
}

// Pop removes and returns a node from the stack in last to first order.
func (s *SuiteStack) Pop() *Suite {
	if s.count == 0 {
		return nil
	}
	s.count--
	return s.nodes[s.count]
}

func (suite *Suite) NumFailed() int {
	count := 0
	for _, test := range suite.Tests {
		if test.Failed {
			count++
		}
	}

	return count
}

func (suite *Suite) NumSkipped() int {
	count := 0
	for _, test := range suite.Tests {
		if test.Skipped {
			count++
		}
	}

	return count
}

func (suite *Suite) Count() int {
	return len(suite.Tests)
}

func hasDatarace(lines []string) bool {
	has_datarace := regexp.MustCompile("^WARNING: DATA RACE$").MatchString
	for _, line := range lines {
		if has_datarace(line) {
			return true
		}
	}
	return false
}

func gt_Parse(rd io.Reader) ([]*Suite, error) {
	find_start := regexp.MustCompile(gt_startRE).FindStringSubmatch
	find_end := regexp.MustCompile(gt_endRE).FindStringSubmatch
	find_suite := regexp.MustCompile(gt_suiteRE).FindStringSubmatch
	is_nofiles := regexp.MustCompile(gt_noFiles).MatchString
	is_buildFailed := regexp.MustCompile(gt_buildFailed).MatchString
	is_exit := regexp.MustCompile("^exit status -?\\d+").MatchString

	suites := []*Suite{}
	var curTest *Test
	var curSuite *Suite
	var out []string
	suiteStack := SuiteStack{}
	// Handles a test that ended with a panic.
	handlePanic := func() {
		curTest.Failed = true
		curTest.Skipped = false
		curTest.Time = "N/A"
		curSuite.Tests = append(curSuite.Tests, curTest)
		curTest = nil
	}

	// Appends output to the last test.
	appendError := func() error {
		if len(out) > 0 && curSuite != nil && len(curSuite.Tests) > 0 {
			message := strings.Join(out, "\n")
			if curSuite.Tests[len(curSuite.Tests)-1].Message == "" {
				curSuite.Tests[len(curSuite.Tests)-1].Message = message
			} else {
				curSuite.Tests[len(curSuite.Tests)-1].Message += "\n" + message
			}
		}
		out = []string{}
		return nil
	}

	scanner := bufio.NewScanner(rd)
	for lnum := 1; scanner.Scan(); lnum++ {
		line := scanner.Text()

		// TODO: Only outside a suite/test, report as empty suite?
		if is_nofiles(line) {
			continue
		}

		if is_buildFailed(line) {
			return nil, fmt.Errorf("%d: package build failed: %s", lnum, line)
		}

		if curSuite == nil {
			curSuite = &Suite{}
		}

		tokens := find_start(line)
		if tokens != nil {
			if curTest != nil {
				// This occurs when the last test ended with a panic.
				if suiteStack.count == 0 {
					suiteStack.Push(curSuite)
					curSuite = &Suite{Name: curTest.Name}
				} else {
					handlePanic()
				}
			}
			if e := appendError(); e != nil {
				return nil, e
			}
			curTest = &Test{
				Name: tokens[1],
			}
			continue
		}

		tokens = find_end(line)
		if tokens != nil {
			if curTest == nil {
				if suiteStack.count > 0 {
					prevSuite := suiteStack.Pop()
					suites = append(suites, curSuite)
					curSuite = prevSuite
					continue
				} else {
					return nil, fmt.Errorf("%d: orphan end test", lnum)
				}
			}
			if tokens[2] != curTest.Name {
				err := fmt.Errorf("%d: name mismatch (try disabling parallel mode)", lnum)
				return nil, err
			}
			curTest.Failed = (tokens[1] == "FAIL") || (failOnRace && hasDatarace(out))
			curTest.Skipped = (tokens[1] == "SKIP")
			curTest.Time = tokens[3]
			curTest.Message = strings.Join(out, "\n")
			curSuite.Tests = append(curSuite.Tests, curTest)
			curTest = nil
			out = []string{}
			continue
		}

		tokens = find_suite(line)
		if tokens != nil {
			if curTest != nil {
				// This occurs when the last test ended with a panic.
				handlePanic()
			}
			if e := appendError(); e != nil {
				return nil, e
			}
			curSuite.Name = tokens[2]
			curSuite.Time = tokens[3]
			suites = append(suites, curSuite)
			curSuite = nil
			continue
		}

		if is_exit(line) || (line == "FAIL") || (line == "PASS") {
			continue
		}

		out = append(out, line)
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return suites, nil
}

func map2arr(m map[string]*Suite) []*Suite {
	arr := make([]*Suite, 0, len(m))
	for _, suite := range m {
		/* FIXME:
		suite.Status =
		suite.Time =
		*/
		arr = append(arr, suite)
	}

	return arr
}

// gc_Parse parses output of "go test -gocheck.vv", returns a list of tests
// See data/gocheck.out for an example
func gc_Parse(rd io.Reader) ([]*Suite, error) {
	find_start := regexp.MustCompile(gc_startRE).FindStringSubmatch
	find_end := regexp.MustCompile(gc_endRE).FindStringSubmatch

	scanner := bufio.NewScanner(rd)
	var test *Test
	var suites = make(map[string]*Suite)
	var suiteName string
	var out []string

	for lnum := 1; scanner.Scan(); lnum++ {
		line := scanner.Text()
		tokens := find_start(line)
		if len(tokens) > 0 {
			if test != nil {
				return nil, fmt.Errorf("%d: start in middle\n", lnum)
			}
			suiteName = tokens[1]
			test = &Test{Name: tokens[2]}
			out = []string{}
			continue
		}

		tokens = find_end(line)
		if len(tokens) > 0 {
			if test == nil {
				return nil, fmt.Errorf("%d: orphan end", lnum)
			}
			if (tokens[2] != suiteName) || (tokens[3] != test.Name) {
				return nil, fmt.Errorf("%d: suite/name mismatch", lnum)
			}
			test.Message = strings.Join(out, "\n")
			test.Time = tokens[4]
			test.Failed = (tokens[1] == "FAIL")

			suite, ok := suites[suiteName]
			if !ok {
				suite = &Suite{Name: suiteName}
			}
			suite.Tests = append(suite.Tests, test)
			suites[suiteName] = suite

			test = nil
			suiteName = ""
			out = []string{}

			continue
		}

		if test != nil {
			out = append(out, line)
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return map2arr(suites), nil
}

func hasFailures(suites []*Suite) bool {
	for _, suite := range suites {
		if suite.NumFailed() > 0 {
			return true
		}
	}
	return false
}

var xmlTemplate string = `<?xml version="1.0" encoding="utf-8"?>
<testsuite name="{{.Name}}" tests="{{.Count}}" errors="0" failures="{{.NumFailed}}" skip="{{.NumSkipped}}">
{{range  $test := .Tests}}
<testcase classname="{{.Name}}" name="{{$test.Name}}" time="{{$test.Time}}">
{{if $test.Skipped }}
<skipped/>
{{end}}
{{if $test.Failed }}
<failure type="go.error" message="error">
<![CDATA[{{$test.Message}}]]>
</failure>
{{end}}
</testcase>
{{end}}
</testsuite>
`

// writeXML exits xunit XML of tests to out
func writeXML(suites []*Suite, outputDir string) error {
	fmt.Printf("Total number of suites: %d\n", len(suites))

	_, derr := os.Stat(outputDir)
	if derr == nil {
		os.RemoveAll(outputDir)
	}
	if derr = os.Mkdir(outputDir, 0777); derr != nil {
		return derr
	}

	for _, suite := range suites {
		resultFile := path.Join(outputDir, strings.Replace(suite.Name, "/", "_", -1)+".xml")
		fmt.Printf("Writing file: %s\n", resultFile)

		out, cerr := os.Create(resultFile)
		if cerr != nil {
			fmt.Printf("Unable to create file: %s (%s)\n", resultFile, cerr)
			return cerr
		}

		t := template.New("test template")
		t, perr := t.Parse(xmlTemplate)
		if perr != nil {
			fmt.Printf("Error in parse %v\n", perr)
			return perr
		}
		eerr := t.Execute(out, suite)
		if eerr != nil {
			fmt.Printf("Error in execute %v\n", eerr)
			return eerr
		}
	}
	return nil
}

// getInput return input io.Reader from file name, if file name is - it will
// return os.Stdin
func getInput(filename string) (io.Reader, error) {
	if filename == "-" || filename == "" {
		return os.Stdin, nil
	}

	return os.Open(filename)
}

// getIO returns input and output streams from file names
func getIO(inputFile string) (io.Reader, error) {
	input, err := getInput(inputFile)
	if err != nil {
		return nil, fmt.Errorf("can't open %s for reading: %s", inputFile, err)
	}

	return input, nil
}

func main() {
	inputFile := flag.String("input", "", "input file (default to stdin)")
	outputDir := flag.String("output", "", "output directory")
	fail := flag.Bool("fail", false, "fail (non zero exit) if any test failed")
	showVersion := flag.Bool("version", false, "print version and exit")
	is_gocheck := flag.Bool("gocheck", false, "parse gocheck output")
	flag.BoolVar(&failOnRace, "fail-on-race", false, "mark test as failing if it exposes a data race")
	flag.Parse()

	if *showVersion {
		fmt.Printf("go2xunit %s\n", version)
		os.Exit(0)
	}

	if len(*outputDir) == 0 {
		log.Fatalf("error: output directory is required (-output)")
	}

	// No time ... prefix for error messages
	log.SetFlags(0)

	if flag.NArg() > 0 {
		log.Fatalf("error: %s does not take parameters (did you mean -input?)", os.Args[0])
	}

	input, err := getIO(*inputFile)
	if err != nil {
		log.Fatalf("error: %s", err)
	}

	var parse func(rd io.Reader) ([]*Suite, error)

	if *is_gocheck {
		parse = gc_Parse
	} else {
		parse = gt_Parse
	}

	suites, err := parse(input)
	if err != nil {
		log.Fatalf("error: %s", err)
	}
	if len(suites) == 0 {
		log.Fatalf("error: no tests found")
		os.Exit(1)
	}

	writeXML(suites, *outputDir)
	if *fail && hasFailures(suites) {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Parse data from the collectd network plugin
// This is modeled after collectd's own network.c
package gollectd

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"os"
	"strings"
)

const (
	TypeCounter  = 0
	TypeGauge    = 1
	TypeDerive   = 2
	TypeAbsolute = 3
)

const (
	// Values taken from commit 633c3966f7 of
	// https://github.com/collectd/collectd/commits/master/src/network.h

	ParseHost           = 0x0000
	ParseTime           = 0x0001
	ParsePlugin         = 0x0002
	ParsePluginInstance = 0x0003
	ParseType           = 0x0004
	ParseTypeInstance   = 0x0005
	ParseValues         = 0x0006
	ParseInterval       = 0x0007
	ParseTimeHR         = 0x0008
	ParseIntervalHR     = 0x0009

	// Notifications
	ParseMessage  = 0x0100
	ParseSeverity = 0x0101

	ParseSignature  = 0x0200
	ParseEncryption = 0x0210
)

var ErrorInvalid = errors.New("gollectd: Invalid packet")
var ErrorUnsupported = errors.New("gollectd: Unsupported packet")
var ErrorUnknownType = errors.New("gollectd: Unknown value type")
var ErrorUnknownDataType = errors.New("gollectd: Unknown data source type")

type Packet struct {
	Hostname       string
	Interval       uint64
	IntervalHR     uint64
	Plugin         string
	PluginInstance string
	Time           uint64
	TimeHR         uint64
	Type           string
	TypeInstance   string
	Values         []Value
}

type Type struct {
	Name string
	Type uint8
	Min  string
	Max  string
}

type Types map[string][]Type

type Value struct {
	Name  string
	Type  uint8
	Value float64
}

func Packets(b []byte, types Types) (*[]Packet, error) {
	packets := make([]Packet, 0)

	buf := bytes.NewBuffer(b)

	var packetHeader struct {
		PartType   uint16
		PartLength uint16
	}

	var err error
	var packet Packet
	var time uint64
	var valueCount uint16
	var valueTypes []uint8

	for buf.Len() > 0 {
		err = binary.Read(buf, binary.BigEndian, &packetHeader)
		if err != nil {
			return nil, err
		}

		if packetHeader.PartLength < 5 {
			return nil, ErrorInvalid
		}

		nextPos := int(packetHeader.PartLength) - 4

		partBytes := buf.Next(nextPos)
		if len(partBytes) < nextPos {
			return nil, ErrorInvalid
		}

		partBuffer := bytes.NewBuffer(partBytes)

		switch packetHeader.PartType {
		case ParseEncryption:
			return nil, ErrorUnsupported
		case ParseHost:
			str := partBuffer.String()
			packet.Hostname = str[0 : len(str)-1]
		case ParseInterval:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.Interval = time
		case ParseIntervalHR:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.IntervalHR = time
		case ParseMessage:
			// ignore (notification)
		case ParsePlugin:
			str := partBuffer.String()
			packet.Plugin = str[0 : len(str)-1]
		case ParsePluginInstance:
			str := partBuffer.String()
			packet.PluginInstance = str[0 : len(str)-1]
		case ParseSeverity:
			// ignore (notification)
		case ParseSignature:
			return nil, ErrorUnsupported
		case ParseTime:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.Time = time
		case ParseTimeHR:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.TimeHR = time
		case ParseType:
			str := partBuffer.String()
			packet.Type = str[0 : len(str)-1]
		case ParseTypeInstance:
			str := partBuffer.String()
			packet.TypeInstance = str[0 : len(str)-1]
		case ParseValues:
			err = binary.Read(partBuffer, binary.BigEndian, &valueCount)
			if err != nil {
				return nil, err
			}

			valueTypes = make([]uint8, valueCount, valueCount)
			packet.Values = make([]Value, valueCount, valueCount)
			var packetValue Value

			err = binary.Read(partBuffer, binary.BigEndian, &valueTypes)
			if err != nil {
				return nil, err
			}

			for i, t := range valueTypes {
				packetValue.Type = t

				if _, ok := types[packet.Type]; ok {
					packetValue.Name = types[packet.Type][i].Name
				}

				switch t {
				case TypeAbsolute:
					var value uint64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeCounter:
					var value uint64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeDerive:
					var value int64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeGauge:
					var value float64
					err = binary.Read(partBuffer, binary.LittleEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				default:
					return nil, ErrorUnknownType
				}

				packet.Values[i] = packetValue
			}

			packets = append(packets, packet)
		default:
			// Ignore unknown fields
		}
	}

	return &packets, nil
}

func TypesDB(path string) (Types, error) {
	// See https://collectd.org/documentation/manpages/types.db.5.shtml

	types := make(Types)

	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	defer file.Close()

	var dsSpec Type

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.Replace(scanner.Text(), "\t", " ", -1)
		fields := strings.Split(line, " ")

		if len(fields) < 2 {
			continue
		}

		if string(fields[0]) == "#" {
			continue
		}

		dataSet := fields[0]
		types[dataSet] = make([]Type, 0)

		for _, dataSources := range fields[1:] {
			if len(dataSources) == 0 {
				continue
			}

			dataSources = strings.Trim(dataSources, ",")

			dataSource := strings.Split(dataSources, ":")

			if len(dataSource) != 4 {
				// set ErrorUnknownDataType somehow
				continue
			}

			dsSpec.Name = dataSource[0]

			switch dataSource[1] {
			case "ABSOLUTE":
				dsSpec.Type = TypeAbsolute
			case "COUNTER":
				dsSpec.Type = TypeCounter
			case "DERIVE":
				dsSpec.Type = TypeDerive
			case "GAUGE":
				dsSpec.Type = TypeGauge
			default:
				// set ErrorUnknownDataType somehow
				continue
			}

			dsSpec.Min = dataSource[2]
			dsSpec.Max = dataSource[3]

			types[dataSet] = append(types[dataSet], dsSpec)
		}
	}

	return types, nil
}
<commit_msg>Add a map of type values to names (e.g. counter -> 0)<commit_after>// Parse data from the collectd network plugin
// This is modeled after collectd's own network.c
package gollectd

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"os"
	"strings"
)

const (
	TypeCounter  = 0
	TypeGauge    = 1
	TypeDerive   = 2
	TypeAbsolute = 3
)

const (
	// Values taken from commit 633c3966f7 of
	// https://github.com/collectd/collectd/commits/master/src/network.h

	ParseHost           = 0x0000
	ParseTime           = 0x0001
	ParsePlugin         = 0x0002
	ParsePluginInstance = 0x0003
	ParseType           = 0x0004
	ParseTypeInstance   = 0x0005
	ParseValues         = 0x0006
	ParseInterval       = 0x0007
	ParseTimeHR         = 0x0008
	ParseIntervalHR     = 0x0009

	// Notifications
	ParseMessage  = 0x0100
	ParseSeverity = 0x0101

	ParseSignature  = 0x0200
	ParseEncryption = 0x0210
)

var ErrorInvalid = errors.New("gollectd: Invalid packet")
var ErrorUnsupported = errors.New("gollectd: Unsupported packet")
var ErrorUnknownType = errors.New("gollectd: Unknown value type")
var ErrorUnknownDataType = errors.New("gollectd: Unknown data source type")

var ValueTypeNames = map[string]uint8{
	"absolute": TypeAbsolute,
	"counter":  TypeCounter,
	"derive":   TypeDerive,
	"gauge":    TypeGauge,
}

var ValueTypeValues = map[uint8]string{
	TypeAbsolute: "absolute",
	TypeCounter:  "counter",
	TypeDerive:   "derive",
	TypeGauge:    "gauge",
}

type Packet struct {
	Hostname       string
	Interval       uint64
	IntervalHR     uint64
	Plugin         string
	PluginInstance string
	Time           uint64
	TimeHR         uint64
	Type           string
	TypeInstance   string
	Values         []Value
}

type Type struct {
	Name string
	Type uint8
	Min  string
	Max  string
}

type Types map[string][]Type

type Value struct {
	Name     string
	Type     uint8
	TypeName string
	Value    float64
}

func Packets(b []byte, types Types) (*[]Packet, error) {
	packets := make([]Packet, 0)

	buf := bytes.NewBuffer(b)

	var packetHeader struct {
		PartType   uint16
		PartLength uint16
	}

	var err error
	var packet Packet
	var time uint64
	var valueCount uint16
	var valueTypes []uint8

	for buf.Len() > 0 {
		err = binary.Read(buf, binary.BigEndian, &packetHeader)
		if err != nil {
			return nil, err
		}

		if packetHeader.PartLength < 5 {
			return nil, ErrorInvalid
		}

		nextPos := int(packetHeader.PartLength) - 4

		partBytes := buf.Next(nextPos)
		if len(partBytes) < nextPos {
			return nil, ErrorInvalid
		}

		partBuffer := bytes.NewBuffer(partBytes)

		switch packetHeader.PartType {
		case ParseEncryption:
			return nil, ErrorUnsupported
		case ParseHost:
			str := partBuffer.String()
			packet.Hostname = str[0 : len(str)-1]
		case ParseInterval:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.Interval = time
		case ParseIntervalHR:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.IntervalHR = time
		case ParseMessage:
			// ignore (notification)
		case ParsePlugin:
			str := partBuffer.String()
			packet.Plugin = str[0 : len(str)-1]
		case ParsePluginInstance:
			str := partBuffer.String()
			packet.PluginInstance = str[0 : len(str)-1]
		case ParseSeverity:
			// ignore (notification)
		case ParseSignature:
			return nil, ErrorUnsupported
		case ParseTime:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.Time = time
		case ParseTimeHR:
			err = binary.Read(partBuffer, binary.BigEndian, &time)
			if err != nil {
				return nil, err
			}

			packet.TimeHR = time
		case ParseType:
			str := partBuffer.String()
			packet.Type = str[0 : len(str)-1]
		case ParseTypeInstance:
			str := partBuffer.String()
			packet.TypeInstance = str[0 : len(str)-1]
		case ParseValues:
			err = binary.Read(partBuffer, binary.BigEndian, &valueCount)
			if err != nil {
				return nil, err
			}

			valueTypes = make([]uint8, valueCount, valueCount)
			packet.Values = make([]Value, valueCount, valueCount)
			var packetValue Value

			err = binary.Read(partBuffer, binary.BigEndian, &valueTypes)
			if err != nil {
				return nil, err
			}

			for i, t := range valueTypes {
				packetValue.Type = t

				if typeName, ok := ValueTypeValues[t]; ok {
					packetValue.TypeName = typeName
				}

				if _, ok := types[packet.Type]; ok {
					packetValue.Name = types[packet.Type][i].Name
				}

				switch t {
				case TypeAbsolute:
					var value uint64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeCounter:
					var value uint64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeDerive:
					var value int64
					err = binary.Read(partBuffer, binary.BigEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				case TypeGauge:
					var value float64
					err = binary.Read(partBuffer, binary.LittleEndian, &value)
					if err != nil {
						return nil, err
					}

					packetValue.Value = float64(value)
				default:
					return nil, ErrorUnknownType
				}

				packet.Values[i] = packetValue
			}

			packets = append(packets, packet)
		default:
			// Ignore unknown fields
		}
	}

	return &packets, nil
}

func TypesDB(path string) (Types, error) {
	// See https://collectd.org/documentation/manpages/types.db.5.shtml

	types := make(Types)

	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	defer file.Close()

	var dsSpec Type

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.Replace(scanner.Text(), "\t", " ", -1)
		fields := strings.Split(line, " ")

		if len(fields) < 2 {
			continue
		}

		if string(fields[0]) == "#" {
			continue
		}

		dataSet := fields[0]
		types[dataSet] = make([]Type, 0)

		for _, dataSources := range fields[1:] {
			if len(dataSources) == 0 {
				continue
			}

			dataSources = strings.Trim(dataSources, ",")

			dataSource := strings.Split(dataSources, ":")

			if len(dataSource) != 4 {
				// set ErrorUnknownDataType somehow
				continue
			}

			dsSpec.Name = dataSource[0]

			if dsType, ok := ValueTypeNames[strings.ToLower(dataSource[1])]; ok {
				dsSpec.Type = dsType
			} else {
				// set ErrorUnknownDataType somehow
				continue
			}

			dsSpec.Min = dataSource[2]
			dsSpec.Max = dataSource[3]

			types[dataSet] = append(types[dataSet], dsSpec)
		}
	}

	return types, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"time"
)

const (
	PomodoriMessage = "Starting Pomodoro Run"
	ShortMessage    = "Starting Short Break"
	LargeMessage    = "Starting Large Break"
)

var pomodori, shortBreak, largeBreak, pomodoriRun int

// initialize the flags/options for the command line
func init() {
	flag.IntVar(&pomodori, "p", 25, "Pomodoros work time (minutes)")
	flag.IntVar(&shortBreak, "s", 5, "Short break time (minutes)")
	flag.IntVar(&largeBreak, "l", 30, "Large break time (minutes)")
	flag.IntVar(&pomodoriRun, "r", 4, "Pomodori Runs, How many pomodoro runs until large break")
}

func sleepTimer(t int, message string) {
	// notify is a function that lives in notification.go
	notify(message)
	fmt.Println(message)
	time.Sleep(time.Duration(t) * time.Minute)
}

// pretty prints the usage of the gomodoro command when a bad flag is used
func show_usage() {
	fmt.Fprintf(os.Stderr,
		"Usage: %s [options]\n\n",
		os.Args[0])
	fmt.Fprintf(os.Stderr,
		"Options:\n")
	flag.PrintDefaults()
}

func main() {
	flag.Usage = show_usage
	flag.Parse()

	for i := 1; i <= pomodoriRun; i++ {
		fmt.Println("Pomodoro run #", i)
		sleepTimer(pomodori, PomodoriMessage)

		if i%4 == 0 || i == (pomodoriRun) {
			fmt.Print("Large break: ")
			sleepTimer(largeBreak, LargeMessage)
		} else {
			fmt.Print("Short break: ")
			sleepTimer(shortBreak, ShortMessage)
		}
	}

}
<commit_msg>Clean console output a bit<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"time"
)

const (
	PomodoriMessage = "Starting Pomodoro Run"
	ShortMessage    = "Starting Short Break"
	LargeMessage    = "Starting Large Break"
)

var pomodori, shortBreak, largeBreak, pomodoriRun int

// initialize the flags/options for the command line
func init() {
	flag.IntVar(&pomodori, "p", 25, "Pomodoros work time (minutes)")
	flag.IntVar(&shortBreak, "s", 5, "Short break time (minutes)")
	flag.IntVar(&largeBreak, "l", 30, "Large break time (minutes)")
	flag.IntVar(&pomodoriRun, "r", 4, "Pomodori Runs, How many pomodoro runs until large break")
}

func sleepTimer(t int, message string) {
	// notify is a function that lives in notification.go
	notify(message)
	fmt.Println(message)
	time.Sleep(time.Duration(t) * time.Minute)
}

// pretty prints the usage of the gomodoro command when a bad flag is used
func show_usage() {
	fmt.Fprintf(os.Stderr,
		"Usage: %s [options]\n\n",
		os.Args[0])
	fmt.Fprintf(os.Stderr,
		"Options:\n")
	flag.PrintDefaults()
}

func main() {
	flag.Usage = show_usage
	flag.Parse()

	for i := 1; i <= pomodoriRun; i++ {
		fmt.Println("Run #", i)
		sleepTimer(pomodori, PomodoriMessage)

		if i%4 == 0 || i == (pomodoriRun) {
			sleepTimer(largeBreak, LargeMessage)
		} else {
			sleepTimer(shortBreak, ShortMessage)
		}
	}

}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Fredy Wijaya
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"os"
)

const (
	author string = "Fredy Wijaya"
	leftX  int    = 2
	leftY  int    = 0
	rightX int    = 22
	rightY int    = 20
	xStep  int    = 1
	yStep  int    = 1
)

type coordinate struct {
	y      int
	x      int
	filled bool
}

type game struct {
	coordinates [][]coordinate
}

func (g *game) moveLeft() {
	revert := false
	for row := 0; row < len(g.coordinates); row++ {
		for col := 0; col < len(g.coordinates[row]); col++ {
			g.coordinates[row][col].x -= xStep
			if g.coordinates[row][col].x <= leftX && g.coordinates[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.coordinates); row++ {
			for col := 0; col < len(g.coordinates[row]); col++ {
				g.coordinates[row][col].x += xStep
			}
		}
	}
}

func (g *game) moveRight() {
	revert := false
	for row := 0; row < len(g.coordinates); row++ {
		for col := len(g.coordinates[row]) - 1; col >= 0; col-- {
			g.coordinates[row][col].x += xStep
			if g.coordinates[row][col].x+1 >= rightX && g.coordinates[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.coordinates); row++ {
			for col := 0; col < len(g.coordinates[row]); col++ {
				g.coordinates[row][col].x -= xStep
			}
		}
	}
}

func (g *game) moveDown() {
	revert := false
	for row := 0; row < len(g.coordinates); row++ {
		for col := 0; col < len(g.coordinates[row]); col++ {
			g.coordinates[row][col].y += yStep
			if g.coordinates[row][col].y >= rightY && g.coordinates[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.coordinates); row++ {
			for col := 0; col < len(g.coordinates[row]); col++ {
				g.coordinates[row][col].y -= yStep
			}
		}
	}
}

func (g *game) rotate() {
	// keep a backup for reverting
	oldCoordinates := [][]coordinate{}
	for row := 0; row < len(g.coordinates); row++ {
		oldCoordinates = append(oldCoordinates, []coordinate{})
		for col := 0; col < len(g.coordinates[row]); col++ {
			oldCoordinate := coordinate{
				x:      g.coordinates[row][col].x,
				y:      g.coordinates[row][col].y,
				filled: g.coordinates[row][col].filled,
			}
			oldCoordinates[row] = append(oldCoordinates[row], oldCoordinate)
		}
	}

	// transpose
	tmpCoordinates := [][]coordinate{}
	for row := 0; row < len(g.coordinates); row++ {
		tmpCoordinates = append(tmpCoordinates, []coordinate{})
		for col := 0; col < len(g.coordinates[row]); col++ {
			tmpCoordinates[row] = append(tmpCoordinates[row], g.coordinates[col][row])
		}
	}

	for row := 0; row < len(g.coordinates); row++ {
		for col := 0; col < len(g.coordinates[row]); col++ {
			g.coordinates[row][col].filled = tmpCoordinates[row][col].filled
		}
	}

	// reverse
	for row := 0; row < len(g.coordinates); row++ {
		lcol := 0
		rcol := len(g.coordinates[row]) - 1
		for lcol < len(g.coordinates[row])/2 {
			tmp := g.coordinates[row][rcol].filled
			g.coordinates[row][rcol].filled = g.coordinates[row][lcol].filled
			g.coordinates[row][lcol].filled = tmp
			lcol++
			rcol--
		}
	}

	revert := false
	for row := 0; row < len(g.coordinates); row++ {
		for col := len(g.coordinates[row]) - 1; col >= 0; col-- {
			if g.coordinates[row][col].x+1 >= rightX && g.coordinates[row][col].filled ||
				g.coordinates[row][col].x <= leftX && g.coordinates[row][col].filled ||
				g.coordinates[row][col].y >= rightY && g.coordinates[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		g.coordinates = oldCoordinates
	}
}

func drawTopLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u250c'
		} else if i == rightX {
			c = '\u2510'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, leftY, c, colorDefault, colorDefault)
	}
}

func drawLeftLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(leftX, i, c, colorDefault, colorDefault)
	}
}

func drawBottomLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u2514'
		} else if i == rightX {
			c = '\u2518'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, rightY, c, colorDefault, colorDefault)
	}
}

func drawRightLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(rightX, i, c, colorDefault, colorDefault)
	}
}

func drawBox() {
	drawTopLine()
	drawLeftLine()
	drawRightLine()
	drawBottomLine()
}

func drawBlock(g *game) {
	colorDefault := termbox.ColorDefault
	for row := 0; row < len(g.coordinates); row++ {
		for col := 0; col < len(g.coordinates[row]); col++ {
			c := '\u2588'
			filled := g.coordinates[row][col].filled
			if !filled {
				c = ' '
			}
			x := g.coordinates[row][col].x
			y := g.coordinates[row][col].y
			termbox.SetCell(x, y, c, colorDefault, colorDefault)
			//if col != len(g.coordinates[row])-1 {
			termbox.SetCell(x+1, y, c, colorDefault, colorDefault)
			//}
		}
	}
}

func redrawAll(game *game) {
	colorDefault := termbox.ColorDefault
	termbox.Clear(colorDefault, colorDefault)

	drawBlock(game)
	drawBox()

	termbox.Flush()
}

func runGame() {
	err := termbox.Init()
	if err != nil {
		errorAndExit(err)
	}
	defer termbox.Close()

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	game := &game{
		coordinates: [][]coordinate{
			//{
			//	{4, 4, false}, {4, 6, false}, {4, 8, true},
			//},
			//{
			//	{5, 4, true}, {5, 6, true}, {5, 8, true},
			//},
			//{
			//	{6, 4, false}, {6, 6, false}, {6, 8, false},
			//},

			{
				{4, 4, false}, {4, 6, false}, {4, 8, false}, {4, 10, false},
			},
			{
				{5, 4, true}, {5, 6, true}, {5, 8, true}, {5, 10, true},
			},
			{
				{6, 4, false}, {6, 6, false}, {6, 8, false}, {6, 10, false},
			},
			{
				{7, 4, false}, {7, 6, false}, {7, 8, false}, {7, 10, false},
			},
		},
	}

	redrawAll(game)
exitGame:
	for {
		for {
			select {
			case ev := <-eventQueue:
				switch ev.Key {
				case termbox.KeyEsc:
					break exitGame
				case termbox.KeyArrowLeft:
					game.moveLeft()
				case termbox.KeyArrowRight:
					game.moveRight()
				case termbox.KeyArrowDown:
					game.moveDown()
				case termbox.KeySpace:
					game.rotate()
				}
			}
			redrawAll(game)
		}
	}
}

func errorAndExit(message interface{}) {
	fmt.Println(message)
	os.Exit(1)
}

func main() {
	runGame()
}
<commit_msg>Define all the shapes<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Fredy Wijaya
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"os"
)

const (
	author string = "Fredy Wijaya"
	leftX  int    = 2
	leftY  int    = 0
	rightX int    = 22
	rightY int    = 20
	xStep  int    = 1
	yStep  int    = 1
)

type block [][]coordinate

var (
	shapes []block = []block{
		{
			{
				{1, 8, false}, {1, 10, false}, {1, 12, false}, {1, 14, false},
			},
			{
				{2, 8, true}, {2, 10, true}, {2, 12, true}, {2, 14, true},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false}, {3, 14, false},
			},
			{
				{4, 8, false}, {4, 10, false}, {4, 12, false}, {4, 14, false},
			},
		},
		{
			{
				{1, 8, true}, {1, 10, false}, {1, 12, false},
			},
			{
				{2, 8, true}, {2, 10, true}, {2, 12, true},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false},
			},
		},
		{
			{
				{1, 8, false}, {1, 10, false}, {1, 12, true},
			},
			{
				{2, 8, true}, {2, 10, true}, {2, 12, true},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false},
			},
		},
		{
			{
				{1, 10, true}, {1, 12, true},
			},
			{
				{2, 10, true}, {2, 12, true},
			},
		},
		{
			{
				{1, 8, false}, {1, 10, true}, {1, 12, true},
			},
			{
				{2, 8, true}, {2, 10, true}, {2, 12, false},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false},
			},
		},
		{
			{
				{1, 8, false}, {1, 10, true}, {1, 12, false},
			},
			{
				{2, 8, true}, {2, 10, true}, {2, 12, true},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false},
			},
		},
		{
			{
				{1, 8, true}, {1, 10, true}, {1, 12, false},
			},
			{
				{2, 8, false}, {2, 10, true}, {2, 12, true},
			},
			{
				{3, 8, false}, {3, 10, false}, {3, 12, false},
			},
		},
	}
)

type coordinate struct {
	y      int
	x      int
	filled bool
}

type game struct {
	block block
}

func (g *game) moveLeft() {
	revert := false
	for row := 0; row < len(g.block); row++ {
		for col := 0; col < len(g.block[row]); col++ {
			g.block[row][col].x -= xStep
			if g.block[row][col].x <= leftX && g.block[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.block); row++ {
			for col := 0; col < len(g.block[row]); col++ {
				g.block[row][col].x += xStep
			}
		}
	}
}

func (g *game) moveRight() {
	revert := false
	for row := 0; row < len(g.block); row++ {
		for col := len(g.block[row]) - 1; col >= 0; col-- {
			g.block[row][col].x += xStep
			if g.block[row][col].x+1 >= rightX && g.block[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.block); row++ {
			for col := 0; col < len(g.block[row]); col++ {
				g.block[row][col].x -= xStep
			}
		}
	}
}

func (g *game) moveDown() {
	revert := false
	for row := 0; row < len(g.block); row++ {
		for col := 0; col < len(g.block[row]); col++ {
			g.block[row][col].y += yStep
			if g.block[row][col].y >= rightY && g.block[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		for row := 0; row < len(g.block); row++ {
			for col := 0; col < len(g.block[row]); col++ {
				g.block[row][col].y -= yStep
			}
		}
	}
}

func (g *game) rotate() {
	// keep a backup for reverting
	oldBlock := block{}
	for row := 0; row < len(g.block); row++ {
		oldBlock = append(oldBlock, []coordinate{})
		for col := 0; col < len(g.block[row]); col++ {
			oldCoordinate := coordinate{
				x:      g.block[row][col].x,
				y:      g.block[row][col].y,
				filled: g.block[row][col].filled,
			}
			oldBlock[row] = append(oldBlock[row], oldCoordinate)
		}
	}

	// transpose
	tmpBlock := block{}
	for row := 0; row < len(g.block); row++ {
		tmpBlock = append(tmpBlock, []coordinate{})
		for col := 0; col < len(g.block[row]); col++ {
			tmpBlock[row] = append(tmpBlock[row], g.block[col][row])
		}
	}

	for row := 0; row < len(g.block); row++ {
		for col := 0; col < len(g.block[row]); col++ {
			g.block[row][col].filled = tmpBlock[row][col].filled
		}
	}

	// reverse
	for row := 0; row < len(g.block); row++ {
		lcol := 0
		rcol := len(g.block[row]) - 1
		for lcol < len(g.block[row])/2 {
			tmp := g.block[row][rcol].filled
			g.block[row][rcol].filled = g.block[row][lcol].filled
			g.block[row][lcol].filled = tmp
			lcol++
			rcol--
		}
	}

	revert := false
	for row := 0; row < len(g.block); row++ {
		for col := len(g.block[row]) - 1; col >= 0; col-- {
			if g.block[row][col].x+1 >= rightX && g.block[row][col].filled ||
				g.block[row][col].x <= leftX && g.block[row][col].filled ||
				g.block[row][col].y >= rightY && g.block[row][col].filled {
				revert = true
			}
		}
	}
	if revert {
		g.block = oldBlock
	}
}

func drawTopLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u250c'
		} else if i == rightX {
			c = '\u2510'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, leftY, c, colorDefault, colorDefault)
	}
}

func drawLeftLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(leftX, i, c, colorDefault, colorDefault)
	}
}

func drawBottomLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u2514'
		} else if i == rightX {
			c = '\u2518'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, rightY, c, colorDefault, colorDefault)
	}
}

func drawRightLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(rightX, i, c, colorDefault, colorDefault)
	}
}

func drawBox() {
	drawTopLine()
	drawLeftLine()
	drawRightLine()
	drawBottomLine()
}

func drawBlock(g *game) {
	colorDefault := termbox.ColorDefault
	for row := 0; row < len(g.block); row++ {
		for col := 0; col < len(g.block[row]); col++ {
			c := '\u2588'
			filled := g.block[row][col].filled
			if !filled {
				c = ' '
			}
			x := g.block[row][col].x
			y := g.block[row][col].y
			termbox.SetCell(x, y, c, colorDefault, colorDefault)
			//if col != len(g.coordinates[row])-1 {
			termbox.SetCell(x+1, y, c, colorDefault, colorDefault)
			//}
		}
	}
}

func redrawAll(game *game) {
	colorDefault := termbox.ColorDefault
	termbox.Clear(colorDefault, colorDefault)

	drawBlock(game)
	drawBox()

	termbox.Flush()
}

func runGame() {
	err := termbox.Init()
	if err != nil {
		errorAndExit(err)
	}
	defer termbox.Close()

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	game := &game{
		block: shapes[6],
	}

	redrawAll(game)
exitGame:
	for {
		for {
			select {
			case ev := <-eventQueue:
				switch ev.Key {
				case termbox.KeyEsc:
					break exitGame
				case termbox.KeyArrowLeft:
					game.moveLeft()
				case termbox.KeyArrowRight:
					game.moveRight()
				case termbox.KeyArrowDown:
					game.moveDown()
				case termbox.KeySpace:
					game.rotate()
				}
			}
			redrawAll(game)
		}
	}
}

func errorAndExit(message interface{}) {
	fmt.Println(message)
	os.Exit(1)
}

func main() {
	runGame()
}
<|endoftext|>


<commit_before>package mansion

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/itchio/butler/buildinfo"
	"github.com/itchio/butler/comm"
	itchio "github.com/itchio/go-itchio"
	"github.com/itchio/httpkit/timeout"
	"github.com/itchio/wharf/pwr"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type DoCommand func(ctx *Context)

type Context struct {
	App      *kingpin.Application
	Commands map[string]DoCommand

	// Identity is the path to the credentials file
	Identity string

	// String to include in our user-agent
	UserAgentAddition string

	// Quiet silences all output
	Quiet bool

	// Verbose enables chatty output
	Verbose bool

	// Verbose enables JSON output
	JSON bool

	// Path to the local sqlite database
	DBPath string

	CompressionAlgorithm string
	CompressionQuality   int

	HTTPClient    *http.Client
	HTTPTransport *http.Transport

	// url of the itch.io API server we're talking to
	apiAddress string
	// url of the itch.io web instance we're talking to
	webAddress string
}

func NewContext(app *kingpin.Application) *Context {
	client := timeout.NewDefaultClient()
	originalTransport := client.Transport.(*http.Transport)

	ctx := &Context{
		App:           app,
		Commands:      make(map[string]DoCommand),
		HTTPClient:    client,
		HTTPTransport: originalTransport,
	}

	client.Transport = &UserAgentSetter{
		OriginalTransport: originalTransport,
		Context:           ctx,
	}

	return ctx
}

func (ctx *Context) Register(clause *kingpin.CmdClause, do DoCommand) {
	ctx.Commands[clause.FullCommand()] = do
}

func (ctx *Context) Must(err error) {
	if err != nil {
		if ctx.Verbose || ctx.JSON {
			comm.Dief("%+v", err)
		} else {
			comm.Dief("%s", err)
		}
	}
}

func (ctx *Context) UserAgent() string {
	version := buildinfo.Version
	if version == "head" && buildinfo.Commit != "" {
		version = buildinfo.Commit
	}

	res := fmt.Sprintf("butler/%s", version)
	if ctx.UserAgentAddition != "" {
		res = fmt.Sprintf("%s %s", res, ctx.UserAgentAddition)
	}
	return res
}

func (ctx *Context) CompressionSettings() pwr.CompressionSettings {
	var algo pwr.CompressionAlgorithm

	switch ctx.CompressionAlgorithm {
	case "none":
		algo = pwr.CompressionAlgorithm_NONE
	case "brotli":
		algo = pwr.CompressionAlgorithm_BROTLI
	case "gzip":
		algo = pwr.CompressionAlgorithm_GZIP
	default:
		panic(fmt.Errorf("Unknown compression algorithm: %s", algo))
	}

	return pwr.CompressionSettings{
		Algorithm: algo,
		Quality:   int32(ctx.CompressionQuality),
	}
}

func (ctx *Context) DefaultCtx() context.Context {
	defaultCtx, _ := context.WithTimeout(context.Background(), 2*time.Second)
	return defaultCtx
}

func (ctx *Context) NewClient(key string) *itchio.Client {
	client := itchio.ClientWithKey(key)
	client.HTTPClient = ctx.HTTPClient
	client.SetServer(ctx.APIAddress())
	client.UserAgent = ctx.UserAgent()
	return client
}

func (ctx *Context) WebAddress() string {
	return ctx.webAddress
}

func (ctx *Context) APIAddress() string {
	return ctx.apiAddress
}

func (ctx *Context) SetAddress(address string) {
	var err error
	ctx.webAddress, err = stripApiSubdomain(address)
	ctx.Must(err)
	ctx.apiAddress, err = addApiSubdomain(address)
	ctx.Must(err)
}

func (ctx *Context) EnsureDBPath() {
	if ctx.DBPath == "" {
		comm.Dief("butlerd: Missing database path: use --dbpath path/to/butler.db")
	}
}

//

type UserAgentSetter struct {
	OriginalTransport http.RoundTripper
	Context           *Context
}

var _ http.RoundTripper = (*UserAgentSetter)(nil)

func (uas *UserAgentSetter) RoundTrip(req *http.Request) (*http.Response, error) {
	req.Header.Set("User-Agent", uas.Context.UserAgent())
	return uas.OriginalTransport.RoundTrip(req)
}
<commit_msg>update default context timeout to 15 seconds<commit_after>package mansion

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/itchio/butler/buildinfo"
	"github.com/itchio/butler/comm"
	itchio "github.com/itchio/go-itchio"
	"github.com/itchio/httpkit/timeout"
	"github.com/itchio/wharf/pwr"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type DoCommand func(ctx *Context)

type Context struct {
	App      *kingpin.Application
	Commands map[string]DoCommand

	// Identity is the path to the credentials file
	Identity string

	// String to include in our user-agent
	UserAgentAddition string

	// Quiet silences all output
	Quiet bool

	// Verbose enables chatty output
	Verbose bool

	// Verbose enables JSON output
	JSON bool

	// Path to the local sqlite database
	DBPath string

	CompressionAlgorithm string
	CompressionQuality   int

	HTTPClient    *http.Client
	HTTPTransport *http.Transport

	// url of the itch.io API server we're talking to
	apiAddress string
	// url of the itch.io web instance we're talking to
	webAddress string
}

func NewContext(app *kingpin.Application) *Context {
	client := timeout.NewDefaultClient()
	originalTransport := client.Transport.(*http.Transport)

	ctx := &Context{
		App:           app,
		Commands:      make(map[string]DoCommand),
		HTTPClient:    client,
		HTTPTransport: originalTransport,
	}

	client.Transport = &UserAgentSetter{
		OriginalTransport: originalTransport,
		Context:           ctx,
	}

	return ctx
}

func (ctx *Context) Register(clause *kingpin.CmdClause, do DoCommand) {
	ctx.Commands[clause.FullCommand()] = do
}

func (ctx *Context) Must(err error) {
	if err != nil {
		if ctx.Verbose || ctx.JSON {
			comm.Dief("%+v", err)
		} else {
			comm.Dief("%s", err)
		}
	}
}

func (ctx *Context) UserAgent() string {
	version := buildinfo.Version
	if version == "head" && buildinfo.Commit != "" {
		version = buildinfo.Commit
	}

	res := fmt.Sprintf("butler/%s", version)
	if ctx.UserAgentAddition != "" {
		res = fmt.Sprintf("%s %s", res, ctx.UserAgentAddition)
	}
	return res
}

func (ctx *Context) CompressionSettings() pwr.CompressionSettings {
	var algo pwr.CompressionAlgorithm

	switch ctx.CompressionAlgorithm {
	case "none":
		algo = pwr.CompressionAlgorithm_NONE
	case "brotli":
		algo = pwr.CompressionAlgorithm_BROTLI
	case "gzip":
		algo = pwr.CompressionAlgorithm_GZIP
	default:
		panic(fmt.Errorf("Unknown compression algorithm: %s", algo))
	}

	return pwr.CompressionSettings{
		Algorithm: algo,
		Quality:   int32(ctx.CompressionQuality),
	}
}

func (ctx *Context) DefaultCtx() context.Context {
	defaultCtx, _ := context.WithTimeout(context.Background(), 15*time.Second)
	return defaultCtx
}

func (ctx *Context) NewClient(key string) *itchio.Client {
	client := itchio.ClientWithKey(key)
	client.HTTPClient = ctx.HTTPClient
	client.SetServer(ctx.APIAddress())
	client.UserAgent = ctx.UserAgent()
	return client
}

func (ctx *Context) WebAddress() string {
	return ctx.webAddress
}

func (ctx *Context) APIAddress() string {
	return ctx.apiAddress
}

func (ctx *Context) SetAddress(address string) {
	var err error
	ctx.webAddress, err = stripApiSubdomain(address)
	ctx.Must(err)
	ctx.apiAddress, err = addApiSubdomain(address)
	ctx.Must(err)
}

func (ctx *Context) EnsureDBPath() {
	if ctx.DBPath == "" {
		comm.Dief("butlerd: Missing database path: use --dbpath path/to/butler.db")
	}
}

//

type UserAgentSetter struct {
	OriginalTransport http.RoundTripper
	Context           *Context
}

var _ http.RoundTripper = (*UserAgentSetter)(nil)

func (uas *UserAgentSetter) RoundTrip(req *http.Request) (*http.Response, error) {
	req.Header.Set("User-Agent", uas.Context.UserAgent())
	return uas.OriginalTransport.RoundTrip(req)
}
<|endoftext|>


<commit_before>package master

import (
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/h2oai/steamY/lib/fs"
	"github.com/h2oai/steamY/master/az"
	"github.com/h2oai/steamY/srv/compiler"
	srvweb "github.com/h2oai/steamY/srv/web"
)

const (
	paramType      = "type"
	paramTypeModel = "model"
	paramArtifact  = "artifact"
	paramProjectId = "project-id"
	paramLabelName = "label-name"

	// model artifact types
	javaClass    = "java-class"     // foo.java
	javaClassDep = "java-class-dep" // gen-model.jar
	javaJar      = "java-jar"       // foo.jar
	javaWar      = "java-war"       // foo.war
)

type DownloadHandler struct {
	az                     az.Az
	workingDirectory       string
	webService             srvweb.Service
	compilerServiceAddress string
}

func newDownloadHandler(az az.Az, workingDirectory string, webService srvweb.Service, compilerServiceAddress string) *DownloadHandler {
	return &DownloadHandler{
		az,
		workingDirectory,
		webService,
		compilerServiceAddress,
	}
}

func (s *DownloadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("File download request received.")

	pz, azerr := s.az.Identify(r)
	if azerr != nil {
		log.Println(azerr)
		http.Error(w, fmt.Sprintf("Authentication failed: %s", azerr), http.StatusForbidden)
	}

	values := r.URL.Query()

	typ := values.Get(paramType)

	if len(typ) == 0 {
		http.Error(w, fmt.Sprintf("Missing %s", paramType), http.StatusBadRequest)
		return
	}

	switch typ {
	case paramTypeModel:
		artifact := values.Get(paramArtifact)

		if len(artifact) == 0 {
			http.Error(w, fmt.Sprintf("Missing %s", paramArtifact), http.StatusBadRequest)
			return
		}

		switch artifact {
		case javaClass, javaClassDep, javaJar, javaWar:
			projectIdValue := values.Get(paramProjectId)
			if len(projectIdValue) == 0 {
				http.Error(w, fmt.Sprintf("Missing %s", paramProjectId), http.StatusBadRequest)
				return
			}

			projectId, err := strconv.ParseInt(projectIdValue, 10, 64)
			if err != nil {
				http.Error(w, fmt.Sprintf("Not a serial number %s=%s: %s", paramProjectId, projectIdValue, err), http.StatusBadRequest)
				return
			}

			if projectId <= 0 {
				http.Error(w, fmt.Sprintf("Invalid %s: %s", paramProjectId, projectId), http.StatusBadRequest)
				return
			}

			labelName := values.Get(paramLabelName)
			if len(labelName) == 0 {
				http.Error(w, fmt.Sprintf("Missing %s", paramLabelName), http.StatusBadRequest)
				return
			}

			labels, err := s.webService.GetLabelsForProject(pz, projectId)
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed reading labels for project %d: %s", projectId, err), http.StatusInternalServerError)
				return
			}

			for _, label := range labels {
				if label.Name == labelName {
					if label.ModelId > 0 {
						// Call the API to get the model details.
						// We assume that if the GetModel() call succeeds, the principal has
						//   permissions and privileges to read this model, and consequently
						//   allowed to download it.
						model, err := s.webService.GetModel(pz, label.ModelId)
						if err != nil {
							http.Error(w, fmt.Sprintf("Failed reading model for project %d, label %s: %s", projectId, labelName, err), http.StatusUnauthorized)
							return
						}
						modelLocation := model.Location
						if len(modelLocation) == 0 {
							http.Error(w, fmt.Sprintf("Failed reading model %d: the model was not saved correctly", model.Id), http.StatusNotFound)
							return
						}

						var filePath string
						switch artifact {
						case javaClass:
							filePath = fs.GetJavaModelPath(s.workingDirectory, model.Location, model.LogicalName)

						case javaClassDep:
							filePath = fs.GetGenModelPath(s.workingDirectory, model.Location)
						case javaWar:
							compilerService := compiler.NewService(s.compilerServiceAddress)
							warFilePath, err := compilerService.CompileModel(
								s.workingDirectory,
								model.Location,
								model.LogicalName,
								"war",
							)
							if err != nil {
								http.Error(w, err.Error(), http.StatusInternalServerError)
								return
							}
							filePath = warFilePath

						case javaJar:
							compilerService := compiler.NewService(s.compilerServiceAddress)
							jarFilePath, err := compilerService.CompileModel(
								s.workingDirectory,
								model.Location,
								model.LogicalName,
								"jar",
							)
							if err != nil {
								http.Error(w, err.Error(), http.StatusInternalServerError)
								return
							}
							filePath = jarFilePath
						}

						// Delegate to builtin.
						// Can result in 200, 404, 403 or 500 based on file availability and permissions.
						http.ServeFile(w, r, filePath)
						return
					}
					break
				}
			}

			http.Error(w, fmt.Sprintf("No models found for label: %s", labelName), http.StatusNotFound)
			return

		default:
			http.Error(w, fmt.Sprintf("Invalid %s: %s", paramArtifact, artifact), http.StatusBadRequest)
			return
		}
	default:
		http.Error(w, fmt.Sprintf("Invalid %s: %s", paramType, typ), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusNotFound)
	http.Error(w, "Not Found", http.StatusNotFound)
}
<commit_msg>STEAM-272 Implement API for downloading model assets by model id.<commit_after>package master

import (
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/h2oai/steamY/lib/fs"
	"github.com/h2oai/steamY/master/az"
	"github.com/h2oai/steamY/srv/compiler"
	srvweb "github.com/h2oai/steamY/srv/web"
)

const (
	paramType      = "type"
	paramTypeModel = "model"
	paramArtifact  = "artifact"
	paramProjectId = "project-id"
	paramLabelName = "label-name"
	paramModelId   = "model-id"

	// model artifact types
	javaClass    = "java-class"     // foo.java
	javaClassDep = "java-class-dep" // gen-model.jar
	javaJar      = "java-jar"       // foo.jar
	javaWar      = "java-war"       // foo.war
)

type DownloadHandler struct {
	az                     az.Az
	workingDirectory       string
	webService             srvweb.Service
	compilerServiceAddress string
}

func newDownloadHandler(az az.Az, workingDirectory string, webService srvweb.Service, compilerServiceAddress string) *DownloadHandler {
	return &DownloadHandler{
		az,
		workingDirectory,
		webService,
		compilerServiceAddress,
	}
}

func (s *DownloadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("File download request received.")

	pz, azerr := s.az.Identify(r)
	if azerr != nil {
		log.Println(azerr)
		http.Error(w, fmt.Sprintf("Authentication failed: %s", azerr), http.StatusForbidden)
	}

	values := r.URL.Query()

	typ := values.Get(paramType)

	if len(typ) == 0 {
		http.Error(w, fmt.Sprintf("Missing %s", paramType), http.StatusBadRequest)
		return
	}

	switch typ {
	case paramTypeModel:
		artifact := values.Get(paramArtifact)

		if len(artifact) == 0 {
			http.Error(w, fmt.Sprintf("Missing %s", paramArtifact), http.StatusBadRequest)
			return
		}

		modelIdValue := values.Get(paramModelId)
		if len(modelIdValue) != 0 {
			modelId, err := strconv.ParseInt(modelIdValue, 10, 64)
			if err != nil {
				http.Error(w, fmt.Sprintf("Not a serial number %s=%s: %s", paramModelId, modelIdValue, err), http.StatusBadRequest)
				return
			}

			s.serveModel(w, r, pz, modelId, artifact)
			return
		}

		labelName := values.Get(paramLabelName)
		if len(labelName) != 0 {
			projectIdValue := values.Get(paramProjectId)
			if len(projectIdValue) == 0 {
				http.Error(w, fmt.Sprintf("Missing %s", paramProjectId), http.StatusBadRequest)
				return
			}

			projectId, err := strconv.ParseInt(projectIdValue, 10, 64)
			if err != nil {
				http.Error(w, fmt.Sprintf("Not a serial number %s=%s: %s", paramProjectId, projectIdValue, err), http.StatusBadRequest)
				return
			}

			if projectId <= 0 {
				http.Error(w, fmt.Sprintf("Invalid %s: %s", paramProjectId, projectId), http.StatusBadRequest)
				return
			}

			labels, err := s.webService.GetLabelsForProject(pz, projectId)
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed reading labels for project %d: %s", projectId, err), http.StatusInternalServerError)
				return
			}

			for _, label := range labels {
				if label.Name == labelName {
					if label.ModelId > 0 {
						s.serveModel(w, r, pz, label.ModelId, artifact)
						return
					}
					http.Error(w, fmt.Sprintf("No model associated with label: %s", labelName), http.StatusNotFound)
					return
				}
			}

			http.Error(w, fmt.Sprintf("No label found: %s", labelName), http.StatusNotFound)
			return

		}
	default:
		http.Error(w, fmt.Sprintf("Invalid %s: %s", paramType, typ), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusNotFound)
	http.Error(w, "Not Found", http.StatusNotFound)
}

func (s *DownloadHandler) serveModel(w http.ResponseWriter, r *http.Request, pz az.Principal, modelId int64, artifact string) {
	switch artifact {
	case javaClass, javaClassDep, javaJar, javaWar:
		// Call the API to get the model details.
		// We assume that if the GetModel() call succeeds, the principal has
		//   permissions and privileges to read this model, and consequently
		//   allowed to download it.
		model, err := s.webService.GetModel(pz, modelId)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed reading model %d: %s", modelId, err), http.StatusUnauthorized)
			return
		}
		modelLocation := model.Location
		if len(modelLocation) == 0 {
			http.Error(w, fmt.Sprintf("Failed reading model %d: the model was not saved correctly", model.Id), http.StatusNotFound)
			return
		}

		var filePath string
		switch artifact {
		case javaClass:
			filePath = fs.GetJavaModelPath(s.workingDirectory, model.Location, model.LogicalName)

		case javaClassDep:
			filePath = fs.GetGenModelPath(s.workingDirectory, model.Location)
		case javaWar:
			compilerService := compiler.NewService(s.compilerServiceAddress)
			warFilePath, err := compilerService.CompileModel(
				s.workingDirectory,
				model.Location,
				model.LogicalName,
				"war",
			)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			filePath = warFilePath

		case javaJar:
			compilerService := compiler.NewService(s.compilerServiceAddress)
			jarFilePath, err := compilerService.CompileModel(
				s.workingDirectory,
				model.Location,
				model.LogicalName,
				"jar",
			)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			filePath = jarFilePath
		}

		// Delegate to builtin.
		// Can result in 200, 404, 403 or 500 based on file availability and permissions.
		http.ServeFile(w, r, filePath)
		return

	default:
		http.Error(w, fmt.Sprintf("Invalid %s: %s", paramArtifact, artifact), http.StatusBadRequest)
		return
	}
}
<|endoftext|>


<commit_before>package pixel

// Sprite is a drawable Picture. It's always anchored by the center of it's Picture.
type Sprite struct {
	tri *TrianglesData
	d   Drawer
}

// NewSprite creates a Sprite from the supplied Picture.
func NewSprite(pic Picture) *Sprite {
	tri := MakeTrianglesData(6)
	s := &Sprite{
		tri: tri,
		d:   Drawer{Triangles: tri},
	}
	s.SetPicture(pic)
	return s
}

// SetPicture changes the Sprite's Picture. The new Picture may have a different size, everything
// works.
func (s *Sprite) SetPicture(pic Picture) {
	oldPic := s.d.Picture
	s.d.Picture = pic

	if oldPic.Bounds() == pic.Bounds() {
		return
	}

	var (
		bounds     = pic.Bounds()
		center     = bounds.Center()
		horizontal = V(bounds.W()/2, 0)
		vertical   = V(0, bounds.H()/2)
	)

	(*s.tri)[0].Position = -horizontal - vertical
	(*s.tri)[1].Position = +horizontal - vertical
	(*s.tri)[2].Position = +horizontal + vertical
	(*s.tri)[3].Position = -horizontal - vertical
	(*s.tri)[4].Position = +horizontal + vertical
	(*s.tri)[5].Position = -horizontal + vertical

	for i := range *s.tri {
		(*s.tri)[i].Color = NRGBA{1, 1, 1, 1}
		(*s.tri)[i].Picture = center + (*s.tri)[i].Position
		(*s.tri)[i].Intensity = 1
	}

	s.d.Dirty()
}

// Picture returns the current Sprite's Picture.
func (s *Sprite) Picture() Picture {
	return s.d.Picture
}

// Draw draws the Sprite onto the provided Target.
func (s *Sprite) Draw(t Target) {
	s.d.Draw(t)
}
<commit_msg>fix newly introduced bug in Sprite.SetPicture<commit_after>package pixel

// Sprite is a drawable Picture. It's always anchored by the center of it's Picture.
type Sprite struct {
	tri *TrianglesData
	d   Drawer
}

// NewSprite creates a Sprite from the supplied Picture.
func NewSprite(pic Picture) *Sprite {
	tri := MakeTrianglesData(6)
	s := &Sprite{
		tri: tri,
		d:   Drawer{Triangles: tri},
	}
	s.SetPicture(pic)
	return s
}

// SetPicture changes the Sprite's Picture. The new Picture may have a different size, everything
// works.
func (s *Sprite) SetPicture(pic Picture) {
	oldPic := s.d.Picture
	s.d.Picture = pic

	if oldPic != nil && oldPic.Bounds() == pic.Bounds() {
		return
	}

	var (
		bounds     = pic.Bounds()
		center     = bounds.Center()
		horizontal = V(bounds.W()/2, 0)
		vertical   = V(0, bounds.H()/2)
	)

	(*s.tri)[0].Position = -horizontal - vertical
	(*s.tri)[1].Position = +horizontal - vertical
	(*s.tri)[2].Position = +horizontal + vertical
	(*s.tri)[3].Position = -horizontal - vertical
	(*s.tri)[4].Position = +horizontal + vertical
	(*s.tri)[5].Position = -horizontal + vertical

	for i := range *s.tri {
		(*s.tri)[i].Color = NRGBA{1, 1, 1, 1}
		(*s.tri)[i].Picture = center + (*s.tri)[i].Position
		(*s.tri)[i].Intensity = 1
	}

	s.d.Dirty()
}

// Picture returns the current Sprite's Picture.
func (s *Sprite) Picture() Picture {
	return s.d.Picture
}

// Draw draws the Sprite onto the provided Target.
func (s *Sprite) Draw(t Target) {
	s.d.Draw(t)
}
<|endoftext|>