<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"github.com/mitchellh/colorstring"
	"github.com/mitchellh/go-homedir"
	"github.com/olekukonko/tablewriter"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
	ExitCodeErrorCache
)

const (
	// DefaultOutput is default output file name
	DefaultOutput = "LICENSE"
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {

	var output string
	var useCache bool

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprintf(cli.errStream, helpText)
	}

	flags.StringVar(&output, "output", DefaultOutput, "")
	flags.BoolVar(&useCache, "no-cache", true, "")

	flList := flags.Bool("list", false, "")
	flChoose := flags.Bool("choose", false, "")

	flDebug := flags.Bool("debug", false, "")
	flVersion := flags.Bool("version", false, "")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if *flVersion {

		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		select {
		case <-time.After(CheckTimeout):
			// Do nothing
		case res := <-verCheckCh:
			if res != nil {
				msg := fmt.Sprintf("Latest version of license is %s, please update it\n", res.Current)
				fmt.Fprint(cli.errStream, msg)
			}
		}

		return ExitCodeOK
	}

	// Set Debug environmental variable
	if *flDebug {
		os.Setenv(EnvDebug, "1")
		Debugf("Run as DEBUG mode")
	}

	// Show list of LICENSE and quit
	if *flList {
		Debugf("Show list of LICENSE")

		// Create default client
		client := github.NewClient(nil)

		// Fetch list from Github API
		list, res, err := client.Licenses.List()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE list: %s\n", err.Error())
			return ExitCodeError
		}

		if res.StatusCode != http.StatusOK {
			fmt.Fprintf(cli.errStream, "Invalid status code from GitHub\n %s\n", res.String())
			return ExitCodeError
		}

		// Write LICENSE list as a table
		outBuffer := new(bytes.Buffer)
		table := tablewriter.NewWriter(outBuffer)

		header := []string{"Key", "Name"}
		table.SetHeader(header)
		for _, l := range list {
			Debugf("%s (%s)", *l.Name, *l.Key)
			table.Append([]string{*l.Key, *l.Name})
		}
		table.Render()

		outBuffer.WriteString("See more about these LICENSE at http://choosealicense.com/licenses/\n")
		fmt.Fprintf(cli.outStream, outBuffer.String())

		return ExitCodeOK
	}

	// Check file exist or not
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		fmt.Fprintf(cli.errStream, "Cannot create file %q: file exists\n", output)
		return ExitCodeError
	}

	parsedArgs := flags.Args()
	if len(parsedArgs) > 1 {
		fmt.Fprintf(cli.errStream, "Invalid arguments\n")
		return ExitCodeError
	}

	var key string
	if len(parsedArgs) == 1 {
		key = parsedArgs[0]
		// Every key must be lower case
		key = strings.ToLower(key)
	}

	// Choose a LICENSE like http://choosealicense.com/
	if len(key) == 0 && *flChoose {
		Debugf("Choose a LICENSE like http://choosealicense.com/")
		var err error
		key, err = cli.Choose()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to choose a LICENSE: %s\n", err.Error())
			return ExitCodeError
		}
	}

	// Show all LICENSE available and ask user to select.
	if len(key) == 0 {
		Debugf("Show all LICENSE available and ask user to select")

		list, err := fetchLicenseList()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to show LICENSE list: %s", err.Error())
			return ExitCodeError
		}

		var buf bytes.Buffer
		buf.WriteString("Which of the following do you want to use?\n")
		for i, l := range list {
			fmt.Fprintf(&buf, "  %2d) %s\n", i+1, *l.Name)
		}
		fmt.Fprintf(cli.errStream, buf.String())

		num, err := cli.AskNumber(len(list), 1)
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to scan user input: %s\n", err.Error())
			return ExitCodeError
		}

		key = *(list[num-1]).Key
	}

	home, err := homedir.Dir()
	if err != nil {
		Debugf("Faild to get home directory: %s", err.Error())
		useCache = false
		home = "."
	}
	cacheDir := filepath.Join(home, CacheDirName)

	// By default useCache is true and check cache is exist or not
	var r io.Reader
	if useCache {
		var err error
		r, err = getCache(key, cacheDir)
		if err != nil {
			Debugf("Failed to get cache: %s", err.Error())
		}

		if r != nil {
			fmt.Fprintf(cli.errStream, "Use cache\n")
		}
	}

	// If cache is not exist, fetch it from GitHub
	var fetched bool = false
	if r == nil {
		var err error
		r, err = fetchLicense(key)
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to get LICENSE file: %s\n", err.Error())
			return ExitCodeError
		}
		fetched = true
	}

	// Create output path if it is not exist
	dir, _ := filepath.Split(output)
	if len(dir) != 0 {
		os.MkdirAll(dir, 0777)
	}

	licenseWriter, err := os.Create(output)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to create file %s: %s\n", output, err.Error())
		return ExitCodeError
	}
	defer licenseWriter.Close()
	Debugf("Output filename: %s", output)

	var w io.Writer
	if fetched && useCache {
		// if new LICESE file is fetched from GitHub
		// Create new cache file for it
		cacheWriter, err := newCache(key, cacheDir)
		if err == nil {
			defer cacheWriter.Close()
			w = io.MultiWriter(licenseWriter, cacheWriter)
		}
	} else {
		w = licenseWriter
	}

	_, err = io.Copy(w, r)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to write license body to %q: %s\n", output, err.Error())
		return ExitCodeError
	}

	fmt.Fprintf(cli.outStream, "Successfully generated %q LICENSE\n", key)
	return ExitCodeOK
}

// AskNumber asks user to choose number from 1 to max
func (cli CLI) AskNumber(max int, defaultNum int) (int, error) {

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	result := make(chan int, 1)
	go func() {
		for {

			fmt.Fprintf(cli.errStream, "Your choice? [default: %d] ", defaultNum)

			var line string
			if _, err := fmt.Fscanln(os.Stdin, &line); err != nil {
				Debugf("Failed to scan stdin: %s", err.Error())
			}

			Debugf("Input: %q", line)

			// Use Default value
			if line == "" {
				result <- defaultNum
				break
			}

			// Convert string to int
			n, err := strconv.Atoi(line)
			if err != nil {
				fmt.Fprintf(cli.errStream, "  is not a valid choice. Choose by number.\n\n")
				continue
			}

			// Check input is in range
			if n < 1 || max < n {
				fmt.Fprintf(cli.errStream, "  is not a valid choice. Choose from 1 to %d\n\n", max)
				continue
			}

			result <- n
			break
		}
	}()

	select {
	case <-sigCh:
		return -1, fmt.Errorf("interrupted")
	case num := <-result:
		return num, nil
	}
}

// Choose shows shows LICENSE description from http://choosealicense.com/
// And ask user to choose LICENSE. It returns key to fetch LICENSE file.
// If something is wrong, return error.
func (cli *CLI) Choose() (string, error) {
	colorstring.Fprintf(cli.errStream, chooseText)

	num, err := cli.AskNumber(4, 1)
	if err != nil {
		return "", err
	}

	// If user selects 3, should ask user GPL V2 or V3
	if num == 3 {
		var buf bytes.Buffer
		buf.WriteString("\n")
		buf.WriteString("Which version do you want?\n")
		buf.WriteString("  1) V2\n")
		buf.WriteString("  2) V3\n")
		fmt.Fprintf(cli.errStream, buf.String())

		num, err = cli.AskNumber(2, 1)
		if err != nil {
			return "", err
		}
		num += 4
	}

	var key string
	switch num {
	case 1:
		key = "mit"
	case 2:
		key = "apache-2.0"
	case 4:
		key = ""
	case 5:
		key = "gpl-2.0"
	case 6:
		key = "gpl-3.0"
	default:
		// Should not reach here
		panic("Invalid number")
	}

	return key, nil
}

var chooseText = `Choose LICENSE like http://choosealicense.com/

  [blue]Choosing an OSS license doesn't need to be scary[reset]

Which of the following best describes your situation?

  1) I want it simple and permissive.

    The [red][bold]MIT License[reset] is a permissive license that is short and to the
    point. It lets people do anything they want with your code as long as they
    provide attribution back to you and don't hold you liable.
    e.g., jQuery, Rails

  2) I'm concerned about patents.

    The [red][bold]Apache License[reset] (apache-2.0) is a permissive license similar to the MIT License,
    but also provides an express grant of patent rights from contributors to users.
    e.g., Apache, SVN, NuGet

  3) I care about sharing improvements.

    The [red][bold]GPL V2[reset] (gpl-2.0) or [red][bold]GPL V3[reset] (gpl-3.0) is a copyleft license that requires
    anyone who distributes your code or a derivative work to make the source available under
    the same terms. V3 is similar to V2, but further restricts use in hardware that forbids
    software alterations.
    e.g., Linux, Git, WordPress

  4) I want more choices.

`

var helpText = `Usage: license [option] [KEY]

  Generate LICENSE file. If you provide KEY, it will try to get LICENSE by
  it. If you don't provide it, it will ask you to choose from avairable list.
  You can check avairable LICESE list by '-list' option.

Options:

  -list               Show all avairable LICENSE list and quit.
                      It will fetch information from GitHub.

  -choose             Choose LICENSE like http://choosealicense.com/
                      It shows you which LICENSE is useful for you.

  -output=NAME        Change output file name.
                      By default, output file name is 'LICENSE'

  -no-chache          Not use local cache.

`
<commit_msg>Fix -no-cache flag<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
	"github.com/mitchellh/colorstring"
	"github.com/mitchellh/go-homedir"
	"github.com/olekukonko/tablewriter"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
	ExitCodeErrorCache
)

const (
	// DefaultOutput is default output file name
	DefaultOutput = "LICENSE"
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {

	var output string
	var noCache bool

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprintf(cli.errStream, helpText)
	}

	flags.StringVar(&output, "output", DefaultOutput, "")
	flags.BoolVar(&noCache, "no-cache", false, "")

	flList := flags.Bool("list", false, "")
	flChoose := flags.Bool("choose", false, "")

	flDebug := flags.Bool("debug", false, "")
	flVersion := flags.Bool("version", false, "")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if *flVersion {

		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		select {
		case <-time.After(CheckTimeout):
			// Do nothing
		case res := <-verCheckCh:
			if res != nil {
				msg := fmt.Sprintf("Latest version of license is %s, please update it\n", res.Current)
				fmt.Fprint(cli.errStream, msg)
			}
		}

		return ExitCodeOK
	}

	// Set Debug environmental variable
	if *flDebug {
		os.Setenv(EnvDebug, "1")
		Debugf("Run as DEBUG mode")
	}

	// Show list of LICENSE and quit
	if *flList {
		Debugf("Show list of LICENSE")

		// Create default client
		client := github.NewClient(nil)

		// Fetch list from Github API
		list, res, err := client.Licenses.List()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE list: %s\n", err.Error())
			return ExitCodeError
		}

		if res.StatusCode != http.StatusOK {
			fmt.Fprintf(cli.errStream, "Invalid status code from GitHub\n %s\n", res.String())
			return ExitCodeError
		}

		// Write LICENSE list as a table
		outBuffer := new(bytes.Buffer)
		table := tablewriter.NewWriter(outBuffer)

		header := []string{"Key", "Name"}
		table.SetHeader(header)
		for _, l := range list {
			Debugf("%s (%s)", *l.Name, *l.Key)
			table.Append([]string{*l.Key, *l.Name})
		}
		table.Render()

		outBuffer.WriteString("See more about these LICENSE at http://choosealicense.com/licenses/\n")
		fmt.Fprintf(cli.outStream, outBuffer.String())

		return ExitCodeOK
	}

	// Check file exist or not
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		fmt.Fprintf(cli.errStream, "Cannot create file %q: file exists\n", output)
		return ExitCodeError
	}

	parsedArgs := flags.Args()
	if len(parsedArgs) > 1 {
		fmt.Fprintf(cli.errStream, "Invalid arguments\n")
		return ExitCodeError
	}

	var key string
	if len(parsedArgs) == 1 {
		key = parsedArgs[0]
		// Every key must be lower case
		key = strings.ToLower(key)
	}

	// Choose a LICENSE like http://choosealicense.com/
	if len(key) == 0 && *flChoose {
		Debugf("Choose a LICENSE like http://choosealicense.com/")
		var err error
		key, err = cli.Choose()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to choose a LICENSE: %s\n", err.Error())
			return ExitCodeError
		}
	}

	// Show all LICENSE available and ask user to select.
	if len(key) == 0 {
		Debugf("Show all LICENSE available and ask user to select")

		list, err := fetchLicenseList()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to show LICENSE list: %s", err.Error())
			return ExitCodeError
		}

		var buf bytes.Buffer
		buf.WriteString("Which of the following do you want to use?\n")
		for i, l := range list {
			fmt.Fprintf(&buf, "  %2d) %s\n", i+1, *l.Name)
		}
		fmt.Fprintf(cli.errStream, buf.String())

		num, err := cli.AskNumber(len(list), 1)
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to scan user input: %s\n", err.Error())
			return ExitCodeError
		}

		key = *(list[num-1]).Key
	}

	home, err := homedir.Dir()
	if err != nil {
		Debugf("Faild to get home directory: %s", err.Error())
		noCache = true
		home = "."
	}
	cacheDir := filepath.Join(home, CacheDirName)

	// By default noCache is false (useCache) and check cache is exist or not
	var r io.Reader
	if !noCache {
		var err error
		r, err = getCache(key, cacheDir)
		if err != nil {
			Debugf("Failed to get cache: %s", err.Error())
		}
	}

	// If cache is not exist, fetch it from GitHub
	var fetched bool = false
	if r == nil {
		var err error
		r, err = fetchLicense(key)
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to get LICENSE file: %s\n", err.Error())
			return ExitCodeError
		}
		fetched = true
	}

	// Create output path if it is not exist
	dir, _ := filepath.Split(output)
	if len(dir) != 0 {
		os.MkdirAll(dir, 0777)
	}

	licenseWriter, err := os.Create(output)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to create file %s: %s\n", output, err.Error())
		return ExitCodeError
	}
	defer licenseWriter.Close()
	Debugf("Output filename: %s", output)

	var w io.Writer
	if fetched && !noCache {
		// if new LICESE file is fetched from GitHub
		// Create new cache file for it
		cacheWriter, err := newCache(key, cacheDir)
		if err == nil {
			defer cacheWriter.Close()
			w = io.MultiWriter(licenseWriter, cacheWriter)
		}
	} else {
		w = licenseWriter
	}

	_, err = io.Copy(w, r)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to write license body to %q: %s\n", output, err.Error())
		return ExitCodeError
	}

	var msg bytes.Buffer
	msg.WriteString(fmt.Sprintf("Successfully generated %q LICENSE ", key))
	if !noCache && !fetched {
		msg.WriteString("(Use cache)")
	}

	fmt.Fprintf(cli.errStream, msg.String()+"\n")

	return ExitCodeOK
}

// AskNumber asks user to choose number from 1 to max
func (cli CLI) AskNumber(max int, defaultNum int) (int, error) {

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	result := make(chan int, 1)
	go func() {
		for {

			fmt.Fprintf(cli.errStream, "Your choice? [default: %d] ", defaultNum)

			var line string
			if _, err := fmt.Fscanln(os.Stdin, &line); err != nil {
				Debugf("Failed to scan stdin: %s", err.Error())
			}

			Debugf("Input: %q", line)

			// Use Default value
			if line == "" {
				result <- defaultNum
				break
			}

			// Convert string to int
			n, err := strconv.Atoi(line)
			if err != nil {
				fmt.Fprintf(cli.errStream, "  is not a valid choice. Choose by number.\n\n")
				continue
			}

			// Check input is in range
			if n < 1 || max < n {
				fmt.Fprintf(cli.errStream, "  is not a valid choice. Choose from 1 to %d\n\n", max)
				continue
			}

			result <- n
			break
		}
	}()

	select {
	case <-sigCh:
		return -1, fmt.Errorf("interrupted")
	case num := <-result:
		return num, nil
	}
}

// Choose shows shows LICENSE description from http://choosealicense.com/
// And ask user to choose LICENSE. It returns key to fetch LICENSE file.
// If something is wrong, return error.
func (cli *CLI) Choose() (string, error) {
	colorstring.Fprintf(cli.errStream, chooseText)

	num, err := cli.AskNumber(4, 1)
	if err != nil {
		return "", err
	}

	// If user selects 3, should ask user GPL V2 or V3
	if num == 3 {
		var buf bytes.Buffer
		buf.WriteString("\n")
		buf.WriteString("Which version do you want?\n")
		buf.WriteString("  1) V2\n")
		buf.WriteString("  2) V3\n")
		fmt.Fprintf(cli.errStream, buf.String())

		num, err = cli.AskNumber(2, 1)
		if err != nil {
			return "", err
		}
		num += 4
	}

	var key string
	switch num {
	case 1:
		key = "mit"
	case 2:
		key = "apache-2.0"
	case 4:
		key = ""
	case 5:
		key = "gpl-2.0"
	case 6:
		key = "gpl-3.0"
	default:
		// Should not reach here
		panic("Invalid number")
	}

	return key, nil
}

var chooseText = `Choose LICENSE like http://choosealicense.com/

  [blue]Choosing an OSS license doesn't need to be scary[reset]

Which of the following best describes your situation?

  1) I want it simple and permissive.

    The [red][bold]MIT License[reset] is a permissive license that is short and to the
    point. It lets people do anything they want with your code as long as they
    provide attribution back to you and don't hold you liable.
    e.g., jQuery, Rails

  2) I'm concerned about patents.

    The [red][bold]Apache License[reset] (apache-2.0) is a permissive license similar to the MIT License,
    but also provides an express grant of patent rights from contributors to users.
    e.g., Apache, SVN, NuGet

  3) I care about sharing improvements.

    The [red][bold]GPL V2[reset] (gpl-2.0) or [red][bold]GPL V3[reset] (gpl-3.0) is a copyleft license that requires
    anyone who distributes your code or a derivative work to make the source available under
    the same terms. V3 is similar to V2, but further restricts use in hardware that forbids
    software alterations.
    e.g., Linux, Git, WordPress

  4) I want more choices.

`

var helpText = `Usage: license [option] [KEY]

  Generate LICENSE file. If you provide KEY, it will try to get LICENSE by
  it. If you don't provide it, it will ask you to choose from avairable list.
  You can check avairable LICESE list by '-list' option.

Options:

  -list               Show all avairable LICENSE list and quit.
                      It will fetch information from GitHub.

  -choose             Choose LICENSE like http://choosealicense.com/
                      It shows you which LICENSE is useful for you.

  -output=NAME        Change output file name.
                      By default, output file name is 'LICENSE'

  -no-chache          Not use local cache.

`
<|endoftext|>


<commit_before>// +build linux

package namespaces

import (
	"encoding/json"
	"io"
	"os"
	"os/exec"
	"syscall"

	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/cgroups/fs"
	"github.com/docker/libcontainer/cgroups/systemd"
	"github.com/docker/libcontainer/configs"
	"github.com/docker/libcontainer/network"
	"github.com/docker/libcontainer/system"
)

// TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work.
// Move this to libcontainer package.
// Exec performs setup outside of a namespace so that a container can be
// executed.  Exec is a high level function for working with container namespaces.
func Exec(args []string, env []string, command *exec.Cmd, container *configs.Config, state *configs.State) error {
	var err error

	// create a pipe so that we can syncronize with the namespaced process and
	// pass the state and configuration to the child process
	parent, child, err := newInitPipe()
	if err != nil {
		return err
	}
	defer parent.Close()

	command.ExtraFiles = []*os.File{child}
	command.Dir = container.RootFs

	if err := command.Start(); err != nil {
		child.Close()
		return err
	}
	child.Close()

	terminate := func(terr error) error {
		// TODO: log the errors for kill and wait
		command.Process.Kill()
		command.Wait()
		return terr
	}

	encoder := json.NewEncoder(parent)

	if err := encoder.Encode(container); err != nil {
		return terminate(err)
	}

	process := processArgs{
		Env:  env,
		Args: args,
	}
	if err := encoder.Encode(process); err != nil {
		return terminate(err)
	}

	started, err := system.GetProcessStartTime(command.Process.Pid)
	if err != nil {
		return terminate(err)
	}

	// Do this before syncing with child so that no children
	// can escape the cgroup
	cgroupPaths, err := SetupCgroups(container, command.Process.Pid)
	if err != nil {
		return terminate(err)
	}
	defer cgroups.RemovePaths(cgroupPaths)

	var networkState network.NetworkState
	if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil {
		return terminate(err)
	}
	// send the state to the container's init process then shutdown writes for the parent
	if err := encoder.Encode(networkState); err != nil {
		return terminate(err)
	}
	// shutdown writes for the parent side of the pipe
	if err := syscall.Shutdown(int(parent.Fd()), syscall.SHUT_WR); err != nil {
		return terminate(err)
	}

	// wait for the child process to fully complete and receive an error message
	// if one was encoutered
	var ierr *initError
	if err := json.NewDecoder(parent).Decode(&ierr); err != nil && err != io.EOF {
		return terminate(err)
	}
	if ierr != nil {
		return terminate(ierr)
	}

	state.InitPid = command.Process.Pid
	state.InitStartTime = started
	state.NetworkState = networkState
	state.CgroupPaths = cgroupPaths

	return nil
}

// DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
//
// console: the /dev/console to setup inside the container
// init: the program executed inside the namespaces
// root: the path to the container json file and information
// pipe: sync pipe to synchronize the parent and child processes
// args: the arguments to pass to the container to run as the user's program
func DefaultCreateCommand(container *configs.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
	// get our binary name from arg0 so we can always reexec ourself
	env := []string{
		"console=" + console,
		"pipe=3",
		"data_path=" + dataPath,
	}

	command := exec.Command(init, append([]string{"init", "--"}, args...)...)
	// make sure the process is executed inside the context of the rootfs
	command.Dir = container.RootFs
	command.Env = append(os.Environ(), env...)

	if command.SysProcAttr == nil {
		command.SysProcAttr = &syscall.SysProcAttr{}
	}
	command.SysProcAttr.Cloneflags = uintptr(GetNamespaceFlags(container.Namespaces))

	command.SysProcAttr.Pdeathsig = syscall.SIGKILL
	command.ExtraFiles = []*os.File{pipe}

	return command
}

// SetupCgroups applies the cgroup restrictions to the process running in the container based
// on the container's configuration
func SetupCgroups(container *configs.Config, nspid int) (map[string]string, error) {
	if container.Cgroups != nil {
		c := container.Cgroups
		if systemd.UseSystemd() {
			return systemd.Apply(c, nspid)
		}
		return fs.Apply(c, nspid)
	}
	return map[string]string{}, nil
}

// InitializeNetworking creates the container's network stack outside of the namespace and moves
// interfaces into the container's net namespaces if necessary
func InitializeNetworking(container *configs.Config, nspid int, networkState *network.NetworkState) error {
	for _, config := range container.Networks {
		strategy, err := network.GetStrategy(config.Type)
		if err != nil {
			return err
		}
		if err := strategy.Create((*network.Network)(config), nspid, networkState); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>namespaces: combine Process.Env and Container.Env<commit_after>// +build linux

package namespaces

import (
	"encoding/json"
	"io"
	"os"
	"os/exec"
	"syscall"

	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/cgroups/fs"
	"github.com/docker/libcontainer/cgroups/systemd"
	"github.com/docker/libcontainer/configs"
	"github.com/docker/libcontainer/network"
	"github.com/docker/libcontainer/system"
)

// TODO(vishh): This is part of the libcontainer API and it does much more than just namespaces related work.
// Move this to libcontainer package.
// Exec performs setup outside of a namespace so that a container can be
// executed.  Exec is a high level function for working with container namespaces.
func Exec(args []string, env []string, command *exec.Cmd, container *configs.Config, state *configs.State) error {
	var err error

	// create a pipe so that we can syncronize with the namespaced process and
	// pass the state and configuration to the child process
	parent, child, err := newInitPipe()
	if err != nil {
		return err
	}
	defer parent.Close()

	command.ExtraFiles = []*os.File{child}
	command.Dir = container.RootFs

	if err := command.Start(); err != nil {
		child.Close()
		return err
	}
	child.Close()

	terminate := func(terr error) error {
		// TODO: log the errors for kill and wait
		command.Process.Kill()
		command.Wait()
		return terr
	}

	encoder := json.NewEncoder(parent)

	if err := encoder.Encode(container); err != nil {
		return terminate(err)
	}

	process := processArgs{
		Env:  append(env[0:], container.Env...),
		Args: args,
	}
	if err := encoder.Encode(process); err != nil {
		return terminate(err)
	}

	started, err := system.GetProcessStartTime(command.Process.Pid)
	if err != nil {
		return terminate(err)
	}

	// Do this before syncing with child so that no children
	// can escape the cgroup
	cgroupPaths, err := SetupCgroups(container, command.Process.Pid)
	if err != nil {
		return terminate(err)
	}
	defer cgroups.RemovePaths(cgroupPaths)

	var networkState network.NetworkState
	if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil {
		return terminate(err)
	}
	// send the state to the container's init process then shutdown writes for the parent
	if err := encoder.Encode(networkState); err != nil {
		return terminate(err)
	}
	// shutdown writes for the parent side of the pipe
	if err := syscall.Shutdown(int(parent.Fd()), syscall.SHUT_WR); err != nil {
		return terminate(err)
	}

	// wait for the child process to fully complete and receive an error message
	// if one was encoutered
	var ierr *initError
	if err := json.NewDecoder(parent).Decode(&ierr); err != nil && err != io.EOF {
		return terminate(err)
	}
	if ierr != nil {
		return terminate(ierr)
	}

	state.InitPid = command.Process.Pid
	state.InitStartTime = started
	state.NetworkState = networkState
	state.CgroupPaths = cgroupPaths

	return nil
}

// DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
//
// console: the /dev/console to setup inside the container
// init: the program executed inside the namespaces
// root: the path to the container json file and information
// pipe: sync pipe to synchronize the parent and child processes
// args: the arguments to pass to the container to run as the user's program
func DefaultCreateCommand(container *configs.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
	// get our binary name from arg0 so we can always reexec ourself
	env := []string{
		"console=" + console,
		"pipe=3",
		"data_path=" + dataPath,
	}

	command := exec.Command(init, append([]string{"init", "--"}, args...)...)
	// make sure the process is executed inside the context of the rootfs
	command.Dir = container.RootFs
	command.Env = append(os.Environ(), env...)

	if command.SysProcAttr == nil {
		command.SysProcAttr = &syscall.SysProcAttr{}
	}
	command.SysProcAttr.Cloneflags = uintptr(GetNamespaceFlags(container.Namespaces))

	command.SysProcAttr.Pdeathsig = syscall.SIGKILL
	command.ExtraFiles = []*os.File{pipe}

	return command
}

// SetupCgroups applies the cgroup restrictions to the process running in the container based
// on the container's configuration
func SetupCgroups(container *configs.Config, nspid int) (map[string]string, error) {
	if container.Cgroups != nil {
		c := container.Cgroups
		if systemd.UseSystemd() {
			return systemd.Apply(c, nspid)
		}
		return fs.Apply(c, nspid)
	}
	return map[string]string{}, nil
}

// InitializeNetworking creates the container's network stack outside of the namespace and moves
// interfaces into the container's net namespaces if necessary
func InitializeNetworking(container *configs.Config, nspid int, networkState *network.NetworkState) error {
	for _, config := range container.Networks {
		strategy, err := network.GetStrategy(config.Type)
		if err != nil {
			return err
		}
		if err := strategy.Create((*network.Network)(config), nspid, networkState); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>//   Copyright 2017 MSolution.IO
//
//   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 costs

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

	"github.com/trackit/jsonlog"
	"github.com/trackit/trackit-server/aws"
	"github.com/trackit/trackit-server/db"
	"github.com/trackit/trackit-server/es"
	"github.com/trackit/trackit-server/routes"
	"github.com/trackit/trackit-server/users"

	"gopkg.in/olivere/elastic.v5"
)

// simpleCriterionMap will map simple criterion to the boolean true.
// This will be used in parseCriterionQueryParams to validate the queryParam.
// It does not take into account the 'tag:*' criterion as it is not fixed.
var simpleCriterionMap = map[string]bool{
	"year":             true,
	"month":            true,
	"week":             true,
	"day":              true,
	"account":          true,
	"product":          true,
	"region":           true,
	"availabilityzone": true,
}

// esQueryParams will store the parsed query params
type esQueryParams struct {
	dateBegin         time.Time
	dateEnd           time.Time
	accountList       []string
	aggregationParams []string
}

// costQueryArgs allows to get required queryArgs params
var costsQueryArgs = []routes.QueryArg{
	routes.AwsAccountsOptionalQueryArg,
	routes.DateBeginQueryArg,
	routes.DateEndQueryArg,
	routes.QueryArg{
		Name:        "by",
		Description: "Criteria for the ES aggregation, comma separated. Possible values are year, month, week, day, account, product, region, tag(soon)",
		Type:        routes.QueryArgStringSlice{},
		Optional:    false,
	},
}

func init() {
	routes.MethodMuxer{
		http.MethodGet: routes.H(getCostData).With(
			db.RequestTransaction{Db: db.Db},
			users.RequireAuthenticatedUser{users.ViewerAsParent},
			routes.QueryArgs(costsQueryArgs),
			routes.Documentation{
				Summary:     "get the costs data",
				Description: "Responds with cost data based on the query args passed to it",
			},
		),
	}.H().Register("/costs")
}

// validateCriteraParam will validate the different criterions.
// It validate the criterion by checking its presence in the simpleCriterionMap
// or, in the case of the special criterion tag, will check if it is in the
// correct format : 'tag:*' (with no more than one ':')
// Right now the tags are not enabled and will generate an error if they are
// used because they are not yet implemented in the new ElasticSearch mapping
func validateCriteriaParam(parsedParams esQueryParams) error {
	for _, criterion := range parsedParams.aggregationParams {
		if !simpleCriterionMap[criterion] {
			if len(criterion) >= 5 && criterion[:4] == "tag:" && strings.Count(criterion, ":") == 1 {
				return fmt.Errorf("tags not yet implemented")
			}
			return fmt.Errorf("Error parsing criterion : %s", criterion)
		}
	}
	return nil
}

// makeElasticSearchRequestAndParseIt will make the actual request to the ElasticSearch parse the results and return them
// It will return the data, an http status code (as int) and an error.
// Because an error can be generated, but is not critical and is not needed to be known by
// the user (e.g if the index does not exists because it was not yet indexed ) the error will
// be returned, but instead of having a 500 status code, it will return the provided status code
// with empy data
func makeElasticSearchRequestAndParseIt(ctx context.Context, parsedParams esQueryParams, user users.User) (es.SimplifiedCostsDocument, int, error) {
	l := jsonlog.LoggerFromContextOrDefault(ctx)
	index := es.IndexNameForUser(user, "lineitems")
	searchService := GetElasticSearchParams(
		parsedParams.accountList,
		parsedParams.dateBegin,
		parsedParams.dateEnd,
		parsedParams.aggregationParams,
		es.Client,
		index,
	)
	res, err := searchService.Do(ctx)
	if err != nil {
		if elastic.IsNotFound(err) {
			l.Warning("Query execution failed, ES index does not exists : "+index, err)
			return es.SimplifiedCostsDocument{}, http.StatusOK, err
		}
		l.Error("Query execution failed : "+err.Error(), nil)
		return es.SimplifiedCostsDocument{}, http.StatusInternalServerError, fmt.Errorf("could not execute the ElasticSearch query")
	}
	simplifiedCostDocument, err := es.SimplifyCostsDocument(ctx, res)
	if err != nil {
		l.Error("Error parsing cost response : "+err.Error(), nil)
		return simplifiedCostDocument, http.StatusInternalServerError, fmt.Errorf("could not parse ElasticSearch response")
	}
	return simplifiedCostDocument, http.StatusOK, nil
}

// getCostsData returns the cost data based on the query params, in JSON format.
func getCostData(request *http.Request, a routes.Arguments) (int, interface{}) {
	user := a[users.AuthenticatedUser].(users.User)
	parsedParams := esQueryParams{
		accountList:       []string{},
		dateBegin:         a[costsQueryArgs[1]].(time.Time),
		dateEnd:           a[costsQueryArgs[2]].(time.Time).Add(time.Hour*time.Duration(23) + time.Minute*time.Duration(59) + time.Second*time.Duration(59)),
		aggregationParams: a[costsQueryArgs[3]].([]string),
	}
	if a[costsQueryArgs[0]] != nil {
		parsedParams.accountList = a[costsQueryArgs[0]].([]string)
	}
	if err := validateCriteriaParam(parsedParams); err != nil {
		return http.StatusBadRequest, err
	}
	if err := aws.ValidateAwsAccounts(parsedParams.accountList); err != nil {
		return http.StatusBadRequest, err
	}
	simplifiedCostDocument, returnCode, err := makeElasticSearchRequestAndParseIt(request.Context(), parsedParams, user)
	if err != nil {
		if returnCode == http.StatusOK {
			return returnCode, es.SimplifiedCostsDocument{}.ToJsonable()
		} else {
			return returnCode, err
		}
	}
	return http.StatusOK, simplifiedCostDocument.ToJsonable()
}
<commit_msg>added ES account sharing on the cost route<commit_after>//   Copyright 2017 MSolution.IO
//
//   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 costs

import (
	"context"
	"database/sql"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/trackit/jsonlog"
	"github.com/trackit/trackit-server/aws/s3"
	"github.com/trackit/trackit-server/db"
	"github.com/trackit/trackit-server/es"
	"github.com/trackit/trackit-server/routes"
	"github.com/trackit/trackit-server/users"

	"gopkg.in/olivere/elastic.v5"
)

// simpleCriterionMap will map simple criterion to the boolean true.
// This will be used in parseCriterionQueryParams to validate the queryParam.
// It does not take into account the 'tag:*' criterion as it is not fixed.
var simpleCriterionMap = map[string]bool{
	"year":             true,
	"month":            true,
	"week":             true,
	"day":              true,
	"account":          true,
	"product":          true,
	"region":           true,
	"availabilityzone": true,
}

// esQueryParams will store the parsed query params
type esQueryParams struct {
	dateBegin         time.Time
	dateEnd           time.Time
	accountList       []string
	indexList         []string
	aggregationParams []string
}

// costQueryArgs allows to get required queryArgs params
var costsQueryArgs = []routes.QueryArg{
	routes.AwsAccountsOptionalQueryArg,
	routes.DateBeginQueryArg,
	routes.DateEndQueryArg,
	routes.QueryArg{
		Name:        "by",
		Description: "Criteria for the ES aggregation, comma separated. Possible values are year, month, week, day, account, product, region, tag(soon)",
		Type:        routes.QueryArgStringSlice{},
		Optional:    false,
	},
}

func init() {
	routes.MethodMuxer{
		http.MethodGet: routes.H(getCostData).With(
			db.RequestTransaction{Db: db.Db},
			users.RequireAuthenticatedUser{users.ViewerAsParent},
			routes.QueryArgs(costsQueryArgs),
			routes.Documentation{
				Summary:     "get the costs data",
				Description: "Responds with cost data based on the query args passed to it",
			},
		),
	}.H().Register("/costs")
}

// validateCriteraParam will validate the different criterions.
// It validate the criterion by checking its presence in the simpleCriterionMap
// or, in the case of the special criterion tag, will check if it is in the
// correct format : 'tag:*' (with no more than one ':')
// Right now the tags are not enabled and will generate an error if they are
// used because they are not yet implemented in the new ElasticSearch mapping
func validateCriteriaParam(parsedParams esQueryParams) error {
	for _, criterion := range parsedParams.aggregationParams {
		if !simpleCriterionMap[criterion] {
			if len(criterion) >= 5 && criterion[:4] == "tag:" && strings.Count(criterion, ":") == 1 {
				return fmt.Errorf("tags not yet implemented")
			}
			return fmt.Errorf("Error parsing criterion : %s", criterion)
		}
	}
	return nil
}

// makeElasticSearchRequestAndParseIt will make the actual request to the ElasticSearch parse the results and return them
// It will return the data, an http status code (as int) and an error.
// Because an error can be generated, but is not critical and is not needed to be known by
// the user (e.g if the index does not exists because it was not yet indexed ) the error will
// be returned, but instead of having a 500 status code, it will return the provided status code
// with empy data
func makeElasticSearchRequestAndParseIt(ctx context.Context, parsedParams esQueryParams) (es.SimplifiedCostsDocument, int, error) {
	l := jsonlog.LoggerFromContextOrDefault(ctx)
	index := strings.Join(parsedParams.indexList, ",")
	searchService := GetElasticSearchParams(
		parsedParams.accountList,
		parsedParams.dateBegin,
		parsedParams.dateEnd,
		parsedParams.aggregationParams,
		es.Client,
		index,
	)
	res, err := searchService.Do(ctx)
	if err != nil {
		if elastic.IsNotFound(err) {
			l.Warning("Query execution failed, ES index does not exists : "+index, err)
			return es.SimplifiedCostsDocument{}, http.StatusOK, err
		}
		l.Error("Query execution failed : "+err.Error(), nil)
		return es.SimplifiedCostsDocument{}, http.StatusInternalServerError, fmt.Errorf("could not execute the ElasticSearch query")
	}
	simplifiedCostDocument, err := es.SimplifyCostsDocument(ctx, res)
	if err != nil {
		l.Error("Error parsing cost response : "+err.Error(), nil)
		return simplifiedCostDocument, http.StatusInternalServerError, fmt.Errorf("could not parse ElasticSearch response")
	}
	return simplifiedCostDocument, http.StatusOK, nil
}

// getCostsData returns the cost data based on the query params, in JSON format.
func getCostData(request *http.Request, a routes.Arguments) (int, interface{}) {
	user := a[users.AuthenticatedUser].(users.User)
	parsedParams := esQueryParams{
		accountList:       []string{},
		dateBegin:         a[costsQueryArgs[1]].(time.Time),
		dateEnd:           a[costsQueryArgs[2]].(time.Time).Add(time.Hour*time.Duration(23) + time.Minute*time.Duration(59) + time.Second*time.Duration(59)),
		aggregationParams: a[costsQueryArgs[3]].([]string),
	}
	if a[costsQueryArgs[0]] != nil {
		parsedParams.accountList = a[costsQueryArgs[0]].([]string)
	}
	if err := validateCriteriaParam(parsedParams); err != nil {
		return http.StatusBadRequest, err
	}
	tx := a[db.Transaction].(*sql.Tx)
	accountsAndIndexes, returnCode, err := es.GetAccountsAndIndexes(parsedParams.accountList, user, tx, s3.IndexPrefixLineItem)
	if err != nil {
		return returnCode, err
	}
	parsedParams.accountList = accountsAndIndexes.Accounts
	parsedParams.indexList = accountsAndIndexes.Indexes
	simplifiedCostDocument, returnCode, err := makeElasticSearchRequestAndParseIt(request.Context(), parsedParams)
	if err != nil {
		if returnCode == http.StatusOK {
			return returnCode, es.SimplifiedCostsDocument{}.ToJsonable()
		} else {
			return returnCode, err
		}
	}
	return http.StatusOK, simplifiedCostDocument.ToJsonable()
}
<|endoftext|>


<commit_before>// +build go1.2

// Copyright 2013 com authors
//
// 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 com is an open source project for commonly used functions for the Go programming language.
package com

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/admpub/log"
)

// ElapsedMemory 内存占用
func ElapsedMemory() (ret string) {
	memStat := new(runtime.MemStats)
	runtime.ReadMemStats(memStat)
	ret = FormatByte(memStat.Alloc, 3)
	return
}

// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
	bufOut := new(bytes.Buffer)
	bufErr := new(bytes.Buffer)

	cmd := exec.Command(cmdName, args...)
	cmd.Dir = dir
	cmd.Stdout = bufOut
	cmd.Stderr = bufErr

	err := cmd.Run()
	return bufOut.Bytes(), bufErr.Bytes(), err
}

// ExecCmdBytes executes system command
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
	return ExecCmdDirBytes("", cmdName, args...)
}

// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
	bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
	return string(bufOut), string(bufErr), err
}

// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
	return ExecCmdDir("", cmdName, args...)
}

// WritePidFile writes the process ID to the file at PidFile.
// It does nothing if PidFile is not set.
func WritePidFile(pidFile string) error {
	if pidFile == "" {
		return nil
	}
	pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
	return ioutil.WriteFile(pidFile, pid, 0644)
}

var (
	space  = rune(' ')
	quote  = rune('"')
	slash  = rune('\\')
	envOS  = regexp.MustCompile(`\{\$[a-zA-Z0-9_]+\}`)
	envWin = regexp.MustCompile(`\{%[a-zA-Z0-9_]+%\}`)
)

func ParseArgs(command string) (params []string) {
	item := []rune{}
	hasQuote := false
	hasSlash := false
	maxIndex := len(command) - 1
	//tower.exe -c tower.yaml -p "eee\"ddd" -t aaaa
	for k, v := range command {
		if !hasQuote {
			if v == space {
				params = append(params, string(item))
				item = []rune{}
				continue
			}
			if v == quote {
				hasQuote = true
				continue
			}
		} else {
			if !hasSlash && v == quote {
				hasQuote = false
				continue
			}
			if !hasSlash && v == slash && k+1 <= maxIndex && command[k+1] == '"' {
				hasSlash = true
				continue
			}
			hasSlash = false
		}
		item = append(item, v)
	}
	if len(item) > 0 {
		params = append(params, string(item))
	}
	for k, v := range params {
		v = envWin.ReplaceAllStringFunc(v, getWinEnv)
		params[k] = envOS.ReplaceAllStringFunc(v, getEnv)
	}
	//fmt.Printf("---> %#v\n", params)
	//params = []string{}
	return
}

func getWinEnv(s string) string {
	s = strings.TrimPrefix(s, `{%`)
	s = strings.TrimSuffix(s, `%}`)
	return os.Getenv(s)
}

func getEnv(s string) string {
	s = strings.TrimPrefix(s, `{$`)
	s = strings.TrimSuffix(s, `}`)
	return os.Getenv(s)
}

type CmdResultCapturer struct {
	Do func([]byte) error
}

func (this CmdResultCapturer) Write(p []byte) (n int, err error) {
	err = this.Do(p)
	n = len(p)
	return
}

func (this CmdResultCapturer) WriteString(p string) (n int, err error) {
	err = this.Do([]byte(p))
	n = len(p)
	return
}

func NewCmdStartResultCapturer(writer io.Writer, duration time.Duration) *CmdStartResultCapturer {
	return &CmdStartResultCapturer{
		Writer:   writer,
		duration: duration,
		started:  time.Now(),
		buffer:   bytes.NewBuffer(nil),
	}
}

type CmdStartResultCapturer struct {
	io.Writer
	started  time.Time
	duration time.Duration
	buffer   *bytes.Buffer
}

func (this CmdStartResultCapturer) Write(p []byte) (n int, err error) {
	if time.Now().Sub(this.started) < this.duration {
		this.buffer.Write(p)
	}
	return this.Write(p)
}

func (this CmdStartResultCapturer) WriteString(p string) (n int, err error) {
	if time.Now().Sub(this.started) < this.duration {
		this.buffer.WriteString(p)
	}
	return this.WriteString(p)
}

func (this CmdStartResultCapturer) Buffer() *bytes.Buffer {
	return this.buffer
}

func CreateCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdStrWithWriter(command, out)
}

func CreateCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdWithWriter(params, out)
}

func CreateCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return CreateCmdWithWriter(params, writer...)
}

func CreateCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	var cmd *exec.Cmd
	length := len(params)
	if length == 0 || len(params[0]) == 0 {
		return cmd
	}
	if length > 1 {
		cmd = exec.Command(params[0], params[1:]...)
	} else {
		cmd = exec.Command(params[0])
	}
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	length = len(writer)
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 && writer[1] != nil {
			wErr = writer[1]
		}
	}
	cmd.Stdout = wOut
	cmd.Stderr = wErr
	return cmd
}

func RunCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdStrWithWriter(command, out)
}

func RunCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdWithWriter(params, out)
}

func RunCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return RunCmdWithWriter(params, writer...)
}

func RunCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	cmd := CreateCmdWithWriter(params, writer...)

	go func() {
		err := cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()

	return cmd
}

func RunCmdWithWriterx(params []string, wait time.Duration, writer ...io.Writer) (cmd *exec.Cmd, err error, newOut *CmdStartResultCapturer, newErr *CmdStartResultCapturer) {
	length := len(writer)
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 {
			if writer[1] != nil {
				wErr = writer[1]
			}
		}
	}
	newOut = NewCmdStartResultCapturer(wOut, wait)
	newErr = NewCmdStartResultCapturer(wErr, wait)
	writer = []io.Writer{newOut, newErr}
	cmd = CreateCmdWithWriter(params, writer...)
	go func() {
		err = cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()
	time.Sleep(wait)
	return
}

func CloseProcessFromPidFile(pidFile string) (err error) {
	if pidFile == `` {
		return
	}
	b, err := ioutil.ReadFile(pidFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return
	}
	pid, err := strconv.Atoi(strings.TrimSpace(string(b)))
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return CloseProcessFromPid(pid)
}

func CloseProcessFromPid(pid int) (err error) {
	if pid <= 0 {
		return nil
	}
	procs, err := os.FindProcess(pid)
	if err == nil {
		return procs.Kill()
	}
	return
}
<commit_msg>update<commit_after>// +build go1.2

// Copyright 2013 com authors
//
// 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 com is an open source project for commonly used functions for the Go programming language.
package com

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/admpub/log"
)

// ElapsedMemory 内存占用
func ElapsedMemory() (ret string) {
	memStat := new(runtime.MemStats)
	runtime.ReadMemStats(memStat)
	ret = FormatByte(memStat.Alloc, 3)
	return
}

// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
	bufOut := new(bytes.Buffer)
	bufErr := new(bytes.Buffer)

	cmd := exec.Command(cmdName, args...)
	cmd.Dir = dir
	cmd.Stdout = bufOut
	cmd.Stderr = bufErr

	err := cmd.Run()
	return bufOut.Bytes(), bufErr.Bytes(), err
}

// ExecCmdBytes executes system command
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
	return ExecCmdDirBytes("", cmdName, args...)
}

// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
	bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
	return string(bufOut), string(bufErr), err
}

// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
	return ExecCmdDir("", cmdName, args...)
}

// WritePidFile writes the process ID to the file at PidFile.
// It does nothing if PidFile is not set.
func WritePidFile(pidFile string) error {
	if pidFile == "" {
		return nil
	}
	pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
	return ioutil.WriteFile(pidFile, pid, 0644)
}

var (
	space  = rune(' ')
	quote  = rune('"')
	slash  = rune('\\')
	envOS  = regexp.MustCompile(`\{\$[a-zA-Z0-9_]+\}`)
	envWin = regexp.MustCompile(`\{%[a-zA-Z0-9_]+%\}`)
)

func ParseArgs(command string) (params []string) {
	item := []rune{}
	hasQuote := false
	hasSlash := false
	maxIndex := len(command) - 1
	//tower.exe -c tower.yaml -p "eee\"ddd" -t aaaa
	for k, v := range command {
		if !hasQuote {
			if v == space {
				params = append(params, string(item))
				item = []rune{}
				continue
			}
			if v == quote {
				hasQuote = true
				continue
			}
		} else {
			if !hasSlash && v == quote {
				hasQuote = false
				continue
			}
			if !hasSlash && v == slash && k+1 <= maxIndex && command[k+1] == '"' {
				hasSlash = true
				continue
			}
			hasSlash = false
		}
		item = append(item, v)
	}
	if len(item) > 0 {
		params = append(params, string(item))
	}
	for k, v := range params {
		v = envWin.ReplaceAllStringFunc(v, getWinEnv)
		params[k] = envOS.ReplaceAllStringFunc(v, getEnv)
	}
	//fmt.Printf("---> %#v\n", params)
	//params = []string{}
	return
}

func getWinEnv(s string) string {
	s = strings.TrimPrefix(s, `{%`)
	s = strings.TrimSuffix(s, `%}`)
	return os.Getenv(s)
}

func getEnv(s string) string {
	s = strings.TrimPrefix(s, `{$`)
	s = strings.TrimSuffix(s, `}`)
	return os.Getenv(s)
}

type CmdResultCapturer struct {
	Do func([]byte) error
}

func (this CmdResultCapturer) Write(p []byte) (n int, err error) {
	err = this.Do(p)
	n = len(p)
	return
}

func (this CmdResultCapturer) WriteString(p string) (n int, err error) {
	err = this.Do([]byte(p))
	n = len(p)
	return
}

func NewCmdStartResultCapturer(writer io.Writer, duration time.Duration) *CmdStartResultCapturer {
	return &CmdStartResultCapturer{
		Writer:   writer,
		duration: duration,
		started:  time.Now(),
		buffer:   bytes.NewBuffer(nil),
	}
}

type CmdStartResultCapturer struct {
	io.Writer
	started  time.Time
	duration time.Duration
	buffer   *bytes.Buffer
}

func (this CmdStartResultCapturer) Write(p []byte) (n int, err error) {
	if time.Now().Sub(this.started) < this.duration {
		this.buffer.Write(p)
	}
	return this.Writer.Write(p)
}

func (this CmdStartResultCapturer) Buffer() *bytes.Buffer {
	return this.buffer
}

func CreateCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdStrWithWriter(command, out)
}

func CreateCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdWithWriter(params, out)
}

func CreateCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return CreateCmdWithWriter(params, writer...)
}

func CreateCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	var cmd *exec.Cmd
	length := len(params)
	if length == 0 || len(params[0]) == 0 {
		return cmd
	}
	if length > 1 {
		cmd = exec.Command(params[0], params[1:]...)
	} else {
		cmd = exec.Command(params[0])
	}
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	length = len(writer)
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 && writer[1] != nil {
			wErr = writer[1]
		}
	}
	cmd.Stdout = wOut
	cmd.Stderr = wErr
	return cmd
}

func RunCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdStrWithWriter(command, out)
}

func RunCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdWithWriter(params, out)
}

func RunCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return RunCmdWithWriter(params, writer...)
}

func RunCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	cmd := CreateCmdWithWriter(params, writer...)

	go func() {
		err := cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()

	return cmd
}

func RunCmdWithWriterx(params []string, wait time.Duration, writer ...io.Writer) (cmd *exec.Cmd, err error, newOut *CmdStartResultCapturer, newErr *CmdStartResultCapturer) {
	length := len(writer)
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 {
			if writer[1] != nil {
				wErr = writer[1]
			}
		}
	}
	newOut = NewCmdStartResultCapturer(wOut, wait)
	newErr = NewCmdStartResultCapturer(wErr, wait)
	writer = []io.Writer{newOut, newErr}
	cmd = CreateCmdWithWriter(params, writer...)
	go func() {
		err = cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()
	time.Sleep(wait)
	return
}

func CloseProcessFromPidFile(pidFile string) (err error) {
	if pidFile == `` {
		return
	}
	b, err := ioutil.ReadFile(pidFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return
	}
	pid, err := strconv.Atoi(strings.TrimSpace(string(b)))
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return CloseProcessFromPid(pid)
}

func CloseProcessFromPid(pid int) (err error) {
	if pid <= 0 {
		return nil
	}
	procs, err := os.FindProcess(pid)
	if err == nil {
		return procs.Kill()
	}
	return
}
<|endoftext|>


<commit_before>package rw

import (
	"io/ioutil"
	"testing"
	"time"
)

func TestWaitWriter(t *testing.T) {
	cases := map[string][]string{
		"foo": {"opasd", "asdasdf", "osdfsdf", "rtyfoot"},
		"bar": {"sdfba", "sdfswe34", "w3psgb", "ar2al"},
		"baz": {"alqlqpqp102bBBAZ", "baz"},
		"qux": {"quxpwo300ls,"},
		"quu": {"dldl20slw", "wejznmqo10f8w0-ak", "04j0qm204n2", "ofg0qkquu"},
		"209skswkwprt,mxg;dfglsp": {"a", "b", "209skswk", "wprt,mx", "g;dfglsp"},
	}
	for msg, parts := range cases {
		w := WaitWriter(ioutil.Discard, []byte(msg))
		go func() {
			for _, s := range parts {
				if _, err := w.Write([]byte(s)); err != nil {
					panic(err)
				}
			}
		}()
		if err := w.Wait(time.Second); err != nil {
			t.Errorf("want w.Wait(...)=nil; got %v", err)
			continue
		}
	}
}
<commit_msg>Add more test-cases for WaitingWriter.Write<commit_after>package rw

import (
	"io"
	"io/ioutil"
	"testing"
	"time"
)

var cases = map[string][]string{
	"foo": {"opasd", "asdasdf", "osdfsdf", "rtyfoot"},
	"bar": {"sdfba", "sdfswe34", "w3psgb", "ar2al"},
	"baz": {"alqlqpqp102bBBAZ", "baz"},
	"qux": {"quxpwo300ls,"},
	"quu": {"dldl20slw", "wejznmqo10f8w0-ak", "04j0qm204n2", "ofg0qkquu"},
	"209skswkwprt,mxg;dfglsp": {"a", "b", "209skswk", "wprt,mx", "g;dfglsp"},
}

func write(w io.Writer, s []string) {
	for _, s := range s {
		if _, err := w.Write([]byte(s)); err != nil {
			panic(err)
		}
	}
}

func TestWaitWriter(t *testing.T) {
	for msg, parts := range cases {
		w := WaitWriter(ioutil.Discard, []byte(msg))
		go write(w, parts)
		if err := w.Wait(time.Second); err != nil {
			t.Errorf("want w.Wait(...)=nil; got %v", err)
			continue
		}
	}
}

func TestWaitWriterTimeout(t *testing.T) {
	for msg, parts := range cases {
		w := WaitWriter(ioutil.Discard, []byte(msg+"must timeout"))
		err := make(chan error)
		go write(w, parts)
		go func() { err <- w.Wait(20 * time.Millisecond) }()
		select {
		case err := <-err:
			if err == nil {
				t.Errorf("want err != nil (msg=%s)", msg)
			}
		case <-time.After(time.Second):
			t.Errorf("test has timed out (msg=%s)", msg)
		}
	}
}
<|endoftext|>


<commit_before>package dht

import (
	"sync"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	peer "github.com/jbenet/go-ipfs/peer"
	"github.com/jbenet/go-ipfs/routing"
	pb "github.com/jbenet/go-ipfs/routing/dht/pb"
	kb "github.com/jbenet/go-ipfs/routing/kbucket"
	u "github.com/jbenet/go-ipfs/util"
)

// This file implements the Routing interface for the IpfsDHT struct.

// Basic Put/Get

// PutValue adds value corresponding to given Key.
// This is the top level "Store" operation of the DHT
func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error {
	log.Debugf("PutValue %s", key)
	err := dht.putLocal(key, value)
	if err != nil {
		return err
	}

	rec, err := dht.makePutRecord(key, value)
	if err != nil {
		log.Error("Creation of record failed!")
		return err
	}

	var peers []peer.Peer
	for _, route := range dht.routingTables {
		npeers := route.NearestPeers(kb.ConvertKey(key), KValue)
		peers = append(peers, npeers...)
	}

	query := newQuery(key, dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
		log.Debugf("%s PutValue qry part %v", dht.self, p)
		err := dht.putValueToNetwork(ctx, p, string(key), rec)
		if err != nil {
			return nil, err
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err = query.Run(ctx, peers)
	return err
}

// GetValue searches for the value corresponding to given Key.
// If the search does not succeed, a multiaddr string of a closer peer is
// returned along with util.ErrSearchIncomplete
func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
	log.Debugf("Get Value [%s]", key)

	// If we have it local, dont bother doing an RPC!
	// NOTE: this might not be what we want to do...
	val, err := dht.getLocal(key)
	if err == nil {
		log.Debug("Got value locally!")
		return val, nil
	}

	// get closest peers in the routing tables
	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertKey(key), PoolSize)
	if closest == nil || len(closest) == 0 {
		log.Warning("Got no peers back from routing table!")
		return nil, kb.ErrLookupFailure
	}

	// setup the Query
	query := newQuery(key, dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {

		val, peers, err := dht.getValueOrPeers(ctx, p, key, routeLevel)
		if err != nil {
			return nil, err
		}

		res := &dhtQueryResult{value: val, closerPeers: peers}
		if val != nil {
			res.success = true
		}

		return res, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	log.Debugf("GetValue %v %v", key, result.value)
	if result.value == nil {
		return nil, routing.ErrNotFound
	}

	return result.value, nil
}

// Value provider layer of indirection.
// This is what DSHTs (Coral and MainlineDHT) do to store large values in a DHT.

// Provide makes this node announce that it can provide a value for the given key
func (dht *IpfsDHT) Provide(ctx context.Context, key u.Key) error {

	dht.providers.AddProvider(key, dht.self)
	peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), PoolSize)
	if len(peers) == 0 {
		return nil
	}

	//TODO FIX: this doesn't work! it needs to be sent to the actual nearest peers.
	// `peers` are the closest peers we have, not the ones that should get the value.
	for _, p := range peers {
		err := dht.putProvider(ctx, p, string(key))
		if err != nil {
			return err
		}
	}
	return nil
}

func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan peer.Peer {
	peerOut := make(chan peer.Peer, count)
	go func() {
		ps := newPeerSet()
		provs := dht.providers.GetProviders(key)
		for _, p := range provs {
			count--
			// NOTE: assuming that this list of peers is unique
			ps.Add(p)
			peerOut <- p
			if count <= 0 {
				return
			}
		}

		wg := new(sync.WaitGroup)
		peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), AlphaValue)
		for _, pp := range peers {
			wg.Add(1)
			go func(p peer.Peer) {
				defer wg.Done()
				pmes, err := dht.findProvidersSingle(ctx, p, key, 0)
				if err != nil {
					log.Error(err)
					return
				}
				dht.addPeerListAsync(ctx, key, pmes.GetProviderPeers(), ps, count, peerOut)
			}(pp)
		}
		wg.Wait()
		close(peerOut)
	}()
	return peerOut
}

func (dht *IpfsDHT) addPeerListAsync(ctx context.Context, k u.Key, peers []*pb.Message_Peer, ps *peerSet, count int, out chan peer.Peer) {
	done := make(chan struct{})
	for _, pbp := range peers {
		go func(mp *pb.Message_Peer) {
			defer func() { done <- struct{}{} }()
			// construct new peer
			p, err := dht.ensureConnectedToPeer(ctx, mp)
			if err != nil {
				log.Errorf("%s", err)
				return
			}
			if p == nil {
				log.Error("Got nil peer from ensureConnectedToPeer")
				return
			}

			dht.providers.AddProvider(k, p)
			if ps.AddIfSmallerThan(p, count) {
				out <- p
			} else if ps.Size() >= count {
				return
			}
		}(pbp)
	}
	for _ = range peers {
		<-done
	}
}

// Find specific Peer
// FindPeer searches for a peer with given ID.
func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.FindLocal(id)
	if p != nil {
		return p, nil
	}

	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
	if closest == nil || len(closest) == 0 {
		return nil, kb.ErrLookupFailure
	}

	// Sanity...
	for _, p := range closest {
		if p.ID().Equal(id) {
			log.Error("Found target peer in list of closest peers...")
			return p, nil
		}
	}

	// setup the Query
	query := newQuery(u.Key(id), dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {

		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		if err != nil {
			return nil, err
		}

		closer := pmes.GetCloserPeers()
		var clpeers []peer.Peer
		for _, pbp := range closer {
			np, err := dht.getPeer(peer.ID(pbp.GetId()))
			if err != nil {
				log.Warningf("Received invalid peer from query: %v", err)
				continue
			}
			ma, err := pbp.Address()
			if err != nil {
				log.Warning("Received peer with bad or missing address.")
				continue
			}
			np.AddAddress(ma)
			if pbp.GetId() == string(id) {
				return &dhtQueryResult{
					peer:    np,
					success: true,
				}, nil
			}
			clpeers = append(clpeers, np)
		}

		return &dhtQueryResult{closerPeers: clpeers}, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	log.Debugf("FindPeer %v %v", id, result.success)
	if result.peer == nil {
		return nil, routing.ErrNotFound
	}

	return result.peer, nil
}

// Ping a peer, log the time it took
func (dht *IpfsDHT) Ping(ctx context.Context, p peer.Peer) error {
	// Thoughts: maybe this should accept an ID and do a peer lookup?
	log.Infof("ping %s start", p)

	pmes := pb.NewMessage(pb.Message_PING, "", 0)
	_, err := dht.sendRequest(ctx, p, pmes)
	log.Infof("ping %s end (err = %s)", p, err)
	return err
}
<commit_msg>switch over to using sendMessage vs sendRequest<commit_after>package dht

import (
	"sync"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	peer "github.com/jbenet/go-ipfs/peer"
	"github.com/jbenet/go-ipfs/routing"
	pb "github.com/jbenet/go-ipfs/routing/dht/pb"
	kb "github.com/jbenet/go-ipfs/routing/kbucket"
	u "github.com/jbenet/go-ipfs/util"
)

// This file implements the Routing interface for the IpfsDHT struct.

// Basic Put/Get

// PutValue adds value corresponding to given Key.
// This is the top level "Store" operation of the DHT
func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error {
	log.Debugf("PutValue %s", key)
	err := dht.putLocal(key, value)
	if err != nil {
		return err
	}

	rec, err := dht.makePutRecord(key, value)
	if err != nil {
		log.Error("Creation of record failed!")
		return err
	}

	var peers []peer.Peer
	for _, route := range dht.routingTables {
		npeers := route.NearestPeers(kb.ConvertKey(key), KValue)
		peers = append(peers, npeers...)
	}

	query := newQuery(key, dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {
		log.Debugf("%s PutValue qry part %v", dht.self, p)
		err := dht.putValueToNetwork(ctx, p, string(key), rec)
		if err != nil {
			return nil, err
		}
		return &dhtQueryResult{success: true}, nil
	})

	_, err = query.Run(ctx, peers)
	return err
}

// GetValue searches for the value corresponding to given Key.
// If the search does not succeed, a multiaddr string of a closer peer is
// returned along with util.ErrSearchIncomplete
func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) {
	log.Debugf("Get Value [%s]", key)

	// If we have it local, dont bother doing an RPC!
	// NOTE: this might not be what we want to do...
	val, err := dht.getLocal(key)
	if err == nil {
		log.Debug("Got value locally!")
		return val, nil
	}

	// get closest peers in the routing tables
	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertKey(key), PoolSize)
	if closest == nil || len(closest) == 0 {
		log.Warning("Got no peers back from routing table!")
		return nil, kb.ErrLookupFailure
	}

	// setup the Query
	query := newQuery(key, dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {

		val, peers, err := dht.getValueOrPeers(ctx, p, key, routeLevel)
		if err != nil {
			return nil, err
		}

		res := &dhtQueryResult{value: val, closerPeers: peers}
		if val != nil {
			res.success = true
		}

		return res, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	log.Debugf("GetValue %v %v", key, result.value)
	if result.value == nil {
		return nil, routing.ErrNotFound
	}

	return result.value, nil
}

// Value provider layer of indirection.
// This is what DSHTs (Coral and MainlineDHT) do to store large values in a DHT.

// Provide makes this node announce that it can provide a value for the given key
func (dht *IpfsDHT) Provide(ctx context.Context, key u.Key) error {

	dht.providers.AddProvider(key, dht.self)
	peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), PoolSize)
	if len(peers) == 0 {
		return nil
	}

	//TODO FIX: this doesn't work! it needs to be sent to the actual nearest peers.
	// `peers` are the closest peers we have, not the ones that should get the value.
	for _, p := range peers {
		err := dht.putProvider(ctx, p, string(key))
		if err != nil {
			return err
		}
	}
	return nil
}

func (dht *IpfsDHT) FindProvidersAsync(ctx context.Context, key u.Key, count int) <-chan peer.Peer {
	log.Debug("Find Providers: %s", key)
	peerOut := make(chan peer.Peer, count)
	go func() {
		ps := newPeerSet()
		provs := dht.providers.GetProviders(key)
		for _, p := range provs {
			count--
			// NOTE: assuming that this list of peers is unique
			ps.Add(p)
			peerOut <- p
			if count <= 0 {
				return
			}
		}

		wg := new(sync.WaitGroup)
		peers := dht.routingTables[0].NearestPeers(kb.ConvertKey(key), AlphaValue)
		for _, pp := range peers {
			wg.Add(1)
			go func(p peer.Peer) {
				defer wg.Done()
				pmes, err := dht.findProvidersSingle(ctx, p, key, 0)
				if err != nil {
					log.Error(err)
					return
				}
				dht.addPeerListAsync(ctx, key, pmes.GetProviderPeers(), ps, count, peerOut)
			}(pp)
		}
		wg.Wait()
		close(peerOut)
	}()
	return peerOut
}

func (dht *IpfsDHT) addPeerListAsync(ctx context.Context, k u.Key, peers []*pb.Message_Peer, ps *peerSet, count int, out chan peer.Peer) {
	done := make(chan struct{})
	for _, pbp := range peers {
		go func(mp *pb.Message_Peer) {
			defer func() { done <- struct{}{} }()
			// construct new peer
			p, err := dht.ensureConnectedToPeer(ctx, mp)
			if err != nil {
				log.Errorf("%s", err)
				return
			}
			if p == nil {
				log.Error("Got nil peer from ensureConnectedToPeer")
				return
			}

			dht.providers.AddProvider(k, p)
			if ps.AddIfSmallerThan(p, count) {
				out <- p
			} else if ps.Size() >= count {
				return
			}
		}(pbp)
	}
	for _ = range peers {
		<-done
	}
}

// Find specific Peer
// FindPeer searches for a peer with given ID.
func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (peer.Peer, error) {

	// Check if were already connected to them
	p, _ := dht.FindLocal(id)
	if p != nil {
		return p, nil
	}

	routeLevel := 0
	closest := dht.routingTables[routeLevel].NearestPeers(kb.ConvertPeerID(id), AlphaValue)
	if closest == nil || len(closest) == 0 {
		return nil, kb.ErrLookupFailure
	}

	// Sanity...
	for _, p := range closest {
		if p.ID().Equal(id) {
			log.Error("Found target peer in list of closest peers...")
			return p, nil
		}
	}

	// setup the Query
	query := newQuery(u.Key(id), dht.dialer, func(ctx context.Context, p peer.Peer) (*dhtQueryResult, error) {

		pmes, err := dht.findPeerSingle(ctx, p, id, routeLevel)
		if err != nil {
			return nil, err
		}

		closer := pmes.GetCloserPeers()
		var clpeers []peer.Peer
		for _, pbp := range closer {
			np, err := dht.getPeer(peer.ID(pbp.GetId()))
			if err != nil {
				log.Warningf("Received invalid peer from query: %v", err)
				continue
			}
			ma, err := pbp.Address()
			if err != nil {
				log.Warning("Received peer with bad or missing address.")
				continue
			}
			np.AddAddress(ma)
			if pbp.GetId() == string(id) {
				return &dhtQueryResult{
					peer:    np,
					success: true,
				}, nil
			}
			clpeers = append(clpeers, np)
		}

		return &dhtQueryResult{closerPeers: clpeers}, nil
	})

	// run it!
	result, err := query.Run(ctx, closest)
	if err != nil {
		return nil, err
	}

	log.Debugf("FindPeer %v %v", id, result.success)
	if result.peer == nil {
		return nil, routing.ErrNotFound
	}

	return result.peer, nil
}

// Ping a peer, log the time it took
func (dht *IpfsDHT) Ping(ctx context.Context, p peer.Peer) error {
	// Thoughts: maybe this should accept an ID and do a peer lookup?
	log.Infof("ping %s start", p)

	pmes := pb.NewMessage(pb.Message_PING, "", 0)
	_, err := dht.sendRequest(ctx, p, pmes)
	log.Infof("ping %s end (err = %s)", p, err)
	return err
}
<|endoftext|>


<commit_before>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"fmt"
	"math/rand"
	"time"
)

// pc is the program counter
type pc uint16

// Increments the counter
func (p *pc) Increment() {
	(*p) += 2
}

// The stack
type stack struct {
	data [16]pc
	sp   uint16 // Stack Pointer
}

// Push the addr to the stack
func (s *stack) Push(data pc) {
	s.data[s.sp] = data
	s.sp++
}

// Pop a value from stack
func (s *stack) Pop() pc {
	s.sp--
	return s.data[s.sp]
}

// cpu is the chip8 main cpu
type cpu struct {
	regs  [16]byte // Registers v0 - vF
	stack stack    // The Stack
	i     uint16   // Index
	pc    pc       // Program Counter

	gfx    gfx      // Graphics
	memory memory   // Memory - 4K
	keys   [16]bool // Key State
	dt     byte     // Delay Timer
	st     byte     // Sound Timer
}

// Chip8 Fonts
var font = [80]byte{
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
}

// newCpu creates a new cpu and initialize it
func newCpu() cpu {
	rand.Seed(time.Now().UTC().UnixNano())

	c := cpu{
		pc:    0x200,
		i:     0,
		dt:    0,
		st:    0,
		stack: stack{sp: 0},
	}

	// Load font into memory
	for i, e := range font {
		c.memory.Write(uint16(i), e)
	}

	return c
}

// Step the cpu one instruction at a time
func (c *cpu) Step() {
	opcode := c.memory.ReadWord(uint16(c.pc))
	x := opcode & 0x0F00
	y := opcode & 0x00F0

	c.pc.Increment()

	switch opcode & 0xF000 {
	case 0x0000:
		switch opcode {
		case 0x00E0: // 00E0 - CLS
			c.gfx.Cls()
		case 0x00EE: // 00EE - RET
			c.pc = c.stack.Pop()
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0x1000: // 1nnn - JP addr
		c.pc = pc(opcode & 0x0FFF)
	case 0x2000: // 2nnn - CALL addr
		c.stack.Push(c.pc)
		c.pc = pc(opcode & 0x0FFF)
	case 0x3000: // 3xkk - SE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] == byte(kk) {
			c.pc.Increment()
		}
	case 0x4000: // 4xkk - SNE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] != byte(kk) {
			c.pc.Increment()
		}
	case 0x5000: // 5xy0 - SE Vx, Vy
		if c.regs[x] == c.regs[y] {
			c.pc.Increment()
		}
	case 0x6000: // 6xkk - LD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] = byte(kk)
	case 0x7000: // 7xkk - ADD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] += byte(kk)
	case 0x8000:
		switch opcode & 0x000F {
		case 0x0000: // 8xy0 - LD Vx, Vy
			c.regs[x] = c.regs[y]
		case 0x0001: // 8xy1 - OR Vx, Vy
			c.regs[x] |= c.regs[y]
		case 0x0002: // 8xy2 - AND Vx, Vy
			c.regs[x] &= c.regs[y]
		case 0x0003: // 8xy3 - XOR Vx, Vy
			c.regs[x] ^= c.regs[y]
		case 0x0004: // 8xy4 - ADD Vx, Vy
			r := c.regs[x] + c.regs[y]

			if r > 0xFF {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = r
		case 0x0005: // 8xy5 - SUB Vx, Vy
			if c.regs[x] > c.regs[y] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = c.regs[x] - c.regs[y]
		case 0x0006: // 8xy6 - SHR Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] / 2
		case 0x0007: // 8xy7 - SUBN Vx, Vy
			if c.regs[y] > c.regs[x] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}
			c.regs[x] = c.regs[y] - c.regs[x]
		case 0x000E: // 8xyE - SHL Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] * 2
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0x9000: // 9xy0 - SNE Vx, Vy
		if c.regs[x] != c.regs[y] {
			c.pc.Increment()
		}
	case 0xA000: // Annn - LD I, addr
		c.i = opcode & 0x0FFF
	case 0xB000: // Bnnn - JP V0, addr
		addr := opcode & 0x0FFF
		c.pc = pc(addr + uint16(c.regs[0]))
	case 0xC000: // Cxkk - RND Vx, byte
		kk := opcode & 0x00FF
		c.regs[x] = byte(rand.Intn(256)) & byte(kk)
	case 0xD000: // Dxyn - DRW Vx, Vy, nibble
		// TODO:  Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
	case 0xE000:
		switch opcode & 0x000F {
		case 0x000E: // Ex9E - SKP Vx
			if c.keys[x] {
				c.pc.Increment()
			}
		case 0x0001: // ExA1 - SKNP Vx
			if !c.keys[x] {
				c.pc.Increment()
			}
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0xF000:
		switch opcode & 0x00FF {
		case 0x0007: // Fx07 - LD Vx, DT
			c.regs[x] = c.dt
		case 0x000A: // Fx0A - LD Vx, K
			// TODO: Wait for a key press, store the value of the key in Vx.
			// All execution stops until a key is pressed, then the value of that key is stored in Vx.
		case 0x0015: // Fx15 - LD DT, Vx
			c.dt = c.regs[x]
		case 0x0018: // Fx18 - LD ST, Vx
			c.st = c.regs[x]
		case 0x001E: // Fx1E - ADD I, Vx
			c.i += uint16(c.regs[x])
		case 0x0029: // Fx29 - LD F, Vx
			c.i = uint16(c.regs[x] * 5) // 5 is the number of rows per character.
		case 0x0033: // Fx33 - LD B, Vx
			c.memory.Write(c.i, c.regs[x]/100)
			c.memory.Write(c.i+1, (c.regs[x]/10)%10)
			c.memory.Write(c.i+2, (c.regs[x]%100)%10)
		case 0x0055: // Fx55 - LD [I], Vx
			for i := uint16(0); i <= x; i++ {
				c.memory.Write(c.i+i, c.regs[i])
			}
		case 0x0065: // Fx65 - LD Vx, [I]
			for i := uint16(0); i <= x; i++ {
				c.regs[i] = c.memory.Read(c.i + i)
			}
		}
	default:
		panic(fmt.Sprintf("Unknown opcode %+v", opcode))
	}
}
<commit_msg>Simplified implementation Fx33<commit_after>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"fmt"
	"math/rand"
	"time"
)

// pc is the program counter
type pc uint16

// Increments the counter
func (p *pc) Increment() {
	(*p) += 2
}

// The stack
type stack struct {
	data [16]pc
	sp   uint16 // Stack Pointer
}

// Push the addr to the stack
func (s *stack) Push(data pc) {
	s.data[s.sp] = data
	s.sp++
}

// Pop a value from stack
func (s *stack) Pop() pc {
	s.sp--
	return s.data[s.sp]
}

// cpu is the chip8 main cpu
type cpu struct {
	regs  [16]byte // Registers v0 - vF
	stack stack    // The Stack
	i     uint16   // Index
	pc    pc       // Program Counter

	gfx    gfx      // Graphics
	memory memory   // Memory - 4K
	keys   [16]bool // Key State
	dt     byte     // Delay Timer
	st     byte     // Sound Timer
}

// Chip8 Fonts
var font = [80]byte{
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
}

// newCpu creates a new cpu and initialize it
func newCpu() cpu {
	rand.Seed(time.Now().UTC().UnixNano())

	c := cpu{
		pc:    0x200,
		i:     0,
		dt:    0,
		st:    0,
		stack: stack{sp: 0},
	}

	// Load font into memory
	for i, e := range font {
		c.memory.Write(uint16(i), e)
	}

	return c
}

// Step the cpu one instruction at a time
func (c *cpu) Step() {
	opcode := c.memory.ReadWord(uint16(c.pc))
	x := opcode & 0x0F00
	y := opcode & 0x00F0

	c.pc.Increment()

	switch opcode & 0xF000 {
	case 0x0000:
		switch opcode {
		case 0x00E0: // 00E0 - CLS
			c.gfx.Cls()
		case 0x00EE: // 00EE - RET
			c.pc = c.stack.Pop()
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0x1000: // 1nnn - JP addr
		c.pc = pc(opcode & 0x0FFF)
	case 0x2000: // 2nnn - CALL addr
		c.stack.Push(c.pc)
		c.pc = pc(opcode & 0x0FFF)
	case 0x3000: // 3xkk - SE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] == byte(kk) {
			c.pc.Increment()
		}
	case 0x4000: // 4xkk - SNE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] != byte(kk) {
			c.pc.Increment()
		}
	case 0x5000: // 5xy0 - SE Vx, Vy
		if c.regs[x] == c.regs[y] {
			c.pc.Increment()
		}
	case 0x6000: // 6xkk - LD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] = byte(kk)
	case 0x7000: // 7xkk - ADD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] += byte(kk)
	case 0x8000:
		switch opcode & 0x000F {
		case 0x0000: // 8xy0 - LD Vx, Vy
			c.regs[x] = c.regs[y]
		case 0x0001: // 8xy1 - OR Vx, Vy
			c.regs[x] |= c.regs[y]
		case 0x0002: // 8xy2 - AND Vx, Vy
			c.regs[x] &= c.regs[y]
		case 0x0003: // 8xy3 - XOR Vx, Vy
			c.regs[x] ^= c.regs[y]
		case 0x0004: // 8xy4 - ADD Vx, Vy
			r := c.regs[x] + c.regs[y]

			if r > 0xFF {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = r
		case 0x0005: // 8xy5 - SUB Vx, Vy
			if c.regs[x] > c.regs[y] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = c.regs[x] - c.regs[y]
		case 0x0006: // 8xy6 - SHR Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] / 2
		case 0x0007: // 8xy7 - SUBN Vx, Vy
			if c.regs[y] > c.regs[x] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}
			c.regs[x] = c.regs[y] - c.regs[x]
		case 0x000E: // 8xyE - SHL Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] * 2
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0x9000: // 9xy0 - SNE Vx, Vy
		if c.regs[x] != c.regs[y] {
			c.pc.Increment()
		}
	case 0xA000: // Annn - LD I, addr
		c.i = opcode & 0x0FFF
	case 0xB000: // Bnnn - JP V0, addr
		addr := opcode & 0x0FFF
		c.pc = pc(addr + uint16(c.regs[0]))
	case 0xC000: // Cxkk - RND Vx, byte
		kk := opcode & 0x00FF
		c.regs[x] = byte(rand.Intn(256)) & byte(kk)
	case 0xD000: // Dxyn - DRW Vx, Vy, nibble
		// TODO:  Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
	case 0xE000:
		switch opcode & 0x000F {
		case 0x000E: // Ex9E - SKP Vx
			if c.keys[x] {
				c.pc.Increment()
			}
		case 0x0001: // ExA1 - SKNP Vx
			if !c.keys[x] {
				c.pc.Increment()
			}
		default:
			panic(fmt.Sprintf("Unknown opcode %+v", opcode))
		}
	case 0xF000:
		switch opcode & 0x00FF {
		case 0x0007: // Fx07 - LD Vx, DT
			c.regs[x] = c.dt
		case 0x000A: // Fx0A - LD Vx, K
			// TODO: Wait for a key press, store the value of the key in Vx.
			// All execution stops until a key is pressed, then the value of that key is stored in Vx.
		case 0x0015: // Fx15 - LD DT, Vx
			c.dt = c.regs[x]
		case 0x0018: // Fx18 - LD ST, Vx
			c.st = c.regs[x]
		case 0x001E: // Fx1E - ADD I, Vx
			c.i += uint16(c.regs[x])
		case 0x0029: // Fx29 - LD F, Vx
			c.i = uint16(c.regs[x] * 5) // 5 is the number of rows per character.
		case 0x0033: // Fx33 - LD B, Vx
			num := c.regs[x]

			for i := uint16(3); i > 0; i-- {
				c.memory.Write(c.i+i-1, num%10)
				num /= 10
			}
		case 0x0055: // Fx55 - LD [I], Vx
			for i := uint16(0); i <= x; i++ {
				c.memory.Write(c.i+i, c.regs[i])
			}
		case 0x0065: // Fx65 - LD Vx, [I]
			for i := uint16(0); i <= x; i++ {
				c.regs[i] = c.memory.Read(c.i + i)
			}
		}
	default:
		panic(fmt.Sprintf("Unknown opcode %+v", opcode))
	}
}
<|endoftext|>


<commit_before>package rpigpio

import (
	"errors"
	"fmt"
)

var piPinToBCMPinRev2 = [27]int8{
	-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1,
	22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7,
}

// Deteriming GPIO number
func (gpio *RpiGpio) getBCMGpio(pin Pin) (Pin, error) {
	if gpio.mode == GPIO {
		return pin, nil
	} else if gpio.mode == PI && int(pin) > len(gpio.pinToBCMPin) {
		return 255, fmt.Errorf("Pin %d must be < %d", pin, len(gpio.pinToBCMPin))
	} else if gpio.pinToBCMPin[pin] == -1 {
		return 255, fmt.Errorf("Pin %d not valid for GPIO", pin)
	}
	return Pin(gpio.pinToBCMPin[pin]), nil
}

// NewGPIO sets up a new GPIO object
func NewGPIO() (*RpiGpio, error) {
	var err error
	gpio := new(RpiGpio)
	gpio.bcm = NewBCMGPIO()
	gpio.mode = GPIO
	gpio.status = NEW
	gpio.rpi = new(RpiInfo)
	gpio.rpi.GetCPUInfo()
	switch int(gpio.rpi.piRevision) {
	case 2:
		gpio.pinToBCMPin = piPinToBCMPinRev2
	default:
		return nil, errors.New("Unknown Raspberry Pi hardware")
	}
	// set gpio "direction"  (in/out??)
	// pinTopin = pinToGpiopinRev??
	err = gpio.bcm.open()
	if err != nil {
		return nil, err
	}
	gpio.status = OK
	return gpio, nil
}

// Mode sets the pin interpretation for the rpigpio functions
func (gpio *RpiGpio) Mode(m Mode) error {
	if m != GPIO && m != PI {
		return fmt.Errorf("Mode must be GPIO or PI")
	}
	gpio.mode = m
	return nil
}

// Pull sets the direction of the built-in pull-up/pull-down resistor
func (gpio *RpiGpio) Pull(p Pin, d Pull) error {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return err
	}
	return gpio.bcm.Pull(pin, d)
}

func (gpio *RpiGpio) Read(p Pin) (PinState, error) {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return 255, err
	}
	return gpio.bcm.Read(pin), nil
}

func (gpio *RpiGpio) Write(p Pin, s PinState) error {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return err
	}
	gpio.bcm.Write(pin, s)
	return nil
}

// Cleanup the pin ; reset to INPUT and pull up/down to off
func (gpio *RpiGpio) Cleanup(pin uint8) {
	// Verify pin is valid, package status is OK, etc
	// get gpio number from pin
	// call c_gpio::cleanup_one()
	//    * call event_cleanup()
	//    * set gpio_direction = -1
	//    * set gpio to INPUT and pull up/down to off
	//    * set found for error checking later on (if working on > 1 pin at a time)
}

// eventCleanup
func eventCleanup(gpio uint) {
	// event_gpio.c:403
}
<commit_msg>Add Direction() as a method for rpigpio<commit_after>package rpigpio

import (
	"errors"
	"fmt"
)

var piPinToBCMPinRev2 = [27]int8{
	-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1,
	22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7,
}

// Deteriming GPIO number
func (gpio *RpiGpio) getBCMGpio(pin Pin) (Pin, error) {
	if gpio.mode == GPIO {
		return pin, nil
	} else if gpio.mode == PI && int(pin) > len(gpio.pinToBCMPin) {
		return 255, fmt.Errorf("Pin %d must be < %d", pin, len(gpio.pinToBCMPin))
	} else if gpio.pinToBCMPin[pin] == -1 {
		return 255, fmt.Errorf("Pin %d not valid for GPIO", pin)
	}
	return Pin(gpio.pinToBCMPin[pin]), nil
}

// NewGPIO sets up a new GPIO object
func NewGPIO() (*RpiGpio, error) {
	var err error
	gpio := new(RpiGpio)
	gpio.bcm = NewBCMGPIO()
	gpio.mode = GPIO
	gpio.status = NEW
	gpio.rpi = new(RpiInfo)
	gpio.rpi.GetCPUInfo()
	switch int(gpio.rpi.piRevision) {
	case 2:
		gpio.pinToBCMPin = piPinToBCMPinRev2
	default:
		return nil, errors.New("Unknown Raspberry Pi hardware")
	}
	// set gpio "direction"  (in/out??)
	// pinTopin = pinToGpiopinRev??
	err = gpio.bcm.open()
	if err != nil {
		return nil, err
	}
	gpio.status = OK
	return gpio, nil
}

// Direction sets the pin as either input or output
func (gpio *RpiGpio) Direction(p Pin, d PinDirection) error {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return err
	}
	return gpio.bcm.Direction(pin, d)
}

// Mode sets the pin interpretation for the rpigpio functions
func (gpio *RpiGpio) Mode(m Mode) error {
	if m != GPIO && m != PI {
		return fmt.Errorf("Mode must be GPIO or PI")
	}
	gpio.mode = m
	return nil
}

// Pull sets the direction of the built-in pull-up/pull-down resistor
func (gpio *RpiGpio) Pull(p Pin, d Pull) error {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return err
	}
	return gpio.bcm.Pull(pin, d)
}

func (gpio *RpiGpio) Read(p Pin) (PinState, error) {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return 255, err
	}
	return gpio.bcm.Read(pin), nil
}

func (gpio *RpiGpio) Write(p Pin, s PinState) error {
	pin, err := gpio.getBCMGpio(p)
	if err != nil {
		return err
	}
	gpio.bcm.Write(pin, s)
	return nil
}

// Cleanup the pin ; reset to INPUT and pull up/down to off
func (gpio *RpiGpio) Cleanup(pin uint8) {
	// Verify pin is valid, package status is OK, etc
	// get gpio number from pin
	// call c_gpio::cleanup_one()
	//    * call event_cleanup()
	//    * set gpio_direction = -1
	//    * set gpio to INPUT and pull up/down to off
	//    * set found for error checking later on (if working on > 1 pin at a time)
}

// eventCleanup
func eventCleanup(gpio uint) {
	// event_gpio.c:403
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"html/template"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/lemmi/ghfs"
	g "github.com/lemmi/git"
	"github.com/lemmi/glubcms"
	"github.com/raymondbutcher/tidyhtml"
)

func POE(err error, prefix ...interface{}) {
	if err != nil {
		log.Print(prefix...)
		log.Fatal(err)
	}
}

func parseTemplates(commit *g.Commit) (*template.Template, error) {
	ttree, err := commit.Tree.SubTree("templates")
	if err != nil {
		return nil, err
	}
	scan, err := ttree.Scanner()
	if err != nil {
		return nil, err
	}
	tmain := template.New("templatecontainer")
	for scan.Scan() {
		entry := scan.TreeEntry()
		if !strings.HasSuffix(entry.Name(), ".tmpl") {
			continue
		}
		data, err := entry.Blob().Data()
		if err != nil {
			return nil, err
		}
		defer data.Close()
		databytes, err := ioutil.ReadAll(data)
		if err != nil {
			return nil, err
		}

		_, err = tmain.New(entry.Name()).Parse(string(databytes))
		if err != nil {
			return nil, err
		}
	}

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

	return tmain, nil
}

func newStaticHandler(c *g.Commit) (http.Handler, error) {
	stree, err := c.Tree.SubTree("static")
	return http.FileServer(ghfs.FromCommit(c, stree)), err
}

type pageHandler struct {
	c *g.Commit
}

func newPageHandler(c *g.Commit) http.Handler {
	return pageHandler{c}
}
func (h pageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tmpl := template.Must(parseTemplates(h.c))
	stree, err := h.c.Tree.SubTree("pages")
	POE(err, "Pages")

	p := glubcms.PageFromDir(ghfs.FromCommit(h.c, stree), r.URL.Path)
	buf := bytes.Buffer{}
	if err := tmpl.ExecuteTemplate(&buf, "main.tmpl", p); err != nil {
		log.Println(err)
		return
	}
	tbuf := bytes.Buffer{}
	if err := tidyhtml.Copy(&tbuf, &buf); err != nil {
		log.Println(err)
		return
	}
	w.Header().Set("Content-Type", "text/html")
	http.ServeContent(w, r, "", h.c.Author.When, bytes.NewReader(tbuf.Bytes()))
}

type handler struct {
	prefix string
}

func newHandler(prefix string) handler {
	return handler{
		prefix: prefix,
	}
}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path, err := filepath.Abs(h.prefix)
	POE(err, "Filepath")

	repo, err := g.OpenRepository(path)
	POE(err, "OpenRepository")

	commit, err := repo.GetCommitOfBranch("master")
	POE(err, "LookupBranch")

	mux := http.NewServeMux()

	staticHandler, err := newStaticHandler(commit)
	POE(err, "StaticHandler")

	mux.Handle("/static/", http.StripPrefix("/static/", staticHandler))
	mux.Handle("/robots.txt", staticHandler)
	mux.Handle("/favicon.ico", staticHandler)
	mux.Handle("/", newPageHandler(commit))
	mux.ServeHTTP(w, r)
}

func main() {
	prefix := flag.String("prefix", "../example_page", "path to the root dir")
	addr := flag.String("bind", "localhost:8080", "address or path to bind to")
	network := flag.String("net", "tcp", `"tcp", "tcp4", "tcp6", "unix" or "unixpacket"`)
	flag.Parse()
	ln, err := net.Listen(*network, *addr)
	if err != nil {
		panic(err)
	}
	defer ln.Close()
	if strings.HasPrefix(*network, "unix") {
		err = os.Chmod(*network, 0666)
	}
	if err != nil {
		panic(err)
	}
	log.Fatal(http.Serve(ln, newHandler(*prefix)))
}
<commit_msg>gcserver: fix chmod<commit_after>package main

import (
	"bytes"
	"flag"
	"html/template"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/lemmi/ghfs"
	g "github.com/lemmi/git"
	"github.com/lemmi/glubcms"
	"github.com/raymondbutcher/tidyhtml"
)

func POE(err error, prefix ...interface{}) {
	if err != nil {
		log.Print(prefix...)
		log.Fatal(err)
	}
}

func parseTemplates(commit *g.Commit) (*template.Template, error) {
	ttree, err := commit.Tree.SubTree("templates")
	if err != nil {
		return nil, err
	}
	scan, err := ttree.Scanner()
	if err != nil {
		return nil, err
	}
	tmain := template.New("templatecontainer")
	for scan.Scan() {
		entry := scan.TreeEntry()
		if !strings.HasSuffix(entry.Name(), ".tmpl") {
			continue
		}
		data, err := entry.Blob().Data()
		if err != nil {
			return nil, err
		}
		defer data.Close()
		databytes, err := ioutil.ReadAll(data)
		if err != nil {
			return nil, err
		}

		_, err = tmain.New(entry.Name()).Parse(string(databytes))
		if err != nil {
			return nil, err
		}
	}

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

	return tmain, nil
}

func newStaticHandler(c *g.Commit) (http.Handler, error) {
	stree, err := c.Tree.SubTree("static")
	return http.FileServer(ghfs.FromCommit(c, stree)), err
}

type pageHandler struct {
	c *g.Commit
}

func newPageHandler(c *g.Commit) http.Handler {
	return pageHandler{c}
}
func (h pageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tmpl := template.Must(parseTemplates(h.c))
	stree, err := h.c.Tree.SubTree("pages")
	POE(err, "Pages")

	p := glubcms.PageFromDir(ghfs.FromCommit(h.c, stree), r.URL.Path)
	buf := bytes.Buffer{}
	if err := tmpl.ExecuteTemplate(&buf, "main.tmpl", p); err != nil {
		log.Println(err)
		return
	}
	tbuf := bytes.Buffer{}
	if err := tidyhtml.Copy(&tbuf, &buf); err != nil {
		log.Println(err)
		return
	}
	w.Header().Set("Content-Type", "text/html")
	http.ServeContent(w, r, "", h.c.Author.When, bytes.NewReader(tbuf.Bytes()))
}

type handler struct {
	prefix string
}

func newHandler(prefix string) handler {
	return handler{
		prefix: prefix,
	}
}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path, err := filepath.Abs(h.prefix)
	POE(err, "Filepath")

	repo, err := g.OpenRepository(path)
	POE(err, "OpenRepository")

	commit, err := repo.GetCommitOfBranch("master")
	POE(err, "LookupBranch")

	mux := http.NewServeMux()

	staticHandler, err := newStaticHandler(commit)
	POE(err, "StaticHandler")

	mux.Handle("/static/", http.StripPrefix("/static/", staticHandler))
	mux.Handle("/robots.txt", staticHandler)
	mux.Handle("/favicon.ico", staticHandler)
	mux.Handle("/", newPageHandler(commit))
	mux.ServeHTTP(w, r)
}

func main() {
	prefix := flag.String("prefix", "../example_page", "path to the root dir")
	addr := flag.String("bind", "localhost:8080", "address or path to bind to")
	network := flag.String("net", "tcp", `"tcp", "tcp4", "tcp6", "unix" or "unixpacket"`)
	flag.Parse()
	ln, err := net.Listen(*network, *addr)
	if err != nil {
		panic(err)
	}
	defer ln.Close()
	if strings.HasPrefix(*network, "unix") {
		err = os.Chmod(*addr, 0666)
	}
	if err != nil {
		panic(err)
	}
	log.Fatal(http.Serve(ln, newHandler(*prefix)))
}
<|endoftext|>