<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"sync"
	"syscall"
	"time"

	serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
	manet "github.com/jbenet/go-multiaddr-net"
	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// GetNumNodes returns the number of testbed nodes configured in the testbed directory
func GetNumNodes() int {
	for i := 0; i < 2000; i++ {
		_, err := os.Stat(IpfsDirN(i))
		if os.IsNotExist(err) {
			return i
		}
	}
	panic("i dont know whats going on")
}

func TestBedDir() string {
	tbd := os.Getenv("IPTB_ROOT")
	if len(tbd) != 0 {
		return tbd
	}

	home := os.Getenv("HOME")
	if len(home) == 0 {
		panic("could not find home")
	}

	return path.Join(home, "testbed")
}

func IpfsDirN(n int) string {
	return path.Join(TestBedDir(), fmt.Sprint(n))
}

func YesNoPrompt(prompt string) bool {
	var s string
	for {
		fmt.Println(prompt)
		fmt.Scanf("%s", &s)
		switch s {
		case "y", "Y":
			return true
		case "n", "N":
			return false
		}
		fmt.Println("Please press either 'y' or 'n'")
	}
}

type initCfg struct {
	Count     int
	Force     bool
	Bootstrap string
	PortStart int
}

func (c *initCfg) swarmAddrForPeer(i int) string {
	return fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", c.PortStart+i)
}

func (c *initCfg) apiAddrForPeer(i int) string {
	return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.PortStart+1000+i)
}

func IpfsInit(cfg *initCfg) error {
	p := IpfsDirN(0)
	if _, err := os.Stat(p); !os.IsNotExist(err) {
		if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") {
			return nil
		}
		err := os.RemoveAll(TestBedDir())
		if err != nil {
			return err
		}
	}
	wait := sync.WaitGroup{}
	for i := 0; i < cfg.Count; i++ {
		wait.Add(1)
		go func(v int) {
			defer wait.Done()
			dir := IpfsDirN(v)
			err := os.MkdirAll(dir, 0777)
			if err != nil {
				log.Println("ERROR: ", err)
				return
			}

			cmd := exec.Command("ipfs", "init", "-b=1024")
			cmd.Env = append(cmd.Env, "IPFS_PATH="+dir)
			out, err := cmd.CombinedOutput()
			if err != nil {
				log.Println("ERROR: ", err)
				log.Println(string(out))
			}
		}(i)
	}
	wait.Wait()

	// Now setup bootstrapping
	switch cfg.Bootstrap {
	case "star":
		err := starBootstrap(cfg)
		if err != nil {
			return err
		}
	case "none":
		err := clearBootstrapping(cfg)
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap)
	}

	return nil
}

func starBootstrap(icfg *initCfg) error {
	// '0' node is the bootstrap node
	cfgpath := path.Join(IpfsDirN(0), "config")
	bcfg, err := serial.Load(cfgpath)
	if err != nil {
		return err
	}
	bcfg.Bootstrap = nil
	bcfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(0)}
	bcfg.Addresses.API = icfg.apiAddrForPeer(0)
	bcfg.Addresses.Gateway = ""
	err = serial.WriteConfigFile(cfgpath, bcfg)
	if err != nil {
		return err
	}

	for i := 1; i < icfg.Count; i++ {
		cfgpath := path.Join(IpfsDirN(i), "config")
		cfg, err := serial.Load(cfgpath)
		if err != nil {
			return err
		}

		cfg.Bootstrap = []string{fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID)}
		cfg.Addresses.Gateway = ""
		cfg.Addresses.Swarm = []string{
			icfg.swarmAddrForPeer(i),
		}
		cfg.Addresses.API = icfg.apiAddrForPeer(i)
		err = serial.WriteConfigFile(cfgpath, cfg)
		if err != nil {
			return err
		}
	}
	return nil
}

func clearBootstrapping(icfg *initCfg) error {
	for i := 0; i < icfg.Count; i++ {
		cfgpath := path.Join(IpfsDirN(i), "config")
		cfg, err := serial.Load(cfgpath)
		if err != nil {
			return err
		}

		cfg.Bootstrap = nil
		cfg.Addresses.Gateway = ""
		cfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(i)}
		cfg.Addresses.API = icfg.apiAddrForPeer(i)
		err = serial.WriteConfigFile(cfgpath, cfg)
		if err != nil {
			return err
		}
	}
	return nil
}

func IpfsPidOf(n int) (int, error) {
	dir := IpfsDirN(n)
	b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid"))
	if err != nil {
		return -1, err
	}

	return strconv.Atoi(string(b))
}

func IpfsKill() error {
	n := GetNumNodes()
	for i := 0; i < n; i++ {
		pid, err := IpfsPidOf(i)
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}

		p, err := os.FindProcess(pid)
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}
		err = p.Kill()
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}

		p.Wait()

		err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid"))
		if err != nil {
			fmt.Printf("error removing pid file for daemon %d: %s\n", i, err)
			continue
		}
	}
	return nil
}

func IpfsStart(waitall bool) error {
	n := GetNumNodes()
	for i := 0; i < n; i++ {
		dir := IpfsDirN(i)
		cmd := exec.Command("ipfs", "daemon")
		cmd.Dir = dir
		cmd.Env = []string{"IPFS_PATH=" + dir}

		cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

		stdout, err := os.Create(path.Join(dir, "daemon.stdout"))
		if err != nil {
			return err
		}

		stderr, err := os.Create(path.Join(dir, "daemon.stderr"))
		if err != nil {
			return err
		}

		cmd.Stdout = stdout
		cmd.Stderr = stderr

		err = cmd.Start()
		if err != nil {
			return err
		}
		pid := cmd.Process.Pid

		fmt.Printf("Started daemon %d, pid = %d\n", i, pid)
		err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666)
		if err != nil {
			return err
		}

		// Make sure node 0 is up before starting the rest so
		// bootstrapping works properly
		if i == 0 || waitall {
			cfg, err := serial.Load(path.Join(IpfsDirN(i), "config"))
			if err != nil {
				return err
			}

			maddr := ma.StringCast(cfg.Addresses.API)
			_, addr, err := manet.DialArgs(maddr)
			if err != nil {
				return err
			}

			err = waitForLive(cfg.Identity.PeerID, addr)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// waitForLive polls the given endpoint until it is up, or until
// a timeout
func waitForLive(peerid, addr string) error {
	for i := 0; i < 50; i++ {
		resp, err := http.Get("http://" + addr + "/api/v0/id")
		if err == nil {
			out := make(map[string]interface{})
			err := json.NewDecoder(resp.Body).Decode(&out)
			if err != nil {
				return fmt.Errorf("liveness check failed: %s", err)
			}
			id, ok := out["ID"]
			if !ok {
				return fmt.Errorf("liveness check failed: ID field not present in output")
			}
			idstr := id.(string)
			if idstr != peerid {
				return fmt.Errorf("liveness check failed: unexpected peer at endpoint")
			}

			return nil
		}
		time.Sleep(time.Millisecond * 200)
	}
	return fmt.Errorf("node at %s failed to come online in given time period", addr)
}

// GetPeerID reads the config of node 'n' and returns its peer ID
func GetPeerID(n int) (string, error) {
	cfg, err := serial.Load(path.Join(IpfsDirN(n), "config"))
	if err != nil {
		return "", err
	}
	return cfg.Identity.PeerID, nil
}

// IpfsShell sets up environment variables for a new shell to more easily
// control the given daemon
func IpfsShell(n int) error {
	shell := os.Getenv("SHELL")
	if shell == "" {
		return fmt.Errorf("couldnt find shell!")
	}

	dir := IpfsDirN(n)
	nenvs := []string{"IPFS_PATH=" + dir}

	nnodes := GetNumNodes()
	for i := 0; i < nnodes; i++ {
		peerid, err := GetPeerID(i)
		if err != nil {
			return err
		}
		nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid))
	}
	nenvs = append(os.Environ(), nenvs...)

	return syscall.Exec(shell, []string{shell}, nenvs)
}

func GetAttr(attr string, node int) (string, error) {
	switch attr {
	case "id":
		return GetPeerID(node)
	default:
		return "", errors.New("unrecognized attribute")
	}
}

var helptext = `Ipfs Testbed

Commands:
	init
	    creates and initializes 'n' repos

		Options:
			-n=[number of nodes]
			-f - force overwriting of existing nodes
			-bootstrap - select bootstrapping style for cluster
				choices: star, none

	start
	    starts up all testbed nodes

		Options:
			-wait - wait until daemons are fully initialized
	stop
	    kills all testbed nodes
	restart
	    kills, then restarts all testbed nodes

	shell [n]
	    execs your shell with environment variables set as follows:
	        IPFS_PATH - set to testbed node n's IPFS_PATH
	        NODE[x] - set to the peer ID of node x

	get [attribute] [node]
		get an attribute of the given node
		currently supports: "id"

Env Vars:

IPTB_ROOT:
	Used to specify the directory that nodes will be created in.
`

func handleErr(s string, err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, s, err)
		os.Exit(1)
	}
}

func main() {
	cfg := new(initCfg)
	flag.IntVar(&cfg.Count, "n", 0, "number of ipfs nodes to initialize")
	flag.IntVar(&cfg.PortStart, "p", 4002, "port to start allocations from")
	flag.BoolVar(&cfg.Force, "f", false, "force initialization (overwrite existing configs)")
	flag.StringVar(&cfg.Bootstrap, "bootstrap", "star", "select bootstrapping style for cluster")

	wait := flag.Bool("wait", false, "wait for nodes to come fully online before exiting")
	flag.Usage = func() {
		fmt.Println(helptext)
	}

	flag.Parse()

	switch flag.Arg(0) {
	case "init":
		if cfg.Count == 0 {
			fmt.Printf("please specify number of nodes: '%s -n=10 init'\n", os.Args[0])
			os.Exit(1)
		}
		err := IpfsInit(cfg)
		handleErr("ipfs init err: ", err)
	case "start":
		err := IpfsStart(*wait)
		handleErr("ipfs start err: ", err)
	case "stop", "kill":
		err := IpfsKill()
		handleErr("ipfs kill err: ", err)
	case "restart":
		err := IpfsKill()
		handleErr("ipfs kill err: ", err)

		err = IpfsStart(*wait)
		handleErr("ipfs start err: ", err)
	case "shell":
		if len(flag.Args()) < 2 {
			fmt.Println("please specify which node you want a shell for")
			os.Exit(1)
		}
		n, err := strconv.Atoi(flag.Arg(1))
		handleErr("parse err: ", err)

		err = IpfsShell(n)
		handleErr("ipfs shell err: ", err)
	case "get":
		if len(flag.Args()) < 3 {
			fmt.Println("iptb get [attr] [node]")
			os.Exit(1)
		}
		attr := flag.Arg(1)
		num, err := strconv.Atoi(flag.Arg(2))
		handleErr("error parsing node number: ", err)

		val, err := GetAttr(attr, num)
		handleErr("error getting attribute: ", err)
		fmt.Println(val)
	default:
		flag.Usage()
		os.Exit(1)
	}
}
<commit_msg>better waiting for daemon start<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"sync"
	"syscall"
	"time"

	serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
	manet "github.com/jbenet/go-multiaddr-net"
	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// GetNumNodes returns the number of testbed nodes configured in the testbed directory
func GetNumNodes() int {
	for i := 0; i < 2000; i++ {
		_, err := os.Stat(IpfsDirN(i))
		if os.IsNotExist(err) {
			return i
		}
	}
	panic("i dont know whats going on")
}

func TestBedDir() string {
	tbd := os.Getenv("IPTB_ROOT")
	if len(tbd) != 0 {
		return tbd
	}

	home := os.Getenv("HOME")
	if len(home) == 0 {
		panic("could not find home")
	}

	return path.Join(home, "testbed")
}

func IpfsDirN(n int) string {
	return path.Join(TestBedDir(), fmt.Sprint(n))
}

func YesNoPrompt(prompt string) bool {
	var s string
	for {
		fmt.Println(prompt)
		fmt.Scanf("%s", &s)
		switch s {
		case "y", "Y":
			return true
		case "n", "N":
			return false
		}
		fmt.Println("Please press either 'y' or 'n'")
	}
}

type initCfg struct {
	Count     int
	Force     bool
	Bootstrap string
	PortStart int
}

func (c *initCfg) swarmAddrForPeer(i int) string {
	return fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", c.PortStart+i)
}

func (c *initCfg) apiAddrForPeer(i int) string {
	return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.PortStart+1000+i)
}

func IpfsInit(cfg *initCfg) error {
	p := IpfsDirN(0)
	if _, err := os.Stat(p); !os.IsNotExist(err) {
		if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") {
			return nil
		}
		err := os.RemoveAll(TestBedDir())
		if err != nil {
			return err
		}
	}
	wait := sync.WaitGroup{}
	for i := 0; i < cfg.Count; i++ {
		wait.Add(1)
		go func(v int) {
			defer wait.Done()
			dir := IpfsDirN(v)
			err := os.MkdirAll(dir, 0777)
			if err != nil {
				log.Println("ERROR: ", err)
				return
			}

			cmd := exec.Command("ipfs", "init", "-b=1024")
			cmd.Env = append(cmd.Env, "IPFS_PATH="+dir)
			out, err := cmd.CombinedOutput()
			if err != nil {
				log.Println("ERROR: ", err)
				log.Println(string(out))
			}
		}(i)
	}
	wait.Wait()

	// Now setup bootstrapping
	switch cfg.Bootstrap {
	case "star":
		err := starBootstrap(cfg)
		if err != nil {
			return err
		}
	case "none":
		err := clearBootstrapping(cfg)
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap)
	}

	return nil
}

func starBootstrap(icfg *initCfg) error {
	// '0' node is the bootstrap node
	cfgpath := path.Join(IpfsDirN(0), "config")
	bcfg, err := serial.Load(cfgpath)
	if err != nil {
		return err
	}
	bcfg.Bootstrap = nil
	bcfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(0)}
	bcfg.Addresses.API = icfg.apiAddrForPeer(0)
	bcfg.Addresses.Gateway = ""
	err = serial.WriteConfigFile(cfgpath, bcfg)
	if err != nil {
		return err
	}

	for i := 1; i < icfg.Count; i++ {
		cfgpath := path.Join(IpfsDirN(i), "config")
		cfg, err := serial.Load(cfgpath)
		if err != nil {
			return err
		}

		cfg.Bootstrap = []string{fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID)}
		cfg.Addresses.Gateway = ""
		cfg.Addresses.Swarm = []string{
			icfg.swarmAddrForPeer(i),
		}
		cfg.Addresses.API = icfg.apiAddrForPeer(i)
		err = serial.WriteConfigFile(cfgpath, cfg)
		if err != nil {
			return err
		}
	}
	return nil
}

func clearBootstrapping(icfg *initCfg) error {
	for i := 0; i < icfg.Count; i++ {
		cfgpath := path.Join(IpfsDirN(i), "config")
		cfg, err := serial.Load(cfgpath)
		if err != nil {
			return err
		}

		cfg.Bootstrap = nil
		cfg.Addresses.Gateway = ""
		cfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(i)}
		cfg.Addresses.API = icfg.apiAddrForPeer(i)
		err = serial.WriteConfigFile(cfgpath, cfg)
		if err != nil {
			return err
		}
	}
	return nil
}

func IpfsPidOf(n int) (int, error) {
	dir := IpfsDirN(n)
	b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid"))
	if err != nil {
		return -1, err
	}

	return strconv.Atoi(string(b))
}

func IpfsKill() error {
	n := GetNumNodes()
	for i := 0; i < n; i++ {
		pid, err := IpfsPidOf(i)
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}

		p, err := os.FindProcess(pid)
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}
		err = p.Kill()
		if err != nil {
			fmt.Printf("error killing daemon %d: %s\n", i, err)
			continue
		}

		p.Wait()

		err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid"))
		if err != nil {
			fmt.Printf("error removing pid file for daemon %d: %s\n", i, err)
			continue
		}
	}
	return nil
}

func IpfsStart(waitall bool) error {
	var addrs []string
	n := GetNumNodes()
	for i := 0; i < n; i++ {
		dir := IpfsDirN(i)
		cmd := exec.Command("ipfs", "daemon")
		cmd.Dir = dir
		cmd.Env = []string{"IPFS_PATH=" + dir}

		cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

		stdout, err := os.Create(path.Join(dir, "daemon.stdout"))
		if err != nil {
			return err
		}

		stderr, err := os.Create(path.Join(dir, "daemon.stderr"))
		if err != nil {
			return err
		}

		cmd.Stdout = stdout
		cmd.Stderr = stderr

		err = cmd.Start()
		if err != nil {
			return err
		}
		pid := cmd.Process.Pid

		fmt.Printf("Started daemon %d, pid = %d\n", i, pid)
		err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666)
		if err != nil {
			return err
		}

		// Make sure node 0 is up before starting the rest so
		// bootstrapping works properly
		if i == 0 || waitall {
			cfg, err := serial.Load(path.Join(IpfsDirN(i), "config"))
			if err != nil {
				return err
			}

			maddr := ma.StringCast(cfg.Addresses.API)
			_, addr, err := manet.DialArgs(maddr)
			if err != nil {
				return err
			}

			addrs = append(addrs, addr)

			err = waitOnAPI(cfg.Identity.PeerID, addr)
			if err != nil {
				return err
			}
		}
	}
	if waitall {
		for i := 0; i < n; i++ {
			err := waitOnSwarmPeers(addrs[i])
			if err != nil {
				return err
			}
		}

	}
	return nil
}

func waitOnAPI(peerid, addr string) error {
	for i := 0; i < 50; i++ {
		resp, err := http.Get("http://" + addr + "/api/v0/id")
		if err == nil {
			out := make(map[string]interface{})
			err := json.NewDecoder(resp.Body).Decode(&out)
			if err != nil {
				return fmt.Errorf("liveness check failed: %s", err)
			}
			id, ok := out["ID"]
			if !ok {
				return fmt.Errorf("liveness check failed: ID field not present in output")
			}
			idstr := id.(string)
			if idstr != peerid {
				return fmt.Errorf("liveness check failed: unexpected peer at endpoint")
			}

			return nil
		}
		time.Sleep(time.Millisecond * 200)
	}
	return fmt.Errorf("node at %s failed to come online in given time period", addr)
}

func waitOnSwarmPeers(addr string) error {
	for i := 0; i < 50; i++ {
		resp, err := http.Get("http://" + addr + "/api/v0/swarm/peers")
		if err == nil {
			out := make(map[string]interface{})
			err := json.NewDecoder(resp.Body).Decode(&out)
			if err != nil {
				return fmt.Errorf("liveness check failed: %s", err)
			}

			peers := out["Strings"].([]interface{})
			if len(peers) == 0 {
				time.Sleep(time.Millisecond * 200)
				continue
			}

			return nil
		}
		time.Sleep(time.Millisecond * 200)
	}
	return fmt.Errorf("node at %s failed to bootstrap in given time period", addr)
}

// GetPeerID reads the config of node 'n' and returns its peer ID
func GetPeerID(n int) (string, error) {
	cfg, err := serial.Load(path.Join(IpfsDirN(n), "config"))
	if err != nil {
		return "", err
	}
	return cfg.Identity.PeerID, nil
}

// IpfsShell sets up environment variables for a new shell to more easily
// control the given daemon
func IpfsShell(n int) error {
	shell := os.Getenv("SHELL")
	if shell == "" {
		return fmt.Errorf("couldnt find shell!")
	}

	dir := IpfsDirN(n)
	nenvs := []string{"IPFS_PATH=" + dir}

	nnodes := GetNumNodes()
	for i := 0; i < nnodes; i++ {
		peerid, err := GetPeerID(i)
		if err != nil {
			return err
		}
		nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid))
	}
	nenvs = append(os.Environ(), nenvs...)

	return syscall.Exec(shell, []string{shell}, nenvs)
}

func GetAttr(attr string, node int) (string, error) {
	switch attr {
	case "id":
		return GetPeerID(node)
	default:
		return "", errors.New("unrecognized attribute")
	}
}

var helptext = `Ipfs Testbed

Commands:
	init
	    creates and initializes 'n' repos

		Options:
			-n=[number of nodes]
			-f - force overwriting of existing nodes
			-bootstrap - select bootstrapping style for cluster
				choices: star, none

	start
	    starts up all testbed nodes

		Options:
			-wait - wait until daemons are fully initialized
	stop
	    kills all testbed nodes
	restart
	    kills, then restarts all testbed nodes

	shell [n]
	    execs your shell with environment variables set as follows:
	        IPFS_PATH - set to testbed node n's IPFS_PATH
	        NODE[x] - set to the peer ID of node x

	get [attribute] [node]
		get an attribute of the given node
		currently supports: "id"

Env Vars:

IPTB_ROOT:
	Used to specify the directory that nodes will be created in.
`

func handleErr(s string, err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, s, err)
		os.Exit(1)
	}
}

func main() {
	cfg := new(initCfg)
	flag.IntVar(&cfg.Count, "n", 0, "number of ipfs nodes to initialize")
	flag.IntVar(&cfg.PortStart, "p", 4002, "port to start allocations from")
	flag.BoolVar(&cfg.Force, "f", false, "force initialization (overwrite existing configs)")
	flag.StringVar(&cfg.Bootstrap, "bootstrap", "star", "select bootstrapping style for cluster")

	wait := flag.Bool("wait", false, "wait for nodes to come fully online before exiting")
	flag.Usage = func() {
		fmt.Println(helptext)
	}

	flag.Parse()

	switch flag.Arg(0) {
	case "init":
		if cfg.Count == 0 {
			fmt.Printf("please specify number of nodes: '%s -n=10 init'\n", os.Args[0])
			os.Exit(1)
		}
		err := IpfsInit(cfg)
		handleErr("ipfs init err: ", err)
	case "start":
		err := IpfsStart(*wait)
		handleErr("ipfs start err: ", err)
	case "stop", "kill":
		err := IpfsKill()
		handleErr("ipfs kill err: ", err)
	case "restart":
		err := IpfsKill()
		handleErr("ipfs kill err: ", err)

		err = IpfsStart(*wait)
		handleErr("ipfs start err: ", err)
	case "shell":
		if len(flag.Args()) < 2 {
			fmt.Println("please specify which node you want a shell for")
			os.Exit(1)
		}
		n, err := strconv.Atoi(flag.Arg(1))
		handleErr("parse err: ", err)

		err = IpfsShell(n)
		handleErr("ipfs shell err: ", err)
	case "get":
		if len(flag.Args()) < 3 {
			fmt.Println("iptb get [attr] [node]")
			os.Exit(1)
		}
		attr := flag.Arg(1)
		num, err := strconv.Atoi(flag.Arg(2))
		handleErr("error parsing node number: ", err)

		val, err := GetAttr(attr, num)
		handleErr("error getting attribute: ", err)
		fmt.Println(val)
	default:
		flag.Usage()
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"./service"
	// "github.com/gorilla/mux"
	// "net/http"
	// "github.com/jessevdk/go-flags"
	"os"
)

// type options struct {
// 	ListenPort int  `short:"l" long:"listen-port" value-name:"<port number>" description:"Port to listen on for REST requests." required:"true"`
// 	Help       bool `short:"h" long:"help" description:"Show usage information."`
// }

// TODO: get rid of this global, need an easier way to pass data store to handlers
var service urlservice.Service

func main() {
	// var opts options
	// parser := flags.NewParser(&opts, 0)
	// _, err := parser.ParseArgs(os.Args[1:])
	// if err != nil {
	// 	fmt.Println("Error: ", err)
	// 	os.Exit(1)
	// }

	// if opts.Help {
	// 	parser.WriteHelp(os.Stdout)
	// 	os.Exit(0)
	// }
	log.SetOutput(os.Stdout)
	service.InitService()
	log.Println("Starting URLCheck service.")

	// seed with some fake data to start
	service.DataStore.Upload("google.com,google.ca,youtube.com,amazon.com,amazon.com/a_thing")

	service.Run(":8080")
}
<commit_msg>clean up main, remove unused/commented out code<commit_after>package main

import (
	"log"
	"./service"
	"os"
)

func main() {
	var service urlservice.Service

	log.SetOutput(os.Stdout)
	service.InitService()
	log.Println("Starting URLCheck service.")

	// seed with some fake data to start
	service.DataStore.Upload("google.com,google.ca,youtube.com,amazon.com,amazon.com/a_thing")

	service.Run(":8080")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/mbndr/logo"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"
)

const (
	VERSION     = "0.1.2"
	minDuration = time.Duration(15) * time.Minute
	maxDuration = time.Duration(36) * time.Hour
)

var (
	listRoles       *bool
	listMfa         *bool
	showExpire      *bool
	sesCreds        *bool
	refresh         *bool
	verbose         *bool
	version         *bool
	makeConf        *bool
	profile         *string
	duration        *time.Duration
	cmd             *[]string
	defaultDuration = time.Duration(12) * time.Hour
	cacheDir        = filepath.Dir(defaults.SharedCredentialsFilename())
	logLevel        = logo.WARN
)

func init() {
	const (
		cmdDesc         = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc = "duration of the retrieved session token"
		listRoleArgDesc = "list role ARNs you are able to assume"
		listMfaArgDesc  = "list the ARN of the MFA device associated with your account"
		showExpArgDesc  = "Show token expiration time"
		sesCredArgDesc  = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc  = "force a refresh of the cached credentials"
		verboseArgDesc  = "print verbose/debug messages"
		profileArgDesc  = "name of profile"
		cmdArgDesc      = "command to execute using configured profile"
		makeConfArgDesc = "Build an AWS extended switch-role plugin configuration for all available roles"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Default(defaultDuration.String()).Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	profile = kingpin.Arg("profile", profileArgDesc).Default("default").String()
	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func dedupAndSort(ary *[]string) *[]string {
	m := make(map[string]bool)

	// dedup
	for _, v := range *ary {
		trimV := strings.TrimSpace(v)
		if len(trimV) > 0 {
			m[trimV] = true
		}
	}

	// array-ify
	i := 0
	newAry := make([]string, len(m))
	for k := range m {
		newAry[i] = k
		i++
	}

	// sort & return
	sort.Strings(newAry)
	return &newAry
}

func printCredentials(creds credentials.Value) {
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SESSION_TOKEN", creds.SessionToken)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECURITY_TOKEN", creds.SessionToken)
}

func getRoles(sess *session.Session) *[]string {
	// Used to return an array of role ARN's available to the user
	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)
	roles := make([]string, 0)

	s := iam.New(sess)

	u, err := s.GetUser(&iam.GetUserInput{})
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	userName := *u.User.UserName
	log.Debugf("USER: %s", userName)

	urg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.UserRoleGetter", true)
	urg := UserRoleGetter{Client: s, Logger: urg_logger}
	roles = append(roles, *urg.FetchRoles(userName)...)

	i := iam.ListGroupsForUserInput{UserName: &userName}
	grg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.GroupRoleGetter", true)
	grg := GroupRoleGetter{Client: s, Logger: grg_logger}
	truncated := true
	for truncated {
		g, err := s.ListGroupsForUser(&i)
		if err != nil {
			log.Errorf("Error getting user's IAM group list: %v", err)
			break
		}

		if *verbose {
			for x, grp := range g.Groups {
				log.Debugf("GROUP[%d]: %s", x, *grp.GroupName)
			}
		}
		roles = append(roles, *grg.FetchRoles(g.Groups...)...)

		truncated = *g.IsTruncated
		if truncated {
			i.Marker = g.Marker
		}
	}

	fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.User.Arn)
	dedupAndSort(&roles)
	return &roles
}

func getAWSSession() *session.Session {

	//  Unset the environment
	env := []string{"AWS_SECRET_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"}
	for _, env := range env {
		os.Unsetenv(env)
	}

	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *profile,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
	}))

	return sess
}

func main() {
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}

	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	if *duration < minDuration || *duration > maxDuration {
		log.Warnf("Duration should be between %s and %s, using default of %s",
			minDuration.String(), maxDuration.String(), defaultDuration.String())
		duration = &defaultDuration
	}

	// These are magic words to change AssumeRole credential expiration
	stscreds.DefaultDuration = time.Duration(1) * time.Hour

	log.Debugf("PROFILE: %s", *profile)

	//	Unset the environment
	env := []string{"AWS_SECRET_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"}
	for _, env := range env {
		os.Unsetenv(env)
	}

	// This is how to get the MFA and AssumeRole config for a given profile.
	//sess := getsession.Must(session.NewSessionWithOptions(session.Options{
	//	SharedConfigState:       session.SharedConfigEnable,
	//	Profile:                 *profile,
	//	AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
	//}))

	sess := getAWSSession()

	switch {
	case *listMfa:
		log.Debug("List MFA")
		s := iam.New(sess)

		res, err := s.ListMFADevices(&iam.ListMFADevicesInput{})
		if err != nil {
			log.Fatalf("Error listing MFA devices: %v", err)
		}

		fmt.Printf("%s\n", *res.MFADevices[0].SerialNumber)
	case *makeConf:
		log.Debug("Make Configuration Files.")
	case *listRoles, *makeConf:
		log.Debug("List Roles")
		roles := getRoles(sess)

		for _, v := range *roles {
			fmt.Printf("  %s\n", v)
		}
	default:
		cfgParser := AWSConfigParser{Logger: logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.AWSConfigParser", true)}
		profile_cfg, err := cfgParser.GetProfile(profile)
		if err != nil {
			log.Fatalf("Unable to get configuration for profile '%s': %+v", *profile, err)
		}

		credProvider := CachingSessionTokenProvider{
			Profile:  profile_cfg.SourceProfile,
			Duration: *duration,
			Logger:   logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.CachingSessionTokenProvider", true),
		}

		if len(profile_cfg.MfaSerial) > 0 {
			credProvider.MfaSerial = profile_cfg.MfaSerial
		}

		if *refresh {
			os.Remove(credProvider.CacheFile())
		}

		p := credentials.NewCredentials(&credProvider)
		creds, err := p.Get()
		if err != nil {
			log.Fatalf("Unable to get SessionToken credentials: +%v", err)
		}

		if *showExpire {
			exp_t := credProvider.ExpirationTime()
			fmt.Printf("Session credentials will expire on %s (%s)\n", exp_t, exp_t.Sub(time.Now()).Round(time.Second))
			os.Exit(0)
		}

		if !*sesCreds {
			creds, err = credProvider.AssumeRole(profile_cfg)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
		}

		if len(*cmd) > 1 {
			os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
			os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
			if len(creds.SessionToken) > 0 {
				os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
				os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
			}

			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials(creds)
		}
	}
}
<commit_msg>removed duplicate/dead code since AWS session setup was moved to getAWSSession()<commit_after>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/mbndr/logo"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"
)

const (
	VERSION     = "0.1.2"
	minDuration = time.Duration(15) * time.Minute
	maxDuration = time.Duration(36) * time.Hour
)

var (
	listRoles       *bool
	listMfa         *bool
	showExpire      *bool
	sesCreds        *bool
	refresh         *bool
	verbose         *bool
	version         *bool
	makeConf        *bool
	profile         *string
	duration        *time.Duration
	cmd             *[]string
	defaultDuration = time.Duration(12) * time.Hour
	cacheDir        = filepath.Dir(defaults.SharedCredentialsFilename())
	logLevel        = logo.WARN
)

func init() {
	const (
		cmdDesc         = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc = "duration of the retrieved session token"
		listRoleArgDesc = "list role ARNs you are able to assume"
		listMfaArgDesc  = "list the ARN of the MFA device associated with your account"
		showExpArgDesc  = "Show token expiration time"
		sesCredArgDesc  = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc  = "force a refresh of the cached credentials"
		verboseArgDesc  = "print verbose/debug messages"
		profileArgDesc  = "name of profile"
		cmdArgDesc      = "command to execute using configured profile"
		makeConfArgDesc = "Build an AWS extended switch-role plugin configuration for all available roles"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Default(defaultDuration.String()).Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	profile = kingpin.Arg("profile", profileArgDesc).Default("default").String()
	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func dedupAndSort(ary *[]string) *[]string {
	m := make(map[string]bool)

	// dedup
	for _, v := range *ary {
		trimV := strings.TrimSpace(v)
		if len(trimV) > 0 {
			m[trimV] = true
		}
	}

	// array-ify
	i := 0
	newAry := make([]string, len(m))
	for k := range m {
		newAry[i] = k
		i++
	}

	// sort & return
	sort.Strings(newAry)
	return &newAry
}

func printCredentials(creds credentials.Value) {
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SESSION_TOKEN", creds.SessionToken)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECURITY_TOKEN", creds.SessionToken)
}

func getRoles(sess *session.Session) *[]string {
	// Used to return an array of role ARN's available to the user
	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)
	roles := make([]string, 0)

	s := iam.New(sess)

	u, err := s.GetUser(&iam.GetUserInput{})
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	userName := *u.User.UserName
	log.Debugf("USER: %s", userName)

	urg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.UserRoleGetter", true)
	urg := UserRoleGetter{Client: s, Logger: urg_logger}
	roles = append(roles, *urg.FetchRoles(userName)...)

	i := iam.ListGroupsForUserInput{UserName: &userName}
	grg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.GroupRoleGetter", true)
	grg := GroupRoleGetter{Client: s, Logger: grg_logger}
	truncated := true
	for truncated {
		g, err := s.ListGroupsForUser(&i)
		if err != nil {
			log.Errorf("Error getting user's IAM group list: %v", err)
			break
		}

		if *verbose {
			for x, grp := range g.Groups {
				log.Debugf("GROUP[%d]: %s", x, *grp.GroupName)
			}
		}
		roles = append(roles, *grg.FetchRoles(g.Groups...)...)

		truncated = *g.IsTruncated
		if truncated {
			i.Marker = g.Marker
		}
	}

	fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.User.Arn)
	dedupAndSort(&roles)
	return &roles
}

func getAWSSession() *session.Session {
	//  Unset the environment
	env := []string{"AWS_SECRET_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"}
	for _, env := range env {
		os.Unsetenv(env)
	}

	// This is how to get the MFA and AssumeRole config for a given profile.
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *profile,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
	}))

	return sess
}

func main() {
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}

	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	if *duration < minDuration || *duration > maxDuration {
		log.Warnf("Duration should be between %s and %s, using default of %s",
			minDuration.String(), maxDuration.String(), defaultDuration.String())
		duration = &defaultDuration
	}

	// These are magic words to change AssumeRole credential expiration
	stscreds.DefaultDuration = time.Duration(1) * time.Hour

	log.Debugf("PROFILE: %s", *profile)
	sess := getAWSSession()

	switch {
	case *listMfa:
		log.Debug("List MFA")
		s := iam.New(sess)

		res, err := s.ListMFADevices(&iam.ListMFADevicesInput{})
		if err != nil {
			log.Fatalf("Error listing MFA devices: %v", err)
		}

		fmt.Printf("%s\n", *res.MFADevices[0].SerialNumber)
	case *makeConf:
		log.Debug("Make Configuration Files.")
	case *listRoles, *makeConf:
		log.Debug("List Roles")
		roles := getRoles(sess)

		for _, v := range *roles {
			fmt.Printf("  %s\n", v)
		}
	default:
		cfgParser := AWSConfigParser{Logger: logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.AWSConfigParser", true)}
		profile_cfg, err := cfgParser.GetProfile(profile)
		if err != nil {
			log.Fatalf("Unable to get configuration for profile '%s': %+v", *profile, err)
		}

		credProvider := CachingSessionTokenProvider{
			Profile:  profile_cfg.SourceProfile,
			Duration: *duration,
			Logger:   logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.CachingSessionTokenProvider", true),
		}

		if len(profile_cfg.MfaSerial) > 0 {
			credProvider.MfaSerial = profile_cfg.MfaSerial
		}

		if *refresh {
			os.Remove(credProvider.CacheFile())
		}

		p := credentials.NewCredentials(&credProvider)
		creds, err := p.Get()
		if err != nil {
			log.Fatalf("Unable to get SessionToken credentials: +%v", err)
		}

		if *showExpire {
			exp_t := credProvider.ExpirationTime()
			fmt.Printf("Session credentials will expire on %s (%s)\n", exp_t, exp_t.Sub(time.Now()).Round(time.Second))
			os.Exit(0)
		}

		if !*sesCreds {
			creds, err = credProvider.AssumeRole(profile_cfg)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
		}

		if len(*cmd) > 1 {
			os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
			os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
			if len(creds.SessionToken) > 0 {
				os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
				os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
			}

			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials(creds)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	jd "github.com/josephburnett/jd/lib"
	"github.com/josephburnett/jd/web/serve"
)

var mset = flag.Bool("mset", false, "Arrays as multisets")
var output = flag.String("o", "", "Output file")
var patch = flag.Bool("p", false, "Patch mode")
var port = flag.Int("port", 0, "Serve web UI on port")
var set = flag.Bool("set", false, "Arrays as sets")
var setkeys = flag.String("setkeys", "", "Keys to identify set objects")
var yaml = flag.Bool("yaml", false, "Read and write YAML")

func main() {
	flag.Parse()
	if *port != 0 {
		serveWeb(strconv.Itoa(*port))
		return
	}
	metadata, err := parseMetadata()
	if err != nil {
		log.Fatalf(err.Error())
	}
	var a, b string
	switch len(flag.Args()) {
	case 1:
		a = readFile(flag.Arg(0))
		b = readStdin()
	case 2:
		a = readFile(flag.Arg(0))
		b = readFile(flag.Arg(1))
	default:
		printUsageAndExit()
	}
	if *patch {
		printPatch(a, b, metadata)
	} else {
		printDiff(a, b, metadata)
	}
}

func serveWeb(port string) error {
	http.HandleFunc("/", serve.Handle)
	log.Printf("Listening on :%v...", port)
	return http.ListenAndServe(":"+port, nil)
}

func parseMetadata() ([]jd.Metadata, error) {
	metadata := make([]jd.Metadata, 0)
	if *set {
		metadata = append(metadata, jd.SET)
	}
	if *mset {
		metadata = append(metadata, jd.MULTISET)
	}
	if *setkeys != "" {
		keys := make([]string, 0)
		ks := strings.Split(*setkeys, ",")
		for _, k := range ks {
			trimmed := strings.TrimSpace(k)
			if trimmed == "" {
				return nil, fmt.Errorf("Invalid set key: %v", k)
			}
			keys = append(keys, trimmed)
		}
		metadata = append(metadata, jd.Setkeys(keys...))
	}
	return metadata, nil
}

func printUsageAndExit() {
	for _, line := range []string{
		``,
		`Usage: jd [OPTION]... FILE1 [FILE2]`,
		`Diff and patch JSON files.`,
		``,
		`Prints the diff of FILE1 and FILE2 to STDOUT.`,
		`When FILE2 is omitted the second input is read from STDIN.`,
		`When patching (-p) FILE1 is a diff.`,
		``,
		`Options:`,
		`  -p        Apply patch FILE1 to FILE2 or STDIN.`,
		`  -o=FILE3  Write to FILE3 instead of STDOUT.`,
		`  -set      Treat arrays as sets.`,
		`  -mset     Treat arrays as multisets (bags).`,
		`  -setkeys  Keys to identify set objects`,
		`  -yaml     Read and write YAML instead of JSON.`,
		`  -port=N   Serve web UI on port N`,
		``,
		`Examples:`,
		`  jd a.json b.json`,
		`  cat b.json | jd a.json`,
		`  jd -o patch a.json b.json; jd patch a.json`,
		`  jd -set a.json b.json`,
		``,
		`Version: HEAD`,
		``,
	} {
		fmt.Println(line)
	}
	os.Exit(1)
}

func printDiff(a, b string, metadata []jd.Metadata) {
	var aNode, bNode jd.JsonNode
	var err error
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	if *yaml {
		bNode, err = jd.ReadYamlString(b)
	} else {
		bNode, err = jd.ReadJsonString(b)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	diff := aNode.Diff(bNode, metadata...)
	if *output == "" {
		fmt.Print(diff.Render())
	} else {
		ioutil.WriteFile(*output, []byte(diff.Render()), 0644)
	}
}

func printPatch(p, a string, metadata []jd.Metadata) {
	diff, err := jd.ReadDiffString(p)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var aNode jd.JsonNode
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	bNode, err := aNode.Patch(diff)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var out string
	if *yaml {
		out = bNode.Yaml(metadata...)
	} else {
		out = bNode.Json(metadata...)
	}
	if *output == "" {
		fmt.Print(out)
	} else {
		ioutil.WriteFile(*output, []byte(out), 0644)
	}
}

func readFile(filename string) string {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}

func readStdin() string {
	r := bufio.NewReader(os.Stdin)
	bytes, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}
<commit_msg>Add --version flag.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	jd "github.com/josephburnett/jd/lib"
	"github.com/josephburnett/jd/web/serve"
)

const version = "HEAD"

var mset = flag.Bool("mset", false, "Arrays as multisets")
var output = flag.String("o", "", "Output file")
var patch = flag.Bool("p", false, "Patch mode")
var port = flag.Int("port", 0, "Serve web UI on port")
var set = flag.Bool("set", false, "Arrays as sets")
var setkeys = flag.String("setkeys", "", "Keys to identify set objects")
var ver = flag.Bool("version", false, "Print version and exit")
var yaml = flag.Bool("yaml", false, "Read and write YAML")

func main() {
	flag.Parse()
	if *ver {
		fmt.Printf("jd version %v\n", version)
		return
	}
	if *port != 0 {
		serveWeb(strconv.Itoa(*port))
		return
	}
	metadata, err := parseMetadata()
	if err != nil {
		log.Fatalf(err.Error())
	}
	var a, b string
	switch len(flag.Args()) {
	case 1:
		a = readFile(flag.Arg(0))
		b = readStdin()
	case 2:
		a = readFile(flag.Arg(0))
		b = readFile(flag.Arg(1))
	default:
		printUsageAndExit()
	}
	if *patch {
		printPatch(a, b, metadata)
	} else {
		printDiff(a, b, metadata)
	}
}

func serveWeb(port string) error {
	http.HandleFunc("/", serve.Handle)
	log.Printf("Listening on :%v...", port)
	return http.ListenAndServe(":"+port, nil)
}

func parseMetadata() ([]jd.Metadata, error) {
	metadata := make([]jd.Metadata, 0)
	if *set {
		metadata = append(metadata, jd.SET)
	}
	if *mset {
		metadata = append(metadata, jd.MULTISET)
	}
	if *setkeys != "" {
		keys := make([]string, 0)
		ks := strings.Split(*setkeys, ",")
		for _, k := range ks {
			trimmed := strings.TrimSpace(k)
			if trimmed == "" {
				return nil, fmt.Errorf("Invalid set key: %v", k)
			}
			keys = append(keys, trimmed)
		}
		metadata = append(metadata, jd.Setkeys(keys...))
	}
	return metadata, nil
}

func printUsageAndExit() {
	for _, line := range []string{
		``,
		`Usage: jd [OPTION]... FILE1 [FILE2]`,
		`Diff and patch JSON files.`,
		``,
		`Prints the diff of FILE1 and FILE2 to STDOUT.`,
		`When FILE2 is omitted the second input is read from STDIN.`,
		`When patching (-p) FILE1 is a diff.`,
		``,
		`Options:`,
		`  -p        Apply patch FILE1 to FILE2 or STDIN.`,
		`  -o=FILE3  Write to FILE3 instead of STDOUT.`,
		`  -set      Treat arrays as sets.`,
		`  -mset     Treat arrays as multisets (bags).`,
		`  -setkeys  Keys to identify set objects`,
		`  -yaml     Read and write YAML instead of JSON.`,
		`  -port=N   Serve web UI on port N`,
		``,
		`Examples:`,
		`  jd a.json b.json`,
		`  cat b.json | jd a.json`,
		`  jd -o patch a.json b.json; jd patch a.json`,
		`  jd -set a.json b.json`,
		``,
		`Version: ` + version,
		``,
	} {
		fmt.Println(line)
	}
	os.Exit(1)
}

func printDiff(a, b string, metadata []jd.Metadata) {
	var aNode, bNode jd.JsonNode
	var err error
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	if *yaml {
		bNode, err = jd.ReadYamlString(b)
	} else {
		bNode, err = jd.ReadJsonString(b)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	diff := aNode.Diff(bNode, metadata...)
	if *output == "" {
		fmt.Print(diff.Render())
	} else {
		ioutil.WriteFile(*output, []byte(diff.Render()), 0644)
	}
}

func printPatch(p, a string, metadata []jd.Metadata) {
	diff, err := jd.ReadDiffString(p)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var aNode jd.JsonNode
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	bNode, err := aNode.Patch(diff)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var out string
	if *yaml {
		out = bNode.Yaml(metadata...)
	} else {
		out = bNode.Json(metadata...)
	}
	if *output == "" {
		fmt.Print(out)
	} else {
		ioutil.WriteFile(*output, []byte(out), 0644)
	}
}

func readFile(filename string) string {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}

func readStdin() string {
	r := bufio.NewReader(os.Stdin)
	bytes, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}
<|endoftext|>


<commit_before>// 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 main

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

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/NoahShen/go-simsimi"
)

var bot *linebot.Client
var session *simsimi.SimSimiSession
func main() {
	var err error
	session, _ = simsimi.CreateSimSimiSession("Wallte")
	bot, err = linebot.New(os.Getenv("CHANNEL_SECRET"), os.Getenv("CHANNEL_TOKEN"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" OK!")).Do(); err != nil {
					log.Print(err)
				}*/
				imageURL := "https://github.com/AdityaMili95/Wallte/blob/master/README/qI5Ujdy9n1"
				template := linebot.NewButtonsTemplate(
					imageURL, "My button sample"+message.Text, "Hello, my button",
					linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
					linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				)
				if _, err := bot.ReplyMessage(
					event.ReplyToken,
					linebot.NewTemplateMessage("Buttons alt text", template),
				).Do(); err != nil {
					return
				}

				responseText, _ := session.Talk(message.Text)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(responseText)).Do(); err != nil {
					log.Print(err)
				}

			}
		}
	}
}
<commit_msg>add postback<commit_after>// 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 main

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

	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/NoahShen/go-simsimi"
)

var bot *linebot.Client
var session *simsimi.SimSimiSession
func main() {
	var err error
	session, _ = simsimi.CreateSimSimiSession("Wallte")
	bot, err = linebot.New(os.Getenv("CHANNEL_SECRET"), os.Getenv("CHANNEL_TOKEN"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				/*if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" OK!")).Do(); err != nil {
					log.Print(err)
				}*/
				imageURL := "https://github.com/AdityaMili95/Wallte/blob/master/README/qI5Ujdy9n1"
				template := linebot.NewButtonsTemplate(
					imageURL, "My button sample"+message.Text, "Hello, my button",
					linebot.NewURITemplateAction("Go to line.me", "https://line.me"),
					linebot.NewPostbackTemplateAction("Say hello1", "hello こんにちは", ""),
					linebot.NewPostbackTemplateAction("言 hello2", "hello こんにちは", "hello こんにちは"),
					linebot.NewMessageTemplateAction("Say message", "Rice=米"),
				)
				if _, err := bot.ReplyMessage(
					event.ReplyToken,
					linebot.NewTemplateMessage("Buttons alt text", template),
				).Do(); err != nil {
					return
				}

				responseText, _ := session.Talk(message.Text)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(responseText)).Do(); err != nil {
					log.Print(err)
				}
			case *linebot.EventTypePostback:
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("iniPostback")).Do(); err != nil {
					log.Print(err)
				}

			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/atotto/clipboard"
)

// re matches FILE:LINE.
var re = regexp.MustCompile(`(.*?)(\S+?\.(?:ego|go)):(\d+)(.*)`)

var matched bool
var mu sync.Mutex

func main() {
	log.SetFlags(0)

	// Use go binary specified in environment variable.
	binPath := "go"
	if v := os.Getenv("GO"); v != "" {
		binPath = v
	}

	// Execute "go" command with the same arguments.
	cmd := exec.Command(binPath, os.Args[1:]...)

	// Pass through standard input.
	stdin, err := cmd.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	go io.Copy(stdin, os.Stdin)

	// Create a wait group for stdout/stderr.
	var wg sync.WaitGroup
	wg.Add(2)

	// Pass through standard out.
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		processPipe(os.Stdout, stdout)
		wg.Done()
	}()

	// Read through stderr and decorate.
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		processPipe(os.Stderr, stderr)
		wg.Done()
	}()

	// Execute command.
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}

	// Forward signals to command.
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c)
		for sig := range c {
			cmd.Process.Signal(sig)
		}
	}()

	// Wait for pipes to finish reading and then wait for command to exit.
	wg.Wait()

	if err := cmd.Wait(); err != nil {
		fmt.Print("\x07\x07") // beep twice on error.
		os.Exit(1)
	}

	fmt.Print("\x07") // beep once on success
}

// processPipe scans the src by line and attempts to match the first FILE:LINE.
func processPipe(dst io.Writer, src io.Reader) {
	// Find absolute path of present wording directory.
	pwd, _ := os.Getwd()
	pwd, _ = filepath.Abs(pwd)

	scanner := bufio.NewScanner(src)
	for scanner.Scan() {
		line := scanner.Text()
		func() {
			mu.Lock()
			defer mu.Unlock()

			// Ignore if already matched a line.
			if matched {
				fmt.Fprintln(dst, line)
				return
			}

			// Find .go path.
			m := re.FindStringSubmatch(line)
			if len(m) == 0 {
				fmt.Fprintln(dst, line)
				return
			}
			prefix, path, num, suffix := m[1], m[2], m[3], m[4]

			// Determine absolute path of Go file.
			abs, _ := filepath.Abs(path)

			// Ignore if path is not relative to pwd or is in vendor directory.
			rel, err := filepath.Rel(pwd, abs)
			if err != nil || strings.HasPrefix(rel, "..") || strings.HasPrefix(rel, "vendor/") {
				fmt.Fprintln(dst, line)
				return
			}

			// Show base path if it was originally in the line.
			var base string
			if strings.HasPrefix(path, "/") {
				base = pwd + "/"
			}

			// Copy match.
			clipboard.WriteAll(rel + ":" + num)

			// Bold line.
			line = prefix + base + "\033[7m" + rel + ":" + num + "\033[0m" + suffix
			fmt.Fprintln(dst, line)

			// Ensure no more lines match.
			matched = true
		}()
	}
}
<commit_msg>Copy char num<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/atotto/clipboard"
)

// re matches FILE:LINE.
var re = regexp.MustCompile(`(.*?)(\S+?\.(?:ego|go)):(\d+):(?:(\d+):)(.*)`)

var matched bool
var mu sync.Mutex

func main() {
	log.SetFlags(0)

	// Use go binary specified in environment variable.
	binPath := "go"
	if v := os.Getenv("GO"); v != "" {
		binPath = v
	}

	// Execute "go" command with the same arguments.
	cmd := exec.Command(binPath, os.Args[1:]...)

	// Pass through standard input.
	stdin, err := cmd.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	go io.Copy(stdin, os.Stdin)

	// Create a wait group for stdout/stderr.
	var wg sync.WaitGroup
	wg.Add(2)

	// Pass through standard out.
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		processPipe(os.Stdout, stdout)
		wg.Done()
	}()

	// Read through stderr and decorate.
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		processPipe(os.Stderr, stderr)
		wg.Done()
	}()

	// Execute command.
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}

	// Forward signals to command.
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c)
		for sig := range c {
			cmd.Process.Signal(sig)
		}
	}()

	// Wait for pipes to finish reading and then wait for command to exit.
	wg.Wait()

	if err := cmd.Wait(); err != nil {
		fmt.Print("\x07\x07") // beep twice on error.
		os.Exit(1)
	}

	fmt.Print("\x07") // beep once on success
}

// processPipe scans the src by line and attempts to match the first FILE:LINE.
func processPipe(dst io.Writer, src io.Reader) {
	// Find absolute path of present wording directory.
	pwd, _ := os.Getwd()
	pwd, _ = filepath.Abs(pwd)

	scanner := bufio.NewScanner(src)
	for scanner.Scan() {
		line := scanner.Text()
		func() {
			mu.Lock()
			defer mu.Unlock()

			// Ignore if already matched a line.
			if matched {
				fmt.Fprintln(dst, line)
				return
			}

			// Find .go path.
			m := re.FindStringSubmatch(line)
			if len(m) == 0 {
				fmt.Fprintln(dst, line)
				return
			}
			prefix, path, lineNum, charNum, suffix := m[1], m[2], m[3], m[4], m[5]

			// Determine absolute path of Go file.
			abs, _ := filepath.Abs(path)

			// Ignore if path is not relative to pwd or is in vendor directory.
			rel, err := filepath.Rel(pwd, abs)
			if err != nil || strings.HasPrefix(rel, "..") || strings.HasPrefix(rel, "vendor/") {
				fmt.Fprintln(dst, line)
				return
			}

			// Show base path if it was originally in the line.
			var base string
			if strings.HasPrefix(path, "/") {
				base = pwd + "/"
			}

			// Copy match.
			if charNum == "" {
				clipboard.WriteAll(rel + ":" + lineNum)
			} else {
				clipboard.WriteAll(rel + ":" + lineNum + ":" + charNum)
			}

			// Bold line.
			line = prefix + base + "\033[7m" + rel + ":" + lineNum
			if charNum != "" {
				line += ":" + charNum
			}
			line += "\033[0m" + suffix
			fmt.Fprintln(dst, line)

			// Ensure no more lines match.
			matched = true
		}()
	}
}
<|endoftext|>


<commit_before>package main

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

var output string

func init() {
	flag.Usage = func() {
		fmt.Printf("Usage: %s [-out=out.path] in.path\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.StringVar(&output, "out", "out.go", "Specify a path to the output file")

	flag.Parse()
}

func main() {
	checkRequirements()

	file, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Printf("Error! %s\n", err)
		os.Exit(2)
	}
	defer file.Close()

	fmt.Printf("input file: %s, output file: %s\n", flag.Arg(0), output)
}

func checkRequirements() {
	args := flag.Args()

	if len(args) == 0 {
		flag.Usage()

		fmt.Printf("Error! The input file is required\n")

		os.Exit(1)
	} else if len(args) > 1 {
		fmt.Printf("Notice! To many positional arguments, ignoring %v\n", args[1:])
	}
}
<commit_msg>Add go binary existence check<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
)

var output string

func init() {
	flag.Usage = func() {
		fmt.Printf("Usage: %s [-out=out.path] in.path\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.StringVar(&output, "out", "out.go", "Specify a path to the output file")

	flag.Parse()
}

func main() {
	checkRequirements()

	file, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Printf("Error! %s\n", err)
		os.Exit(2)
	}
	defer file.Close()

	prog := "go"
	path, err := exec.LookPath(prog)
	if err != nil {
		fmt.Printf("Please, install %s first.", prog)
	}
	fmt.Printf("%s is available at %s\n", prog, path)

	fmt.Printf("input file: %s, output file: %s\n", flag.Arg(0), output)
}

func checkRequirements() {
	args := flag.Args()

	if len(args) == 0 {
		flag.Usage()

		fmt.Printf("Error! The input file is required\n")

		os.Exit(1)
	} else if len(args) > 1 {
		fmt.Printf("Notice! To many positional arguments, ignoring %v\n", args[1:])
	}
}
<|endoftext|>


<commit_before>package main

import (
    "net"
    "log"
    "os"
    "os/signal"
    "syscall"
)

func signalHandler(signalChannel chan os.Signal, doneChannel chan bool){
    // block the goroutine until we get a signal
    signal := <-signalChannel
    log.Printf("Got signal %v, exiting...\n", signal)
    // Send the message to terminate the app
    doneChannel <- true
}

func aggregateCollectorData(socket net.Listener) {
    for {
        readBuffer := make([]byte, 512)
        fd, err := socket.Accept()
        if err != nil {
            log.Fatalf("Failed to accept a connection: err: %v\n", err)
        }
        bytesRead, err := fd.Read(readBuffer)
        if err != nil {
            log.Fatalf("Failed to read from the socket into the buffer: err: %v\n", err)
        }
        fd.Close()
        data := readBuffer[:bytesRead]
        log.Printf("Got data: %s, bytes: %v\n", data, data)
    }
}

func main() {
    // Create a channel to pass to os.Notify for OS signal handling
    signalChannel := make(chan os.Signal, 1)
    signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM)

    doneChannel := make(chan bool, 1)
    go signalHandler(signalChannel, doneChannel)

    socket, err := net.Listen("unix", "/tmp/garnet.sock")
    if err != nil {
        log.Fatalf("Failed to create a new Unix socket: err: %v\n", err)
    }
    defer socket.Close()

    log.Printf("Opened a socket connection '/tmp/garnet.sock'\n")

    go aggregateCollectorData(socket)

    <- doneChannel
}
<commit_msg>"gracefully" terminate the application, dont cut off socket reads mid-way<commit_after>package main

import (
    "fmt"
    "net"
    "log"
    "os"
    "os/signal"
    "syscall"
    "io"
)

// Signal handler catches SIGINT and SIGTERM and sends a "done" flag to the main loop
func signalHandler(signalChannel chan os.Signal, doneChannel chan bool){
    // block the goroutine until we get a signal
    signal := <-signalChannel
    log.Printf("Got signal %v, exiting...\n", signal)
    // Send the message to terminate the app
    doneChannel <- true
}

// Collects data from the socket and sends it to where it needs to go
func aggregateCollectorData(socket net.Listener, doneChannel, finishedChannel chan bool) {
    for {
        select {
        case <- doneChannel:
            log.Println("Ceasing to accept collector connections...")
            finishedChannel <- true
            return
        default:
            log.Println("Accepting a collector connection...")
            data, err := readDataFromClient(socket)
            if err != nil {
                log.Printf("Error: %v\n", err)
            } else {
                log.Println(data)
            }
        }
    }
}

// Accept a connection from the socket and read 512 bytes of data into a buffer
func readDataFromClient(socket net.Listener) ([]byte, error) {
    readBuffer := make([]byte, 512)

    fd, err := socket.Accept()
    if err != nil {
        return nil, fmt.Errorf("Failed to accept a connection: err: %v\n", err)
    }

    defer fd.Close()

    bytesRead, err := fd.Read(readBuffer)

    if err == io.EOF {
        return nil, fmt.Errorf("Received no data from client connection")
    }

    if err != nil {
        return nil, fmt.Errorf("Failed to read from the socket into the buffer: err: %v\n", err)
    }

    return readBuffer[:bytesRead], nil
}

// Connect to the socket as a client to unblock the Accept call
func mimicFinalClient(socketUrl string) {
    log.Println("Creating a mimic client to terminate socket accept thread")
    conn, err := net.Dial("unix", socketUrl)
    if err != nil {
        log.Fatalf("Failed to open the final client connection to Garnet")
    }
    conn.Close()
}

func main() {
    // Create a channel to pass to os.Notify for OS signal handling
    signalChannel := make(chan os.Signal, 1)
    signalDoneChannel := make(chan bool, 1)
    signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM)
    go signalHandler(signalChannel, signalDoneChannel)

    socket, err := net.Listen("unix", "/tmp/garnet.sock")
    if err != nil {
        log.Fatalf("Failed to create a new Unix socket: err: %v\n", err)
    }
    defer socket.Close()

    log.Printf("Opened a socket connection '/tmp/garnet.sock'\n")

    // Start the aggregation collector
    aggregationDoneChannel := make(chan bool, 1)
    cleanUpChannel := make(chan bool, 1)
    go aggregateCollectorData(socket, aggregationDoneChannel, cleanUpChannel)

    // Wait until we get a catchable signal before cleaning up
    <- signalDoneChannel
    aggregationDoneChannel <- true
    mimicFinalClient("/tmp/garnet.sock")
    <- cleanUpChannel
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nlopes/slack"
	"log"
	"os"
	"strings"
)

var (
	helpText []string = []string{
		"Available commands are:",
		"	- `nowplaying` // Display information on the current song",
		"	- `play (song|album) <search text>`	// Play the first song/album result for _search text_ & add it to the queue",
		"	- `search (song|album) <search text>` // Print the first song/album result for _search text_",
		"	- `boombox (start|stop)` // Start or stop displaying the current song in this channel",
	}
)

func main() {
	SLACK_TOKEN := os.Getenv("SLACK_TOKEN")
	slack_api := slack.New(SLACK_TOKEN)

	slack_message_parameters := slack.NewPostMessageParameters()
	slack_message_parameters.AsUser = true

	// Start the boombox thread
	boombox := boomBox{}
	go boombox.start(slack_api)

	logger := log.New(
		os.Stdout,
		"slack-bot: ",
		log.Lshortfile|log.LstdFlags,
	)

	slack.SetLogger(logger)

	rtm := slack_api.NewRTM()
	go rtm.ManageConnection()

	for msg := range rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			casabot_command := parseCommand(ev)
			if casabot_command != nil && casabot_command.UserID == rtm.GetInfo().User.ID {
				log.Printf("Command: %+v", casabot_command)
				switch strings.ToLower(casabot_command.Command) {
				case "nowplaying":
					casa_NowPlaying(slack_api, casabot_command)
				case "play":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "song":
						log.Printf("playing song %s", casabot_command.Args)
						//casa_PlaySong(slack_api, casabot_command)
					case "album":
						log.Printf("playing album %s", casabot_command.Args)
						//casa_PlayAlbum(slack_api, casabot_command)
					default:
						log.Printf("default play song: %s", casabot_command.Args)
						//casa_PlaySong(slack_api, casabot_command)
					}
				case "search":
					switch casabot_command.verb([]string{"song", "album"}) {
					default:
						casa_SearchSong(slack_api, casabot_command)
					}
				case "boombox":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "start":
						boombox.addChannel(ev.Channel, slack_api)
					case "stop":
						boombox.removeChannel(ev.Channel, slack_api)
					}
				case "pause", "resume", "next", "previous":
					casa_PlayerAction(slack_api, casabot_command)
				default:
					var text string
					for _, line := range helpText {
						text += line + "\n"
					}
					slack_api.PostMessage(ev.Channel, text, slack_message_parameters)
				}
			}

		case *slack.RTMError:
			log.Printf("Error: %s\n", ev.Error())

		case *slack.InvalidAuthEvent:
			log.Fatal("Invalid credentials")

		case *slack.ConnectionErrorEvent:
			log.Fatal("Failed to authenticate with Slack API")

		case *slack.ConnectingEvent:
			log.Printf("Connecting to Slack (attempt %d)", ev.Attempt)

		case *slack.HelloEvent:
			log.Printf("Received hello from Slack API.")

		case *slack.ConnectedEvent:
			log.Printf("Connected to %s as %s.", ev.Info.Team.Name, ev.Info.User.Name)

		case *slack.LatencyReport:
			log.Printf("Latency report: %s", ev.Value)

		default:
			// Ignore other events..
			// fmt.Printf("Unexpected: %v\n", msg.Data)
		}
	}
}
<commit_msg>Removed debugging code<commit_after>package main

import (
	"github.com/nlopes/slack"
	"log"
	"os"
	"strings"
)

var (
	helpText []string = []string{
		"Available commands are:",
		"	- `nowplaying` // Display information on the current song",
		"	- `play (song|album) <search text>`	// Play the first song/album result for _search text_ & add it to the queue",
		"	- `search (song|album) <search text>` // Print the first song/album result for _search text_",
		"	- `boombox (start|stop)` // Start or stop displaying the current song in this channel",
	}
)

func main() {
	SLACK_TOKEN := os.Getenv("SLACK_TOKEN")
	slack_api := slack.New(SLACK_TOKEN)

	slack_message_parameters := slack.NewPostMessageParameters()
	slack_message_parameters.AsUser = true

	// Start the boombox thread
	boombox := boomBox{}
	go boombox.start(slack_api)

	logger := log.New(
		os.Stdout,
		"slack-bot: ",
		log.Lshortfile|log.LstdFlags,
	)

	slack.SetLogger(logger)

	rtm := slack_api.NewRTM()
	go rtm.ManageConnection()

	for msg := range rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			casabot_command := parseCommand(ev)
			if casabot_command != nil && casabot_command.UserID == rtm.GetInfo().User.ID {
				switch strings.ToLower(casabot_command.Command) {
				case "nowplaying":
					casa_NowPlaying(slack_api, casabot_command)
				case "play":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "song":
						casa_PlaySong(slack_api, casabot_command)
					case "album":
						casa_PlayAlbum(slack_api, casabot_command)
					default:
						casa_PlaySong(slack_api, casabot_command)
					}
				case "search":
					switch casabot_command.verb([]string{"song", "album"}) {
					default:
						casa_SearchSong(slack_api, casabot_command)
					}
				case "boombox":
					switch casabot_command.verb([]string{"song", "album"}) {
					case "start":
						boombox.addChannel(ev.Channel, slack_api)
					case "stop":
						boombox.removeChannel(ev.Channel, slack_api)
					}
				case "pause", "resume", "next", "previous":
					casa_PlayerAction(slack_api, casabot_command)
				default:
					var text string
					for _, line := range helpText {
						text += line + "\n"
					}
					slack_api.PostMessage(ev.Channel, text, slack_message_parameters)
				}
			}

		case *slack.RTMError:
			log.Printf("Error: %s\n", ev.Error())

		case *slack.InvalidAuthEvent:
			log.Fatal("Invalid credentials")

		case *slack.ConnectionErrorEvent:
			log.Fatal("Failed to authenticate with Slack API")

		case *slack.ConnectingEvent:
			log.Printf("Connecting to Slack (attempt %d)", ev.Attempt)

		case *slack.HelloEvent:
			log.Printf("Received hello from Slack API.")

		case *slack.ConnectedEvent:
			log.Printf("Connected to %s as %s.", ev.Info.Team.Name, ev.Info.User.Name)

		case *slack.LatencyReport:
			log.Printf("Latency report: %s", ev.Value)

		default:
			// Ignore other events..
			// fmt.Printf("Unexpected: %v\n", msg.Data)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"fmt"
	"go/ast"
	"go/token"
	"go/parser"
	"path/filepath"
)

func main() {
	if len(os.Args) != 3 {
		usage()
		os.Exit(1)
	}

	sprinkleSugarOn(os.Args[1], os.Args[2])
}

func usage() {
	println("Error: Not enough args. Expected path to file and interface to mock")
	println("usage: sugar /path/to/some/file InterfaceToMock")
}

func sprinkleSugarOn(pathToFile, interfaceToMock string) {
	if _, err := os.Stat(pathToFile); err != nil {
		dir, _ := os.Getwd()
		fmt.Printf("Couldn't find file from dir %s\n", dir)
		fmt.Printf("Error: given file '%s' does not exist\n", pathToFile)
		return
	}

	fileSet := token.NewFileSet()
	parsedFile, err := parser.ParseFile(fileSet, pathToFile, nil, 0)
	if err != nil {
		fmt.Printf("Error parsing '%s':\n%s\n", pathToFile, err)
		return
	}

	packageName := ""
	expectingNamedInterface := false
	var interfaceNode *ast.InterfaceType

	ast.Inspect(parsedFile, func(n ast.Node) bool {
		if n == nil {
			return true
		}

	 	switch n := n.(type) {
	 	case *ast.Ident:
	 		if n.Obj == nil && packageName == "" {
	 			packageName = n.Name
	 		} else if n.Name == interfaceToMock {
	 			expectingNamedInterface = true
	 		}
		case *ast.InterfaceType:
			if expectingNamedInterface {
				interfaceNode = n
			}
	 	default:
	 		expectingNamedInterface = false
		}

		return true
	})

	fmt.Printf("\nmocking out %s.%s Interface\n", packageName, interfaceToMock)

	outputFileName := filepath.Base(pathToFile)
	outputDir := filepath.Dir(pathToFile)
	outputFilePath := filepath.Join(outputDir, "fake_" + outputFileName)

	fmt.Printf("Writing a mock interface to %s\n\n", outputFilePath)

	i := createInterfaceFromNameAndNode(interfaceToMock, interfaceNode)

	fakeStruct := i.fakeStructDeclaration()
	fmt.Printf("fake implementation:\n**********\n%s\n**********\n", fakeStruct)
}
<commit_msg>Alert when interface can't be found<commit_after>package main

import (
	"os"
	"fmt"
	"go/ast"
	"go/token"
	"go/parser"
	"path/filepath"
)

func main() {
	if len(os.Args) != 3 {
		usage()
		os.Exit(1)
	}

	sprinkleSugarOn(os.Args[1], os.Args[2])
}

func usage() {
	println("Error: Not enough args. Expected path to file and interface to mock")
	println("usage: sugar /path/to/some/file InterfaceToMock")
}

func sprinkleSugarOn(pathToFile, interfaceToMock string) {
	if _, err := os.Stat(pathToFile); err != nil {
		dir, _ := os.Getwd()
		fmt.Printf("Couldn't find file from dir %s\n", dir)
		fmt.Printf("Error: given file '%s' does not exist\n", pathToFile)
		return
	}

	fileSet := token.NewFileSet()
	parsedFile, err := parser.ParseFile(fileSet, pathToFile, nil, 0)
	if err != nil {
		fmt.Printf("Error parsing '%s':\n%s\n", pathToFile, err)
		return
	}

	packageName := ""
	expectingNamedInterface := false
	var interfaceNode *ast.InterfaceType

	ast.Inspect(parsedFile, func(n ast.Node) bool {
		if n == nil {
			return true
		}

	 	switch n := n.(type) {
	 	case *ast.Ident:
	 		if n.Obj == nil && packageName == "" {
	 			packageName = n.Name
	 		} else if n.Name == interfaceToMock {
	 			expectingNamedInterface = true
	 		}
		case *ast.InterfaceType:
			if expectingNamedInterface {
				interfaceNode = n
			}
	 	default:
	 		expectingNamedInterface = false
		}

		return true
	})

	if interfaceNode == nil || packageName == "" {
		println("Could not find interface:", interfaceToMock)
		os.Exit(1)
	}

	fmt.Printf("\nmocking out %s.%s Interface\n", packageName, interfaceToMock)

	outputFileName := filepath.Base(pathToFile)
	outputDir := filepath.Dir(pathToFile)
	outputFilePath := filepath.Join(outputDir, "fake_" + outputFileName)

	fmt.Printf("Writing a mock interface to %s\n\n", outputFilePath)

	i := createInterfaceFromNameAndNode(interfaceToMock, interfaceNode)

	fakeStruct := i.fakeStructDeclaration()
	fmt.Printf("fake implementation:\n**********\n%s\n**********\n", fakeStruct)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/admpub/chardet"
	"github.com/admpub/log"
	sc "github.com/admpub/mahonia"
	"github.com/mitool/find2/model"
)

func main() {
	model.CmdOptions.DefineFlag()
	flag.Parse()
	log.Sync()

	var regexpFileName, regexpContent, regexpIgnoreFile *regexp.Regexp
	if model.CmdOptions.TargetFileRule != nil && len(*model.CmdOptions.TargetFileRule) > 0 {
		regexpFileName = regexp.MustCompile(*model.CmdOptions.TargetFileRule)
	}
	if model.CmdOptions.FindRule != nil && len(*model.CmdOptions.FindRule) > 0 {
		regexpContent = regexp.MustCompile(*model.CmdOptions.FindRule)
	}
	if model.CmdOptions.IgnoreFileRule != nil && len(*model.CmdOptions.IgnoreFileRule) > 0 {
		regexpIgnoreFile = regexp.MustCompile(*model.CmdOptions.IgnoreFileRule)
	}
	replaceWithBytes := []byte{}
	if model.CmdOptions.ReplaceWith == nil {
		replaceWithBytes = []byte(``)
	} else {
		replaceWithBytes = []byte(*model.CmdOptions.ReplaceWith)
	}
	doFn := func(b []byte) []byte {
		return b
	}
	if model.CmdOptions.ConvertEncoding != nil {
		encs := strings.SplitN(*model.CmdOptions.ConvertEncoding, `->`, 2)
		var fromEnc, toEnc string
		if len(encs) == 2 {
			fromEnc = strings.TrimSpace(encs[0])
			toEnc = strings.TrimSpace(encs[1])
			if len(fromEnc) == 0 {
				doFn = func(b []byte) []byte {
					charset := chardet.Mostlike(b)
					dec := sc.NewDecoder(charset)
					s := dec.ConvertString(string(b))
					enc := sc.NewEncoder(toEnc)
					s = enc.ConvertString(s)
					b = []byte(s)
					return b
				}
			} else {
				doFn = func(b []byte) []byte {
					dec := sc.NewDecoder(fromEnc)
					s := dec.ConvertString(string(b))
					enc := sc.NewEncoder(toEnc)
					s = enc.ConvertString(s)
					b = []byte(s)
					return b
				}
			}
		}
	}
	if model.CmdOptions.TargetFilePath == nil || len(*model.CmdOptions.TargetFilePath) == 0 {
		s := `./`
		model.CmdOptions.TargetFilePath = &s
	}
	root, err := filepath.Abs(*model.CmdOptions.TargetFilePath)
	if err != nil {
		log.Fatal(err)
	}
	log.Info(`Scan dir: `, root)
	err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		name := info.Name()
		nameBytes := []byte(name)
		if info.IsDir() {
			if regexpIgnoreFile != nil && regexpIgnoreFile.Match(nameBytes) {
				return filepath.SkipDir
			}
			return nil
		} else if regexpIgnoreFile != nil {
			if regexpIgnoreFile.Match(nameBytes) {
				return nil
			}
		}
		if regexpFileName != nil && !regexpFileName.Match(nameBytes) {
			return nil
		}
		savePath := *model.CmdOptions.SaveToPath
		if regexpContent != nil {
			b, err := ioutil.ReadFile(path)
			if err != nil {
				return err
			}
			if *model.CmdOptions.ReplaceMode {
				b = regexpContent.ReplaceAll(b, replaceWithBytes)
			} else {
				if !regexpContent.Match(b) {
					return nil
				}
			}
			b = doFn(b)

			if len(savePath) == 0 && !*model.CmdOptions.CompressSave { //如果没有指定另存路径,且不需要压缩保存修改后的文件，则覆盖原文件
				savePath = path
			} else {
				if *model.CmdOptions.CompressSave {
					savePath = filepath.Join(savePath, `_tmp`)
					err := os.MkdirAll(savePath, os.ModePerm)
					if err != nil {
						return err
					}
				}
				filePath := strings.TrimPrefix(path, root)
				savePath = filepath.Join(savePath, filePath)
				err := os.MkdirAll(filepath.Dir(savePath), os.ModePerm)
				if err != nil {
					return err
				}
			}
			log.Info(`Modified ` + path + ` and save to ` + savePath + `.`)
			err = ioutil.WriteFile(savePath, b, os.ModePerm)
			if err != nil {
				return err
			}
		} else if len(savePath) > 0 || *model.CmdOptions.CompressSave { //不需要访问内容，直接拷贝文件
			if *model.CmdOptions.CompressSave {
				savePath = filepath.Join(savePath, `_tmp`)
				err := os.MkdirAll(savePath, os.ModePerm)
				if err != nil {
					return err
				}
			}
			filePath := strings.TrimPrefix(root, path)
			savePath = filepath.Join(savePath, filePath)
			err := os.MkdirAll(filepath.Dir(savePath), os.ModePerm)
			if err != nil {
				return err
			}
			sr, err := os.Open(path)
			if err != nil {
				return err
			}
			defer sr.Close()

			dw, err := os.Create(savePath)
			if err != nil {
				return err
			}
			defer dw.Close()

			if _, err = io.Copy(dw, sr); err != nil {
				return err
			}
			log.Info(`Copy ` + path + ` to ` + savePath + `.`)
		}
		return nil
	})
	done := make(chan int)
	if err == nil && *model.CmdOptions.CompressSave {
		srcPath := filepath.Join(*model.CmdOptions.SaveToPath, `_tmp`)
		savePath := filepath.Join(*model.CmdOptions.SaveToPath, `compress.zip`)
		_, err = model.Zip(srcPath, savePath)
		if err == nil {
			err = os.RemoveAll(srcPath)
			if err != nil {
				go func() {
					for i := 1; err != nil && i < 10; i++ {
						log.Error(err)
						time.Sleep(1 * time.Second)
						err = os.RemoveAll(srcPath)
					}
					done <- 1
				}()
			} else {
				close(done)
			}
		}
	}

	if err != nil {
		log.Error(err)
	}
	log.Info(`Find complete.`)
	<-done
}
<commit_msg>update<commit_after>package main

import (
	"flag"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/admpub/chardet"
	"github.com/admpub/log"
	sc "github.com/admpub/mahonia"
	"github.com/mitool/find2/model"
)

func main() {
	model.CmdOptions.DefineFlag()
	flag.Parse()
	log.Sync()

	var regexpFileName, regexpContent, regexpIgnoreFile *regexp.Regexp
	if model.CmdOptions.TargetFileRule != nil && len(*model.CmdOptions.TargetFileRule) > 0 {
		regexpFileName = regexp.MustCompile(*model.CmdOptions.TargetFileRule)
	}
	if model.CmdOptions.FindRule != nil && len(*model.CmdOptions.FindRule) > 0 {
		regexpContent = regexp.MustCompile(*model.CmdOptions.FindRule)
	}
	if model.CmdOptions.IgnoreFileRule != nil && len(*model.CmdOptions.IgnoreFileRule) > 0 {
		regexpIgnoreFile = regexp.MustCompile(*model.CmdOptions.IgnoreFileRule)
	}
	replaceWithBytes := []byte{}
	if model.CmdOptions.ReplaceWith == nil {
		replaceWithBytes = []byte(``)
	} else {
		replaceWithBytes = []byte(*model.CmdOptions.ReplaceWith)
	}
	doFn := func(b []byte) []byte {
		return b
	}
	if model.CmdOptions.ConvertEncoding != nil {
		encs := strings.SplitN(*model.CmdOptions.ConvertEncoding, `->`, 2)
		var fromEnc, toEnc string
		if len(encs) == 2 {
			fromEnc = strings.TrimSpace(encs[0])
			toEnc = strings.TrimSpace(encs[1])
			if len(fromEnc) == 0 {
				doFn = func(b []byte) []byte {
					charset := chardet.Mostlike(b)
					dec := sc.NewDecoder(charset)
					s := dec.ConvertString(string(b))
					enc := sc.NewEncoder(toEnc)
					s = enc.ConvertString(s)
					b = []byte(s)
					return b
				}
			} else {
				doFn = func(b []byte) []byte {
					dec := sc.NewDecoder(fromEnc)
					s := dec.ConvertString(string(b))
					enc := sc.NewEncoder(toEnc)
					s = enc.ConvertString(s)
					b = []byte(s)
					return b
				}
			}
		}
	}
	if model.CmdOptions.TargetFilePath == nil || len(*model.CmdOptions.TargetFilePath) == 0 {
		s := `./`
		model.CmdOptions.TargetFilePath = &s
	}
	root, err := filepath.Abs(*model.CmdOptions.TargetFilePath)
	if err != nil {
		log.Fatal(err)
	}
	log.Info(`Scan dir: `, root)
	err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		name := info.Name()
		nameBytes := []byte(name)
		if info.IsDir() {
			if regexpIgnoreFile != nil && regexpIgnoreFile.Match(nameBytes) {
				return filepath.SkipDir
			}
			return nil
		} else if regexpIgnoreFile != nil {
			if regexpIgnoreFile.Match(nameBytes) {
				return nil
			}
		}
		if regexpFileName != nil && !regexpFileName.Match(nameBytes) {
			return nil
		}
		savePath := *model.CmdOptions.SaveToPath
		if regexpContent != nil {
			b, err := ioutil.ReadFile(path)
			if err != nil {
				return err
			}
			if *model.CmdOptions.ReplaceMode {
				b = regexpContent.ReplaceAll(b, replaceWithBytes)
			} else {
				if !regexpContent.Match(b) {
					return nil
				}
			}
			b = doFn(b)

			if len(savePath) == 0 && !*model.CmdOptions.CompressSave { //如果没有指定另存路径,且不需要压缩保存修改后的文件，则覆盖原文件
				savePath = path
			} else {
				if *model.CmdOptions.CompressSave {
					savePath = filepath.Join(savePath, `_tmp`)
					err := os.MkdirAll(savePath, os.ModePerm)
					if err != nil {
						return err
					}
				}
				filePath := strings.TrimPrefix(path, root)
				savePath = filepath.Join(savePath, filePath)
				err := os.MkdirAll(filepath.Dir(savePath), os.ModePerm)
				if err != nil {
					return err
				}
			}
			log.Info(`Modified ` + path + ` and save to ` + savePath + `.`)
			err = ioutil.WriteFile(savePath, b, os.ModePerm)
			if err != nil {
				return err
			}
		} else if len(savePath) > 0 || *model.CmdOptions.CompressSave { //不需要访问内容，直接拷贝文件
			if *model.CmdOptions.CompressSave {
				savePath = filepath.Join(savePath, `_tmp`)
				err := os.MkdirAll(savePath, os.ModePerm)
				if err != nil {
					return err
				}
			}
			filePath := strings.TrimPrefix(root, path)
			savePath = filepath.Join(savePath, filePath)
			err := os.MkdirAll(filepath.Dir(savePath), os.ModePerm)
			if err != nil {
				return err
			}
			sr, err := os.Open(path)
			if err != nil {
				return err
			}
			defer sr.Close()

			dw, err := os.Create(savePath)
			if err != nil {
				return err
			}
			defer dw.Close()

			if _, err = io.Copy(dw, sr); err != nil {
				return err
			}
			log.Info(`Copy ` + path + ` to ` + savePath + `.`)
		}
		return nil
	})
	done := make(chan int)
	if err == nil && *model.CmdOptions.CompressSave {
		srcPath := filepath.Join(*model.CmdOptions.SaveToPath, `_tmp`)
		savePath := filepath.Join(*model.CmdOptions.SaveToPath, `compress.zip`)
		_, err = model.Zip(srcPath, savePath)
		if err == nil {
			err = os.RemoveAll(srcPath)
			if err != nil {
				go func() {
					for i := 1; err != nil && i < 10; i++ {
						log.Error(err)
						time.Sleep(1 * time.Second)
						err = os.RemoveAll(srcPath)
					}
					close(done)
				}()
			} else {
				close(done)
			}
		}
	}

	if err != nil {
		log.Error(err)
	}
	log.Info(`Find complete.`)
	<-done
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the MPL
*  License. If a copy of the same was not distributed with this
*  file, You can obtain one at
*  https://github.com/AkhilHector/pubundsci/blob/master/LICENSE.
 */

package numgo

import (
	"fmt"
	"log"
	"math"
	"strings"
)

type NArray struct {
	Data    []float64
	Details []float64
	Index   []float64
}

func Init(length float64) (n *NArray) {
	n = &NArray{
		Data:    make([]float64, 0),
		Details: []float64{1, length},
		Index:   make([]float64, 2),
	}
	return n
}

func Round(number, decimal, precision float64) float64 {
	var result float64
	var zeros float64 = math.Pow(10, precision)
	var new_number float64 = zeros * number
	_, mod_decimal := math.Modf(new_number)
	if mod_decimal >= decimal {
		result = math.Ceil(new_number)
	} else {
		result = math.Floor(new_number)
	}
	result /= zeros
	return result
}

func RowColFormula(details []float64) float64 {
	var result float64 = 1
	for x := 0; x < len(details); x++ {
		result *= details[x]
	}
	return result
}

func GetIndex(n *NArray, details ...float64) float64 {
	var result float64 = 0
	parameters := extract_parameters(details)
	if len(parameters) == len(n.Details) {
		for x := 0; x < len(n.Details); x++ {
			result += parameters[x] * RowColFormula(n.Details[x+1:])
		}
		return result
	} else {
		log.Fatal("incorrect shape given as index")
		return -1
	}
}

func extract_parameters(args []float64) []float64 {
	var parameters []float64

	// store the parameters in a list
	for _, p := range args {
		parameters = append(parameters, p)
	}
	return parameters
}

func NDArrayGenElements(value float64, details ...float64) []float64 {
	parameters := extract_parameters(details)
	if len(parameters) > 0 {
		dim := parameters[0]
		rem := parameters[1:]
		arr := []float64{}
		for i := 0; i < int(dim); i++ {
			arr = append(arr, NDArrayGenElements(value, rem...)...)
		}
		return arr
	} else {
		return []float64{value}
	}
}

func NDArray(details ...float64) (n *NArray) {
	parameters := extract_parameters(details)
	n = &NArray{
		Data:    NDArrayGenElements(0, details...),
		Details: parameters,
		Index:   make([]float64, len(parameters)),
	}
	return n
}

func (n *NArray) String() (array string) {
	array = "NDArray>\n("
	if len(n.Details) == 0 {
		return "NDArray>(<nil>)"
	} else {
		var i float64 = 0
		var details []float64
		var index_number float64 = n.Details[len(n.Details)-1]
		var element float64 = index_number

		// store the rows and cols number for adding [ and ] symbols
		// at appropriate places
		for index := len(n.Details) - 1; index > 0; index-- {
			details = append(details, index_number*n.Details[index-1])
			index_number = index_number * n.Details[index-1]
		}
		for i = 0; i+element <= float64(len(n.Data)); i += element {
			var array_symbol string = ""
			// add the '[' symbol at the start of every new dimension
			for _, d := range details {
				if int(i)%int(d) == 0 {
					array_symbol += "["
				}
			}
			array += strings.Repeat(" ", len(n.Details)-len(array_symbol)-1) + array_symbol

			// add the data between the '[' ']' symbols
			array += fmt.Sprint(n.Data[int(i):int(i+element)])

			array_symbol = ""

			// add the ']' symbol at the end of every new dimension
			for _, d := range details {
				if int((i+element))%int(d) == 0 {
					array_symbol += "]"
				}
			}
			array += array_symbol + strings.Repeat(" ", (len(n.Details)-len(array_symbol))-1)

			// add proper spacing for displaying arrays in presentable manner
			if i+element != float64(len(n.Data)) {
				if n.Details[0] == 1 && len(n.Details) == 2 {
					array += ""
				} else {
					if len(array_symbol) > 0 {
						array += "\n"
					}
					array += "\n"
				}
			}
		}
	}
	return array + ")"
}

func (n *NArray) GetElement(details ...float64) float64 {
	var result float64
	if int(GetIndex(n, details...)) < len(n.Data) {
		result = GetIndex(n, details...)
		return n.Data[int(result)]
	} else {
		log.Fatal("Incorrect Shape passed as an argument")
		return -1
	}
}

func Range(start, end float64) (n *NArray) {
	n = Init(end - start)
	for i := start; i < end; i++ {
		n.Data = append(n.Data, i)
	}
	return n
}

func Xrange(args ...float64) (n *NArray) {
	var i float64
	number_of_args := len(args)
	parameters := extract_parameters(args)

	// now generate the array basiing on the number of arguments
	if number_of_args == 1 {
		n = Init(parameters[0])
		for i = 0; i < parameters[0]; i++ {
			n.Data = append(n.Data, i)
		}
	} else if number_of_args == 2 {
		n = Init(parameters[1] - parameters[0])
		for i = parameters[0]; i < parameters[1]; i++ {
			n.Data = append(n.Data, i)
		}
	} else if number_of_args == 3 {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, 1))
		}
	} else if number_of_args == 4 {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, parameters[3]))
		}
	} else {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, 1))
		}
	}
	return n
}
<commit_msg>Issue #6: Added numgo.SetElement() (#8)<commit_after>/* This Source Code Form is subject to the terms of the MPL
*  License. If a copy of the same was not distributed with this
*  file, You can obtain one at
*  https://github.com/AkhilHector/pubundsci/blob/master/LICENSE.
 */

package numgo

import (
	"fmt"
	"log"
	"math"
	"strings"
)

type NArray struct {
	Data    []float64
	Details []float64
	Index   []float64
}

func Init(length float64) (n *NArray) {
	n = &NArray{
		Data:    make([]float64, 0),
		Details: []float64{1, length},
		Index:   make([]float64, 2),
	}
	return n
}

func Round(number, decimal, precision float64) float64 {
	var result float64
	var zeros float64 = math.Pow(10, precision)
	var new_number float64 = zeros * number
	_, mod_decimal := math.Modf(new_number)
	if mod_decimal >= decimal {
		result = math.Ceil(new_number)
	} else {
		result = math.Floor(new_number)
	}
	result /= zeros
	return result
}

func RowColFormula(details []float64) float64 {
	var result float64 = 1
	for x := 0; x < len(details); x++ {
		result *= details[x]
	}
	return result
}

func GetIndex(n *NArray, details ...float64) float64 {
	var result float64 = 0
	parameters := extract_parameters(details)
	if len(parameters) == len(n.Details) {
		for x := 0; x < len(n.Details); x++ {
			result += parameters[x] * RowColFormula(n.Details[x+1:])
		}
		return result
	} else {
		log.Fatal("incorrect shape given as index")
		return -1
	}
}

func extract_parameters(args []float64) []float64 {
	var parameters []float64

	// store the parameters in a list
	for _, p := range args {
		parameters = append(parameters, p)
	}
	return parameters
}

func NDArrayGenElements(value float64, details ...float64) []float64 {
	parameters := extract_parameters(details)
	if len(parameters) > 0 {
		dim := parameters[0]
		rem := parameters[1:]
		arr := []float64{}
		for i := 0; i < int(dim); i++ {
			arr = append(arr, NDArrayGenElements(value, rem...)...)
		}
		return arr
	} else {
		return []float64{value}
	}
}

func NDArray(details ...float64) (n *NArray) {
	parameters := extract_parameters(details)
	n = &NArray{
		Data:    NDArrayGenElements(0, details...),
		Details: parameters,
		Index:   make([]float64, len(parameters)),
	}
	return n
}

func (n *NArray) String() (array string) {
	array = "NDArray>\n("
	if len(n.Details) == 0 {
		return "NDArray>(<nil>)"
	} else {
		var i float64 = 0
		var details []float64
		var index_number float64 = n.Details[len(n.Details)-1]
		var element float64 = index_number

		// store the rows and cols number for adding [ and ] symbols
		// at appropriate places
		for index := len(n.Details) - 1; index > 0; index-- {
			details = append(details, index_number*n.Details[index-1])
			index_number = index_number * n.Details[index-1]
		}
		for i = 0; i+element <= float64(len(n.Data)); i += element {
			var array_symbol string = ""
			// add the '[' symbol at the start of every new dimension
			for _, d := range details {
				if int(i)%int(d) == 0 {
					array_symbol += "["
				}
			}
			array += strings.Repeat(" ", len(n.Details)-len(array_symbol)-1) + array_symbol

			// add the data between the '[' ']' symbols
			array += fmt.Sprint(n.Data[int(i):int(i+element)])

			array_symbol = ""

			// add the ']' symbol at the end of every new dimension
			for _, d := range details {
				if int((i+element))%int(d) == 0 {
					array_symbol += "]"
				}
			}
			array += array_symbol + strings.Repeat(" ", (len(n.Details)-len(array_symbol))-1)

			// add proper spacing for displaying arrays in presentable manner
			if i+element != float64(len(n.Data)) {
				if n.Details[0] == 1 && len(n.Details) == 2 {
					array += ""
				} else {
					if len(array_symbol) > 0 {
						array += "\n"
					}
					array += "\n"
				}
			}
		}
	}
	return array + ")"
}

func (n *NArray) GetElement(details ...float64) float64 {
	var result float64
	if int(GetIndex(n, details...)) < len(n.Data) {
		result = GetIndex(n, details...)
		return n.Data[int(result)]
	} else {
		log.Fatal("Incorrect Shape passed as an argument")
		return -1
	}
}

func (n *NArray) SetElement(details []float64, value float64) *NArray {
	var result float64
	if int(GetIndex(n, details...)) < len(n.Data) {
		result = GetIndex(n, details...)
		n.Data[int(result)] = value
	} else {
		log.Fatal("Incorrect Shape passed as an argument")
	}
	return n
}

func Range(start, end float64) (n *NArray) {
	n = Init(end - start)
	for i := start; i < end; i++ {
		n.Data = append(n.Data, i)
	}
	return n
}

func Xrange(args ...float64) (n *NArray) {
	var i float64
	number_of_args := len(args)
	parameters := extract_parameters(args)

	// now generate the array basiing on the number of arguments
	if number_of_args == 1 {
		n = Init(parameters[0])
		for i = 0; i < parameters[0]; i++ {
			n.Data = append(n.Data, i)
		}
	} else if number_of_args == 2 {
		n = Init(parameters[1] - parameters[0])
		for i = parameters[0]; i < parameters[1]; i++ {
			n.Data = append(n.Data, i)
		}
	} else if number_of_args == 3 {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, 1))
		}
	} else if number_of_args == 4 {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, parameters[3]))
		}
	} else {
		n = Init((parameters[1] - parameters[0]) / parameters[2])
		for i = parameters[0]; i < parameters[1]; i += parameters[2] {
			n.Data = append(n.Data, Round(i, 0.5, 1))
		}
	}
	return n
}
<|endoftext|>