<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"path"
	"reflect"
	"regexp"
	"strings"
	"text/template"

	"github.com/Masterminds/sprig/v3"
)

var environment = make(map[string]interface{})
var templateFile *string

// add custom functions
var customFuctions = template.FuncMap{
	"include":     include,
	"mustInclude": mustInclude,
}

func inputToObject(inputStr string, debug *bool) (result interface{}, err error) {
	if *debug {
		fmt.Fprintf(os.Stderr, "----\ninput is: %v\n", inputStr)
	}

	// try to parse a plain json first
	jsonStr := inputStr
	err = json.Unmarshal([]byte(jsonStr), &result)

	// now try to enrich unquoted json
	if err != nil {
		// insert " after , if next is none of [ { "
		jsonStr = regexp.MustCompile(`,([^[{"])`).ReplaceAllString(jsonStr, ",\"$1")
		// insert " before , if previous is none of ] } "
		jsonStr = regexp.MustCompile(`([^]}"]),`).ReplaceAllString(jsonStr, "$1\",")
		// insert " after [ { if next is none of ] [ } { , "
		jsonStr = regexp.MustCompile(`([\[{])([^][}{,"])`).ReplaceAllString(jsonStr, "$1\"$2")
		// insert " before ] } if previous is none of ] [ } { , "
		jsonStr = regexp.MustCompile(`([^][}{,"])([\]}])`).ReplaceAllString(jsonStr, "$1\"$2")
		// insert " after : if next is none of : [ { "
		jsonStr = regexp.MustCompile(`([^:]):([^:[{"])`).ReplaceAllString(jsonStr, "$1:\"$2")
		// insert " before : if previous is not :
		jsonStr = regexp.MustCompile(`([^:"]):([^:])`).ReplaceAllString(jsonStr, "$1\":$2")
		// replace :: with : (double colons can be used to escape a colon)
		jsonStr = regexp.MustCompile(`::`).ReplaceAllString(jsonStr, ":")
	}
	if *debug {
		fmt.Fprintf(os.Stderr, "json is: %v\n", jsonStr)
	}

	// try parsing json again, if it fails fall back to the plain input value
	err = json.Unmarshal([]byte(jsonStr), &result)
	if err != nil || result == nil || reflect.TypeOf(result).Kind() == reflect.Float64 {
		result = inputStr
	}

	if *debug {
		if err != nil {
			fmt.Fprintf(os.Stderr, "result is: %v, error: %v\n----\n", result, err)
		} else {
			fmt.Fprintf(os.Stderr, "result is: %v\n----\n", result)
		}
	}

	return result, err
}

func renderInclude(fileName string, safeMode bool) string {
	// lookup relative file names in same directory like main template
	lookupDir := ""
	if !strings.HasPrefix(fileName, "/") && !strings.HasPrefix(fileName, "/") {
		lookupDir = path.Dir(*templateFile)
	}

	// ignore non-existing files
	if safeMode {
		if _, err := os.Stat(path.Join(lookupDir, fileName)); os.IsNotExist(err) {
			return ""
		}
	}

	tpl := template.Must(template.New(path.Base(fileName)).Funcs(sprig.TxtFuncMap()).ParseFiles(path.Join(lookupDir, fileName)))

	var result bytes.Buffer
	tpl.Execute(&result, environment)
	return result.String()
}

func include(fileName string) string {
	return renderInclude(fileName, true)
}

func mustInclude(fileName string) string {
	return renderInclude(fileName, false)
}

func main() {
	// set and parse cmd line flags
	debug := flag.Bool("d", false, "enable debug mode")
	prefix := flag.String("p", "", "only consider variables starting with prefix")
	templateFile = flag.String("t", "", "template file")
	version := flag.Bool("v", false, "show version")
	outputFile := flag.String("o", "", "output file")

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "version %s\n", "0.6.1")
		os.Exit(0)
	}

	if len(*templateFile) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(*templateFile); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "%s not found\n", *templateFile)
		os.Exit(2)
	}

	// generate environment map
	for _, envVar := range os.Environ() {
		envKeyValuePair := strings.SplitN(envVar, "=", 2)
		envKey, envValue := envKeyValuePair[0], envKeyValuePair[1]

		if !strings.HasPrefix(envKey, *prefix) {
			continue
		}

		data, err := inputToObject(envValue, debug)
		if err != nil {
			environment[envKey] = envValue
		} else {
			environment[envKey] = data
		}
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "environment map is: %v\n", environment)
	}

	outputWriter := os.Stdout
	if len(*outputFile) > 0 {
		// Create file and truncate it if it already exists
		out, err := os.OpenFile(*outputFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error opening output file: %s", err)
			return
		}
		outputWriter = out
	}

	// render template
	tpl := template.Must(template.New(path.Base(*templateFile)).Funcs(sprig.TxtFuncMap()).Funcs(customFuctions).ParseFiles(*templateFile))
	err := tpl.Execute(outputWriter, environment)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error rendering template %v: %v\n", *templateFile, err)
		os.Exit(2)
	}
}
<commit_msg>bump version<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"path"
	"reflect"
	"regexp"
	"strings"
	"text/template"

	"github.com/Masterminds/sprig/v3"
)

var environment = make(map[string]interface{})
var templateFile *string

// add custom functions
var customFuctions = template.FuncMap{
	"include":     include,
	"mustInclude": mustInclude,
}

func inputToObject(inputStr string, debug *bool) (result interface{}, err error) {
	if *debug {
		fmt.Fprintf(os.Stderr, "----\ninput is: %v\n", inputStr)
	}

	// try to parse a plain json first
	jsonStr := inputStr
	err = json.Unmarshal([]byte(jsonStr), &result)

	// now try to enrich unquoted json
	if err != nil {
		// insert " after , if next is none of [ { "
		jsonStr = regexp.MustCompile(`,([^[{"])`).ReplaceAllString(jsonStr, ",\"$1")
		// insert " before , if previous is none of ] } "
		jsonStr = regexp.MustCompile(`([^]}"]),`).ReplaceAllString(jsonStr, "$1\",")
		// insert " after [ { if next is none of ] [ } { , "
		jsonStr = regexp.MustCompile(`([\[{])([^][}{,"])`).ReplaceAllString(jsonStr, "$1\"$2")
		// insert " before ] } if previous is none of ] [ } { , "
		jsonStr = regexp.MustCompile(`([^][}{,"])([\]}])`).ReplaceAllString(jsonStr, "$1\"$2")
		// insert " after : if next is none of : [ { "
		jsonStr = regexp.MustCompile(`([^:]):([^:[{"])`).ReplaceAllString(jsonStr, "$1:\"$2")
		// insert " before : if previous is not :
		jsonStr = regexp.MustCompile(`([^:"]):([^:])`).ReplaceAllString(jsonStr, "$1\":$2")
		// replace :: with : (double colons can be used to escape a colon)
		jsonStr = regexp.MustCompile(`::`).ReplaceAllString(jsonStr, ":")
	}
	if *debug {
		fmt.Fprintf(os.Stderr, "json is: %v\n", jsonStr)
	}

	// try parsing json again, if it fails fall back to the plain input value
	err = json.Unmarshal([]byte(jsonStr), &result)
	if err != nil || result == nil || reflect.TypeOf(result).Kind() == reflect.Float64 {
		result = inputStr
	}

	if *debug {
		if err != nil {
			fmt.Fprintf(os.Stderr, "result is: %v, error: %v\n----\n", result, err)
		} else {
			fmt.Fprintf(os.Stderr, "result is: %v\n----\n", result)
		}
	}

	return result, err
}

func renderInclude(fileName string, safeMode bool) string {
	// lookup relative file names in same directory like main template
	lookupDir := ""
	if !strings.HasPrefix(fileName, "/") && !strings.HasPrefix(fileName, "/") {
		lookupDir = path.Dir(*templateFile)
	}

	// ignore non-existing files
	if safeMode {
		if _, err := os.Stat(path.Join(lookupDir, fileName)); os.IsNotExist(err) {
			return ""
		}
	}

	tpl := template.Must(template.New(path.Base(fileName)).Funcs(sprig.TxtFuncMap()).ParseFiles(path.Join(lookupDir, fileName)))

	var result bytes.Buffer
	tpl.Execute(&result, environment)
	return result.String()
}

func include(fileName string) string {
	return renderInclude(fileName, true)
}

func mustInclude(fileName string) string {
	return renderInclude(fileName, false)
}

func main() {
	// set and parse cmd line flags
	debug := flag.Bool("d", false, "enable debug mode")
	prefix := flag.String("p", "", "only consider variables starting with prefix")
	templateFile = flag.String("t", "", "template file")
	version := flag.Bool("v", false, "show version")
	outputFile := flag.String("o", "", "output file")

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "version %s\n", "0.7.0")
		os.Exit(0)
	}

	if len(*templateFile) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if _, err := os.Stat(*templateFile); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "%s not found\n", *templateFile)
		os.Exit(2)
	}

	// generate environment map
	for _, envVar := range os.Environ() {
		envKeyValuePair := strings.SplitN(envVar, "=", 2)
		envKey, envValue := envKeyValuePair[0], envKeyValuePair[1]

		if !strings.HasPrefix(envKey, *prefix) {
			continue
		}

		data, err := inputToObject(envValue, debug)
		if err != nil {
			environment[envKey] = envValue
		} else {
			environment[envKey] = data
		}
	}

	if *debug {
		fmt.Fprintf(os.Stderr, "environment map is: %v\n", environment)
	}

	outputWriter := os.Stdout
	if len(*outputFile) > 0 {
		// Create file and truncate it if it already exists
		out, err := os.OpenFile(*outputFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error opening output file: %s", err)
			return
		}
		outputWriter = out
	}

	// render template
	tpl := template.Must(template.New(path.Base(*templateFile)).Funcs(sprig.TxtFuncMap()).Funcs(customFuctions).ParseFiles(*templateFile))
	err := tpl.Execute(outputWriter, environment)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error rendering template %v: %v\n", *templateFile, err)
		os.Exit(2)
	}
}
<|endoftext|>


<commit_before>package main

const Name string = "gcredstash"
const Version string = "0.1.0"

// GitCommit describes latest commit hash.
// This value is extracted by git command when building.
// To set this from outside, use go build -ldflags "-X main.GitCommit \"$(COMMIT)\""
var GitCommit string
<commit_msg>Bump up version<commit_after>package main

const Name string = "gcredstash"
const Version string = "0.1.1"

// GitCommit describes latest commit hash.
// This value is extracted by git command when building.
// To set this from outside, use go build -ldflags "-X main.GitCommit \"$(COMMIT)\""
var GitCommit string
<|endoftext|>


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

package sdk

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/coreos/mantle/system"
	"github.com/coreos/mantle/system/user"
)

const (
	// This command is the absolute bare minimum to enter the SDK
	// and run repo. It *must* be run in a new mount namespace.
	repoScript = "mkdir -p {{.Chroot}}/mnt/host/source && " +
		"mount --make-rslave / && " +
		"mount --bind {{.RepoRoot}} {{.Chroot}}/mnt/host/source && " +
		"exec chroot {{.Chroot}} " +
		"/usr/bin/sudo -u {{.Username}} sh -c " +
		"'cd /mnt/host/source && repo {{.RepoArgs}}'"
	enterChroot = "src/scripts/sdk_lib/enter_chroot.sh"
)

var repoTemplate = template.Must(template.New("script").Parse(repoScript))

type repoParams struct {
	*user.User
	Chroot   string
	RepoRoot string
	RepoArgs string
}

// Set an environment variable if it isn't already defined.
func setDefault(environ []string, key, value string) []string {
	prefix := key + "="
	for _, env := range environ {
		if strings.HasPrefix(env, prefix) {
			return environ
		}
	}
	return append(environ, prefix+value)
}

// Set a default email address so repo doesn't explode on 'u@h.(none)'
func setDefaultEmail(environ []string) []string {
	username := "nobody"
	if u, err := user.Current(); err == nil {
		username = u.Username
	}
	domain := system.FullHostname()
	email := fmt.Sprintf("%s@%s", username, domain)
	return setDefault(environ, "EMAIL", email)
}

func repo(name, args string) error {
	chroot := filepath.Join(RepoRoot(), name)
	u, err := user.Current()
	if err != nil {
		return err
	}

	params := repoParams{
		User:     u,
		Chroot:   chroot,
		RepoRoot: RepoRoot(),
		RepoArgs: args,
	}

	var sc bytes.Buffer
	if err := repoTemplate.Execute(&sc, &params); err != nil {
		return err
	}

	sh := exec.Command("sudo", sudoPrompt, "-E",
		"unshare", "--mount",
		"sh", "-e", "-c", sc.String())
	sh.Env = setDefaultEmail(os.Environ())
	sh.Stdin = os.Stdin
	sh.Stdout = os.Stdout
	sh.Stderr = os.Stderr

	return sh.Run()
}

func Enter(name string, args ...string) error {
	chroot := filepath.Join(RepoRoot(), name)

	// TODO(marineam): the original cros_sdk uses a white list to
	// selectively pass through environment variables instead of the
	// catch-all -E which is probably a better way to do it.
	enterCmd := exec.Command(
		"sudo", sudoPrompt, "-E",
		"unshare", "--mount", "--",
		filepath.Join(RepoRoot(), enterChroot),
		"--chroot", chroot, "--cache_dir", RepoCache(), "--")
	enterCmd.Args = append(enterCmd.Args, args...)
	enterCmd.Env = setDefaultEmail(os.Environ())
	enterCmd.Stdin = os.Stdin
	enterCmd.Stdout = os.Stdout
	enterCmd.Stderr = os.Stderr

	return enterCmd.Run()
}

func RepoInit(name, manifest string) error {
	if err := repo(name, "init -u "+manifest); err != nil {
		return err
	}

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

package sdk

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"

	"github.com/coreos/mantle/system"
	"github.com/coreos/mantle/system/exec"
	"github.com/coreos/mantle/system/user"
)

const enterChroot = "src/scripts/sdk_lib/enter_chroot.sh"

var simpleChroot exec.Entrypoint

func init() {
	simpleChroot = exec.NewEntrypoint("simpleChroot", simpleChrootHelper)
}

// bind mount the repo source tree into the chroot and run a command
func simpleChrootHelper(args []string) error {
	if len(args) < 3 {
		return fmt.Errorf("got %d args, need at least 3", len(args))
	}
	hostRepoRoot := args[0]
	chroot := args[1]
	chrootCmd := args[2:]
	username := os.Getenv("SUDO_USER")
	if username == "" {
		return fmt.Errorf("SUDO_USER environment variable is not set.")
	}

	newRepoRoot := filepath.Join(chroot, chrootRepoRoot)
	if err := os.MkdirAll(newRepoRoot, 0755); err != nil {
		return err
	}

	// namespaces are per-thread attributes
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
		return fmt.Errorf("Unsharing mount namespace failed: %v", err)
	}

	if err := syscall.Mount(
		"none", "/", "none", syscall.MS_REC|syscall.MS_SLAVE, ""); err != nil {
		return fmt.Errorf("Unsharing mount points failed: %v", err)
	}

	if err := syscall.Mount(
		hostRepoRoot, newRepoRoot, "none", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("Mounting %q failed: %v", newRepoRoot, err)
	}

	if err := syscall.Chroot(chroot); err != nil {
		return fmt.Errorf("Chrooting to %q failed: %v", chroot, err)
	}

	if err := os.Chdir(chrootRepoRoot); err != nil {
		return err
	}

	sudo := "/usr/bin/sudo"
	sudoArgs := append([]string{sudo, "-u", username, "--"}, chrootCmd...)
	return syscall.Exec(sudo, sudoArgs, os.Environ())
}

// Set an environment variable if it isn't already defined.
func setDefault(environ []string, key, value string) []string {
	prefix := key + "="
	for _, env := range environ {
		if strings.HasPrefix(env, prefix) {
			return environ
		}
	}
	return append(environ, prefix+value)
}

// Set a default email address so repo doesn't explode on 'u@h.(none)'
func setDefaultEmail(environ []string) []string {
	username := "nobody"
	if u, err := user.Current(); err == nil {
		username = u.Username
	}
	domain := system.FullHostname()
	email := fmt.Sprintf("%s@%s", username, domain)
	return setDefault(environ, "EMAIL", email)
}

func SimpleEnter(name string, args ...string) error {
	reroot := RepoRoot()
	chroot := filepath.Join(reroot, name)
	args = append([]string{reroot, chroot}, args...)

	sudo := simpleChroot.Sudo(args...)
	sudo.Env = setDefaultEmail(os.Environ())
	sudo.Stdin = os.Stdin
	sudo.Stdout = os.Stdout
	sudo.Stderr = os.Stderr

	return sudo.Run()
}

func Enter(name string, args ...string) error {
	chroot := filepath.Join(RepoRoot(), name)

	// TODO(marineam): the original cros_sdk uses a white list to
	// selectively pass through environment variables instead of the
	// catch-all -E which is probably a better way to do it.
	enterCmd := exec.Command(
		"sudo", sudoPrompt, "-E",
		"unshare", "--mount", "--",
		filepath.Join(RepoRoot(), enterChroot),
		"--chroot", chroot, "--cache_dir", RepoCache(), "--")
	enterCmd.Args = append(enterCmd.Args, args...)
	enterCmd.Env = setDefaultEmail(os.Environ())
	enterCmd.Stdin = os.Stdin
	enterCmd.Stdout = os.Stdout
	enterCmd.Stderr = os.Stderr

	return enterCmd.Run()
}

func RepoInit(name, manifest string) error {
	if err := SimpleEnter(name, "repo", "init", "-u", manifest); err != nil {
		return err
	}

	return SimpleEnter(name, "repo", "sync")
}
<|endoftext|>


<commit_before>package sdl

// #include "sdl_wrapper.h"
import "C"
import (
	"reflect"
	"unsafe"
)

const (
	AUDIO_MASK_BITSIZE  = C.SDL_AUDIO_MASK_BITSIZE
	AUDIO_MASK_DATATYPE = C.SDL_AUDIO_MASK_DATATYPE
	AUDIO_MASK_ENDIAN   = C.SDL_AUDIO_MASK_ENDIAN
	AUDIO_MASK_SIGNED   = C.SDL_AUDIO_MASK_SIGNED
)

const (
	AUDIO_U8     = C.AUDIO_U8
	AUDIO_S8     = C.AUDIO_S8
	AUDIO_U16LSB = C.AUDIO_U16LSB
	AUDIO_S16LSB = C.AUDIO_S16LSB
	AUDIO_U16MSB = C.AUDIO_U16MSB
	AUDIO_S16MSB = C.AUDIO_S16MSB
	AUDIO_U16    = C.AUDIO_U16
	AUDIO_S16    = C.AUDIO_S16
	AUDIO_S32LSB = C.AUDIO_S32LSB
	AUDIO_S32MSB = C.AUDIO_S32MSB
	AUDIO_S32    = C.AUDIO_S32
	AUDIO_F32LSB = C.AUDIO_F32LSB
	AUDIO_F32MSB = C.AUDIO_F32MSB
	AUDIO_F32    = C.AUDIO_F32
	AUDIO_U16SYS = C.AUDIO_U16SYS
	AUDIO_S16SYS = C.AUDIO_S16SYS
	AUDIO_S32SYS = C.AUDIO_S32SYS
	AUDIO_F32SYS = C.AUDIO_F32SYS
)

const (
	AUDIO_ALLOW_FREQUENCY_CHANGE = C.SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
	AUDIO_ALLOW_FORMAT_CHANGE    = C.SDL_AUDIO_ALLOW_FORMAT_CHANGE
	AUDIO_ALLOW_CHANNELS_CHANGE  = C.SDL_AUDIO_ALLOW_CHANNELS_CHANGE
	AUDIO_ALLOW_ANY_CHANGE       = C.SDL_AUDIO_ALLOW_ANY_CHANGE
)

const (
	AUDIO_STOPPED AudioStatus = C.SDL_AUDIO_STOPPED
	AUDIO_PLAYING             = C.SDL_AUDIO_PLAYING
	AUDIO_PAUSED              = C.SDL_AUDIO_PAUSED
)

const MIX_MAXVOLUME = C.SDL_MIX_MAXVOLUME

// AudioFormat (https://wiki.libsdl.org/SDL_AudioFormat)
type AudioFormat uint16
type AudioCallback C.SDL_AudioCallback
type AudioFilter C.SDL_AudioFilter
type AudioDeviceID uint32

// AudioStatus (https://wiki.libsdl.org/SDL_AudioStatus)
type AudioStatus uint32
type cAudioStatus C.SDL_AudioStatus

// AudioSpec (https://wiki.libsdl.org/SDL_AudioSpec)
type AudioSpec struct {
	Freq     int32
	Format   AudioFormat
	Channels uint8
	Silence  uint8
	Samples  uint16
	Padding  uint16
	Size     uint32
	Callback AudioCallback
	UserData unsafe.Pointer
}
type cAudioSpec C.SDL_AudioSpec

// AudioCVT (https://wiki.libsdl.org/SDL_AudioCVT)
type AudioCVT struct {
	Needed      int32
	SrcFormat   AudioFormat
	DstFormat   AudioFormat
	RateIncr    float64
	Buf         *uint8
	Len         int32
	LenCVT      int32
	LenMult     int32
	LenRatio    float64
	filters     [10]AudioFilter // internal
	filterIndex int32           // internal
}
type cAudioCVT C.SDL_AudioCVT

func (fmt AudioFormat) c() C.SDL_AudioFormat {
	return C.SDL_AudioFormat(fmt)
}

func (id AudioDeviceID) c() C.SDL_AudioDeviceID {
	return C.SDL_AudioDeviceID(id)
}

func (as *AudioSpec) cptr() *C.SDL_AudioSpec {
	return (*C.SDL_AudioSpec)(unsafe.Pointer(as))
}

func (cvt *AudioCVT) cptr() *C.SDL_AudioCVT {
	return (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
}

func (format AudioFormat) BitSize() uint8 {
	return uint8(format & AUDIO_MASK_BITSIZE)
}

func (format AudioFormat) IsFloat() bool {
	return (format & AUDIO_MASK_DATATYPE) > 0
}

func (format AudioFormat) IsBigEndian() bool {
	return (format & AUDIO_MASK_ENDIAN) > 0
}

func (format AudioFormat) IsSigned() bool {
	return (format & AUDIO_MASK_SIGNED) > 0
}

func (format AudioFormat) IsInt() bool {
	return !format.IsFloat()
}

func (format AudioFormat) IsLittleEndian() bool {
	return !format.IsBigEndian()
}

func (format AudioFormat) IsUnsigned() bool {
	return !format.IsSigned()
}

// GetNumAudioDrivers (https://wiki.libsdl.org/SDL_GetNumAudioDrivers)
func GetNumAudioDrivers() int {
	return int(C.SDL_GetNumAudioDrivers())
}

// GetAudioDriver (https://wiki.libsdl.org/SDL_GetAudioDriver)
func GetAudioDriver(index int) string {
	return string(C.GoString(C.SDL_GetAudioDriver(C.int(index))))
}

// AudioInit (https://wiki.libsdl.org/SDL_AudioInit)
func AudioInit(driverName string) int {
	_driverName := C.CString(driverName)
	defer C.free(unsafe.Pointer(_driverName))
	return int(C.SDL_AudioInit(_driverName))
}

// AudioQuit (https://wiki.libsdl.org/SDL_AudioQuit)
func AudioQuit() {
	C.SDL_AudioQuit()
}

// GetCurrentAudioDriver (https://wiki.libsdl.org/SDL_GetCurrentAudioDriver)
func GetCurrentAudioDriver() string {
	return string(C.GoString(C.SDL_GetCurrentAudioDriver()))
}

// OpenAudio (https://wiki.libsdl.org/SDL_OpenAudio)
func OpenAudio(desired, obtained *AudioSpec) int {
	return int(C.SDL_OpenAudio(desired.cptr(), obtained.cptr()))
}

// GetNumAudioDevices (https://wiki.libsdl.org/SDL_GetNumAudioDevices)
func GetNumAudioDevices(isCapture int) int {
	return int(C.SDL_GetNumAudioDevices(C.int(isCapture)))
}

// GetAudioDeviceName (https://wiki.libsdl.org/SDL_GetAudioDeviceName)
func GetAudioDeviceName(index, isCapture int) string {
	return string(C.GoString(C.SDL_GetAudioDeviceName(C.int(index), C.int(isCapture))))
}

// OpenAudioDevice (https://wiki.libsdl.org/SDL_OpenAudioDevice)
func OpenAudioDevice(device string, isCapture int, desired, obtained *AudioSpec, allowedChanges int) int {
	_device := C.CString(device)
	defer C.free(unsafe.Pointer(_device))
	return int(C.SDL_OpenAudioDevice(_device, C.int(isCapture), desired.cptr(), obtained.cptr(), C.int(allowedChanges)))
}

// GetAudioStatus (https://wiki.libsdl.org/SDL_GetAudioStatus)
func GetAudioStatus() AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioStatus())
}

// GetAudioDeviceStatus (https://wiki.libsdl.org/SDL_GetAudioDeviceStatus)
func GetAudioDeviceStatus(dev AudioDeviceID) AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioDeviceStatus(dev.c()))
}

// PauseAudio (https://wiki.libsdl.org/SDL_PauseAudio)
func PauseAudio(pauseOn int) {
	C.SDL_PauseAudio(C.int(pauseOn))
}

// PauseAudioDevice (https://wiki.libsdl.org/SDL_PauseAudioDevice)
func PauseAudioDevice(dev AudioDeviceID, pauseOn int) {
	C.SDL_PauseAudioDevice(dev.c(), C.int(pauseOn))
}

// LoadWAV_RW (https://wiki.libsdl.org/SDL_LoadWAV_RW)
func LoadWAV_RW(src *RWops, freeSrc int, spec *AudioSpec) ([]byte, *AudioSpec) {
	var _audioBuf *C.Uint8
	var _audioLen C.Uint32
	audioSpec := (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(src.cptr(), C.int(freeSrc), spec.cptr(), &_audioBuf, &_audioLen)))

	var b []byte
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Len = (int)(_audioLen)
	sliceHeader.Cap = (int)(_audioLen)
	sliceHeader.Data = uintptr(unsafe.Pointer(_audioBuf))
	return b, audioSpec
}

// LoadWAV (https://wiki.libsdl.org/SDL_LoadWAV)
func LoadWAV(file string, spec *AudioSpec) ([]byte, *AudioSpec) {
	_file := C.CString(file)
	_rb := C.CString("rb")
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_rb))

	var _audioBuf *C.Uint8
	var _audioLen C.Uint32
	audioSpec := (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(C.SDL_RWFromFile(_file, _rb), 1, spec.cptr(), &_audioBuf, &_audioLen)))

	var b []byte
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Len = (int)(_audioLen)
	sliceHeader.Cap = (int)(_audioLen)
	sliceHeader.Data = uintptr(unsafe.Pointer(_audioBuf))
	return b, audioSpec
}

// FreeWAV (https://wiki.libsdl.org/SDL_FreeWAV)
func FreeWAV(audioBuf []uint8) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&audioBuf))
	_audioBuf := (*C.Uint8)(unsafe.Pointer(sliceHeader.Data))
	C.SDL_FreeWAV(_audioBuf)
}

// BuildAudioCVT (https://wiki.libsdl.org/SDL_BuildAudioCVT)
func BuildAudioCVT(cvt *AudioCVT, srcFormat AudioFormat, srcChannels uint8, srcRate int, dstFormat AudioFormat, dstChannels uint8, dstRate int) int {
	return int(C.SDL_BuildAudioCVT(cvt.cptr(), srcFormat.c(), C.Uint8(srcChannels), C.int(srcRate), dstFormat.c(), C.Uint8(dstChannels), C.int(dstRate)))
}

// ConvertAudio (https://wiki.libsdl.org/SDL_ConvertAudio)
func ConvertAudio(cvt *AudioCVT) int {
	_cvt := (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
	return int(C.SDL_ConvertAudio(_cvt))
}

// MixAudio (https://wiki.libsdl.org/SDL_MixAudio)
func MixAudio(dst, src *uint8, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudio(_dst, _src, C.Uint32(len_), C.int(volume))
}

// MixAudioFormat (https://wiki.libsdl.org/SDL_MixAudioFormat)
func MixAudioFormat(dst, src *uint8, format AudioFormat, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudioFormat(_dst, _src, format.c(), C.Uint32(len_), C.int(volume))
}

// LockAudio (https://wiki.libsdl.org/SDL_LockAudio)
func LockAudio() {
	C.SDL_LockAudio()
}

// LockAudioDevice (https://wiki.libsdl.org/SDL_LockAudioDevice)
func LockAudioDevice(dev AudioDeviceID) {
	C.SDL_LockAudioDevice(dev.c())
}

// UnlockAudio (https://wiki.libsdl.org/SDL_UnlockAudio)
func UnlockAudio() {
	C.SDL_UnlockAudio()
}

// UnlockAudioDevice (https://wiki.libsdl.org/SDL_UnlockAudioDevice)
func UnlockAudioDevice(dev AudioDeviceID) {
	C.SDL_UnlockAudioDevice(dev.c())
}

// CloseAudio (https://wiki.libsdl.org/SDL_CloseAudio)
func CloseAudio() {
	C.SDL_CloseAudio()
}

// CloseAudioDevice (https://wiki.libsdl.org/SDL_CloseAudioDevice)
func CloseAudioDevice(dev AudioDeviceID) {
	C.SDL_CloseAudioDevice(dev.c())
}

/*
func AudioDeviceConnected(dev AudioDeviceID) int {
	_dev := (C.SDL_AudioDeviceID) (dev)
	return int (C.SDL_AudioDeviceConnected(_dev))
}
*/
<commit_msg>Make InitAudio() return error instead of int<commit_after>package sdl

// #include "sdl_wrapper.h"
import "C"
import (
	"reflect"
	"unsafe"
)

const (
	AUDIO_MASK_BITSIZE  = C.SDL_AUDIO_MASK_BITSIZE
	AUDIO_MASK_DATATYPE = C.SDL_AUDIO_MASK_DATATYPE
	AUDIO_MASK_ENDIAN   = C.SDL_AUDIO_MASK_ENDIAN
	AUDIO_MASK_SIGNED   = C.SDL_AUDIO_MASK_SIGNED
)

const (
	AUDIO_U8     = C.AUDIO_U8
	AUDIO_S8     = C.AUDIO_S8
	AUDIO_U16LSB = C.AUDIO_U16LSB
	AUDIO_S16LSB = C.AUDIO_S16LSB
	AUDIO_U16MSB = C.AUDIO_U16MSB
	AUDIO_S16MSB = C.AUDIO_S16MSB
	AUDIO_U16    = C.AUDIO_U16
	AUDIO_S16    = C.AUDIO_S16
	AUDIO_S32LSB = C.AUDIO_S32LSB
	AUDIO_S32MSB = C.AUDIO_S32MSB
	AUDIO_S32    = C.AUDIO_S32
	AUDIO_F32LSB = C.AUDIO_F32LSB
	AUDIO_F32MSB = C.AUDIO_F32MSB
	AUDIO_F32    = C.AUDIO_F32
	AUDIO_U16SYS = C.AUDIO_U16SYS
	AUDIO_S16SYS = C.AUDIO_S16SYS
	AUDIO_S32SYS = C.AUDIO_S32SYS
	AUDIO_F32SYS = C.AUDIO_F32SYS
)

const (
	AUDIO_ALLOW_FREQUENCY_CHANGE = C.SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
	AUDIO_ALLOW_FORMAT_CHANGE    = C.SDL_AUDIO_ALLOW_FORMAT_CHANGE
	AUDIO_ALLOW_CHANNELS_CHANGE  = C.SDL_AUDIO_ALLOW_CHANNELS_CHANGE
	AUDIO_ALLOW_ANY_CHANGE       = C.SDL_AUDIO_ALLOW_ANY_CHANGE
)

const (
	AUDIO_STOPPED AudioStatus = C.SDL_AUDIO_STOPPED
	AUDIO_PLAYING             = C.SDL_AUDIO_PLAYING
	AUDIO_PAUSED              = C.SDL_AUDIO_PAUSED
)

const MIX_MAXVOLUME = C.SDL_MIX_MAXVOLUME

// AudioFormat (https://wiki.libsdl.org/SDL_AudioFormat)
type AudioFormat uint16
type AudioCallback C.SDL_AudioCallback
type AudioFilter C.SDL_AudioFilter
type AudioDeviceID uint32

// AudioStatus (https://wiki.libsdl.org/SDL_AudioStatus)
type AudioStatus uint32
type cAudioStatus C.SDL_AudioStatus

// AudioSpec (https://wiki.libsdl.org/SDL_AudioSpec)
type AudioSpec struct {
	Freq     int32
	Format   AudioFormat
	Channels uint8
	Silence  uint8
	Samples  uint16
	Padding  uint16
	Size     uint32
	Callback AudioCallback
	UserData unsafe.Pointer
}
type cAudioSpec C.SDL_AudioSpec

// AudioCVT (https://wiki.libsdl.org/SDL_AudioCVT)
type AudioCVT struct {
	Needed      int32
	SrcFormat   AudioFormat
	DstFormat   AudioFormat
	RateIncr    float64
	Buf         *uint8
	Len         int32
	LenCVT      int32
	LenMult     int32
	LenRatio    float64
	filters     [10]AudioFilter // internal
	filterIndex int32           // internal
}
type cAudioCVT C.SDL_AudioCVT

func (fmt AudioFormat) c() C.SDL_AudioFormat {
	return C.SDL_AudioFormat(fmt)
}

func (id AudioDeviceID) c() C.SDL_AudioDeviceID {
	return C.SDL_AudioDeviceID(id)
}

func (as *AudioSpec) cptr() *C.SDL_AudioSpec {
	return (*C.SDL_AudioSpec)(unsafe.Pointer(as))
}

func (cvt *AudioCVT) cptr() *C.SDL_AudioCVT {
	return (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
}

func (format AudioFormat) BitSize() uint8 {
	return uint8(format & AUDIO_MASK_BITSIZE)
}

func (format AudioFormat) IsFloat() bool {
	return (format & AUDIO_MASK_DATATYPE) > 0
}

func (format AudioFormat) IsBigEndian() bool {
	return (format & AUDIO_MASK_ENDIAN) > 0
}

func (format AudioFormat) IsSigned() bool {
	return (format & AUDIO_MASK_SIGNED) > 0
}

func (format AudioFormat) IsInt() bool {
	return !format.IsFloat()
}

func (format AudioFormat) IsLittleEndian() bool {
	return !format.IsBigEndian()
}

func (format AudioFormat) IsUnsigned() bool {
	return !format.IsSigned()
}

// GetNumAudioDrivers (https://wiki.libsdl.org/SDL_GetNumAudioDrivers)
func GetNumAudioDrivers() int {
	return int(C.SDL_GetNumAudioDrivers())
}

// GetAudioDriver (https://wiki.libsdl.org/SDL_GetAudioDriver)
func GetAudioDriver(index int) string {
	return string(C.GoString(C.SDL_GetAudioDriver(C.int(index))))
}

// AudioInit (https://wiki.libsdl.org/SDL_AudioInit)
func AudioInit(driverName string) error {
	_driverName := C.CString(driverName)
	defer C.free(unsafe.Pointer(_driverName))
	if C.SDL_AudioInit(_driverName) != 0 {
		return GetError()
	}
	return nil
}

// AudioQuit (https://wiki.libsdl.org/SDL_AudioQuit)
func AudioQuit() {
	C.SDL_AudioQuit()
}

// GetCurrentAudioDriver (https://wiki.libsdl.org/SDL_GetCurrentAudioDriver)
func GetCurrentAudioDriver() string {
	return string(C.GoString(C.SDL_GetCurrentAudioDriver()))
}

// OpenAudio (https://wiki.libsdl.org/SDL_OpenAudio)
func OpenAudio(desired, obtained *AudioSpec) int {
	return int(C.SDL_OpenAudio(desired.cptr(), obtained.cptr()))
}

// GetNumAudioDevices (https://wiki.libsdl.org/SDL_GetNumAudioDevices)
func GetNumAudioDevices(isCapture int) int {
	return int(C.SDL_GetNumAudioDevices(C.int(isCapture)))
}

// GetAudioDeviceName (https://wiki.libsdl.org/SDL_GetAudioDeviceName)
func GetAudioDeviceName(index, isCapture int) string {
	return string(C.GoString(C.SDL_GetAudioDeviceName(C.int(index), C.int(isCapture))))
}

// OpenAudioDevice (https://wiki.libsdl.org/SDL_OpenAudioDevice)
func OpenAudioDevice(device string, isCapture int, desired, obtained *AudioSpec, allowedChanges int) int {
	_device := C.CString(device)
	defer C.free(unsafe.Pointer(_device))
	return int(C.SDL_OpenAudioDevice(_device, C.int(isCapture), desired.cptr(), obtained.cptr(), C.int(allowedChanges)))
}

// GetAudioStatus (https://wiki.libsdl.org/SDL_GetAudioStatus)
func GetAudioStatus() AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioStatus())
}

// GetAudioDeviceStatus (https://wiki.libsdl.org/SDL_GetAudioDeviceStatus)
func GetAudioDeviceStatus(dev AudioDeviceID) AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioDeviceStatus(dev.c()))
}

// PauseAudio (https://wiki.libsdl.org/SDL_PauseAudio)
func PauseAudio(pauseOn int) {
	C.SDL_PauseAudio(C.int(pauseOn))
}

// PauseAudioDevice (https://wiki.libsdl.org/SDL_PauseAudioDevice)
func PauseAudioDevice(dev AudioDeviceID, pauseOn int) {
	C.SDL_PauseAudioDevice(dev.c(), C.int(pauseOn))
}

// LoadWAV_RW (https://wiki.libsdl.org/SDL_LoadWAV_RW)
func LoadWAV_RW(src *RWops, freeSrc int, spec *AudioSpec) ([]byte, *AudioSpec) {
	var _audioBuf *C.Uint8
	var _audioLen C.Uint32
	audioSpec := (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(src.cptr(), C.int(freeSrc), spec.cptr(), &_audioBuf, &_audioLen)))

	var b []byte
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Len = (int)(_audioLen)
	sliceHeader.Cap = (int)(_audioLen)
	sliceHeader.Data = uintptr(unsafe.Pointer(_audioBuf))
	return b, audioSpec
}

// LoadWAV (https://wiki.libsdl.org/SDL_LoadWAV)
func LoadWAV(file string, spec *AudioSpec) ([]byte, *AudioSpec) {
	_file := C.CString(file)
	_rb := C.CString("rb")
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_rb))

	var _audioBuf *C.Uint8
	var _audioLen C.Uint32
	audioSpec := (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(C.SDL_RWFromFile(_file, _rb), 1, spec.cptr(), &_audioBuf, &_audioLen)))

	var b []byte
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Len = (int)(_audioLen)
	sliceHeader.Cap = (int)(_audioLen)
	sliceHeader.Data = uintptr(unsafe.Pointer(_audioBuf))
	return b, audioSpec
}

// FreeWAV (https://wiki.libsdl.org/SDL_FreeWAV)
func FreeWAV(audioBuf []uint8) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&audioBuf))
	_audioBuf := (*C.Uint8)(unsafe.Pointer(sliceHeader.Data))
	C.SDL_FreeWAV(_audioBuf)
}

// BuildAudioCVT (https://wiki.libsdl.org/SDL_BuildAudioCVT)
func BuildAudioCVT(cvt *AudioCVT, srcFormat AudioFormat, srcChannels uint8, srcRate int, dstFormat AudioFormat, dstChannels uint8, dstRate int) int {
	return int(C.SDL_BuildAudioCVT(cvt.cptr(), srcFormat.c(), C.Uint8(srcChannels), C.int(srcRate), dstFormat.c(), C.Uint8(dstChannels), C.int(dstRate)))
}

// ConvertAudio (https://wiki.libsdl.org/SDL_ConvertAudio)
func ConvertAudio(cvt *AudioCVT) int {
	_cvt := (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
	return int(C.SDL_ConvertAudio(_cvt))
}

// MixAudio (https://wiki.libsdl.org/SDL_MixAudio)
func MixAudio(dst, src *uint8, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudio(_dst, _src, C.Uint32(len_), C.int(volume))
}

// MixAudioFormat (https://wiki.libsdl.org/SDL_MixAudioFormat)
func MixAudioFormat(dst, src *uint8, format AudioFormat, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudioFormat(_dst, _src, format.c(), C.Uint32(len_), C.int(volume))
}

// LockAudio (https://wiki.libsdl.org/SDL_LockAudio)
func LockAudio() {
	C.SDL_LockAudio()
}

// LockAudioDevice (https://wiki.libsdl.org/SDL_LockAudioDevice)
func LockAudioDevice(dev AudioDeviceID) {
	C.SDL_LockAudioDevice(dev.c())
}

// UnlockAudio (https://wiki.libsdl.org/SDL_UnlockAudio)
func UnlockAudio() {
	C.SDL_UnlockAudio()
}

// UnlockAudioDevice (https://wiki.libsdl.org/SDL_UnlockAudioDevice)
func UnlockAudioDevice(dev AudioDeviceID) {
	C.SDL_UnlockAudioDevice(dev.c())
}

// CloseAudio (https://wiki.libsdl.org/SDL_CloseAudio)
func CloseAudio() {
	C.SDL_CloseAudio()
}

// CloseAudioDevice (https://wiki.libsdl.org/SDL_CloseAudioDevice)
func CloseAudioDevice(dev AudioDeviceID) {
	C.SDL_CloseAudioDevice(dev.c())
}

/*
func AudioDeviceConnected(dev AudioDeviceID) int {
	_dev := (C.SDL_AudioDeviceID) (dev)
	return int (C.SDL_AudioDeviceConnected(_dev))
}
*/
<|endoftext|>


<commit_before>package sdl

// #include "sdl_wrapper.h"
import "C"
import "errors"

// SDL error codes with their corresponding predefined strings.
const (
	ENOMEM      ErrorCode = C.SDL_ENOMEM      // out of memory
	EFREAD                = C.SDL_EFREAD      // error reading from datastream
	EFWRITE               = C.SDL_EFWRITE     // error writing to datastream
	EFSEEK                = C.SDL_EFSEEK      // error seeking in datastream
	UNSUPPORTED           = C.SDL_UNSUPPORTED // that operation is not supported
	LASTERROR             = C.SDL_LASTERROR   // the highest numbered predefined error
)

// ErrorCode is an SDL error code for common errors.
type ErrorCode uint32
type cErrorCode C.SDL_errorcode

func (ec ErrorCode) c() C.SDL_errorcode {
	return C.SDL_errorcode(ec)
}

// GetError returns the last error that occurred, or an empty string if there hasn't been an error message set since the last call to ClearError().
// (https://wiki.libsdl.org/SDL_GetError)
func GetError() error {
	if err := C.SDL_GetError(); err != nil {
		gostr := C.GoString(err)
		// SDL_GetError returns "an empty string if there hasn't been an error message"
		if len(gostr) > 0 {
			return errors.New(gostr)
		}
	}
	return nil
}

// ClearError clears any previous error message.
// (https://wiki.libsdl.org/SDL_ClearError)
func ClearError() {
	C.SDL_ClearError()
}

// Error sets the SDL error message to the predefined string specified by code.
func Error(code ErrorCode) {
	C.SDL_Error(code.c())
}

// OutOfMemory sets SDL error message to ENOMEM (out of memory).
func OutOfMemory() {
	Error(ENOMEM)
}

// Unsupported sets SDL error message to UNSUPPORTED (unknown SDL error).
func Unsupported() {
	Error(UNSUPPORTED)
}
<commit_msg>sdl: error: Fix documentation #265<commit_after>package sdl

// #include "sdl_wrapper.h"
import "C"
import "errors"

// SDL error codes with their corresponding predefined strings.
const (
	ENOMEM      ErrorCode = C.SDL_ENOMEM      // out of memory
	EFREAD                = C.SDL_EFREAD      // error reading from datastream
	EFWRITE               = C.SDL_EFWRITE     // error writing to datastream
	EFSEEK                = C.SDL_EFSEEK      // error seeking in datastream
	UNSUPPORTED           = C.SDL_UNSUPPORTED // that operation is not supported
	LASTERROR             = C.SDL_LASTERROR   // the highest numbered predefined error
)

// ErrorCode is an error code used in SDL error messages.
type ErrorCode uint32
type cErrorCode C.SDL_errorcode

func (ec ErrorCode) c() C.SDL_errorcode {
	return C.SDL_errorcode(ec)
}

// GetError returns the last error that occurred, or an empty string if there hasn't been an error message set since the last call to ClearError().
// (https://wiki.libsdl.org/SDL_GetError)
func GetError() error {
	if err := C.SDL_GetError(); err != nil {
		gostr := C.GoString(err)
		// SDL_GetError returns "an empty string if there hasn't been an error message"
		if len(gostr) > 0 {
			return errors.New(gostr)
		}
	}
	return nil
}

// ClearError clears any previous error message.
// (https://wiki.libsdl.org/SDL_ClearError)
func ClearError() {
	C.SDL_ClearError()
}

// Error sets the SDL error message to the specified error code.
func Error(code ErrorCode) {
	C.SDL_Error(code.c())
}

// OutOfMemory sets SDL error message to ENOMEM (out of memory).
func OutOfMemory() {
	Error(ENOMEM)
}

// Unsupported sets SDL error message to UNSUPPORTED (unknown SDL error).
func Unsupported() {
	Error(UNSUPPORTED)
}
<|endoftext|>


<commit_before>package sdl

// TODO put these C functions in their own event.c file

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
//
// Uint32 GetType(SDL_Event* ev) {
//		return ev->type;
// }
//
// SDL_QuitEvent* ConvertToQuitEvent(SDL_Event* ev) {
//		return &ev->quit;
// }
//
// SDL_KeyboardEvent* ConvertToKeyboardEvent(SDL_Event* ev) {
//		return &ev->key;
// }
import "C"

import (
	"fmt"
)

// START EventType {{{1

type EventType uint16

const (
	FIRSTEVENT EventType = 0
)

/* Application events */
const (
	QUIT EventType = 0x100 + iota
	/* These application events have special meaning on iOS, see README-ios.txt for details */
	APP_TERMINATING
	APP_LOWMEMORY
	APP_WILLENTERBACKGROUND
	APP_DIDENTERBACKGROUND
	APP_WILLENTERFOREGROUND
	APP_DIDENTERFOREGROUND
)

/* Window events */
const (
	WINDOWEVENT EventType = 0x200 + iota
	SYSWMEVENT
)

/* Keyboard events */
const (
	KEYDOWN EventType = 0x300 + iota
	KEYUP
	TEXTEDITING
	TEXTINPUT
)

/* Mouse events */
const (
	MOUSEMOTION EventType = 0x400 + iota
	MOUSEBUTTONDOWN
	MOUSEBUTTONUP
	MOUSEWHEEL
)

/* Joystick events */
const (
	JOYAXISMOTION EventType = 0x600 + iota
	JOYBALLMOTION
	JOYHATMOTION
	JOYBUTTONDOWN
	JOYBUTTONUP
	JOYDEVICEADDED
	JOYDEVICEREMOVED
)

/* Game controller events */
const (
	CONTROLLERAXISMOTION EventType = 0x650 + iota
	CONTROLLERBUTTONDOWN
	CONTROLLERBUTTONUP
	CONTROLLERDEVICEADDED
	CONTROLLERDEVICEREMOVED
	CONTROLLERDEVICEREMAPPED
)

/* Touch events */
const (
	FINGERDOWN EventType = 0x700 + iota
	FINGERUP
	FINGERMOTION
)

/* Gesture events */
const (
	DOLLARGESTURE EventType = 0x800 + iota
	DOLLARRECORD
	MULTIGESTURE
)

/* Clipboard events */
const (
	CLIPBOARDUPDATE EventType = 0x900
)

/* Drag and drop events */
const (
	DROPFILE EventType = 0x1000
)

/*
Events ::USEREVENT through ::LASTEVENT are for your use
and should be allocated with RegisterEvents()
*/
const (
	USEREVENT EventType = 0x8000
	// This last event is only for bounding internal arrays
	LASTEVENT EventType = 0xFFFF
)

// END EventType }}}1

type Event interface {
	// TODO add Type() EventType
	Timestamp() uint32
}

func PollEvent() (ev Event) {
	var cEvent C.SDL_Event
	if isEvent := C.SDL_PollEvent(&cEvent); isEvent == 0 {
		return nil
	}

	return convertEvent(&cEvent)
}

func convertEvent(cEvent *C.SDL_Event) (ev Event) {
	switch EventType(C.GetType(cEvent)) {
	case QUIT:
		return QuitEvent{*C.ConvertToQuitEvent(cEvent)}
	case KEYDOWN, KEYUP, TEXTEDITING, TEXTINPUT:
		return KeyboardEvent{*C.ConvertToKeyboardEvent(cEvent)}
	default:
		fmt.Printf("Unhandled event with int: %d\n", int(C.GetType(cEvent)))
		return nil
	}
}

// TODO make this implement Event
type CommonEvent struct {
	ev C.SDL_CommonEvent
}

// TODO make this implement Event
type WindowEvent struct {
	ev C.SDL_WindowEvent
}

type KeyboardEvent struct {
	ev C.SDL_KeyboardEvent
}

func (event KeyboardEvent) Timestamp() uint32 {
	return uint32(event.ev.timestamp)
}

func (event KeyboardEvent) WindowID() uint32 {
	return uint32(event.ev.windowID)
}

func (event KeyboardEvent) State() uint8 {
	return uint8(event.ev.state)
}

func (event KeyboardEvent) Repeat() uint8 {
	return uint8(event.ev.repeat)
}

// TODO this
/*
func (event KeyboardEvent) Keysym() Keysym {
}
*/

// TODO make this implement Event
type TextEditingEvent struct {
	ev C.SDL_TextEditingEvent
}

// TODO make this implement Event
type TextInputEvent struct {
	ev C.SDL_TextInputEvent
}

// TODO make this implement Event
type MouseMotionEvent struct {
	ev C.SDL_MouseMotionEvent
}

// TODO make this implement Event
type MouseButtonEvent struct {
	ev C.SDL_MouseButtonEvent
}

// TODO make this implement Event
type MouseWheelEvent struct {
	ev C.SDL_MouseWheelEvent
}

// TODO make this implement Event
type JoyAxisEvent struct {
	ev C.SDL_JoyAxisEvent
}

// TODO make this implement Event
type JoyBallEvent struct {
	ev C.SDL_JoyBallEvent
}

// TODO make this implement Event
type JoyHatEvent struct {
	ev C.SDL_JoyHatEvent
}

// TODO make this implement Event
type JoyButtonEvent struct {
	ev C.SDL_JoyButtonEvent
}

// TODO make this implement Event
type JoyDeviceEvent struct {
	ev C.SDL_JoyDeviceEvent
}

// TODO make this implement Event
type ControllerAxisEvent struct {
	ev C.SDL_ControllerAxisEvent
}

// TODO make this implement Event
type ControllerButtonEvent struct {
	ev C.SDL_ControllerButtonEvent
}

// TODO make this implement Event
type ControllerDeviceEvent struct {
	ev C.SDL_ControllerDeviceEvent
}

type QuitEvent struct {
	ev C.SDL_QuitEvent
}

func (event QuitEvent) Timestamp() uint32 {
	return uint32(event.ev.timestamp)
}

// TODO make this implement Event
type UserEvent struct {
	ev C.SDL_UserEvent
}

// TODO make this implement Event
type SysWMEvent struct {
	ev C.SDL_SysWMEvent
}

// TODO make this implement Event
type TouchFingerEvent struct {
	ev C.SDL_TouchFingerEvent
}

// TODO make this implement Event
type MultiGestureEvent struct {
	ev C.SDL_MultiGestureEvent
}

// TODO make this implement Event
type DollarGestureEvent struct {
	ev C.SDL_DollarGestureEvent
}

// TODO make this implement Event
type DropEvent struct {
	ev C.SDL_DropEvent
}
<commit_msg>Events: fix constant casing, Quit and Keyboard event types<commit_after>package sdl

// TODO put these C functions in their own event.c file

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
//
// Uint32 GetType(SDL_Event* ev) {
//		return ev->type;
// }
//
// SDL_QuitEvent* ConvertToQuitEvent(SDL_Event* ev) {
//		return &ev->quit;
// }
//
// SDL_KeyboardEvent* ConvertToKeyboardEvent(SDL_Event* ev) {
//		return &ev->key;
// }
import "C"

import (
	"fmt"
	"unsafe"
)

// START EventType {{{1

type EventType uint16

const (
	FirstEvent EventType = 0
)

/* Application events */
const (
	QuitEv EventType = 0x100 + iota
	/* These application events have special meaning on iOS, see README-ios.txt for details */
	AppTerminatingEv
	AppLowMemoryEv
	AppWillEnterBackgroundEv
	AppDidEnterBackgroundEv
	AppWillEnterForegroundEv
	AppDidEnterForegroundEv
)

/* Window events */
const (
	WindowEv EventType = 0x200 + iota
	SysWmEv
)

/* Keyboard events */
const (
	KeyDownEv EventType = 0x300 + iota
	KeyUpEv
	TextEditingEv
	TextInputEv
)

/* Mouse events */
const (
	MouseMotionEv EventType = 0x400 + iota
	MouseButtonDownEv
	MouseButtonUpEv
	MouseWheelEv
)

/* Joystick events */
const (
	JoyAxisMotionEv EventType = 0x600 + iota
	JoyBallMotionEv
	JoyHatMotionEv
	JoyButtonDownEv
	JoyButtonUpEv
	JoyDeviceAddedEv
	JoyDeviceRemovedEv
)

/* Game controller events */
const (
	ControllerAxisMotionEv EventType = 0x650 + iota
	ControllerButtonDownEv
	ControllerButtonUpEv
	ControllerDeviceAddedEv
	ControllerDeviceRemovedEv
	ControllerDeviceRemappedEv
)

/* Touch events */
const (
	FingerDownEv EventType = 0x700 + iota
	FingerUpEv
	FingerMotionEv
)

/* Gesture events */
const (
	DollarGestureEv EventType = 0x800 + iota
	DollarRecordEv
	MultiGestureEv
)

/* Clipboard events */
const (
	ClipboardUpdateEv EventType = 0x900
)

/* Drag and drop events */
const (
	DropFileEv EventType = 0x1000
)

/*
Events ::USEREVENT through ::LASTEVENT are for your use
and should be allocated with RegisterEvents()
*/
const (
	UserEv EventType = 0x8000
	// This last event is only for bounding internal arrays
	LastEv EventType = 0xFFFF
)

// END EventType }}}1

type Event interface {
	Timestamp() uint32
	Type() EventType
}

func PollEvent() (ev Event) {
	var cEvent C.SDL_Event
	if isEvent := C.SDL_PollEvent(&cEvent); isEvent == 0 {
		return nil
	}

	return convertEvent(&cEvent)
}

func convertEvent(cEvent *C.SDL_Event) (ev Event) {
	switch EventType(C.GetType(cEvent)) {
	case QuitEv:
		return QuitEvent{C.ConvertToQuitEvent(cEvent)}
	case KeyDownEv, KeyUpEv:
		return KeyboardEvent{C.ConvertToKeyboardEvent(cEvent)}
	default:
		fmt.Printf("Unhandled event with int: %d\n", int(C.GetType(cEvent)))
		return nil
	}
}

// TODO make this implement Event
type CommonEvent struct {
	ev C.SDL_CommonEvent
}

// TODO make this implement Event
type WindowEvent struct {
	ev C.SDL_WindowEvent
}

type KeyboardEvent struct {
	e *C.SDL_KeyboardEvent
}

func (e KeyboardEvent) Timestamp() uint32 {
	return uint32(e.e.timestamp)
}

func (e KeyboardEvent) Type() EventType {
	// Have to do this icky thing to get what type of keyboard event it is
	return EventType(C.GetType((*C.SDL_Event)(unsafe.Pointer(e.e))))
}

func (e KeyboardEvent) WindowID() uint32 {
	return uint32(e.e.windowID)
}

func (e KeyboardEvent) State() uint8 {
	return uint8(e.e.state)
}

func (e KeyboardEvent) Repeat() uint8 {
	return uint8(e.e.repeat)
}

// TODO this
/*
func (e KeyboardEvent) Keysym() Keysym {
}
*/

// TODO make this implement Event
type TextEditingEvent struct {
	ev C.SDL_TextEditingEvent
}

// TODO make this implement Event
type TextInputEvent struct {
	ev C.SDL_TextInputEvent
}

// TODO make this implement Event
type MouseMotionEvent struct {
	ev C.SDL_MouseMotionEvent
}

// TODO make this implement Event
type MouseButtonEvent struct {
	ev C.SDL_MouseButtonEvent
}

// TODO make this implement Event
type MouseWheelEvent struct {
	ev C.SDL_MouseWheelEvent
}

// TODO make this implement Event
type JoyAxisEvent struct {
	ev C.SDL_JoyAxisEvent
}

// TODO make this implement Event
type JoyBallEvent struct {
	ev C.SDL_JoyBallEvent
}

// TODO make this implement Event
type JoyHatEvent struct {
	ev C.SDL_JoyHatEvent
}

// TODO make this implement Event
type JoyButtonEvent struct {
	ev C.SDL_JoyButtonEvent
}

// TODO make this implement Event
type JoyDeviceEvent struct {
	ev C.SDL_JoyDeviceEvent
}

// TODO make this implement Event
type ControllerAxisEvent struct {
	ev C.SDL_ControllerAxisEvent
}

// TODO make this implement Event
type ControllerButtonEvent struct {
	ev C.SDL_ControllerButtonEvent
}

// TODO make this implement Event
type ControllerDeviceEvent struct {
	ev C.SDL_ControllerDeviceEvent
}

type QuitEvent struct {
	e *C.SDL_QuitEvent
}

func (e QuitEvent) Timestamp() uint32 {
	return uint32(e.e.timestamp)
}

func (e QuitEvent) Type() EventType {
	return QuitEv
}

// TODO make this implement Event
type UserEvent struct {
	ev C.SDL_UserEvent
}

// TODO make this implement Event
type SysWMEvent struct {
	ev C.SDL_SysWMEvent
}

// TODO make this implement Event
type TouchFingerEvent struct {
	ev C.SDL_TouchFingerEvent
}

// TODO make this implement Event
type MultiGestureEvent struct {
	ev C.SDL_MultiGestureEvent
}

// TODO make this implement Event
type DollarGestureEvent struct {
	ev C.SDL_DollarGestureEvent
}

// TODO make this implement Event
type DropEvent struct {
	ev C.SDL_DropEvent
}
<|endoftext|>


<commit_before>package termite

import (
	"io/ioutil"
	"log"
	"net/rpc"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type Master struct {
	cache         *ContentCache
	fileServer    *FsServer
	fileServerRpc *rpc.Server
	excluded      map[string]bool
	attr          *AttributeCache
	mirrors       *mirrorConnections
	pending       *PendingConnections
	taskIds       chan int
	options       *MasterOptions
	replayChannel chan *replayRequest
	quit          chan int
}

type MasterOptions struct {
	WritableRoot   string
	SrcRoot        string
	RetryCount     int
	Excludes       []string
	ExcludePrivate bool

	Coordinator string
	Workers     []string
	Secret      []byte
	MaxJobs     int
	Paranoia    bool

	// On startup, fault-in all files.
	FetchAll    bool

	Period    float64
	KeepAlive float64
}

type replayRequest struct {
	NewFiles map[string]string
	Files    []*FileAttr
	Done     chan int
}

func (me *Master) uncachedGetAttr(name string) (rep *FileAttr) {
	rep = &FileAttr{Path: name}
	p := me.path(name)
	fi, _ := os.Lstat(p)

	// We don't want to expose the master's private files to the
	// world.
	if me.options.ExcludePrivate && fi != nil && fi.Mode&0077 == 0 {
		log.Printf("Denied access to private file %q", name)
		return rep
	}

	if me.excluded[name] {
		log.Printf("Denied access to excluded file %q", name)
		return rep
	}
	rep.FileInfo = fi
	if fi != nil {
		me.fillContent(rep)
	}
	return rep
}

func (me *Master) fillContent(rep *FileAttr) {
	if rep.IsSymlink() || rep.IsDirectory() {
		rep.ReadFromFs(me.path(rep.Path))
	} else if rep.IsRegular() {
		fullPath := me.path(rep.Path)
		rep.Hash = me.cache.SavePath(fullPath)
		if rep.Hash == "" {
			// Typically happens if we want to open /etc/shadow as normal user.
			log.Println("fillContent returning EPERM for", rep.Path)
			rep.FileInfo = nil
		}
	}
}

func (me *Master) path(n string) string {
	return "/" + n
}

func NewMaster(cache *ContentCache, options *MasterOptions) *Master {
	me := &Master{
		cache:         cache,
		taskIds:       make(chan int, 100),
		replayChannel: make(chan *replayRequest, 1),
		quit:          make(chan int, 100),
	}
	o := *options
	if o.Period <= 0.0 {
		o.Period = 60.0
	}
	me.options = &o
	me.excluded = make(map[string]bool)
	for _, e := range options.Excludes {
		me.excluded[e] = true
	}

	me.mirrors = newMirrorConnections(
		me, options.Workers, options.Coordinator, options.MaxJobs)
	me.mirrors.keepAliveNs = int64(1e9 * options.KeepAlive)
	me.pending = NewPendingConnections()
	me.attr = NewAttributeCache(func(n string) *FileAttr {
		return me.uncachedGetAttr(n)
	},
		func(n string) *os.FileInfo {
			fi, _ := os.Lstat(me.path(n))
			return fi
		})
	me.fileServer = NewFsServer(me.attr, me.cache)
	me.fileServerRpc = rpc.NewServer()
	me.fileServerRpc.Register(me.fileServer)

	me.CheckPrivate()

	// Generate taskids.
	go func() {
		i := 0
		for {
			me.taskIds <- i
			i++
		}
	}()

	// Make sure we update the filesystem and attributes together.
	go func() {
		for {
			r := <-me.replayChannel
			me.replayFileModifications(r.Files, r.NewFiles)
			r.Done <- 1
		}
	}()

	return me
}

func (me *Master) CheckPrivate() {
	if !me.options.ExcludePrivate {
		return
	}
	d := me.options.WritableRoot
	for d != "" {
		fi, err := os.Lstat(d)
		if err != nil {
			log.Fatal("CheckPrivate:", err)
		}
		if fi != nil && fi.Mode&0077 == 0 {
			log.Fatalf("Error: dir %q is mode %o.", d, fi.Mode&07777)
		}
		d, _ = SplitPath(d)
	}
}

func (me *Master) Start(sock string) {
	// Fetch in the background.
	last := ""

	if me.options.FetchAll {
		for _, r := range []string{me.options.WritableRoot, me.options.SrcRoot} {
			if last == r || r == "" {
				continue
			}
			go me.fetchAll(strings.TrimLeft(r, "/"))
		}
	}
	go localStart(me, sock)
	me.waitForExit()
}

func (me *Master) createMirror(addr string, jobs int) (*mirrorConnection, error) {
	secret := me.options.Secret
	conn, err := DialTypedConnection(addr, RPC_CHANNEL, secret)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	rpcId := ConnectionId()
	rpcConn, err := DialTypedConnection(addr, rpcId, secret)
	if err != nil {
		return nil, err
	}

	revId := ConnectionId()
	revConn, err := DialTypedConnection(addr, revId, secret)
	if err != nil {
		rpcConn.Close()
		return nil, err
	}

	req := CreateMirrorRequest{
		RpcId:        rpcId,
		RevRpcId:     revId,
		WritableRoot: me.options.WritableRoot,
		MaxJobCount:  jobs,
	}
	rep := CreateMirrorResponse{}
	cl := rpc.NewClient(conn)
	err = cl.Call("Worker.CreateMirror", &req, &rep)
	cl.Close()

	if err != nil {
		revConn.Close()
		rpcConn.Close()
		return nil, err
	}

	go me.fileServerRpc.ServeConn(revConn)

	mc := &mirrorConnection{
		master:            me,
		rpcClient:         rpc.NewClient(rpcConn),
		reverseConnection: revConn,
		connection:        rpcConn,
		maxJobs:           rep.GrantedJobCount,
		availableJobs:     rep.GrantedJobCount,
	}
	mc.fileSetWaiter = newFileSetWaiter(func(fset FileSet) error {
		return mc.replay(fset)
	})

	return mc, nil
}

func (me *Master) runOnMirror(mirror *mirrorConnection, req *WorkRequest, rep *WorkResponse) error {
	me.mirrors.stats.Enter("send")
	err := me.fileServer.attr.Send(mirror)
	me.mirrors.stats.Exit("send")
	if err != nil {
		return err
	}

	defer me.mirrors.jobDone(mirror)

	// Tunnel stdin.
	if req.StdinId != "" {
		inputConn := me.pending.WaitConnection(req.StdinId)
		destInputConn, err := DialTypedConnection(mirror.connection.RemoteAddr().String(),
			req.StdinId, me.options.Secret)
		if err != nil {
			return err
		}
		go func() {
			HookedCopy(destInputConn, inputConn, PrintStdinSliceLen)
			destInputConn.Close()
			inputConn.Close()
		}()
	}

	log.Printf("Running task %d on %s: %v", req.TaskId, mirror.workerAddr, req.Argv)
	if req.Debug {
		log.Println("with environment", req.Env)
	}

	mirror.fileSetWaiter.newChannel(req.TaskId)
	me.mirrors.stats.Enter("remote")
	err = mirror.rpcClient.Call("Mirror.Run", req, rep)
	me.mirrors.stats.Exit("remote")
	if err == nil {
		me.mirrors.stats.Enter("filewait")
		err = mirror.fileSetWaiter.wait(rep, req.TaskId)
		me.mirrors.stats.Exit("filewait")
	}
	return err
}

func (me *Master) runOnce(req *WorkRequest, rep *WorkResponse) error {
	mirror, err := me.mirrors.pick()
	if err != nil {
		return err
	}
	err = me.runOnMirror(mirror, req, rep)
	if err != nil {
		me.mirrors.drop(mirror, err)
		return err
	}

	rep.FileSet = nil
	return err
}

func (me *Master) run(req *WorkRequest, rep *WorkResponse) (err error) {
	me.mirrors.stats.Enter("run")
	defer me.mirrors.stats.Exit("run")
	req.TaskId = <-me.taskIds
	if me.MaybeRunInMaster(req, rep) {
		log.Println("Ran in master:", req.Summary())
		return nil
	}

	if req.Worker != "" {
		mc, err := me.mirrors.find(req.Worker)
		if err != nil {
			return err
		}
		return me.runOnMirror(mc, req, rep)
	}

	err = me.runOnce(req, rep)
	for i := 0; i < me.options.RetryCount && err != nil; i++ {
		log.Println("Retrying; last error:", err)
		err = me.runOnce(req, rep)
	}

	return err
}

func (me *Master) replayFileModifications(infos []*FileAttr, newFiles map[string]string) {
	for _, info := range infos {
		logStr := ""
		name := "/" + info.Path
		var err error
		if info.FileInfo != nil && info.FileInfo.IsDirectory() {
			err := os.Mkdir(name, info.FileInfo.Mode&07777)
			if err != nil {
				// some other process may have created
				// the dir.
				if fi, _ := os.Lstat(name); fi != nil && fi.IsDirectory() {
					err = nil
				}
			}
		}
		if info.Hash != "" {
			src := newFiles[info.Path]
			err = os.Rename(src, name)
		}
		if info.Link != "" {
			// Ignore errors.
			os.Remove(name)
			err = os.Symlink(info.Link, name)
			logStr += "Symlink,"
		}
		if info.Deletion() {
			if err := os.Remove(name); err != nil {
				log.Println("delete replay: ", err)
			}
		}

		if info.Hash == "" && info.FileInfo != nil && !info.FileInfo.IsSymlink() {
			if err == nil {
				err = os.Chtimes(name, info.FileInfo.Atime_ns, info.FileInfo.Mtime_ns)
				logStr += "Chtimes,"
			}
			if err == nil {
				err = os.Chmod(name, info.FileInfo.Mode&07777)
				logStr += "Chmod,"
			}
		}

		if err != nil {
			log.Fatal("Replay error ", info.Path, " ", err, infos, logStr)
		}
	}

	me.attr.Update(infos)
}

func (me *Master) replay(fset FileSet) {
	req := replayRequest{
		make(map[string]string),
		fset.Files,
		make(chan int),
	}

	// We prepare the files before we call
	// replayFileModifications(), to limit contention.
	for _, info := range fset.Files {
		if info.Hash == "" {
			continue
		}

		log.Printf("Prepare %x: %s", info.Hash, info.Path)
		f, err := ioutil.TempFile(me.options.WritableRoot, ".tmp-termite")
		if err != nil {
			log.Fatal("TempFile", err)
		}

		req.NewFiles[info.Path] = f.Name()

		content := me.cache.ContentsIfLoaded(info.Hash)

		if content == nil {
			var src *os.File
			src, err = os.Open(me.cache.Path(info.Hash))
			if err != nil {
				log.Panicf("cache path missing %x", info.Hash)
			}
			err = CopyFds(f, src)
		} else {
			_, err = f.Write(content)
		}
		if err != nil {
			log.Fatal("f.Write", err)
		}

		err = f.Chmod(info.FileInfo.Mode & 07777)
		if err != nil {
			log.Fatal("f.Chmod", err)
		}
		err = f.Close()
		if err != nil {
			log.Fatal("f.Close", err)
		}
		err = os.Chtimes(f.Name(), info.FileInfo.Atime_ns, info.FileInfo.Mtime_ns)
		if err != nil {
			log.Fatal("Chtimes", err)
		}
	}

	me.fileServer.attr.Queue(fset)

	me.replayChannel <- &req
	<-req.Done
}

func (me *Master) refreshAttributeCache() {
	last := ""
	for _, r := range []string{me.options.WritableRoot, me.options.SrcRoot} {
		if last == r || r == "" {
			continue
		}
		updated := me.attr.Refresh(r[1:])
		me.attr.Queue(updated)
		last = r
	}
}

func (me *Master) fetchAll(path string) {
	a := me.attr.GetDir(path)
	for n := range a.NameModeMap {
		me.fetchAll(filepath.Join(path, n))
	}
}

func (me *Master) waitForExit() {
	me.mirrors.refreshWorkers()
	ticker := time.NewTicker(int64(1e9 * me.options.Period))
	for {
		select {
		case <-me.quit:
			log.Println("quit received.")
			break
		case <-ticker.C:
			me.mirrors.periodicHouseholding()
		}
	}
}
<commit_msg>Stat file after replaying, to catch timestamp skews.<commit_after>package termite

import (
	"io/ioutil"
	"log"
	"net/rpc"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type Master struct {
	cache         *ContentCache
	fileServer    *FsServer
	fileServerRpc *rpc.Server
	excluded      map[string]bool
	attr          *AttributeCache
	mirrors       *mirrorConnections
	pending       *PendingConnections
	taskIds       chan int
	options       *MasterOptions
	replayChannel chan *replayRequest
	quit          chan int
}

type MasterOptions struct {
	WritableRoot   string
	SrcRoot        string
	RetryCount     int
	Excludes       []string
	ExcludePrivate bool

	Coordinator string
	Workers     []string
	Secret      []byte
	MaxJobs     int
	Paranoia    bool

	// On startup, fault-in all files.
	FetchAll    bool

	Period    float64
	KeepAlive float64
}

type replayRequest struct {
	NewFiles map[string]string
	Files    []*FileAttr
	Done     chan int
}

func (me *Master) uncachedGetAttr(name string) (rep *FileAttr) {
	rep = &FileAttr{Path: name}
	p := me.path(name)
	fi, _ := os.Lstat(p)

	// We don't want to expose the master's private files to the
	// world.
	if me.options.ExcludePrivate && fi != nil && fi.Mode&0077 == 0 {
		log.Printf("Denied access to private file %q", name)
		return rep
	}

	if me.excluded[name] {
		log.Printf("Denied access to excluded file %q", name)
		return rep
	}
	rep.FileInfo = fi
	if fi != nil {
		me.fillContent(rep)
	}
	return rep
}

func (me *Master) fillContent(rep *FileAttr) {
	if rep.IsSymlink() || rep.IsDirectory() {
		rep.ReadFromFs(me.path(rep.Path))
	} else if rep.IsRegular() {
		fullPath := me.path(rep.Path)
		rep.Hash = me.cache.SavePath(fullPath)
		if rep.Hash == "" {
			// Typically happens if we want to open /etc/shadow as normal user.
			log.Println("fillContent returning EPERM for", rep.Path)
			rep.FileInfo = nil
		}
	}
}

func (me *Master) path(n string) string {
	return "/" + n
}

func NewMaster(cache *ContentCache, options *MasterOptions) *Master {
	me := &Master{
		cache:         cache,
		taskIds:       make(chan int, 100),
		replayChannel: make(chan *replayRequest, 1),
		quit:          make(chan int, 100),
	}
	o := *options
	if o.Period <= 0.0 {
		o.Period = 60.0
	}
	me.options = &o
	me.excluded = make(map[string]bool)
	for _, e := range options.Excludes {
		me.excluded[e] = true
	}

	me.mirrors = newMirrorConnections(
		me, options.Workers, options.Coordinator, options.MaxJobs)
	me.mirrors.keepAliveNs = int64(1e9 * options.KeepAlive)
	me.pending = NewPendingConnections()
	me.attr = NewAttributeCache(func(n string) *FileAttr {
		return me.uncachedGetAttr(n)
	},
		func(n string) *os.FileInfo {
			fi, _ := os.Lstat(me.path(n))
			return fi
		})
	me.fileServer = NewFsServer(me.attr, me.cache)
	me.fileServerRpc = rpc.NewServer()
	me.fileServerRpc.Register(me.fileServer)

	me.CheckPrivate()

	// Generate taskids.
	go func() {
		i := 0
		for {
			me.taskIds <- i
			i++
		}
	}()

	// Make sure we update the filesystem and attributes together.
	go func() {
		for {
			r := <-me.replayChannel
			me.replayFileModifications(r.Files, r.NewFiles)
			r.Done <- 1
		}
	}()

	return me
}

func (me *Master) CheckPrivate() {
	if !me.options.ExcludePrivate {
		return
	}
	d := me.options.WritableRoot
	for d != "" {
		fi, err := os.Lstat(d)
		if err != nil {
			log.Fatal("CheckPrivate:", err)
		}
		if fi != nil && fi.Mode&0077 == 0 {
			log.Fatalf("Error: dir %q is mode %o.", d, fi.Mode&07777)
		}
		d, _ = SplitPath(d)
	}
}

func (me *Master) Start(sock string) {
	// Fetch in the background.
	last := ""

	if me.options.FetchAll {
		for _, r := range []string{me.options.WritableRoot, me.options.SrcRoot} {
			if last == r || r == "" {
				continue
			}
			go me.fetchAll(strings.TrimLeft(r, "/"))
		}
	}
	go localStart(me, sock)
	me.waitForExit()
}

func (me *Master) createMirror(addr string, jobs int) (*mirrorConnection, error) {
	secret := me.options.Secret
	conn, err := DialTypedConnection(addr, RPC_CHANNEL, secret)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	rpcId := ConnectionId()
	rpcConn, err := DialTypedConnection(addr, rpcId, secret)
	if err != nil {
		return nil, err
	}

	revId := ConnectionId()
	revConn, err := DialTypedConnection(addr, revId, secret)
	if err != nil {
		rpcConn.Close()
		return nil, err
	}

	req := CreateMirrorRequest{
		RpcId:        rpcId,
		RevRpcId:     revId,
		WritableRoot: me.options.WritableRoot,
		MaxJobCount:  jobs,
	}
	rep := CreateMirrorResponse{}
	cl := rpc.NewClient(conn)
	err = cl.Call("Worker.CreateMirror", &req, &rep)
	cl.Close()

	if err != nil {
		revConn.Close()
		rpcConn.Close()
		return nil, err
	}

	go me.fileServerRpc.ServeConn(revConn)

	mc := &mirrorConnection{
		master:            me,
		rpcClient:         rpc.NewClient(rpcConn),
		reverseConnection: revConn,
		connection:        rpcConn,
		maxJobs:           rep.GrantedJobCount,
		availableJobs:     rep.GrantedJobCount,
	}
	mc.fileSetWaiter = newFileSetWaiter(func(fset FileSet) error {
		return mc.replay(fset)
	})

	return mc, nil
}

func (me *Master) runOnMirror(mirror *mirrorConnection, req *WorkRequest, rep *WorkResponse) error {
	me.mirrors.stats.Enter("send")
	err := me.fileServer.attr.Send(mirror)
	me.mirrors.stats.Exit("send")
	if err != nil {
		return err
	}

	defer me.mirrors.jobDone(mirror)

	// Tunnel stdin.
	if req.StdinId != "" {
		inputConn := me.pending.WaitConnection(req.StdinId)
		destInputConn, err := DialTypedConnection(mirror.connection.RemoteAddr().String(),
			req.StdinId, me.options.Secret)
		if err != nil {
			return err
		}
		go func() {
			HookedCopy(destInputConn, inputConn, PrintStdinSliceLen)
			destInputConn.Close()
			inputConn.Close()
		}()
	}

	log.Printf("Running task %d on %s: %v", req.TaskId, mirror.workerAddr, req.Argv)
	if req.Debug {
		log.Println("with environment", req.Env)
	}

	mirror.fileSetWaiter.newChannel(req.TaskId)
	me.mirrors.stats.Enter("remote")
	err = mirror.rpcClient.Call("Mirror.Run", req, rep)
	me.mirrors.stats.Exit("remote")
	if err == nil {
		me.mirrors.stats.Enter("filewait")
		err = mirror.fileSetWaiter.wait(rep, req.TaskId)
		me.mirrors.stats.Exit("filewait")
	}
	return err
}

func (me *Master) runOnce(req *WorkRequest, rep *WorkResponse) error {
	mirror, err := me.mirrors.pick()
	if err != nil {
		return err
	}
	err = me.runOnMirror(mirror, req, rep)
	if err != nil {
		me.mirrors.drop(mirror, err)
		return err
	}

	rep.FileSet = nil
	return err
}

func (me *Master) run(req *WorkRequest, rep *WorkResponse) (err error) {
	me.mirrors.stats.Enter("run")
	defer me.mirrors.stats.Exit("run")
	req.TaskId = <-me.taskIds
	if me.MaybeRunInMaster(req, rep) {
		log.Println("Ran in master:", req.Summary())
		return nil
	}

	if req.Worker != "" {
		mc, err := me.mirrors.find(req.Worker)
		if err != nil {
			return err
		}
		return me.runOnMirror(mc, req, rep)
	}

	err = me.runOnce(req, rep)
	for i := 0; i < me.options.RetryCount && err != nil; i++ {
		log.Println("Retrying; last error:", err)
		err = me.runOnce(req, rep)
	}

	return err
}

func (me *Master) replayFileModifications(infos []*FileAttr, newFiles map[string]string) {
	for _, info := range infos {
		logStr := ""
		name := "/" + info.Path
		var err error
		if info.FileInfo != nil && info.FileInfo.IsDirectory() {
			err := os.Mkdir(name, info.FileInfo.Mode&07777)
			if err != nil {
				// some other process may have created
				// the dir.
				if fi, _ := os.Lstat(name); fi != nil && fi.IsDirectory() {
					err = nil
				}
			}
		}
		if info.Hash != "" {
			src := newFiles[info.Path]
			err = os.Rename(src, name)
		}
		if info.Link != "" {
			// Ignore errors.
			os.Remove(name)
			err = os.Symlink(info.Link, name)
			logStr += "Symlink,"
		}
		if info.Deletion() {
			if err := os.Remove(name); err != nil {
				log.Println("delete replay: ", err)
			}
		}

		if info.Hash == "" && info.FileInfo != nil && !info.FileInfo.IsSymlink() {
			if err == nil {
				err = os.Chtimes(name, info.FileInfo.Atime_ns, info.FileInfo.Mtime_ns)
				logStr += "Chtimes,"
			}
			if err == nil {
				err = os.Chmod(name, info.FileInfo.Mode&07777)
				logStr += "Chmod,"
			}
		}

		if err != nil {
			log.Fatal("Replay error ", info.Path, " ", err, infos, logStr)
		}

		if info.FileInfo != nil {
			// Reread FileInfo, since some filesystems (eg. ext3) do
			// not have nanosecond timestamps.
			//
			// TODO - test this.
			info.FileInfo, _ = os.Lstat(name)
		}
	}

	me.attr.Update(infos)
}

func (me *Master) replay(fset FileSet) {
	req := replayRequest{
		make(map[string]string),
		fset.Files,
		make(chan int),
	}

	// We prepare the files before we call
	// replayFileModifications(), to limit contention.
	for _, info := range fset.Files {
		if info.Hash == "" {
			continue
		}

		log.Printf("Prepare %x: %s", info.Hash, info.Path)
		f, err := ioutil.TempFile(me.options.WritableRoot, ".tmp-termite")
		if err != nil {
			log.Fatal("TempFile", err)
		}

		req.NewFiles[info.Path] = f.Name()

		content := me.cache.ContentsIfLoaded(info.Hash)

		if content == nil {
			var src *os.File
			src, err = os.Open(me.cache.Path(info.Hash))
			if err != nil {
				log.Panicf("cache path missing %x", info.Hash)
			}
			err = CopyFds(f, src)
		} else {
			_, err = f.Write(content)
		}
		if err != nil {
			log.Fatal("f.Write", err)
		}

		err = f.Chmod(info.FileInfo.Mode & 07777)
		if err != nil {
			log.Fatal("f.Chmod", err)
		}
		err = f.Close()
		if err != nil {
			log.Fatal("f.Close", err)
		}
		err = os.Chtimes(f.Name(), info.FileInfo.Atime_ns, info.FileInfo.Mtime_ns)
		if err != nil {
			log.Fatal("Chtimes", err)
		}
	}

	me.fileServer.attr.Queue(fset)

	me.replayChannel <- &req
	<-req.Done
}

func (me *Master) refreshAttributeCache() {
	last := ""
	for _, r := range []string{me.options.WritableRoot, me.options.SrcRoot} {
		if last == r || r == "" {
			continue
		}
		updated := me.attr.Refresh(r[1:])
		me.attr.Queue(updated)
		last = r
	}
}

func (me *Master) fetchAll(path string) {
	a := me.attr.GetDir(path)
	for n := range a.NameModeMap {
		me.fetchAll(filepath.Join(path, n))
	}
}

func (me *Master) waitForExit() {
	me.mirrors.refreshWorkers()
	ticker := time.NewTicker(int64(1e9 * me.options.Period))
	for {
		select {
		case <-me.quit:
			log.Println("quit received.")
			break
		case <-ticker.C:
			me.mirrors.periodicHouseholding()
		}
	}
}
<|endoftext|>


<commit_before>package try

import "errors"

// MaxRetries is the maximum number of retries before bailing.
var MaxRetries = 10

var errMaxRetriesReached = errors.New("exceeded retry limit")

// Do keeps trying the function until the second argument
// returns false, or no error is returned.
func Do(fn func(attempt int) (retry bool, err error)) error {
	var err error
	var cont bool
	attempt := 1
	for {
		cont, err = fn(attempt)
		if !cont || err == nil {
			break
		}
		attempt++
		if attempt > MaxRetries {
			return errMaxRetriesReached
		}
	}
	return err
}

// IsMaxRetries checks whether the error is due to hitting the
// maximum number of retries or not.
func IsMaxRetries(err error) bool {
	return err == errMaxRetriesReached
}
<commit_msg>added Func for clarity<commit_after>package try

import "errors"

// MaxRetries is the maximum number of retries before bailing.
var MaxRetries = 10

var errMaxRetriesReached = errors.New("exceeded retry limit")

// Func represents functions that can be retried.
type Func func(attempt int) (retry bool, err error)

// Do keeps trying the function until the second argument
// returns false, or no error is returned.
func Do(fn Func) error {
	var err error
	var cont bool
	attempt := 1
	for {
		cont, err = fn(attempt)
		if !cont || err == nil {
			break
		}
		attempt++
		if attempt > MaxRetries {
			return errMaxRetriesReached
		}
	}
	return err
}

// IsMaxRetries checks whether the error is due to hitting the
// maximum number of retries or not.
func IsMaxRetries(err error) bool {
	return err == errMaxRetriesReached
}
<|endoftext|>


<commit_before>/*
The Sensu API provides access to the data that Sensu servers collect, such as client information & current events.
The API can be used to resolve events and request check executions, among other things.
*/
package sensu

import (
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
)

var DefaultAPI *API = &API{
	Host: "localhost",
	Port: 4567,
}

type API struct {
	Host     string
	Port     int
	User     string
	Password string
}

type Response struct {
	Body       string
	StatusCode int
}

func (api API) get(namespace string) (*Response, error) {
	return api.do("GET", namespace, nil)
}

func (api API) post(namespace string, payload io.Reader) (*Response, error) {
	return api.do("POST", namespace, payload)
}

func (api API) delete(namespace string) (*Response, error) {
	return api.do("DELETE", namespace, nil)
}

func (api API) do(method string, namespace string, payload io.Reader) (*Response, error) {
	request, err := api.newRequest(method, namespace, payload)
	if err != nil {
		return nil, err
	}

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	return &Response{
		Body:       string(body),
		StatusCode: response.StatusCode,
	}, nil
}

func (api API) newRequest(method string, namespace string, payload io.Reader) (*http.Request, error) {
	url := "http://" + api.Host + ":" + strconv.Itoa(api.Port) + namespace

	request, err := http.NewRequest(method, url, payload)
	if err != nil {
		return nil, err
	}

	if api.User != "" && api.Password != "" {
		request.SetBasicAuth(api.User, api.Password)
	}

	if payload != nil {
		request.Header.Set("Content-Type", "application/json")
	}

	return request, nil
}
<commit_msg>sensu.Response -> sensu.apiResponse<commit_after>/*
The Sensu API provides access to the data that Sensu servers collect, such as client information & current events.
The API can be used to resolve events and request check executions, among other things.
*/
package sensu

import (
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
)

var DefaultAPI *API = &API{
	Host: "localhost",
	Port: 4567,
}

type API struct {
	Host     string
	Port     int
	User     string
	Password string
}

type apiResponse struct {
	Body       string
	StatusCode int
}

func (api API) get(namespace string) (*apiResponse, error) {
	return api.do("GET", namespace, nil)
}

func (api API) post(namespace string, payload io.Reader) (*apiResponse, error) {
	return api.do("POST", namespace, payload)
}

func (api API) delete(namespace string) (*apiResponse, error) {
	return api.do("DELETE", namespace, nil)
}

func (api API) do(method string, namespace string, payload io.Reader) (*apiResponse, error) {
	request, err := api.newRequest(method, namespace, payload)
	if err != nil {
		return nil, err
	}

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	return &apiResponse{
		Body:       string(body),
		StatusCode: response.StatusCode,
	}, nil
}

func (api API) newRequest(method string, namespace string, payload io.Reader) (*http.Request, error) {
	url := "http://" + api.Host + ":" + strconv.Itoa(api.Port) + namespace

	request, err := http.NewRequest(method, url, payload)
	if err != nil {
		return nil, err
	}

	if api.User != "" && api.Password != "" {
		request.SetBasicAuth(api.User, api.Password)
	}

	if payload != nil {
		request.Header.Set("Content-Type", "application/json")
	}

	return request, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strconv"
)

type SerializableVar struct {
	Type     string
	V        string
	Origin   string
	Children []SerializableVar
}

type SerializableDepNode struct {
	Output             string
	Cmds               []string
	Deps               []string
	HasRule            bool
	IsOrderOnly        bool
	IsPhony            bool
	ActualInputs       []string
	TargetSpecificVars []int
	Filename           string
	Lineno             int
}

type SerializableTargetSpecificVar struct {
	Name  string
	Value SerializableVar
}

type SerializableGraph struct {
	Nodes []*SerializableDepNode
	Vars  map[string]SerializableVar
	Tsvs  []SerializableTargetSpecificVar
}

func encGob(v interface{}) string {
	var buf bytes.Buffer
	e := gob.NewEncoder(&buf)
	err := e.Encode(v)
	if err != nil {
		panic(err)
	}
	return buf.String()
}

type DepNodesSerializer struct {
	nodes  []*SerializableDepNode
	tsvs   []SerializableTargetSpecificVar
	tsvMap map[string]int
	done   map[string]bool
}

func NewDepNodesSerializer() *DepNodesSerializer {
	return &DepNodesSerializer{
		tsvMap: make(map[string]int),
		done:   make(map[string]bool),
	}
}

func (ns *DepNodesSerializer) SerializeDepNodes(nodes []*DepNode) {
	for _, n := range nodes {
		if ns.done[n.Output] {
			continue
		}
		ns.done[n.Output] = true

		var deps []string
		for _, d := range n.Deps {
			deps = append(deps, d.Output)
		}

		// Sort keys for consistent serialization.
		var tsvKeys []string
		for k := range n.TargetSpecificVars {
			tsvKeys = append(tsvKeys, k)
		}
		sort.Strings(tsvKeys)

		var vars []int
		for _, k := range tsvKeys {
			v := n.TargetSpecificVars[k]
			sv := SerializableTargetSpecificVar{Name: k, Value: v.Serialize()}
			gob := encGob(sv)
			id, present := ns.tsvMap[gob]
			if !present {
				id = len(ns.tsvs)
				ns.tsvMap[gob] = id
				ns.tsvs = append(ns.tsvs, sv)
			}
			vars = append(vars, id)
		}

		ns.nodes = append(ns.nodes, &SerializableDepNode{
			Output:             n.Output,
			Cmds:               n.Cmds,
			Deps:               deps,
			HasRule:            n.HasRule,
			IsOrderOnly:        n.IsOrderOnly,
			IsPhony:            n.IsPhony,
			ActualInputs:       n.ActualInputs,
			TargetSpecificVars: vars,
			Filename:           n.Filename,
			Lineno:             n.Lineno,
		})
		ns.SerializeDepNodes(n.Deps)
	}
}

func MakeSerializableVars(vars Vars) (r map[string]SerializableVar) {
	r = make(map[string]SerializableVar)
	for k, v := range vars {
		r[k] = v.Serialize()
	}
	return r
}

func MakeSerializableGraph(nodes []*DepNode, vars Vars) SerializableGraph {
	ns := NewDepNodesSerializer()
	ns.SerializeDepNodes(nodes)
	v := MakeSerializableVars(vars)
	return SerializableGraph{Nodes: ns.nodes, Vars: v, Tsvs: ns.tsvs}
}

func DumpDepGraphAsJson(nodes []*DepNode, vars Vars, filename string) {
	o, err := json.MarshalIndent(MakeSerializableGraph(nodes, vars), " ", " ")
	if err != nil {
		panic(err)
	}
	f, err2 := os.Create(filename)
	if err2 != nil {
		panic(err2)
	}
	f.Write(o)
}

func DumpDepGraph(nodes []*DepNode, vars Vars, filename string) {
	f, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	e := gob.NewEncoder(f)
	e.Encode(MakeSerializableGraph(nodes, vars))
}

func DeserializeSingleChild(sv SerializableVar) Value {
	if len(sv.Children) != 1 {
		panic(fmt.Sprintf("unexpected number of children: %q", sv))
	}
	return DeserializeVar(sv.Children[0])
}

func DeserializeVar(sv SerializableVar) (r Value) {
	switch sv.Type {
	case "literal":
		return literal(sv.V)
	case "tmpval":
		return tmpval([]byte(sv.V))
	case "expr":
		var e Expr
		for _, v := range sv.Children {
			e = append(e, DeserializeVar(v))
		}
		return e
	case "varref":
		return varref{varname: DeserializeSingleChild(sv)}
	case "paramref":
		v, err := strconv.Atoi(sv.V)
		if err != nil {
			panic(err)
		}
		return paramref(v)
	case "varsubst":
		return varsubst{
			varname: DeserializeVar(sv.Children[0]),
			pat:     DeserializeVar(sv.Children[1]),
			subst:   DeserializeVar(sv.Children[2]),
		}

	case "func":
		name := DeserializeVar(sv.Children[0]).(literal)
		f := funcMap[string(name[1:])]()
		f.AddArg(name)
		for _, a := range sv.Children[1:] {
			f.AddArg(DeserializeVar(a))
		}
		return f
	case "funcEvalAssign":
		return &funcEvalAssign{
			lhs: sv.Children[0].V,
			op:  sv.Children[1].V,
			rhs: DeserializeVar(sv.Children[2]),
		}
	case "funcNop":
		return &funcNop{expr: sv.V}

	case "simple":
		return SimpleVar{
			value:  []byte(sv.V),
			origin: sv.Origin,
		}
	case "recursive":
		return RecursiveVar{
			expr:   DeserializeSingleChild(sv),
			origin: sv.Origin,
		}

	case ":=", "=", "+=", "?=":
		return TargetSpecificVar{
			v:  DeserializeSingleChild(sv).(Var),
			op: sv.Type,
		}

	default:
		panic(fmt.Sprintf("unknown serialized variable type: %q", sv))
	}
	return UndefinedVar{}
}

func DeserializeVars(vars map[string]SerializableVar) Vars {
	r := make(Vars)
	for k, v := range vars {
		r[k] = DeserializeVar(v).(Var)
	}
	return r
}

func DeserializeNodes(nodes []*SerializableDepNode, tsvs []SerializableTargetSpecificVar) (r []*DepNode) {
	// Deserialize all TSVs first so that multiple rules can share memory.
	var tsvValues []Var
	for _, sv := range tsvs {
		tsvValues = append(tsvValues, DeserializeVar(sv.Value).(Var))
	}

	nodeMap := make(map[string]*DepNode)
	for _, n := range nodes {
		d := &DepNode{
			Output:             n.Output,
			Cmds:               n.Cmds,
			HasRule:            n.HasRule,
			IsOrderOnly:        n.IsOrderOnly,
			IsPhony:            n.IsPhony,
			ActualInputs:       n.ActualInputs,
			Filename:           n.Filename,
			Lineno:             n.Lineno,
			TargetSpecificVars: make(Vars),
		}

		for _, id := range n.TargetSpecificVars {
			sv := tsvs[id]
			d.TargetSpecificVars[sv.Name] = tsvValues[id]
		}

		nodeMap[n.Output] = d
		r = append(r, d)
	}

	for _, n := range nodes {
		d := nodeMap[n.Output]
		for _, o := range n.Deps {
			c, present := nodeMap[o]
			if !present {
				panic(fmt.Sprintf("unknown target: %s", o))
			}
			d.Deps = append(d.Deps, c)
		}
	}

	return r
}

func human(n int) string {
	if n >= 10 * 1000 * 1000 * 1000 {
		return fmt.Sprintf("%.2fGB", float32(n) / 1000 / 1000 / 1000)
	} else if n >= 10 * 1000 * 1000 {
		return fmt.Sprintf("%.2fMB", float32(n) / 1000 / 1000)
	} else if n >= 10 * 1000 {
		return fmt.Sprintf("%.2fkB", float32(n) / 1000)
	} else {
		return fmt.Sprintf("%dB", n)
	}
}

func showSerializedNodesStats(nodes []*SerializableDepNode) {
	outputSize := 0
	cmdSize := 0
	depsSize := 0
	actualInputSize := 0
	tsvSize := 0
	filenameSize := 0
	linenoSize := 0
	for _, n := range nodes {
		outputSize += len(n.Output)
		for _, c := range n.Cmds {
			cmdSize += len(c)
		}
		for _, d := range n.Deps {
			depsSize += len(d)
		}
		for _, i := range n.ActualInputs {
			actualInputSize += len(i)
		}
		for _ = range n.TargetSpecificVars {
			tsvSize += 4
		}
		filenameSize += len(n.Filename)
		linenoSize += 4
	}
	size := outputSize + cmdSize + depsSize + actualInputSize + tsvSize + filenameSize + linenoSize
	LogStats("%d nodes %s", len(nodes), human(size))
	LogStats(" output %s", human(outputSize))
	LogStats(" command %s", human(cmdSize))
	LogStats(" deps %s", human(depsSize))
	LogStats(" inputs %s", human(actualInputSize))
	LogStats(" tsv %s", human(tsvSize))
	LogStats(" filename %s", human(filenameSize))
	LogStats(" lineno %s", human(linenoSize))
}

func (v SerializableVar) size() int {
	size := 0
	size += len(v.Type)
	size += len(v.V)
	size += len(v.Origin)
	for _, c := range v.Children {
		size += c.size()
	}
	return size
}

func showSerializedVarsStats(vars map[string]SerializableVar) {
	nameSize := 0
	valueSize := 0
	for k, v := range vars {
		nameSize += len(k)
		valueSize += v.size()
	}
	size := nameSize + valueSize
	LogStats("%d vars %s", len(vars), human(size))
	LogStats(" name %s", human(nameSize))
	LogStats(" value %s", human(valueSize))
}

func showSerializedTsvsStats(vars []SerializableTargetSpecificVar) {
	nameSize := 0
	valueSize := 0
	for _, v := range vars {
		nameSize += len(v.Name)
		valueSize += v.Value.size()
	}
	size := nameSize + valueSize
	LogStats("%d tsvs %s", len(vars), human(size))
	LogStats(" name %s", human(nameSize))
	LogStats(" value %s", human(valueSize))
}

func showSerializedGraphStats(g SerializableGraph) {
	showSerializedNodesStats(g.Nodes)
	showSerializedVarsStats(g.Vars)
	showSerializedTsvsStats(g.Tsvs)
}

func DeserializeGraph(g SerializableGraph) ([]*DepNode, Vars) {
	if katiLogFlag || katiStatsFlag {
		showSerializedGraphStats(g)
	}
	nodes := DeserializeNodes(g.Nodes, g.Tsvs)
	vars := DeserializeVars(g.Vars)
	return nodes, vars
}

func LoadDepGraphFromJson(filename string) ([]*DepNode, Vars) {
	f, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	d := json.NewDecoder(f)
	g := SerializableGraph{Vars: make(map[string]SerializableVar)}
	err = d.Decode(&g)
	if err != nil {
		panic(err)
	}
	return DeserializeGraph(g)
}

func LoadDepGraph(filename string) ([]*DepNode, Vars) {
	f, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	d := gob.NewDecoder(f)
	g := SerializableGraph{Vars: make(map[string]SerializableVar)}
	err = d.Decode(&g)
	if err != nil {
		panic(err)
	}
	return DeserializeGraph(g)
}
<commit_msg>Do not serialize the same target names multiple times<commit_after>package main

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strconv"
)

type SerializableVar struct {
	Type     string
	V        string
	Origin   string
	Children []SerializableVar
}

type SerializableDepNode struct {
	Output             int
	Cmds               []string
	Deps               []int
	HasRule            bool
	IsOrderOnly        bool
	IsPhony            bool
	ActualInputs       []int
	TargetSpecificVars []int
	Filename           string
	Lineno             int
}

type SerializableTargetSpecificVar struct {
	Name  string
	Value SerializableVar
}

type SerializableGraph struct {
	Nodes   []*SerializableDepNode
	Vars    map[string]SerializableVar
	Tsvs    []SerializableTargetSpecificVar
	Targets []string
}

func encGob(v interface{}) string {
	var buf bytes.Buffer
	e := gob.NewEncoder(&buf)
	err := e.Encode(v)
	if err != nil {
		panic(err)
	}
	return buf.String()
}

type DepNodesSerializer struct {
	nodes     []*SerializableDepNode
	tsvs      []SerializableTargetSpecificVar
	tsvMap    map[string]int
	targets   []string
	targetMap map[string]int
	done      map[string]bool
}

func NewDepNodesSerializer() *DepNodesSerializer {
	return &DepNodesSerializer{
		tsvMap:    make(map[string]int),
		targetMap: make(map[string]int),
		done:      make(map[string]bool),
	}
}

func (ns *DepNodesSerializer) SerializeTarget(t string) int {
	id, present := ns.targetMap[t]
	if present {
		return id
	}
	id = len(ns.targets)
	ns.targetMap[t] = id
	ns.targets = append(ns.targets, t)
	return id
}

func (ns *DepNodesSerializer) SerializeDepNodes(nodes []*DepNode) {
	for _, n := range nodes {
		if ns.done[n.Output] {
			continue
		}
		ns.done[n.Output] = true

		var deps []int
		for _, d := range n.Deps {
			deps = append(deps, ns.SerializeTarget(d.Output))
		}
		var actualInputs []int
		for _, i := range n.ActualInputs {
			actualInputs = append(actualInputs, ns.SerializeTarget(i))
		}

		// Sort keys for consistent serialization.
		var tsvKeys []string
		for k := range n.TargetSpecificVars {
			tsvKeys = append(tsvKeys, k)
		}
		sort.Strings(tsvKeys)

		var vars []int
		for _, k := range tsvKeys {
			v := n.TargetSpecificVars[k]
			sv := SerializableTargetSpecificVar{Name: k, Value: v.Serialize()}
			gob := encGob(sv)
			id, present := ns.tsvMap[gob]
			if !present {
				id = len(ns.tsvs)
				ns.tsvMap[gob] = id
				ns.tsvs = append(ns.tsvs, sv)
			}
			vars = append(vars, id)
		}

		ns.nodes = append(ns.nodes, &SerializableDepNode{
			Output:             ns.SerializeTarget(n.Output),
			Cmds:               n.Cmds,
			Deps:               deps,
			HasRule:            n.HasRule,
			IsOrderOnly:        n.IsOrderOnly,
			IsPhony:            n.IsPhony,
			ActualInputs:       actualInputs,
			TargetSpecificVars: vars,
			Filename:           n.Filename,
			Lineno:             n.Lineno,
		})
		ns.SerializeDepNodes(n.Deps)
	}
}

func MakeSerializableVars(vars Vars) (r map[string]SerializableVar) {
	r = make(map[string]SerializableVar)
	for k, v := range vars {
		r[k] = v.Serialize()
	}
	return r
}

func MakeSerializableGraph(nodes []*DepNode, vars Vars) SerializableGraph {
	ns := NewDepNodesSerializer()
	ns.SerializeDepNodes(nodes)
	v := MakeSerializableVars(vars)
	return SerializableGraph{
		Nodes: ns.nodes,
		Vars: v,
		Tsvs: ns.tsvs,
		Targets: ns.targets,
	}
}

func DumpDepGraphAsJson(nodes []*DepNode, vars Vars, filename string) {
	o, err := json.MarshalIndent(MakeSerializableGraph(nodes, vars), " ", " ")
	if err != nil {
		panic(err)
	}
	f, err2 := os.Create(filename)
	if err2 != nil {
		panic(err2)
	}
	f.Write(o)
}

func DumpDepGraph(nodes []*DepNode, vars Vars, filename string) {
	f, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	e := gob.NewEncoder(f)
	e.Encode(MakeSerializableGraph(nodes, vars))
}

func DeserializeSingleChild(sv SerializableVar) Value {
	if len(sv.Children) != 1 {
		panic(fmt.Sprintf("unexpected number of children: %q", sv))
	}
	return DeserializeVar(sv.Children[0])
}

func DeserializeVar(sv SerializableVar) (r Value) {
	switch sv.Type {
	case "literal":
		return literal(sv.V)
	case "tmpval":
		return tmpval([]byte(sv.V))
	case "expr":
		var e Expr
		for _, v := range sv.Children {
			e = append(e, DeserializeVar(v))
		}
		return e
	case "varref":
		return varref{varname: DeserializeSingleChild(sv)}
	case "paramref":
		v, err := strconv.Atoi(sv.V)
		if err != nil {
			panic(err)
		}
		return paramref(v)
	case "varsubst":
		return varsubst{
			varname: DeserializeVar(sv.Children[0]),
			pat:     DeserializeVar(sv.Children[1]),
			subst:   DeserializeVar(sv.Children[2]),
		}

	case "func":
		name := DeserializeVar(sv.Children[0]).(literal)
		f := funcMap[string(name[1:])]()
		f.AddArg(name)
		for _, a := range sv.Children[1:] {
			f.AddArg(DeserializeVar(a))
		}
		return f
	case "funcEvalAssign":
		return &funcEvalAssign{
			lhs: sv.Children[0].V,
			op:  sv.Children[1].V,
			rhs: DeserializeVar(sv.Children[2]),
		}
	case "funcNop":
		return &funcNop{expr: sv.V}

	case "simple":
		return SimpleVar{
			value:  []byte(sv.V),
			origin: sv.Origin,
		}
	case "recursive":
		return RecursiveVar{
			expr:   DeserializeSingleChild(sv),
			origin: sv.Origin,
		}

	case ":=", "=", "+=", "?=":
		return TargetSpecificVar{
			v:  DeserializeSingleChild(sv).(Var),
			op: sv.Type,
		}

	default:
		panic(fmt.Sprintf("unknown serialized variable type: %q", sv))
	}
	return UndefinedVar{}
}

func DeserializeVars(vars map[string]SerializableVar) Vars {
	r := make(Vars)
	for k, v := range vars {
		r[k] = DeserializeVar(v).(Var)
	}
	return r
}

func DeserializeNodes(g SerializableGraph) (r []*DepNode) {
	nodes := g.Nodes
	tsvs := g.Tsvs
	targets := g.Targets
	// Deserialize all TSVs first so that multiple rules can share memory.
	var tsvValues []Var
	for _, sv := range tsvs {
		tsvValues = append(tsvValues, DeserializeVar(sv.Value).(Var))
	}

	nodeMap := make(map[string]*DepNode)
	for _, n := range nodes {
		var actualInputs []string
		for _, i := range n.ActualInputs {
			actualInputs = append(actualInputs, targets[i])
		}

		d := &DepNode{
			Output:             targets[n.Output],
			Cmds:               n.Cmds,
			HasRule:            n.HasRule,
			IsOrderOnly:        n.IsOrderOnly,
			IsPhony:            n.IsPhony,
			ActualInputs:       actualInputs,
			Filename:           n.Filename,
			Lineno:             n.Lineno,
			TargetSpecificVars: make(Vars),
		}

		for _, id := range n.TargetSpecificVars {
			sv := tsvs[id]
			d.TargetSpecificVars[sv.Name] = tsvValues[id]
		}

		nodeMap[targets[n.Output]] = d
		r = append(r, d)
	}

	for _, n := range nodes {
		d := nodeMap[targets[n.Output]]
		for _, o := range n.Deps {
			c, present := nodeMap[targets[o]]
			if !present {
				panic(fmt.Sprintf("unknown target: %s", o))
			}
			d.Deps = append(d.Deps, c)
		}
	}

	return r
}

func human(n int) string {
	if n >= 10 * 1000 * 1000 * 1000 {
		return fmt.Sprintf("%.2fGB", float32(n) / 1000 / 1000 / 1000)
	} else if n >= 10 * 1000 * 1000 {
		return fmt.Sprintf("%.2fMB", float32(n) / 1000 / 1000)
	} else if n >= 10 * 1000 {
		return fmt.Sprintf("%.2fkB", float32(n) / 1000)
	} else {
		return fmt.Sprintf("%dB", n)
	}
}

func showSerializedNodesStats(nodes []*SerializableDepNode) {
	outputSize := 0
	cmdSize := 0
	depsSize := 0
	actualInputSize := 0
	tsvSize := 0
	filenameSize := 0
	linenoSize := 0
	for _, n := range nodes {
		outputSize += 4
		for _, c := range n.Cmds {
			cmdSize += len(c)
		}
		for _ = range n.Deps {
			depsSize += 4
		}
		for _ = range n.ActualInputs {
			actualInputSize += 4
		}
		for _ = range n.TargetSpecificVars {
			tsvSize += 4
		}
		filenameSize += len(n.Filename)
		linenoSize += 4
	}
	size := outputSize + cmdSize + depsSize + actualInputSize + tsvSize + filenameSize + linenoSize
	LogStats("%d nodes %s", len(nodes), human(size))
	LogStats(" output %s", human(outputSize))
	LogStats(" command %s", human(cmdSize))
	LogStats(" deps %s", human(depsSize))
	LogStats(" inputs %s", human(actualInputSize))
	LogStats(" tsv %s", human(tsvSize))
	LogStats(" filename %s", human(filenameSize))
	LogStats(" lineno %s", human(linenoSize))
}

func (v SerializableVar) size() int {
	size := 0
	size += len(v.Type)
	size += len(v.V)
	size += len(v.Origin)
	for _, c := range v.Children {
		size += c.size()
	}
	return size
}

func showSerializedVarsStats(vars map[string]SerializableVar) {
	nameSize := 0
	valueSize := 0
	for k, v := range vars {
		nameSize += len(k)
		valueSize += v.size()
	}
	size := nameSize + valueSize
	LogStats("%d vars %s", len(vars), human(size))
	LogStats(" name %s", human(nameSize))
	LogStats(" value %s", human(valueSize))
}

func showSerializedTsvsStats(vars []SerializableTargetSpecificVar) {
	nameSize := 0
	valueSize := 0
	for _, v := range vars {
		nameSize += len(v.Name)
		valueSize += v.Value.size()
	}
	size := nameSize + valueSize
	LogStats("%d tsvs %s", len(vars), human(size))
	LogStats(" name %s", human(nameSize))
	LogStats(" value %s", human(valueSize))
}

func showSerializedTargetsStats(targets []string) {
	size := 0
	for _, t := range targets {
		size += len(t)
	}
	LogStats("%d targets %s", len(targets), human(size))
}

func showSerializedGraphStats(g SerializableGraph) {
	showSerializedNodesStats(g.Nodes)
	showSerializedVarsStats(g.Vars)
	showSerializedTsvsStats(g.Tsvs)
	showSerializedTargetsStats(g.Targets)
}

func DeserializeGraph(g SerializableGraph) ([]*DepNode, Vars) {
	if katiLogFlag || katiStatsFlag {
		showSerializedGraphStats(g)
	}
	nodes := DeserializeNodes(g)
	vars := DeserializeVars(g.Vars)
	return nodes, vars
}

func LoadDepGraphFromJson(filename string) ([]*DepNode, Vars) {
	f, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	d := json.NewDecoder(f)
	g := SerializableGraph{Vars: make(map[string]SerializableVar)}
	err = d.Decode(&g)
	if err != nil {
		panic(err)
	}
	return DeserializeGraph(g)
}

func LoadDepGraph(filename string) ([]*DepNode, Vars) {
	f, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	d := gob.NewDecoder(f)
	g := SerializableGraph{Vars: make(map[string]SerializableVar)}
	err = d.Decode(&g)
	if err != nil {
		panic(err)
	}
	return DeserializeGraph(g)
}
<|endoftext|>


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

package main

import (
	"bufio"
	"bytes"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"

	_ "golang.org/x/tools/playground"
)

func gaeMain() {
	prepContent = gaePrepContent
	socketAddr = gaeSocketAddr
	analyticsHTML = template.HTML(os.Getenv("TOUR_ANALYTICS"))

	if err := initTour(".", "HTTPTransport"); err != nil {
		log.Fatal(err)
	}

	http.Handle("/", hstsHandler(rootHandler))
	http.Handle("/lesson/", hstsHandler(lessonHandler))

	registerStatic(".")

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

// gaePrepContent returns a Reader that produces the content from the given
// Reader, but strips the prefix "#appengine:", optionally followed by a space, from each line.
// It also drops any non-blank line that follows a series of 1 or more lines with the prefix.
func gaePrepContent(in io.Reader) io.Reader {
	var prefix = []byte("#appengine:")
	out, w := io.Pipe()
	go func() {
		r := bufio.NewReader(in)
		drop := false
		for {
			b, err := r.ReadBytes('\n')
			if err != nil && err != io.EOF {
				w.CloseWithError(err)
				return
			}
			if bytes.HasPrefix(b, prefix) {
				b = b[len(prefix):]
				if b[0] == ' ' {
					// Consume a single space after the prefix.
					b = b[1:]
				}
				drop = true
			} else if drop {
				if len(b) > 1 {
					b = nil
				}
				drop = false
			}
			if len(b) > 0 {
				w.Write(b)
			}
			if err == io.EOF {
				w.Close()
				return
			}
		}
	}()
	return out
}

// gaeSocketAddr returns the WebSocket handler address.
// The App Engine version does not provide a WebSocket handler.
func gaeSocketAddr() string { return "" }

// hstsHandler wraps an http.HandlerFunc such that it sets the HSTS header.
func hstsHandler(fn http.HandlerFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Strict-Transport-Security", "max-age=31536000; preload")
		fn(w, r)
	})
}
<commit_msg>tour: fix for new app deployment<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"

	_ "golang.org/x/tools/playground"
)

func gaeMain() {
	prepContent = gaePrepContent
	socketAddr = gaeSocketAddr
	analyticsHTML = template.HTML(os.Getenv("TOUR_ANALYTICS"))

	root := "tour"

	if err := initTour(root, "HTTPTransport"); err != nil {
		log.Fatal(err)
	}

	http.Handle("/", hstsHandler(rootHandler))
	http.Handle("/lesson/", hstsHandler(lessonHandler))

	registerStatic(root)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

// gaePrepContent returns a Reader that produces the content from the given
// Reader, but strips the prefix "#appengine:", optionally followed by a space, from each line.
// It also drops any non-blank line that follows a series of 1 or more lines with the prefix.
func gaePrepContent(in io.Reader) io.Reader {
	var prefix = []byte("#appengine:")
	out, w := io.Pipe()
	go func() {
		r := bufio.NewReader(in)
		drop := false
		for {
			b, err := r.ReadBytes('\n')
			if err != nil && err != io.EOF {
				w.CloseWithError(err)
				return
			}
			if bytes.HasPrefix(b, prefix) {
				b = b[len(prefix):]
				if b[0] == ' ' {
					// Consume a single space after the prefix.
					b = b[1:]
				}
				drop = true
			} else if drop {
				if len(b) > 1 {
					b = nil
				}
				drop = false
			}
			if len(b) > 0 {
				w.Write(b)
			}
			if err == io.EOF {
				w.Close()
				return
			}
		}
	}()
	return out
}

// gaeSocketAddr returns the WebSocket handler address.
// The App Engine version does not provide a WebSocket handler.
func gaeSocketAddr() string { return "" }

// hstsHandler wraps an http.HandlerFunc such that it sets the HSTS header.
func hstsHandler(fn http.HandlerFunc) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Strict-Transport-Security", "max-age=31536000; preload")
		fn(w, r)
	})
}
<|endoftext|>