<commit_before>package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/cobra"
)

// downloadCmd represents the download command
var downloadCmd = &cobra.Command{
	Use:     "download",
	Aliases: []string{"d"},
	Short:   "Download an exercise.",
	Long: `Download an exercise.

You may download an exercise to work on. If you've already
started working on it, the command will also download your
latest solution.

Download other people's solutions by providing the UUID.
`,
	Args: cobra.ExactArgs(0),
	RunE: func(cmd *cobra.Command, args []string) error {
		token, err := cmd.Flags().GetString("token")
		if err != nil {
			return err
		}
		if token != "" {
			RootCmd.SetArgs([]string{"configure", "--token", token})
			if err := RootCmd.Execute(); err != nil {
				return err
			}
		}
		uuid, err := cmd.Flags().GetString("uuid")
		if err != nil {
			return err
		}
		exercise, err := cmd.Flags().GetString("exercise")
		if err != nil {
			return err
		}
		if uuid == "" && exercise == "" {
			return errors.New("need an --exercise name or a solution --uuid")
		}
		usrCfg, err := config.NewUserConfig()
		if err != nil {
			return err
		}

		var slug string
		if uuid == "" {
			slug = "latest"
		} else {
			slug = uuid
		}
		url := fmt.Sprintf("%s/solutions/%s", usrCfg.APIBaseURL, slug)

		client, err := api.NewClient(usrCfg.Token, usrCfg.APIBaseURL)
		if err != nil {
			return err
		}

		req, err := client.NewRequest("GET", url, nil)
		if err != nil {
			return err
		}

		track, err := cmd.Flags().GetString("track")
		if err != nil {
			return err
		}

		if uuid == "" {
			q := req.URL.Query()
			q.Add("exercise_id", exercise)
			if track != "" {
				q.Add("track_id", track)
			}
			req.URL.RawQuery = q.Encode()
		}

		res, err := client.Do(req)
		if err != nil {
			return err
		}

		var payload downloadPayload
		defer res.Body.Close()
		if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
			return fmt.Errorf("unable to parse API response - %s", err)
		}

		if res.StatusCode == http.StatusUnauthorized {
			siteURL := config.InferSiteURL(usrCfg.APIBaseURL)
			return fmt.Errorf("unauthorized request. Please run the configure command. You can find your API token at %s/my/settings", siteURL)
		}

		if res.StatusCode != http.StatusOK {
			switch payload.Error.Type {
			case "track_ambiguous":
				return fmt.Errorf("%s: %s", payload.Error.Message, strings.Join(payload.Error.PossibleTrackIDs, ", "))
			default:
				return errors.New(payload.Error.Message)
			}
		}

		solution := workspace.Solution{
			AutoApprove: payload.Solution.Exercise.AutoApprove,
			Track:       payload.Solution.Exercise.Track.ID,
			Exercise:    payload.Solution.Exercise.ID,
			ID:          payload.Solution.ID,
			URL:         payload.Solution.URL,
			Handle:      payload.Solution.User.Handle,
			IsRequester: payload.Solution.User.IsRequester,
		}

		var ws workspace.Workspace
		if solution.IsRequester {
			ws = workspace.New(filepath.Join(usrCfg.Workspace, solution.Track))
		} else {
			ws = workspace.New(filepath.Join(usrCfg.Workspace, "users", solution.Handle, solution.Track))
		}
		os.MkdirAll(ws.Dir, os.FileMode(0755))

		dir, err := ws.SolutionPath(solution.Exercise, solution.ID)
		if err != nil {
			return err
		}

		os.MkdirAll(dir, os.FileMode(0755))

		err = solution.Write(dir)
		if err != nil {
			return err
		}

		for _, file := range payload.Solution.Files {
			url := fmt.Sprintf("%s%s", payload.Solution.FileDownloadBaseURL, file)
			req, err := client.NewRequest("GET", url, nil)
			if err != nil {
				return err
			}

			res, err := client.Do(req)
			if err != nil {
				return err
			}
			defer res.Body.Close()

			if res.StatusCode != http.StatusOK {
				// TODO: deal with it
				continue
			}
			// Don't bother with empty files.
			if res.Header.Get("Content-Length") == "0" {
				continue
			}

			// TODO: if there's a collision, interactively resolve (show diff, ask if overwrite).
			// TODO: handle --force flag to overwrite without asking.
			relativePath := filepath.FromSlash(file)
			dir := filepath.Join(solution.Dir, filepath.Dir(relativePath))
			os.MkdirAll(dir, os.FileMode(0755))

			f, err := os.Create(filepath.Join(solution.Dir, relativePath))
			if err != nil {
				return err
			}
			defer f.Close()
			_, err = io.Copy(f, res.Body)
			if err != nil {
				return err
			}
		}
		fmt.Fprintf(Err, "\nDownloaded to\n")
		fmt.Fprintf(Out, "%s\n", solution.Dir)
		return nil
	},
}

type downloadPayload struct {
	Solution struct {
		ID   string `json:"id"`
		URL  string `json:"url"`
		User struct {
			Handle      string `json:"handle"`
			IsRequester bool   `json:"is_requester"`
		} `json:"user"`
		Exercise struct {
			ID              string `json:"id"`
			InstructionsURL string `json:"instructions_url"`
			AutoApprove     bool   `json:"auto_approve"`
			Track           struct {
				ID       string `json:"id"`
				Language string `json:"language"`
			} `json:"track"`
		} `json:"exercise"`
		FileDownloadBaseURL string   `json:"file_download_base_url"`
		Files               []string `json:"files"`
		Iteration           struct {
			SubmittedAt *string `json:"submitted_at"`
		}
	} `json:"solution"`
	Error struct {
		Type             string   `json:"type"`
		Message          string   `json:"message"`
		PossibleTrackIDs []string `json:"possible_track_ids"`
	} `json:"error,omitempty"`
}

func initDownloadCmd() {
	downloadCmd.Flags().StringP("uuid", "u", "", "the solution UUID")
	downloadCmd.Flags().StringP("track", "t", "", "the track ID")
	downloadCmd.Flags().StringP("exercise", "e", "", "the exercise ID")
	downloadCmd.Flags().StringP("token", "k", "", "authentication token used to connect to the site")
}

func init() {
	RootCmd.AddCommand(downloadCmd)
	initDownloadCmd()
}
<commit_msg>Match naming convention for exercise identifiers (use 'slug')<commit_after>package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/cobra"
)

// downloadCmd represents the download command
var downloadCmd = &cobra.Command{
	Use:     "download",
	Aliases: []string{"d"},
	Short:   "Download an exercise.",
	Long: `Download an exercise.

You may download an exercise to work on. If you've already
started working on it, the command will also download your
latest solution.

Download other people's solutions by providing the UUID.
`,
	Args: cobra.ExactArgs(0),
	RunE: func(cmd *cobra.Command, args []string) error {
		token, err := cmd.Flags().GetString("token")
		if err != nil {
			return err
		}
		if token != "" {
			RootCmd.SetArgs([]string{"configure", "--token", token})
			if err := RootCmd.Execute(); err != nil {
				return err
			}
		}
		uuid, err := cmd.Flags().GetString("uuid")
		if err != nil {
			return err
		}
		exercise, err := cmd.Flags().GetString("exercise")
		if err != nil {
			return err
		}
		if uuid == "" && exercise == "" {
			return errors.New("need an --exercise name or a solution --uuid")
		}
		usrCfg, err := config.NewUserConfig()
		if err != nil {
			return err
		}

		var slug string
		if uuid == "" {
			slug = "latest"
		} else {
			slug = uuid
		}
		url := fmt.Sprintf("%s/solutions/%s", usrCfg.APIBaseURL, slug)

		client, err := api.NewClient(usrCfg.Token, usrCfg.APIBaseURL)
		if err != nil {
			return err
		}

		req, err := client.NewRequest("GET", url, nil)
		if err != nil {
			return err
		}

		track, err := cmd.Flags().GetString("track")
		if err != nil {
			return err
		}

		if uuid == "" {
			q := req.URL.Query()
			q.Add("exercise_id", exercise)
			if track != "" {
				q.Add("track_id", track)
			}
			req.URL.RawQuery = q.Encode()
		}

		res, err := client.Do(req)
		if err != nil {
			return err
		}

		var payload downloadPayload
		defer res.Body.Close()
		if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
			return fmt.Errorf("unable to parse API response - %s", err)
		}

		if res.StatusCode == http.StatusUnauthorized {
			siteURL := config.InferSiteURL(usrCfg.APIBaseURL)
			return fmt.Errorf("unauthorized request. Please run the configure command. You can find your API token at %s/my/settings", siteURL)
		}

		if res.StatusCode != http.StatusOK {
			switch payload.Error.Type {
			case "track_ambiguous":
				return fmt.Errorf("%s: %s", payload.Error.Message, strings.Join(payload.Error.PossibleTrackIDs, ", "))
			default:
				return errors.New(payload.Error.Message)
			}
		}

		solution := workspace.Solution{
			AutoApprove: payload.Solution.Exercise.AutoApprove,
			Track:       payload.Solution.Exercise.Track.ID,
			Exercise:    payload.Solution.Exercise.ID,
			ID:          payload.Solution.ID,
			URL:         payload.Solution.URL,
			Handle:      payload.Solution.User.Handle,
			IsRequester: payload.Solution.User.IsRequester,
		}

		var ws workspace.Workspace
		if solution.IsRequester {
			ws = workspace.New(filepath.Join(usrCfg.Workspace, solution.Track))
		} else {
			ws = workspace.New(filepath.Join(usrCfg.Workspace, "users", solution.Handle, solution.Track))
		}
		os.MkdirAll(ws.Dir, os.FileMode(0755))

		dir, err := ws.SolutionPath(solution.Exercise, solution.ID)
		if err != nil {
			return err
		}

		os.MkdirAll(dir, os.FileMode(0755))

		err = solution.Write(dir)
		if err != nil {
			return err
		}

		for _, file := range payload.Solution.Files {
			url := fmt.Sprintf("%s%s", payload.Solution.FileDownloadBaseURL, file)
			req, err := client.NewRequest("GET", url, nil)
			if err != nil {
				return err
			}

			res, err := client.Do(req)
			if err != nil {
				return err
			}
			defer res.Body.Close()

			if res.StatusCode != http.StatusOK {
				// TODO: deal with it
				continue
			}
			// Don't bother with empty files.
			if res.Header.Get("Content-Length") == "0" {
				continue
			}

			// TODO: if there's a collision, interactively resolve (show diff, ask if overwrite).
			// TODO: handle --force flag to overwrite without asking.
			relativePath := filepath.FromSlash(file)
			dir := filepath.Join(solution.Dir, filepath.Dir(relativePath))
			os.MkdirAll(dir, os.FileMode(0755))

			f, err := os.Create(filepath.Join(solution.Dir, relativePath))
			if err != nil {
				return err
			}
			defer f.Close()
			_, err = io.Copy(f, res.Body)
			if err != nil {
				return err
			}
		}
		fmt.Fprintf(Err, "\nDownloaded to\n")
		fmt.Fprintf(Out, "%s\n", solution.Dir)
		return nil
	},
}

type downloadPayload struct {
	Solution struct {
		ID   string `json:"id"`
		URL  string `json:"url"`
		User struct {
			Handle      string `json:"handle"`
			IsRequester bool   `json:"is_requester"`
		} `json:"user"`
		Exercise struct {
			ID              string `json:"id"`
			InstructionsURL string `json:"instructions_url"`
			AutoApprove     bool   `json:"auto_approve"`
			Track           struct {
				ID       string `json:"id"`
				Language string `json:"language"`
			} `json:"track"`
		} `json:"exercise"`
		FileDownloadBaseURL string   `json:"file_download_base_url"`
		Files               []string `json:"files"`
		Iteration           struct {
			SubmittedAt *string `json:"submitted_at"`
		}
	} `json:"solution"`
	Error struct {
		Type             string   `json:"type"`
		Message          string   `json:"message"`
		PossibleTrackIDs []string `json:"possible_track_ids"`
	} `json:"error,omitempty"`
}

func initDownloadCmd() {
	downloadCmd.Flags().StringP("uuid", "u", "", "the solution UUID")
	downloadCmd.Flags().StringP("track", "t", "", "the track ID")
	downloadCmd.Flags().StringP("exercise", "e", "", "the exercise slug")
	downloadCmd.Flags().StringP("token", "k", "", "authentication token used to connect to the site")
}

func init() {
	RootCmd.AddCommand(downloadCmd)
	initDownloadCmd()
}
<|endoftext|>


<commit_before>// Copyright 2014, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// A high performance pseudo-random number generator.
package main

import "os"
import "io"
import "fmt"
import "math"
import "syscall"
import "runtime"
import "unsafe"
import "github.com/ogier/pflag"
import "bitbucket.org/rawr/gorandom/rand"
import "bitbucket.org/rawr/golib/strconv"

// Check if the given file descriptor writes to a terminal.
func isatty(fd int) bool {
	// TODO(jtsai): This only works on Linux! Support OSX and Windows.
	var termios syscall.Termios
	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
	return err == 0
}

func main() {
	// Basic user configuration variables
	count := pflag.StringP("count", "n", "+Inf", "Number of random bytes to generate.")
	force := pflag.BoolP("force", "f", false, "Force output to terminal.")
	procs := pflag.IntP("procs", "p", runtime.NumCPU(), "Maximum number of concurrent workers.")
	pflag.Parse()

	if !(*force) && isatty(syscall.Stdout) {
		fmt.Fprintf(os.Stderr, "Random data not written to terminal.\n\n")
		pflag.Usage()
		os.Exit(1)
	}
	if (*procs) < 1 {
		fmt.Fprintf(os.Stderr, "Number of workers must be positive.\n\n")
		pflag.Usage()
		os.Exit(1)
	}
	cnt, err := strconv.ParsePrefix(*count, strconv.AutoParse)
	if err != nil || math.IsNaN(cnt) {
		fmt.Fprintf(os.Stderr, "Number of bytes to generate is invalid.\n\n")
		pflag.Usage()
		os.Exit(1)
	}

	runtime.GOMAXPROCS(*procs)
	rand.SetNumRoutines(*procs)

	// Copy random data to stdout
	if int64(cnt) < 0 || math.IsInf(cnt, 0) {
		_, err = io.Copy(os.Stdout, rand.Reader)
	} else {
		_, err = io.CopyN(os.Stdout, rand.Reader, int64(cnt))
	}
	if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EPIPE {
		err = nil // Expected error is for the sink to close the pipe
	} else if err != nil {
		panic(err)
	}
}
<commit_msg>Used ssh library for platform independent TTY check<commit_after>// Copyright 2014, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// A high performance pseudo-random number generator.
package main

import "os"
import "io"
import "fmt"
import "math"
import "syscall"
import "runtime"
import "golang.org/x/crypto/ssh/terminal"
import "github.com/ogier/pflag"
import "bitbucket.org/rawr/gorandom/rand"
import "bitbucket.org/rawr/golib/strconv"

func main() {
	// Basic user configuration variables
	count := pflag.StringP("count", "n", "+Inf", "Number of random bytes to generate.")
	force := pflag.BoolP("force", "f", false, "Force output to terminal.")
	procs := pflag.IntP("procs", "p", runtime.NumCPU(), "Maximum number of concurrent workers.")
	pflag.Parse()

	if !(*force) && terminal.IsTerminal(int(os.Stdout.Fd())) {
		fmt.Fprintf(os.Stderr, "Random data not written to terminal.\n\n")
		pflag.Usage()
		os.Exit(1)
	}
	if (*procs) < 1 {
		fmt.Fprintf(os.Stderr, "Number of workers must be positive.\n\n")
		pflag.Usage()
		os.Exit(1)
	}
	cnt, err := strconv.ParsePrefix(*count, strconv.AutoParse)
	if err != nil || math.IsNaN(cnt) {
		fmt.Fprintf(os.Stderr, "Number of bytes to generate is invalid.\n\n")
		pflag.Usage()
		os.Exit(1)
	}

	runtime.GOMAXPROCS(*procs)
	rand.SetNumRoutines(*procs)

	// Copy random data to stdout
	if int64(cnt) < 0 || math.IsInf(cnt, 0) {
		_, err = io.Copy(os.Stdout, rand.Reader)
	} else {
		_, err = io.CopyN(os.Stdout, rand.Reader, int64(cnt))
	}
	if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EPIPE {
		err = nil // Expected error is for the sink to close the pipe
	} else if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/ivpusic/golog"
	"github.com/ivpusic/neo"
	"github.com/ivpusic/neo/cmd/neo/scripts"
	"gopkg.in/alecthomas/kingpin.v1"
)

var (
	logger = golog.GetLogger("github.com/ivpusic/neo")
	app    = kingpin.New("Neo", "Command line tool to managing your Neo application")

	// run command
	run        = app.Command("run", "Run Neo application")
	mainFile   = run.Arg("program", "Main file").String()
	configFile = run.Flag("config", "Path to configuration file").Short('c').String()
	verbose    = run.Flag("verbose", "Run in verbose mode").Short('v').Bool()

	// new commmand
	newCmd       = app.Command("new", "Create new Neo application")
	projectName  = newCmd.Arg("name", "Project name").String()
	templateName = newCmd.Flag("tpl", "Create new Neo application based on some template.").Short('t').String()
)

///////////////////////////////////////////////////////////////////
// `run` command
///////////////////////////////////////////////////////////////////

func handleRunCommand() {
	config := &neo.Conf{}

	// check if provided main file exists
	if len(*mainFile) > 0 {
		stat, err := os.Stat(*mainFile)
		if err != nil {
			logger.Errorf("Please provide valid main file. `%s` not found!", *mainFile)
			os.Exit(0)
		} else if stat.IsDir() {
			logger.Errorf("Please provide valid main file. `%s` not valid!", *mainFile)
			os.Exit(0)
		}
	}

	// find project root
	mainFileAbs, err := filepath.Abs(*mainFile)
	if err != nil {
		panic(err)
	}

	// if configuration is not provided by CLI,
	// try to figure out where it could be
	if len(*configFile) == 0 {
		if len(*mainFile) > 0 {
			projectRoot := filepath.Dir(mainFileAbs)
			*configFile = path.Join(projectRoot, "config.toml")
		} else {
			cwd, _ := os.Getwd()
			*configFile = path.Join(cwd, "config.toml")
		}

		// if config file doesn't exists,
		// fallback to empty configuration file -> defaults will be used
		_, err := os.Stat(*configFile)
		if err != nil {
			logger.Warnf("Configuration file at %s not found!", *configFile)
			*configFile = ""
		}
	}

	// parse configuration
	config.Parse(*configFile)

	arguments := []string{}

	// ignore files
	if len(config.Hotreload.Ignore) > 0 {
		arguments = append(arguments, "-i", strings.Join(config.Hotreload.Ignore, ","))
	}

	// suffixes to watch
	if len(config.Hotreload.Suffixes) > 0 {
		arguments = append(arguments, "-s", strings.Join(config.Hotreload.Suffixes, ","))
	}

	// app arguments
	config.App.Args = append(config.App.Args, "--config", *configFile)
	arguments = append(arguments, "-a"+strings.Join(config.App.Args, ","))

	// verbose
	if *verbose {
		arguments = append(arguments, "-v")
	}

	rerun, err := runCmd("rerun", arguments)
	if err != nil {
		logger.Errorf("Error while running rerun command! %s", err.Error())
		os.Exit(0)
	}

	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// on ctrl+c remove build files
	go func(proc *os.Process) {
		<-sigs
		proc.Signal(syscall.SIGTERM)
		os.Exit(0)
	}(rerun.Process)

	err = rerun.Wait()
	if err != nil {
		logger.Errorf("Error while running rerun command! %s", err.Error())
		os.Exit(0)
	}
}

///////////////////////////////////////////////////////////////////
// `new` command
///////////////////////////////////////////////////////////////////

func handleNewCommand() {
	currentLocation, err := os.Getwd()
	if err != nil {
		logger.Error(err.Error())
		os.Exit(0)
	}
	projectLocation := currentLocation + "/" + *projectName

	var template scripts.Template = nil

	if len(*templateName) == 0 {
		logger.Info("Creating Neo project")
		template = &scripts.NeoTemplate{}
	} else {
		switch *templateName {
		case "angular":
			logger.Info("Creating Neo Angular project")
			template = &scripts.AngularTemplate{}
		case "html":
			logger.Info("Creating Neo HTML project")
			template = &scripts.NeoHtmlTemplate{}
		}
	}

	if template == nil {
		logger.Errorf("Unkonown template %s!", *templateName)
	} else {
		template.Build(projectLocation)
	}
}

///////////////////////////////////////////////////////////////////
// main
///////////////////////////////////////////////////////////////////

func main() {
	logger.Level = golog.INFO

	app.Version("1.0.0")

	// install dependencies
	outputCmd("go", []string{"get", "github.com/ivpusic/reload"})

	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case run.FullCommand():
		handleRunCommand()
	case newCmd.FullCommand():
		handleNewCommand()
	default:
		app.Usage(os.Stdout)
	}
}
<commit_msg>exit with non-zero in case of error<commit_after>package main

import (
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/ivpusic/golog"
	"github.com/ivpusic/neo"
	"github.com/ivpusic/neo/cmd/neo/scripts"
	"gopkg.in/alecthomas/kingpin.v1"
)

var (
	logger = golog.GetLogger("github.com/ivpusic/neo")
	app    = kingpin.New("Neo", "Command line tool to managing your Neo application")

	// run command
	run        = app.Command("run", "Run Neo application")
	mainFile   = run.Arg("program", "Main file").String()
	configFile = run.Flag("config", "Path to configuration file").Short('c').String()
	verbose    = run.Flag("verbose", "Run in verbose mode").Short('v').Bool()

	// new commmand
	newCmd       = app.Command("new", "Create new Neo application")
	projectName  = newCmd.Arg("name", "Project name").String()
	templateName = newCmd.Flag("tpl", "Create new Neo application based on some template.").Short('t').String()
)

///////////////////////////////////////////////////////////////////
// `run` command
///////////////////////////////////////////////////////////////////

func handleRunCommand() {
	config := &neo.Conf{}

	// check if provided main file exists
	if len(*mainFile) > 0 {
		stat, err := os.Stat(*mainFile)
		if err != nil {
			logger.Errorf("Please provide valid main file. `%s` not found!", *mainFile)
			os.Exit(0)
		} else if stat.IsDir() {
			logger.Errorf("Please provide valid main file. `%s` not valid!", *mainFile)
			os.Exit(0)
		}
	}

	// find project root
	mainFileAbs, err := filepath.Abs(*mainFile)
	if err != nil {
		panic(err)
	}

	// if configuration is not provided by CLI,
	// try to figure out where it could be
	if len(*configFile) == 0 {
		if len(*mainFile) > 0 {
			projectRoot := filepath.Dir(mainFileAbs)
			*configFile = path.Join(projectRoot, "config.toml")
		} else {
			cwd, _ := os.Getwd()
			*configFile = path.Join(cwd, "config.toml")
		}

		// if config file doesn't exists,
		// fallback to empty configuration file -> defaults will be used
		_, err := os.Stat(*configFile)
		if err != nil {
			logger.Warnf("Configuration file at %s not found!", *configFile)
			*configFile = ""
		}
	}

	// parse configuration
	config.Parse(*configFile)

	arguments := []string{}

	// ignore files
	if len(config.Hotreload.Ignore) > 0 {
		arguments = append(arguments, "-i", strings.Join(config.Hotreload.Ignore, ","))
	}

	// suffixes to watch
	if len(config.Hotreload.Suffixes) > 0 {
		arguments = append(arguments, "-s", strings.Join(config.Hotreload.Suffixes, ","))
	}

	// app arguments
	config.App.Args = append(config.App.Args, "--config", *configFile)
	arguments = append(arguments, "-a"+strings.Join(config.App.Args, ","))

	// verbose
	if *verbose {
		arguments = append(arguments, "-v")
	}

	rerun, err := runCmd("rerun", arguments)
	if err != nil {
		logger.Errorf("Error while running rerun command! %s", err.Error())
		os.Exit(1)
	}

	sigs := make(chan os.Signal)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// on ctrl+c remove build files
	go func(proc *os.Process) {
		<-sigs
		proc.Signal(syscall.SIGTERM)
		os.Exit(0)
	}(rerun.Process)

	err = rerun.Wait()
	if err != nil {
		logger.Errorf("Error while running rerun command! %s", err.Error())
		os.Exit(1)
	}
}

///////////////////////////////////////////////////////////////////
// `new` command
///////////////////////////////////////////////////////////////////

func handleNewCommand() {
	currentLocation, err := os.Getwd()
	if err != nil {
		logger.Error(err.Error())
		os.Exit(0)
	}
	projectLocation := currentLocation + "/" + *projectName

	var template scripts.Template = nil

	if len(*templateName) == 0 {
		logger.Info("Creating Neo project")
		template = &scripts.NeoTemplate{}
	} else {
		switch *templateName {
		case "angular":
			logger.Info("Creating Neo Angular project")
			template = &scripts.AngularTemplate{}
		case "html":
			logger.Info("Creating Neo HTML project")
			template = &scripts.NeoHtmlTemplate{}
		}
	}

	if template == nil {
		logger.Errorf("Unkonown template %s!", *templateName)
	} else {
		template.Build(projectLocation)
	}
}

///////////////////////////////////////////////////////////////////
// main
///////////////////////////////////////////////////////////////////

func main() {
	logger.Level = golog.INFO

	app.Version("1.0.0")

	// install dependencies
	outputCmd("go", []string{"get", "github.com/ivpusic/reload"})

	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case run.FullCommand():
		handleRunCommand()
	case newCmd.FullCommand():
		handleNewCommand()
	default:
		app.Usage(os.Stdout)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"log"
	"os/exec"
	"github.com/fsnotify/fsnotify"
	"errors"
	"github.com/urfave/cli"
	"fmt"
)

var (
	errFlagRunIsPresent = errors.New("flag --run or -r is required ")
)

func main() {
	app := cli.NewApp()
	app.Name = "owl"
	app.Usage = "owl watching all files in directory and when are changed, run the command"

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version",
		Usage: "print only the version",
	}

	app.Flags = []cli.Flag{
		cli.StringSliceFlag{
			Name: "ignore, i",
			Usage:"All directories with name `IGNORE` are ignored",
		},
		cli.StringSliceFlag{
			Name: "run, r",
			Usage:"If is any file changed, run `RUN`",
		},
		cli.BoolFlag{
			Name: "verbose, v",
			Usage:"verbose mode",
		},

	}

	app.Action = func(c *cli.Context) error {

		if c.String("run") == "" {
			return errFlagRunIsPresent
		}

		// set new watcher
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			panic(err)
		}

		// get path to this dir
		path, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		// append path to global paths
		dirList := []string{}

		// this files are ignore
		ignoreList := make(map[string]bool)
		for _, dir := range (c.StringSlice("ignore")) {
			ignoreList[dir] = true
		}

		err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// check if file is not in ignorelist
			if ignoreList[info.Name()] {
				return filepath.SkipDir
			}

			// append dir to list
			if info.IsDir() {
				dirList = append(dirList, path)
			}
			return nil
		})

		if err != nil {
			log.Fatal(err)
		}

		// add all paths for watching
		for _, path := range dirList {
			watcher.Add(path)
		}

		for {
			select {
			case ev := <-watcher.Events:

				// Write is running only once
				if ev.Op == fsnotify.Chmod {
					// execute of function with arguments
					if c.Bool("verbose") {
						log.Println(ev.Name)
					}

					for _, r := range c.StringSlice("run") {
						output, err := exec.Command("bash", "-c", r).CombinedOutput()
						if err != nil {
							os.Stderr.WriteString(err.Error())
						}
						fmt.Print(string(output))
					}

				}

			case err := <-watcher.Errors:
				return err
			}
		}

		return nil
	}

	app.Run(os.Args)

}
<commit_msg>feat(killing) Killing running processes<commit_after>package main

import (
	"os"
	"path/filepath"
	"log"
	"os/exec"
	"github.com/fsnotify/fsnotify"
	"errors"
	"github.com/urfave/cli"
	"fmt"
)

var (
	errFlagRunIsPresent = errors.New("flag --run or -r is required ")
)

func main() {
	app := cli.NewApp()
	app.Name = "owl"
	app.Usage = "owl watching all files in directory and when are changed, run the command"

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version",
		Usage: "print only the version",
	}

	app.Flags = []cli.Flag{
		cli.StringSliceFlag{
			Name: "ignore, i",
			Usage:"All directories with name `IGNORE` are ignored",
		},
		cli.StringFlag{
			Name: "run, r",
			Usage:"If is any file changed, run `RUN`",
		},
		cli.BoolFlag{
			Name: "verbose, v",
			Usage:"verbose mode",
		},

	}

	app.Action = func(c *cli.Context) error {

		if c.String("run") == "" {
			return errFlagRunIsPresent
		}

		// set new watcher
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			panic(err)
		}

		// get path to this dir
		path, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		// append path to global paths
		dirList := []string{}

		// this files are ignore
		ignoreList := make(map[string]bool)
		for _, dir := range (c.StringSlice("ignore")) {
			ignoreList[dir] = true
		}

		err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}

			// check if file is not in ignorelist
			if ignoreList[info.Name()] {
				return filepath.SkipDir
			}

			// append dir to list
			if info.IsDir() {
				dirList = append(dirList, path)
			}
			return nil
		})

		if err != nil {
			log.Fatal(err)
		}

		// add all paths for watching
		for _, path := range dirList {
			watcher.Add(path)
		}

		var command *exec.Cmd = nil

		for {
			select {
			case ev := <-watcher.Events:

				// Write is running only once
				if ev.Op == fsnotify.Chmod {
					// execute of function with arguments
					if c.Bool("verbose") {
						log.Println(ev.Name)
					}

					if command != nil {
						err := command.Process.Kill()
						if err != nil && err.Error() != "os: process already finished" {
							panic(err)
						}
						command = nil
					}

					go func() {
						command = exec.Command("bash", "-c", c.String("r"))

						out, _ := command.CombinedOutput()
						fmt.Print(string(out))
					}()

				}

			case err := <-watcher.Errors:
				return err
			}
		}

		return nil
	}

	app.Run(os.Args)

}
<|endoftext|>


<commit_before>// Copyright © 2017 G. Hussain Chinoy <ghchinoy@gmail.com>
//
// 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 cmd

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"

	toml "github.com/pelletier/go-toml"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// profilesCmd represents the profile command
var profilesCmd = &cobra.Command{
	Use:   "profiles",
	Short: "Manage profiles",
	Long:  `Add, remove, list profiles to manage Cloud Elements access`,
}

// addProfileCmd represents the addProfile command
var addProfileCmd = &cobra.Command{
	Use:   "add <profile>",
	Short: "add a new profile",
	Long:  `Adds a new profile to the available profiles. Provide a name to get started.`,
	Run: func(cmd *cobra.Command, args []string) {
		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		} else {
			fmt.Println("please provide a profile name to add, profile add <name>")
			os.Exit(1)
		}
		fmt.Printf("%7s: %s\n", "profile", profile)
		if viper.IsSet(profile) {
			fmt.Printf("Profile %s exists.\n", profile)
			os.Exit(1)
		}
		reader := bufio.NewReader(os.Stdin)
		fmt.Print("base URI: ")
		base, _ := reader.ReadString('\n')
		base = strings.Replace(base, "\n", "", -1)
		fmt.Print("user token: ")
		user, _ := reader.ReadString('\n')
		user = strings.Replace(user, "\n", "", -1)
		fmt.Print("org token: ")
		org, _ := reader.ReadString('\n')
		org = strings.Replace(org, "\n", "", -1)

		viper.Set(profile+".base", base)
		viper.Set(profile+".org", org)
		viper.Set(profile+".user", user)

		err := writeConfigAs(viper.ConfigFileUsed(), true)
		if err != nil {
			fmt.Println("Unable to write config file", err.Error())
			fmt.Printf("Config file %s unchanged.\n", viper.ConfigFileUsed())
		}
		fmt.Printf("Added profile %s\n", profile)
	},
}

// listProfilesCmd represents the listProfiles command
var listProfilesCmd = &cobra.Command{
	Use:   "list",
	Short: "lists available profiles",
	Long:  `Lists available profiles`,
	Run: func(cmd *cobra.Command, args []string) {
		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		}
		fmt.Printf("%7s: %s", "profile", profile)
		if viper.IsSet(profile) {
			p := viper.GetStringMap(profile)

			if val, ok := p["label"]; ok {
				fmt.Printf(" (%s)\n", val)
			} else {
				fmt.Println()
			}

			for k, v := range p {
				if k == "base" {
					fmt.Printf("%7s: %s\n", k, v)
				}
			}
		} else {
			fmt.Printf("No %s profile exists in config file %s.", profile, cfgFile)
		}
		fmt.Println()
		settings := viper.AllSettings()
		var profiles []string
		for k := range settings {
			profiles = append(profiles, k)
		}
		sort.Strings(profiles)
		posn := sort.SearchStrings(profiles, "profile")
		profiles = append(profiles[:posn], profiles[posn+1:]...)
		fmt.Println("Valid profiles:", strings.Join(profiles, ", "))
	},
}

// setProfileCmd represents the setProfile command
var setProfileCmd = &cobra.Command{
	Use:   "set <profile>",
	Short: "sets a profile to be the default profile",
	Long:  `Sets given profile name as the default profile`,
	Run: func(cmd *cobra.Command, args []string) {

		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		}
		fmt.Printf("%7s: %s\n", "profile", profile)
		// check if specified profile exists
		if viper.IsSet(profile) {
			p := viper.GetStringMap(profile)

			// copy profile data to default, update label
			// indicate change has occurred

			viper.Set("default.base", p["base"])
			viper.Set("default.org", p["org"])
			viper.Set("default.user", p["user"])
			viper.Set("default.label", profile)

			// writing back has a PR to make this more formal: https://github.com/spf13/viper/pull/287
			// Once that PR is merged, replace writeConfigFile with
			/*
				if err := viper.WriteConfigAs(viper.ConfigFileUsed()); err != nil {
					fmt.Fatal(err)
				}
			*/
			err := writeConfigAs(viper.ConfigFileUsed(), true)
			if err != nil {
				fmt.Println("Unable to write config file", err.Error())
				fmt.Printf("Config file %s unchanged.\n", viper.ConfigFileUsed())
			}
			fmt.Printf("Default profile set to %s\n", profile)

			for k, v := range p {
				if k == "base" {
					fmt.Printf("%7s: %s\n", k, v)
				}
				if k == "label" {
					fmt.Printf("%7s: %s\n", k, v)
				}
			}
		} else { // if not, end
			fmt.Printf("No %s profile exists in config file %s.\n", profile, cfgFile)
			fmt.Printf("Cannot set %s as default profile.\n", profile)
			fmt.Println()
			settings := viper.AllSettings()
			var profiles []string
			for k := range settings {
				profiles = append(profiles, k)
			}
			sort.Strings(profiles)
			posn := sort.SearchStrings(profiles, "profile")
			profiles = append(profiles[:posn], profiles[posn+1:]...)
			fmt.Println("Valid profiles:", strings.Join(profiles, ", "))
		}
	},
}

func writeConfigAs(filename string, force bool) error {

	t, err := toml.TreeFromMap(viper.AllSettings())
	if err != nil {
		return err
	}
	s := t.String()

	var flags int
	if force == true {
		flags = os.O_CREATE | os.O_TRUNC | os.O_WRONLY
	} else {
		if _, err := os.Stat(filename); os.IsNotExist(err) {
			flags = os.O_WRONLY
		} else {
			return fmt.Errorf("file: %s exists - cannot overwrite, use force option", filename)
		}
	}

	var AppFs = afero.NewOsFs()
	f, err := AppFs.OpenFile(filename, flags, os.FileMode(0644))
	if err != nil {
		return err
	}

	_, err = f.WriteString(s)

	return nil
}

func init() {
	RootCmd.AddCommand(profilesCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// profileCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// profileCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	profilesCmd.PersistentFlags().StringVar(&cfgFile, "config", "", cfgHelp)
	profilesCmd.PersistentFlags().StringVar(&profile, "profile", "default", "profile name")
	// Set bash-completion
	validConfigFilenames := []string{"toml", ""}
	profilesCmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)

	profilesCmd.AddCommand(listProfilesCmd)
	profilesCmd.AddCommand(addProfileCmd)
	profilesCmd.AddCommand(setProfileCmd)

}
<commit_msg>Adds a --long flag to show a table list of profile info<commit_after>// Copyright © 2017 G. Hussain Chinoy <ghchinoy@gmail.com>
//
// 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 cmd

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/olekukonko/tablewriter"
	toml "github.com/pelletier/go-toml"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// profilesCmd represents the profile command
var profilesCmd = &cobra.Command{
	Use:   "profiles",
	Short: "Manage profiles",
	Long:  `Add, remove, list profiles to manage Cloud Elements access`,
}

// addProfileCmd represents the addProfile command
var addProfileCmd = &cobra.Command{
	Use:   "add <profile>",
	Short: "add a new profile",
	Long:  `Adds a new profile to the available profiles. Provide a name to get started.`,
	Run: func(cmd *cobra.Command, args []string) {
		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		} else {
			fmt.Println("please provide a profile name to add, profile add <name>")
			os.Exit(1)
		}
		fmt.Printf("%7s: %s\n", "profile", profile)
		if viper.IsSet(profile) {
			fmt.Printf("Profile %s exists.\n", profile)
			os.Exit(1)
		}
		reader := bufio.NewReader(os.Stdin)
		fmt.Print("base URI: ")
		base, _ := reader.ReadString('\n')
		base = strings.Replace(base, "\n", "", -1)
		fmt.Print("user token: ")
		user, _ := reader.ReadString('\n')
		user = strings.Replace(user, "\n", "", -1)
		fmt.Print("org token: ")
		org, _ := reader.ReadString('\n')
		org = strings.Replace(org, "\n", "", -1)

		viper.Set(profile+".base", base)
		viper.Set(profile+".org", org)
		viper.Set(profile+".user", user)

		err := writeConfigAs(viper.ConfigFileUsed(), true)
		if err != nil {
			fmt.Println("Unable to write config file", err.Error())
			fmt.Printf("Config file %s unchanged.\n", viper.ConfigFileUsed())
		}
		fmt.Printf("Added profile %s\n", profile)
	},
}

var longProfile bool

// listProfilesCmd represents the listProfiles command
var listProfilesCmd = &cobra.Command{
	Use:   "list",
	Short: "lists available profiles",
	Long:  `Lists available profiles`,
	Run: func(cmd *cobra.Command, args []string) {
		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		}
		fmt.Printf("%7s: %s", "profile", profile)
		if viper.IsSet(profile) {
			p := viper.GetStringMap(profile)

			if val, ok := p["label"]; ok {
				fmt.Printf(" (%s)\n", val)
			} else {
				fmt.Println()
			}

			for k, v := range p {
				if k == "base" {
					fmt.Printf("%7s: %s\n", k, v)
				}
			}
		} else {
			fmt.Printf("No %s profile exists in config file %s.", profile, cfgFile)
		}
		fmt.Println()
		settings := viper.AllSettings()
		var profiles []string
		for k := range settings {
			profiles = append(profiles, k)
		}
		sort.Strings(profiles)
		if longProfile {
			data := [][]string{}
			fmt.Printf("%v profiles\n", len(profiles))
			for _, k := range profiles {
				if k == "profile" {
					break
				}
				v := settings[k].(map[string]interface{})
				if v["base"] == nil {
					break
				}
				data = append(data, []string{
					k,
					fmt.Sprintf("%s", v["base"]),
				})
			}
			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{"profile", "base url"})
			table.SetBorder(false)
			table.SetAlignment(tablewriter.ALIGN_LEFT)
			table.AppendBulk(data)
			table.Render()
			os.Exit(0)
		}
		posn := sort.SearchStrings(profiles, "profile")
		profiles = append(profiles[:posn], profiles[posn+1:]...)
		fmt.Println("Valid profiles:", strings.Join(profiles, ", "))
	},
}

// setProfileCmd represents the setProfile command
var setProfileCmd = &cobra.Command{
	Use:   "set <profile>",
	Short: "sets a profile to be the default profile",
	Long:  `Sets given profile name as the default profile`,
	Run: func(cmd *cobra.Command, args []string) {

		// check for args, if arg, then list the details for that particular profile
		if len(args) > 0 {
			profile = args[0]
		}
		fmt.Printf("%7s: %s\n", "profile", profile)
		// check if specified profile exists
		if viper.IsSet(profile) {
			p := viper.GetStringMap(profile)

			// copy profile data to default, update label
			// indicate change has occurred

			viper.Set("default.base", p["base"])
			viper.Set("default.org", p["org"])
			viper.Set("default.user", p["user"])
			viper.Set("default.label", profile)

			// writing back has a PR to make this more formal: https://github.com/spf13/viper/pull/287
			// Once that PR is merged, replace writeConfigFile with
			/*
				if err := viper.WriteConfigAs(viper.ConfigFileUsed()); err != nil {
					fmt.Fatal(err)
				}
			*/
			err := writeConfigAs(viper.ConfigFileUsed(), true)
			if err != nil {
				fmt.Println("Unable to write config file", err.Error())
				fmt.Printf("Config file %s unchanged.\n", viper.ConfigFileUsed())
			}
			fmt.Printf("Default profile set to %s\n", profile)

			for k, v := range p {
				if k == "base" {
					fmt.Printf("%7s: %s\n", k, v)
				}
				if k == "label" {
					fmt.Printf("%7s: %s\n", k, v)
				}
			}
		} else { // if not, end
			fmt.Printf("No %s profile exists in config file %s.\n", profile, cfgFile)
			fmt.Printf("Cannot set %s as default profile.\n", profile)
			fmt.Println()
			settings := viper.AllSettings()
			var profiles []string
			for k := range settings {
				profiles = append(profiles, k)
			}
			sort.Strings(profiles)
			posn := sort.SearchStrings(profiles, "profile")
			profiles = append(profiles[:posn], profiles[posn+1:]...)
			fmt.Println("Valid profiles:", strings.Join(profiles, ", "))
		}
	},
}

func writeConfigAs(filename string, force bool) error {

	t, err := toml.TreeFromMap(viper.AllSettings())
	if err != nil {
		return err
	}
	s := t.String()

	var flags int
	if force == true {
		flags = os.O_CREATE | os.O_TRUNC | os.O_WRONLY
	} else {
		if _, err := os.Stat(filename); os.IsNotExist(err) {
			flags = os.O_WRONLY
		} else {
			return fmt.Errorf("file: %s exists - cannot overwrite, use force option", filename)
		}
	}

	var AppFs = afero.NewOsFs()
	f, err := AppFs.OpenFile(filename, flags, os.FileMode(0644))
	if err != nil {
		return err
	}

	_, err = f.WriteString(s)

	return nil
}

func init() {
	RootCmd.AddCommand(profilesCmd)

	profilesCmd.PersistentFlags().StringVar(&cfgFile, "config", "", cfgHelp)
	profilesCmd.PersistentFlags().StringVar(&profile, "profile", "default", "profile name")
	// Set bash-completion
	validConfigFilenames := []string{"toml", ""}
	profilesCmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)

	profilesCmd.AddCommand(listProfilesCmd)
	listProfilesCmd.PersistentFlags().BoolVarP(&longProfile, "long", "l", false, "show long profile")
	profilesCmd.AddCommand(addProfileCmd)
	profilesCmd.AddCommand(setProfileCmd)

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/auction/communication/http/auction_http_handlers"
	auctionroutes "github.com/cloudfoundry-incubator/auction/communication/http/routes"
	"github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/executor"
	executorclient "github.com/cloudfoundry-incubator/executor/http/client"
	"github.com/cloudfoundry-incubator/rep/auction_cell_rep"
	"github.com/cloudfoundry-incubator/rep/generator"
	"github.com/cloudfoundry-incubator/rep/harmonizer"
	repserver "github.com/cloudfoundry-incubator/rep/http_server"
	"github.com/cloudfoundry-incubator/rep/lrp_stopper"
	"github.com/cloudfoundry-incubator/rep/maintain"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/bbs/lock_bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	bbsroutes "github.com/cloudfoundry-incubator/runtime-schema/routes"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/cloudfoundry/storeadapter/etcdstoreadapter"
	"github.com/nu7hatch/gouuid"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/localip"
	"github.com/pivotal-golang/operationq"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/tedsuo/rata"
)

var etcdCluster = flag.String(
	"etcdCluster",
	"http://127.0.0.1:4001",
	"comma-separated list of etcd addresses (http://ip:port)",
)

var heartbeatInterval = flag.Duration(
	"heartbeatInterval",
	lock_bbs.HEARTBEAT_INTERVAL,
	"the interval between heartbeats for maintaining presence",
)

var executorURL = flag.String(
	"executorURL",
	"http://127.0.0.1:1700",
	"location of executor to represent",
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:1800",
	"host:port to serve auction and LRP stop requests on",
)

var stack = flag.String(
	"stack",
	"",
	"the rep stack - must be specified",
)

var cellID = flag.String(
	"cellID",
	"",
	"the ID used by the rep to identify itself to external systems - must be specified",
)

var zone = flag.String(
	"zone",
	"",
	"the availability zone associated with the rep",
)

var pollingInterval = flag.Duration(
	"pollingInterval",
	30*time.Second,
	"the interval on which to scan the executor",
)

const (
	dropsondeDestination = "localhost:3457"
	dropsondeOrigin      = "rep"
)

func main() {
	cf_debug_server.AddFlags(flag.CommandLine)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger := cf_lager.New("rep")
	initializeDropsonde(logger)

	if *cellID == "" {
		log.Fatalf("-cellID must be specified")
	}

	if *stack == "" {
		log.Fatalf("-stack must be specified")
	}

	bbs := initializeRepBBS(logger)
	executorClient := executorclient.New(http.DefaultClient, *executorURL)
	server, address := initializeServer(bbs, executorClient, logger)
	opGenerator := generator.New(*cellID, bbs, executorClient)

	// only one outstanding operation per container is necessary
	queue := operationq.NewSlidingQueue(1)

	members := grouper.Members{
		{"server", server},
		{"heartbeater", initializeCellHeartbeat(address, bbs, executorClient, logger)},
		{"bulker", harmonizer.NewBulker(logger, *pollingInterval, timeprovider.NewTimeProvider(), opGenerator, queue)},
		{"event-consumer", harmonizer.NewEventConsumer(logger, opGenerator, queue)},
	}

	if dbgAddr := cf_debug_server.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{
			{"debug-server", cf_debug_server.Runner(dbgAddr)},
		}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)

	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started", lager.Data{"cell-id": *cellID})

	<-monitor.Wait()
	logger.Info("shutting-down")
}

func initializeDropsonde(logger lager.Logger) {
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed to initialize dropsonde: %v", err)
	}
}

func initializeCellHeartbeat(address string, bbs Bbs.RepBBS, executorClient executor.Client, logger lager.Logger) ifrit.Runner {
	cellPresence := models.CellPresence{
		CellID:     *cellID,
		RepAddress: address,
		Stack:      *stack,
		Zone:       *zone,
	}

	heartbeat := bbs.NewCellHeartbeat(cellPresence, *heartbeatInterval)
	return maintain.New(executorClient, heartbeat, logger, *heartbeatInterval, timeprovider.NewTimeProvider())
}

func initializeRepBBS(logger lager.Logger) Bbs.RepBBS {
	etcdAdapter := etcdstoreadapter.NewETCDStoreAdapter(
		strings.Split(*etcdCluster, ","),
		workpool.NewWorkPool(10),
	)

	err := etcdAdapter.Connect()
	if err != nil {
		logger.Fatal("failed-to-connect-to-etcd", err)
	}

	return Bbs.NewRepBBS(etcdAdapter, timeprovider.NewTimeProvider(), logger)
}

func initializeLRPStopper(guid string, executorClient executor.Client, logger lager.Logger) lrp_stopper.LRPStopper {
	return lrp_stopper.New(guid, executorClient, logger)
}

func initializeServer(
	bbs Bbs.RepBBS,
	executorClient executor.Client,
	logger lager.Logger,
) (ifrit.Runner, string) {
	lrpStopper := initializeLRPStopper(*cellID, executorClient, logger)

	auctionCellRep := auction_cell_rep.New(*cellID, *stack, *zone, generateGuid, bbs, executorClient, logger)
	handlers := auction_http_handlers.New(auctionCellRep, logger)

	handlers[bbsroutes.StopLRPInstance] = repserver.NewStopLRPInstanceHandler(logger, lrpStopper)
	routes := append(auctionroutes.Routes, bbsroutes.StopLRPRoutes...)

	router, err := rata.NewRouter(routes, handlers)
	if err != nil {
		logger.Fatal("failed-to-construct-router", err)
	}

	ip, err := localip.LocalIP()
	if err != nil {
		logger.Fatal("failed-to-fetch-ip", err)
	}

	port := strings.Split(*listenAddr, ":")[1]
	address := fmt.Sprintf("http://%s:%s", ip, port)

	return http_server.New(*listenAddr, router), address
}

func generateGuid() (string, error) {
	guid, err := uuid.NewV4()
	if err != nil {
		return "", err
	}
	return guid.String(), nil
}
<commit_msg>Decrease presence heartbeat interval to 5 seconds<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/auction/communication/http/auction_http_handlers"
	auctionroutes "github.com/cloudfoundry-incubator/auction/communication/http/routes"
	"github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/executor"
	executorclient "github.com/cloudfoundry-incubator/executor/http/client"
	"github.com/cloudfoundry-incubator/rep/auction_cell_rep"
	"github.com/cloudfoundry-incubator/rep/generator"
	"github.com/cloudfoundry-incubator/rep/harmonizer"
	repserver "github.com/cloudfoundry-incubator/rep/http_server"
	"github.com/cloudfoundry-incubator/rep/lrp_stopper"
	"github.com/cloudfoundry-incubator/rep/maintain"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/bbs/services_bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	bbsroutes "github.com/cloudfoundry-incubator/runtime-schema/routes"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/cloudfoundry/storeadapter/etcdstoreadapter"
	"github.com/nu7hatch/gouuid"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/localip"
	"github.com/pivotal-golang/operationq"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/tedsuo/rata"
)

var etcdCluster = flag.String(
	"etcdCluster",
	"http://127.0.0.1:4001",
	"comma-separated list of etcd addresses (http://ip:port)",
)

var heartbeatInterval = flag.Duration(
	"heartbeatInterval",
	services_bbs.CELL_HEARTBEAT_INTERVAL,
	"the interval between heartbeats for maintaining presence",
)

var executorURL = flag.String(
	"executorURL",
	"http://127.0.0.1:1700",
	"location of executor to represent",
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:1800",
	"host:port to serve auction and LRP stop requests on",
)

var stack = flag.String(
	"stack",
	"",
	"the rep stack - must be specified",
)

var cellID = flag.String(
	"cellID",
	"",
	"the ID used by the rep to identify itself to external systems - must be specified",
)

var zone = flag.String(
	"zone",
	"",
	"the availability zone associated with the rep",
)

var pollingInterval = flag.Duration(
	"pollingInterval",
	30*time.Second,
	"the interval on which to scan the executor",
)

const (
	dropsondeDestination = "localhost:3457"
	dropsondeOrigin      = "rep"
)

func main() {
	cf_debug_server.AddFlags(flag.CommandLine)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger := cf_lager.New("rep")
	initializeDropsonde(logger)

	if *cellID == "" {
		log.Fatalf("-cellID must be specified")
	}

	if *stack == "" {
		log.Fatalf("-stack must be specified")
	}

	bbs := initializeRepBBS(logger)
	executorClient := executorclient.New(http.DefaultClient, *executorURL)
	server, address := initializeServer(bbs, executorClient, logger)
	opGenerator := generator.New(*cellID, bbs, executorClient)

	// only one outstanding operation per container is necessary
	queue := operationq.NewSlidingQueue(1)

	members := grouper.Members{
		{"server", server},
		{"heartbeater", initializeCellHeartbeat(address, bbs, executorClient, logger)},
		{"bulker", harmonizer.NewBulker(logger, *pollingInterval, timeprovider.NewTimeProvider(), opGenerator, queue)},
		{"event-consumer", harmonizer.NewEventConsumer(logger, opGenerator, queue)},
	}

	if dbgAddr := cf_debug_server.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{
			{"debug-server", cf_debug_server.Runner(dbgAddr)},
		}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)

	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started", lager.Data{"cell-id": *cellID})

	<-monitor.Wait()
	logger.Info("shutting-down")
}

func initializeDropsonde(logger lager.Logger) {
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed to initialize dropsonde: %v", err)
	}
}

func initializeCellHeartbeat(address string, bbs Bbs.RepBBS, executorClient executor.Client, logger lager.Logger) ifrit.Runner {
	cellPresence := models.CellPresence{
		CellID:     *cellID,
		RepAddress: address,
		Stack:      *stack,
		Zone:       *zone,
	}

	heartbeat := bbs.NewCellHeartbeat(cellPresence, *heartbeatInterval)
	return maintain.New(executorClient, heartbeat, logger, *heartbeatInterval, timeprovider.NewTimeProvider())
}

func initializeRepBBS(logger lager.Logger) Bbs.RepBBS {
	etcdAdapter := etcdstoreadapter.NewETCDStoreAdapter(
		strings.Split(*etcdCluster, ","),
		workpool.NewWorkPool(10),
	)

	err := etcdAdapter.Connect()
	if err != nil {
		logger.Fatal("failed-to-connect-to-etcd", err)
	}

	return Bbs.NewRepBBS(etcdAdapter, timeprovider.NewTimeProvider(), logger)
}

func initializeLRPStopper(guid string, executorClient executor.Client, logger lager.Logger) lrp_stopper.LRPStopper {
	return lrp_stopper.New(guid, executorClient, logger)
}

func initializeServer(
	bbs Bbs.RepBBS,
	executorClient executor.Client,
	logger lager.Logger,
) (ifrit.Runner, string) {
	lrpStopper := initializeLRPStopper(*cellID, executorClient, logger)

	auctionCellRep := auction_cell_rep.New(*cellID, *stack, *zone, generateGuid, bbs, executorClient, logger)
	handlers := auction_http_handlers.New(auctionCellRep, logger)

	handlers[bbsroutes.StopLRPInstance] = repserver.NewStopLRPInstanceHandler(logger, lrpStopper)
	routes := append(auctionroutes.Routes, bbsroutes.StopLRPRoutes...)

	router, err := rata.NewRouter(routes, handlers)
	if err != nil {
		logger.Fatal("failed-to-construct-router", err)
	}

	ip, err := localip.LocalIP()
	if err != nil {
		logger.Fatal("failed-to-fetch-ip", err)
	}

	port := strings.Split(*listenAddr, ":")[1]
	address := fmt.Sprintf("http://%s:%s", ip, port)

	return http_server.New(*listenAddr, router), address
}

func generateGuid() (string, error) {
	guid, err := uuid.NewV4()
	if err != nil {
		return "", err
	}
	return guid.String(), nil
}
<|endoftext|>


<commit_before>// Steam JP Finder
package main

import (
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/mikoim/steam-jp-finder"
)

func init() {
	log.SetLevel(log.DebugLevel)
}

func main() {
	// Redis
	redis := newPool("localhost:6379")
	defer redis.Close()

	// App
	a, err := newApp(redis, []byte("REPLACE BY YOUR STRONG KEY"))
	if err != nil {
		log.Fatal(err)
		return
	}

	// Routing
	r := mux.NewRouter()
	r.HandleFunc("/login", a.loginHandler)
	r.HandleFunc("/login/callback", a.loginCallbackHandler)
	r.HandleFunc("/set", a.myHandler)

	// Logging
	h := sjf.Logging(r)

	log.Fatal(http.ListenAndServe(":8080", h))
}
<commit_msg>remove log alias<commit_after>// Steam JP Finder
package main

import (
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/mikoim/steam-jp-finder"
)

func init() {
	logrus.SetLevel(logrus.DebugLevel)
}

func main() {
	// Redis
	redis := newPool("localhost:6379")
	defer redis.Close()

	// App
	a, err := newApp(redis, []byte("REPLACE BY YOUR STRONG KEY"))
	if err != nil {
		logrus.Fatal(err)
		return
	}

	// Routing
	r := mux.NewRouter()
	r.HandleFunc("/login", a.loginHandler)
	r.HandleFunc("/login/callback", a.loginCallbackHandler)
	r.HandleFunc("/set", a.myHandler)

	// Logging
	h := sjf.Logging(r)

	logrus.Fatal(http.ListenAndServe(":8080", h))
}
<|endoftext|>


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

package main

import (
	"github.com/globocom/config"
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/provision"
	_ "github.com/globocom/tsuru/provision/docker"
	_ "github.com/globocom/tsuru/provision/juju"
	"os"
)

const defaultConfigPath = "/etc/tsuru/tsuru.conf"

func buildManager() *cmd.Manager {
	m := cmd.NewManager("tsr", "0.2.10", "", os.Stdout, os.Stderr, os.Stdin)
	m.Register(&tsrCommand{Command: &apiCmd{}})
	m.Register(&tsrCommand{Command: &collectorCmd{}})
	m.Register(&tsrCommand{Command: tokenCmd{}})
	m.Register(&tsrCommand{Command: &healerCmd{}})
	registerProvisionersCommands(m)
	return m
}

func registerProvisionersCommands(m *cmd.Manager) {
	provisioners := provision.Registry()
	for _, p := range provisioners {
		if c, ok := p.(provision.Commandable); ok {
			commands := c.Commands()
			for _, cmd := range commands {
				m.Register(&tsrCommand{Command: cmd})
			}
		}
	}
}

func main() {
	config.ReadConfigFile(defaultConfigPath)
	m := buildManager()
	m.Run(os.Args[1:])
}
<commit_msg>bump to 0.2.11.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"github.com/globocom/config"
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/provision"
	_ "github.com/globocom/tsuru/provision/docker"
	_ "github.com/globocom/tsuru/provision/juju"
	"os"
)

const defaultConfigPath = "/etc/tsuru/tsuru.conf"

func buildManager() *cmd.Manager {
	m := cmd.NewManager("tsr", "0.2.11", "", os.Stdout, os.Stderr, os.Stdin)
	m.Register(&tsrCommand{Command: &apiCmd{}})
	m.Register(&tsrCommand{Command: &collectorCmd{}})
	m.Register(&tsrCommand{Command: tokenCmd{}})
	m.Register(&tsrCommand{Command: &healerCmd{}})
	registerProvisionersCommands(m)
	return m
}

func registerProvisionersCommands(m *cmd.Manager) {
	provisioners := provision.Registry()
	for _, p := range provisioners {
		if c, ok := p.(provision.Commandable); ok {
			commands := c.Commands()
			for _, cmd := range commands {
				m.Register(&tsrCommand{Command: cmd})
			}
		}
	}
}

func main() {
	config.ReadConfigFile(defaultConfigPath)
	m := buildManager()
	m.Run(os.Args[1:])
}
<|endoftext|>


<commit_before>package medias

import (
	"encoding/json"
	"errors"
	"github.com/mitchellh/mapstructure"
	"io/ioutil"
	"log"
	"os"
	"fmt"
	"github.com/Zenika/MARCEL/backend/commons"
	"github.com/Zenika/MARCEL/backend/plugins"
	"strconv"
)

type Manager struct {
	configPath     string
	configFileName string
	configFullpath string
	Config         *Configuration

	pluginManager *plugins.Manager
}

func NewManager(pluginManager *plugins.Manager, configPath, configFilename string) *Manager {
	manager := new(Manager)

	manager.configPath = configPath
	manager.configFileName = configFilename

	manager.pluginManager = pluginManager

	manager.configFullpath = fmt.Sprintf("%s%c%s", configPath, os.PathSeparator, configFilename)
	manager.Config = NewConfiguration()

	return manager
}

// LoadMedias loads medias configuration from DB and stor it in memory
func (m *Manager) Load() {
	log.Printf("Start Loading Medias from DB.")

	m.CreateSaveFileIfNotExist(m.configPath, m.configFileName)

	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(m.configFullpath)
	commons.Check(err)

	var obj interface{}
	json.Unmarshal([]byte(content), &obj)

	if obj == nil {
		obj = make(map[string]interface{})
	}
	err = mapstructure.Decode(obj.(map[string]interface{}), m.Config)
	if err != nil {
		panic(err)
	}

	log.Print("Medias configurations is loaded...")
}

func (m *Manager) GetConfiguration() (*Configuration) {
	log.Println("Getting global medias config")

	return m.Config
}

func (m *Manager) GetAll() ([]Media) {
	log.Println("Getting all medias")

	return m.Config.Medias
}

// GetMedia Return the media with this id
func (m *Manager) Get(idMedia int) (*Media, error) {

	log.Println("Getting media with id: ", idMedia)
	for _, media := range m.Config.Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}

// CreateMedia Create a new Media, save it into memory and commit
func (m *Manager) CreateEmpty() (*Media) {

	log.Println("Creating media")

	newMedia := NewMedia()
	newMedia.ID = m.GetNextID()

	//save it into the MediasConfiguration
	m.Save(newMedia)
	m.Commit()

	return newMedia
}

// RemoveMedia Remove media from memory
func (m *Manager) Remove(media *Media) {
	log.Println("Removing media")
	i := m.getPosition(media)

	if i >= 0 {
		m.Config.Medias = append(m.Config.Medias[:i], m.Config.Medias[i+1:]...)
	}
}

// SaveMedia Save media information in memory.
func (m *Manager) Save(media *Media) {
	log.Println("Saving media")
	m.Remove(media)
	m.Config.Medias = append(m.Config.Medias, *media)
}

// Commit Save all medias in DB.
// Here DB is a JSON file
func (m *Manager) Commit() {
	content, _ := json.Marshal(m.Config)

	err := ioutil.WriteFile(m.configFullpath, content, 0644)

	if err != nil {
		log.Println("Cannot save medias configuration:")
		log.Panic(err)
	}
}

// CreateSaveFileIfNotExist check if the save file for medias exists and create it if not.
func (m *Manager) CreateSaveFileIfNotExist(filePath string, fileName string) {

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		log.Println("Data directory did not exist. Create it.")
		os.Mkdir(filePath, 0755)
	}

	var fullPath string = fmt.Sprintf("%s%c%s", filePath, os.PathSeparator, fileName)
	if _, err := os.Stat(fullPath); os.IsNotExist(err) {

		f, err := os.Create(fullPath)
		commons.Check(err)

		log.Println("Medias configuration file created at %v", fullPath)

		f.Close()

		//commit a first time to ensure the configuration has been saved
		m.Commit()
	}
}

func (m *Manager) Activate(media *Media) error {

	//todo : start all backends instances

	sep := string(os.PathSeparator)

	fmt.Printf("Media '%v' has plugin : ", media.Name)
	for _, mp := range media.Plugins {

		fmt.Printf("    * %v (instanceId = %v)\n", mp.EltName, mp.InstanceId)

		// 2.a : duplicate plugin files into "medias/{idMedia}/{plugins_EltName}/{idInstance}"
		err := commons.CopyDir(
			"/home/gwennael.buchet/PROJETS/MARCEL/backend/dist/plugins"+sep+mp.EltName,
			"/home/gwennael.buchet/PROJETS/MARCEL/backend/dist/medias"+sep+strconv.Itoa(media.ID)+sep+mp.EltName+sep+mp.InstanceId)

		if err != nil {
			return err
		}

		// 2.b : if p has backend
		//           => pull backend image or load it (if it has been tar.gzed) into "/medias/{idMedia}/{plugins_EltName}/{idInstance}/back"
		//           => create a dedicated volume
		//           => get a new port to be mapped with the backend, from the pool of ports (getPortNumberForPlugin)
		//           => run docker container
		//           => save the name of the container into a map to be easily stopped later (with Deactivate)

		//create a new instance for the plugin, i.e.:
		//   - duplicate the folder into /medias/{idMedia}/{plugins_EltName}/{idInstance}
		//   - if the plugin has a backend to launch: map the port and run docker container...

	}

	media.IsActive = true

	m.Save(media)

	return nil
}

func (m *Manager) Deactivate(media *Media) error {

	//stop all backends instances and free ports number
	for _, mp := range media.Plugins {
		if mp.BackEnd != nil {

			//todo : call docker manager to stop container for this plugin
			//containerManager.stopImage(mp.BackEnd.ContainerID)

			if mp.BackEnd.Ports != nil {
				ports := mp.BackEnd.Ports
				for _, port := range ports {
					m.FreePortNumberForPlugin(port)
				}
			}
		}
	}

	//remove plugins files
	sep := string(os.PathSeparator)
	os.RemoveAll("medias" + sep + strconv.Itoa(media.ID))

	media.IsActive = false

	m.Save(media)

	return nil
}

// GetMediaPosition Return position of a media in the list
func (m *Manager) getPosition(media *Media) int {
	for p, m := range m.Config.Medias {
		if m.ID == media.ID {
			return p
		}
	}
	return -1
}

func (m *Manager) GetPortNumberForPlugin() int {

	// 1 : try to pop a port number from the pool
	if len(m.Config.PortsPool) > 0 {
		p := m.Config.PortsPool[0]
		//remove the first number
		m.Config.PortsPool = m.Config.PortsPool[1:]
		return p
	}

	// 2 : if pool is empty, just increment the counter
	p := m.Config.NextFreePortNumber
	m.Config.NextFreePortNumber += 1

	return p
}

func (m *Manager) FreePortNumberForPlugin(portNumber int) {
	for i, v := range m.Config.PortsPool {
		if portNumber == v {
			m.Config.PortsPool = append(m.Config.PortsPool[:i], m.Config.PortsPool[i+1:]...)
		}
	}
}

func (m *Manager) GetNextID() int {
	m.Config.LastID = m.Config.LastID + 1
	return m.Config.LastID
}
<commit_msg>[Fix] plugins path<commit_after>package medias

import (
	"encoding/json"
	"errors"
	"github.com/mitchellh/mapstructure"
	"io/ioutil"
	"log"
	"os"
	"fmt"
	"github.com/Zenika/MARCEL/backend/commons"
	"github.com/Zenika/MARCEL/backend/plugins"
	"strconv"
)

type Manager struct {
	configPath     string
	configFileName string
	configFullpath string
	Config         *Configuration

	pluginManager *plugins.Manager
}

func NewManager(pluginManager *plugins.Manager, configPath, configFilename string) *Manager {
	manager := new(Manager)

	manager.configPath = configPath
	manager.configFileName = configFilename

	manager.pluginManager = pluginManager

	manager.configFullpath = fmt.Sprintf("%s%c%s", configPath, os.PathSeparator, configFilename)
	manager.Config = NewConfiguration()

	return manager
}

// LoadMedias loads medias configuration from DB and stor it in memory
func (m *Manager) Load() {
	log.Printf("Start Loading Medias from DB.")

	m.CreateSaveFileIfNotExist(m.configPath, m.configFileName)

	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(m.configFullpath)
	commons.Check(err)

	var obj interface{}
	json.Unmarshal([]byte(content), &obj)

	if obj == nil {
		obj = make(map[string]interface{})
	}
	err = mapstructure.Decode(obj.(map[string]interface{}), m.Config)
	if err != nil {
		panic(err)
	}

	log.Print("Medias configurations is loaded...")
}

func (m *Manager) GetConfiguration() (*Configuration) {
	log.Println("Getting global medias config")

	return m.Config
}

func (m *Manager) GetAll() ([]Media) {
	log.Println("Getting all medias")

	return m.Config.Medias
}

// GetMedia Return the media with this id
func (m *Manager) Get(idMedia int) (*Media, error) {

	log.Println("Getting media with id: ", idMedia)
	for _, media := range m.Config.Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}

// CreateMedia Create a new Media, save it into memory and commit
func (m *Manager) CreateEmpty() (*Media) {

	log.Println("Creating media")

	newMedia := NewMedia()
	newMedia.ID = m.GetNextID()

	//save it into the MediasConfiguration
	m.Save(newMedia)
	m.Commit()

	return newMedia
}

// RemoveMedia Remove media from memory
func (m *Manager) Remove(media *Media) {
	log.Println("Removing media")
	i := m.getPosition(media)

	if i >= 0 {
		m.Config.Medias = append(m.Config.Medias[:i], m.Config.Medias[i+1:]...)
	}
}

// SaveMedia Save media information in memory.
func (m *Manager) Save(media *Media) {
	log.Println("Saving media")
	m.Remove(media)
	m.Config.Medias = append(m.Config.Medias, *media)
}

// Commit Save all medias in DB.
// Here DB is a JSON file
func (m *Manager) Commit() {
	content, _ := json.Marshal(m.Config)

	err := ioutil.WriteFile(m.configFullpath, content, 0644)

	if err != nil {
		log.Println("Cannot save medias configuration:")
		log.Panic(err)
	}
}

// CreateSaveFileIfNotExist check if the save file for medias exists and create it if not.
func (m *Manager) CreateSaveFileIfNotExist(filePath string, fileName string) {

	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		log.Println("Data directory did not exist. Create it.")
		os.Mkdir(filePath, 0755)
	}

	var fullPath string = fmt.Sprintf("%s%c%s", filePath, os.PathSeparator, fileName)
	if _, err := os.Stat(fullPath); os.IsNotExist(err) {

		f, err := os.Create(fullPath)
		commons.Check(err)

		log.Println("Medias configuration file created at %v", fullPath)

		f.Close()

		//commit a first time to ensure the configuration has been saved
		m.Commit()
	}
}

func (m *Manager) Activate(media *Media) error {

	sep := string(os.PathSeparator)

	fmt.Printf("Media '%v' has plugin : ", media.Name)
	for _, mp := range media.Plugins {

		// 1 : duplicate plugin files into "medias/{idMedia}/{plugins_EltName}/{idInstance}"
		err := commons.CopyDir(
			"plugins"+sep+mp.EltName,
			"medias"+sep+strconv.Itoa(media.ID)+sep+mp.EltName+sep+mp.InstanceId)

		if err != nil {
			return err
		}

		// 2.b : if p has backend
		//           => pull backend image or load it (if it has been tar.gzed) into "/medias/{idMedia}/{plugins_EltName}/{idInstance}/back"
		//           => create a dedicated volume
		//           => get a new port to be mapped with the backend, from the pool of ports (getPortNumberForPlugin)
		//           => run docker container
		//           => save the name of the container into a map to be easily stopped later (with Deactivate)

		//create a new instance for the plugin, i.e.:
		//   - duplicate the folder into /medias/{idMedia}/{plugins_EltName}/{idInstance}
		//   - if the plugin has a backend to launch: map the port and run docker container...

	}

	media.IsActive = true

	m.Save(media)

	return nil
}

func (m *Manager) Deactivate(media *Media) error {

	//stop all backends instances and free ports number
	for _, mp := range media.Plugins {
		if mp.BackEnd != nil {

			//todo : call docker manager to stop container for this plugin
			//containerManager.stopImage(mp.BackEnd.ContainerID)

			if mp.BackEnd.Ports != nil {
				ports := mp.BackEnd.Ports
				for _, port := range ports {
					m.FreePortNumberForPlugin(port)
				}
			}
		}
	}

	//remove plugins files
	sep := string(os.PathSeparator)
	os.RemoveAll("medias" + sep + strconv.Itoa(media.ID))

	media.IsActive = false

	m.Save(media)

	return nil
}

// GetMediaPosition Return position of a media in the list
func (m *Manager) getPosition(media *Media) int {
	for p, m := range m.Config.Medias {
		if m.ID == media.ID {
			return p
		}
	}
	return -1
}

func (m *Manager) GetPortNumberForPlugin() int {

	// 1 : try to pop a port number from the pool
	if len(m.Config.PortsPool) > 0 {
		p := m.Config.PortsPool[0]
		//remove the first number
		m.Config.PortsPool = m.Config.PortsPool[1:]
		return p
	}

	// 2 : if pool is empty, just increment the counter
	p := m.Config.NextFreePortNumber
	m.Config.NextFreePortNumber += 1

	return p
}

func (m *Manager) FreePortNumberForPlugin(portNumber int) {
	for i, v := range m.Config.PortsPool {
		if portNumber == v {
			m.Config.PortsPool = append(m.Config.PortsPool[:i], m.Config.PortsPool[i+1:]...)
		}
	}
}

func (m *Manager) GetNextID() int {
	m.Config.LastID = m.Config.LastID + 1
	return m.Config.LastID
}
<|endoftext|>


<commit_before>package invdapi

import (
	"github.com/Invoiced/invoiced-go/invdendpoint"
	"strconv"
)

type WebhookAttempt struct {
	*Connection
	*invdendpoint.WebhookAttempt
}

type WebhookAttempts []*WebhookAttempt

func (c *Connection) NewWebhookAttempt() *WebhookAttempt {
	webhookAttempt := new(invdendpoint.WebhookAttempt)
	return &WebhookAttempt{c, webhookAttempt}
}

func (c *WebhookAttempt) ListAll(filter *invdendpoint.Filter, sort *invdendpoint.Sort) (WebhookAttempts, error) {
	endpoint := invdendpoint.WebhookEndpoint

	endpoint = addFilterAndSort(endpoint, filter, sort)

	webhookAttempts := make(WebhookAttempts, 0)

NEXT:
	tmpWebhookAttempts := make(WebhookAttempts, 0)

	endpoint, apiErr := c.retrieveDataFromAPI(endpoint, &tmpWebhookAttempts)

	if apiErr != nil {
		return nil, apiErr
	}

	webhookAttempts = append(webhookAttempts, tmpWebhookAttempts...)

	if endpoint != "" {
		goto NEXT
	}

	for _, webhookAttempt := range tmpWebhookAttempts {
		webhookAttempt.Connection = c.Connection
	}

	return webhookAttempts, nil
}

func (c *WebhookAttempt) ReAttempt(webhookId int64) error {

		endpoint := invdendpoint.WebhookEndpoint + "/" + strconv.FormatInt(webhookId, 10) + "/retries"

		err := c.create(endpoint, nil, nil)
		if err != nil {
			return err
		}

		return  nil
	}
<commit_msg>bugfix in webhook attempt<commit_after>package invdapi

import (
	"github.com/Invoiced/invoiced-go/invdendpoint"
	"strconv"
)

type WebhookAttempt struct {
	*Connection
	*invdendpoint.WebhookAttempt
}

type WebhookAttempts []*WebhookAttempt

func (c *Connection) NewWebhookAttempt() *WebhookAttempt {
	webhookAttempt := new(invdendpoint.WebhookAttempt)
	return &WebhookAttempt{c, webhookAttempt}
}

func (c *WebhookAttempt) ListAll(filter *invdendpoint.Filter, sort *invdendpoint.Sort) (WebhookAttempts, error) {
	endpoint := invdendpoint.WebhookEndpoint

	endpoint = addFilterAndSort(endpoint, filter, sort)

	webhookAttempts := make(WebhookAttempts, 0)

NEXT:
	tmpWebhookAttempts := make(WebhookAttempts, 0)

	endpoint, apiErr := c.retrieveDataFromAPI(endpoint, &tmpWebhookAttempts)

	if apiErr != nil {
		return nil, apiErr
	}

	webhookAttempts = append(webhookAttempts, tmpWebhookAttempts...)

	if endpoint != "" {
		goto NEXT
	}

	for _, webhookAttempt := range webhookAttempts {
		webhookAttempt.Connection = c.Connection
	}

	return webhookAttempts, nil
}

func (c *WebhookAttempt) ReAttempt(webhookId int64) error {

		endpoint := invdendpoint.WebhookEndpoint + "/" + strconv.FormatInt(webhookId, 10) + "/retries"

		err := c.create(endpoint, nil, nil)
		if err != nil {
			return err
		}

		return  nil
	}
<|endoftext|>


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

package main

import (
	"bytes"
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"
	"unsafe"

	// We use this ssh because it implements port redirection.
	// It can not, however, unpack password-protected keys yet.

	// TODO: get rid of krpty
	"github.com/u-root/u-root/pkg/termios"
	"github.com/u-root/u-root/pkg/ulog"

	// We use this ssh because it can unpack password-protected private keys.
	ossh "golang.org/x/crypto/ssh"
)

// a nonce is a [32]byte containing only printable characters, suitable for use as a string
type nonce [32]byte

var (
	// For the ssh server part
	bin         = flag.String("bin", "cpud", "path of cpu binary")
	debug       = flag.Bool("d", false, "enable debug prints")
	dbg9p       = flag.Bool("dbg9p", false, "show 9p io")
	dump        = flag.Bool("dump", false, "Dump copious output, including a 9p trace, to a temp file at exit")
	hostKeyFile = flag.String("hk", "" /*"/etc/ssh/ssh_host_rsa_key"*/, "file for host key")
	keyFile     = flag.String("key", filepath.Join(os.Getenv("HOME"), ".ssh/cpu_rsa"), "key file")
	mountopts   = flag.String("mountopts", "", "Extra options to add to the 9p mount")
	msize       = flag.Int("msize", 1048576, "msize to use")
	network     = flag.String("network", "tcp", "network to use")
	port        = flag.String("sp", "23", "cpu default port")
	port9p      = flag.String("port9p", "", "port9p # on remote machine for 9p mount")
	root        = flag.String("root", "/", "9p root")
	timeout9P   = flag.String("timeout9p", "100ms", "time to wait for the 9p mount to happen.")

	v          = func(string, ...interface{}) {}
	pid1       bool
	dumpWriter *os.File
)

func verbose(f string, a ...interface{}) {
	v("\r\n"+f+"\r\n", a...)
}

// generateNonce returns a nonce, or an error if random reader fails.
func generateNonce() (nonce, error) {
	var b [len(nonce{}) / 2]byte
	if _, err := rand.Read(b[:]); err != nil {
		return nonce{}, err
	}
	var n nonce
	copy(n[:], fmt.Sprintf("%02x", b))
	return n, nil
}

// String is a Stringer for nonce.
func (n nonce) String() string {
	return string(n[:])
}

func dial(n, a string, config *ossh.ClientConfig) (*ossh.Client, error) {
	client, err := ossh.Dial(n, a, config)
	if err != nil {
		return nil, fmt.Errorf("Failed to dial: %v", err)
	}
	return client, nil
}

func config(kf string) (*ossh.ClientConfig, error) {
	cb := ossh.InsecureIgnoreHostKey()
	//var hostKey ssh.PublicKey
	// A public key may be used to authenticate against the remote
	// server by using an unencrypted PEM-encoded private key file.
	//
	// If you have an encrypted private key, the crypto/x509 package
	// can be used to decrypt it.
	key, err := ioutil.ReadFile(kf)
	if err != nil {
		return nil, fmt.Errorf("unable to read private key %v: %v", kf, err)
	}

	// Create the Signer for this private key.
	signer, err := ossh.ParsePrivateKey(key)
	if err != nil {
		return nil, fmt.Errorf("ParsePrivateKey %v: %v", kf, err)
	}
	if *hostKeyFile != "" {
		hk, err := ioutil.ReadFile(*hostKeyFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read host key %v: %v", *hostKeyFile, err)
		}
		pk, err := ossh.ParsePublicKey(hk)
		if err != nil {
			return nil, fmt.Errorf("host key %v: %v", string(hk), err)
		}
		cb = ossh.FixedHostKey(pk)
	}
	config := &ossh.ClientConfig{
		User: os.Getenv("USER"),
		Auth: []ossh.AuthMethod{
			// Use the PublicKeys method for remote authentication.
			ossh.PublicKeys(signer),
		},
		HostKeyCallback: cb,
	}
	return config, nil
}

func cmd(client *ossh.Client, s string) ([]byte, error) {
	session, err := client.NewSession()
	if err != nil {
		return nil, fmt.Errorf("Failed to create session: %v", err)
	}
	defer session.Close()

	var b bytes.Buffer
	session.Stdout = &b
	if err := session.Run(s); err != nil {
		return nil, fmt.Errorf("Failed to run %v: %v", s, err.Error())
	}
	return b.Bytes(), nil
}

// To make sure defer gets run and you tty is sane on exit
func runClient(host, a string) error {
	c, err := config(*keyFile)
	if err != nil {
		return err
	}
	cl, err := dial(*network, net.JoinHostPort(host, *port), c)
	if err != nil {
		return err
	}
	// Special case: maybe we don't want a namespace. If so, we don't need
	// to open up the socket.
	wantNameSpace := true
	if n, ok := os.LookupEnv("CPU_NAMESPACE"); ok && len(n) == 0 {
		wantNameSpace = false
	}

	var env []string
	cmd := fmt.Sprintf("%v -remote -bin %v", *bin, *bin)
	if wantNameSpace {
		// From setting up the forward to having the nonce written back to us,
		// we only allow 100ms. This is a lot, considering that at this point,
		// the sshd has forked a server for us and it's waiting to be
		// told what to do. We suggest that making the deadline a flag
		// would be a bad move, since people might be tempted to make it
		// large.
		deadline, err := time.ParseDuration(*timeout9P)
		if err != nil {
			return err
		}
		// Arrange port forwarding from remote ssh to our server.
		// Request the remote side to open port 5640 on all interfaces.
		// Note: cl.Listen returns a TCP listener with network is "tcp"
		// or variants. This lets us use a listen deadline.
		l, err := cl.Listen("tcp", "127.0.0.1:0")
		if err != nil {
			return fmt.Errorf("First cl.Listen %v", err)
		}
		ap := strings.Split(l.Addr().String(), ":")
		if len(ap) == 0 {
			return fmt.Errorf("Can't find a port number in %v", l.Addr().String())
		}
		port9p := ap[len(ap)-1]
		v("listener %T %v addr %v port %v", l, l, l.Addr().String(), port)

		nonce, err := generateNonce()
		if err != nil {
			log.Fatalf("Getting nonce: %v", err)
		}
		go srv(l, *root, nonce, deadline)
		cmd = fmt.Sprintf("%s -port9p %v", cmd, port9p)
		env = append(env, "CPUNONCE="+nonce.String())
	}
	cmd = fmt.Sprintf("%s %q", cmd, a)
	if err := shell(cl, cmd, env...); err != nil {
		return err
	}
	return nil
}

func env(s *ossh.Session, envs ...string) {
	for _, v := range append(os.Environ(), envs...) {
		env := strings.SplitN(v, "=", 2)
		if len(env) == 1 {
			env = append(env, "")
		}
		if err := s.Setenv(env[0], env[1]); err != nil {
			log.Printf("Warning: s.Setenv(%q, %q): %v", v, os.Getenv(v), err)
		}
	}
}

func stdin(s *ossh.Session, w io.WriteCloser, r io.Reader) {
	var newLine, tilde bool
	var t = []byte{'~'}
	var b [1]byte
	for {
		if _, err := r.Read(b[:]); err != nil {
			break
		}
		switch b[0] {
		default:
			newLine = false
			if tilde {
				if _, err := w.Write(t[:]); err != nil {
					return
				}
				tilde = false
			}
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		case '\n', '\r':
			newLine = true
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		case '~':
			if newLine {
				newLine = false
				tilde = true
				break
			}
			if _, err := w.Write(t[:]); err != nil {
				return
			}
		case '.':
			if tilde {
				s.Close()
				return
			}
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		}
	}
}

func shell(client *ossh.Client, cmd string, envs ...string) error {
	t, err := termios.New()
	if err != nil {
		return err
	}
	r, err := t.Raw()
	if err != nil {
		return err
	}
	defer t.Set(r)
	if *bin == "" {
		if *bin, err = exec.LookPath("cpu"); err != nil {
			return err
		}
	}

	v("command is %q", cmd)
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	env(session, envs...)
	// Set up terminal modes
	modes := ossh.TerminalModes{
		ossh.ECHO:          0,     // disable echoing
		ossh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ossh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	// Request pseudo terminal
	if err := session.RequestPty("ansi", 40, 80, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}
	i, err := session.StdinPipe()
	if err != nil {
		return err
	}
	o, err := session.StdoutPipe()
	if err != nil {
		return err
	}
	e, err := session.StderrPipe()
	if err != nil {
		return err
	}

	v("Start remote with command %q", cmd)
	if err := session.Start(cmd); err != nil {
		return fmt.Errorf("Failed to run %v: %v", cmd, err.Error())
	}
	//env(session, "CPUNONCE="+n.String())
	go stdin(session, i, os.Stdin)
	go io.Copy(os.Stdout, o)
	go io.Copy(os.Stderr, e)
	return session.Wait()
}

// We do flag parsing in init so we can
// Unshare if needed while we are still
// single threaded.
func init() {
	flag.Parse()
	if *dump && *debug {
		log.Fatalf("You can only set either dump OR debug")
	}
	if *debug {
		v = log.Printf
	}
	if *dump {
		var err error
		dumpWriter, err = ioutil.TempFile("", "cpu")
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("Logging to %s", dumpWriter.Name())
		*dbg9p = true
		ulog.Log = log.New(dumpWriter, "", log.Ltime|log.Lmicroseconds)
		v = ulog.Log.Printf
	}
}

func setWinsize(f *os.File, w, h int) {
	syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ),
		uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0})))
}

// TODO: we've been tryinmg to figure out the right way to do usage for years.
// If this is a good way, it belongs in the uroot package.
func usage() {
	var b bytes.Buffer
	flag.CommandLine.SetOutput(&b)
	flag.PrintDefaults()
	log.Fatalf("Usage: cpu [options] host [shell command]:\n%v", b.String())
}

func main() {
	args := flag.Args()
	if len(args) == 0 {
		usage()
	}
	host := args[0]
	a := strings.Join(args[1:], " ")
	verbose("Running as client with server 9p deadline of %v", *timeout9P)
	if a == "" {
		a = os.Getenv("SHELL")
	}
	t, err := termios.GetTermios(0)
	if err != nil {
		log.Fatal("Getting Termios")
	}
	if err := runClient(host, a); err != nil {
		e := 1
		log.Printf("SSH error %s", err)
		if x, ok := err.(*ossh.ExitError); ok {
			e = x.ExitStatus()
		}
		defer os.Exit(e)
	}
	if err := termios.SetTermios(0, t); err != nil {
		// Never make this a log.Fatal, it might
		// interfere with the exit handling
		// for errors from the remote process.
		log.Print(err)
	}
}
<commit_msg>cpu command: continue even if a tty is not available<commit_after>// Copyright 2018-2019 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"
	"unsafe"

	// We use this ssh because it implements port redirection.
	// It can not, however, unpack password-protected keys yet.

	// TODO: get rid of krpty
	"github.com/u-root/u-root/pkg/termios"
	"github.com/u-root/u-root/pkg/ulog"

	// We use this ssh because it can unpack password-protected private keys.
	ossh "golang.org/x/crypto/ssh"
)

// a nonce is a [32]byte containing only printable characters, suitable for use as a string
type nonce [32]byte

var (
	// For the ssh server part
	bin         = flag.String("bin", "cpud", "path of cpu binary")
	debug       = flag.Bool("d", false, "enable debug prints")
	dbg9p       = flag.Bool("dbg9p", false, "show 9p io")
	dump        = flag.Bool("dump", false, "Dump copious output, including a 9p trace, to a temp file at exit")
	hostKeyFile = flag.String("hk", "" /*"/etc/ssh/ssh_host_rsa_key"*/, "file for host key")
	keyFile     = flag.String("key", filepath.Join(os.Getenv("HOME"), ".ssh/cpu_rsa"), "key file")
	mountopts   = flag.String("mountopts", "", "Extra options to add to the 9p mount")
	msize       = flag.Int("msize", 1048576, "msize to use")
	network     = flag.String("network", "tcp", "network to use")
	port        = flag.String("sp", "23", "cpu default port")
	port9p      = flag.String("port9p", "", "port9p # on remote machine for 9p mount")
	root        = flag.String("root", "/", "9p root")
	timeout9P   = flag.String("timeout9p", "100ms", "time to wait for the 9p mount to happen.")

	v          = func(string, ...interface{}) {}
	pid1       bool
	dumpWriter *os.File
)

func verbose(f string, a ...interface{}) {
	v("\r\n"+f+"\r\n", a...)
}

// generateNonce returns a nonce, or an error if random reader fails.
func generateNonce() (nonce, error) {
	var b [len(nonce{}) / 2]byte
	if _, err := rand.Read(b[:]); err != nil {
		return nonce{}, err
	}
	var n nonce
	copy(n[:], fmt.Sprintf("%02x", b))
	return n, nil
}

// String is a Stringer for nonce.
func (n nonce) String() string {
	return string(n[:])
}

func dial(n, a string, config *ossh.ClientConfig) (*ossh.Client, error) {
	client, err := ossh.Dial(n, a, config)
	if err != nil {
		return nil, fmt.Errorf("Failed to dial: %v", err)
	}
	return client, nil
}

func config(kf string) (*ossh.ClientConfig, error) {
	cb := ossh.InsecureIgnoreHostKey()
	//var hostKey ssh.PublicKey
	// A public key may be used to authenticate against the remote
	// server by using an unencrypted PEM-encoded private key file.
	//
	// If you have an encrypted private key, the crypto/x509 package
	// can be used to decrypt it.
	key, err := ioutil.ReadFile(kf)
	if err != nil {
		return nil, fmt.Errorf("unable to read private key %v: %v", kf, err)
	}

	// Create the Signer for this private key.
	signer, err := ossh.ParsePrivateKey(key)
	if err != nil {
		return nil, fmt.Errorf("ParsePrivateKey %v: %v", kf, err)
	}
	if *hostKeyFile != "" {
		hk, err := ioutil.ReadFile(*hostKeyFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read host key %v: %v", *hostKeyFile, err)
		}
		pk, err := ossh.ParsePublicKey(hk)
		if err != nil {
			return nil, fmt.Errorf("host key %v: %v", string(hk), err)
		}
		cb = ossh.FixedHostKey(pk)
	}
	config := &ossh.ClientConfig{
		User: os.Getenv("USER"),
		Auth: []ossh.AuthMethod{
			// Use the PublicKeys method for remote authentication.
			ossh.PublicKeys(signer),
		},
		HostKeyCallback: cb,
	}
	return config, nil
}

func cmd(client *ossh.Client, s string) ([]byte, error) {
	session, err := client.NewSession()
	if err != nil {
		return nil, fmt.Errorf("Failed to create session: %v", err)
	}
	defer session.Close()

	var b bytes.Buffer
	session.Stdout = &b
	if err := session.Run(s); err != nil {
		return nil, fmt.Errorf("Failed to run %v: %v", s, err.Error())
	}
	return b.Bytes(), nil
}

// To make sure defer gets run and you tty is sane on exit
func runClient(host, a string) error {
	c, err := config(*keyFile)
	if err != nil {
		return err
	}
	cl, err := dial(*network, net.JoinHostPort(host, *port), c)
	if err != nil {
		return err
	}
	// Special case: maybe we don't want a namespace. If so, we don't need
	// to open up the socket.
	wantNameSpace := true
	if n, ok := os.LookupEnv("CPU_NAMESPACE"); ok && len(n) == 0 {
		wantNameSpace = false
	}

	var env []string
	cmd := fmt.Sprintf("%v -remote -bin %v", *bin, *bin)
	if wantNameSpace {
		// From setting up the forward to having the nonce written back to us,
		// we only allow 100ms. This is a lot, considering that at this point,
		// the sshd has forked a server for us and it's waiting to be
		// told what to do. We suggest that making the deadline a flag
		// would be a bad move, since people might be tempted to make it
		// large.
		deadline, err := time.ParseDuration(*timeout9P)
		if err != nil {
			return err
		}
		// Arrange port forwarding from remote ssh to our server.
		// Request the remote side to open port 5640 on all interfaces.
		// Note: cl.Listen returns a TCP listener with network is "tcp"
		// or variants. This lets us use a listen deadline.
		l, err := cl.Listen("tcp", "127.0.0.1:0")
		if err != nil {
			return fmt.Errorf("First cl.Listen %v", err)
		}
		ap := strings.Split(l.Addr().String(), ":")
		if len(ap) == 0 {
			return fmt.Errorf("Can't find a port number in %v", l.Addr().String())
		}
		port9p := ap[len(ap)-1]
		v("listener %T %v addr %v port %v", l, l, l.Addr().String(), port)

		nonce, err := generateNonce()
		if err != nil {
			log.Fatalf("Getting nonce: %v", err)
		}
		go srv(l, *root, nonce, deadline)
		cmd = fmt.Sprintf("%s -port9p %v", cmd, port9p)
		env = append(env, "CPUNONCE="+nonce.String())
	}
	cmd = fmt.Sprintf("%s %q", cmd, a)
	if err := shell(cl, cmd, env...); err != nil {
		return err
	}
	return nil
}

func env(s *ossh.Session, envs ...string) {
	for _, v := range append(os.Environ(), envs...) {
		env := strings.SplitN(v, "=", 2)
		if len(env) == 1 {
			env = append(env, "")
		}
		if err := s.Setenv(env[0], env[1]); err != nil {
			log.Printf("Warning: s.Setenv(%q, %q): %v", v, os.Getenv(v), err)
		}
	}
}

func stdin(s *ossh.Session, w io.WriteCloser, r io.Reader) {
	var newLine, tilde bool
	var t = []byte{'~'}
	var b [1]byte
	for {
		if _, err := r.Read(b[:]); err != nil {
			break
		}
		switch b[0] {
		default:
			newLine = false
			if tilde {
				if _, err := w.Write(t[:]); err != nil {
					return
				}
				tilde = false
			}
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		case '\n', '\r':
			newLine = true
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		case '~':
			if newLine {
				newLine = false
				tilde = true
				break
			}
			if _, err := w.Write(t[:]); err != nil {
				return
			}
		case '.':
			if tilde {
				s.Close()
				return
			}
			if _, err := w.Write(b[:]); err != nil {
				return
			}
		}
	}
}

func shell(client *ossh.Client, cmd string, envs ...string) error {
	t, err := termios.New()
	if err == nil {
		r, err := t.Raw()
		if err != nil {
			return err
		}
		defer t.Set(r)
	}
	if *bin == "" {
		if *bin, err = exec.LookPath("cpu"); err != nil {
			return err
		}
	}

	v("command is %q", cmd)
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	env(session, envs...)
	// Set up terminal modes
	modes := ossh.TerminalModes{
		ossh.ECHO:          0,     // disable echoing
		ossh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ossh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	// Request pseudo terminal
	if err := session.RequestPty("ansi", 40, 80, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}
	i, err := session.StdinPipe()
	if err != nil {
		return err
	}
	o, err := session.StdoutPipe()
	if err != nil {
		return err
	}
	e, err := session.StderrPipe()
	if err != nil {
		return err
	}

	v("Start remote with command %q", cmd)
	if err := session.Start(cmd); err != nil {
		return fmt.Errorf("Failed to run %v: %v", cmd, err.Error())
	}
	//env(session, "CPUNONCE="+n.String())
	go stdin(session, i, os.Stdin)
	go io.Copy(os.Stdout, o)
	go io.Copy(os.Stderr, e)
	return session.Wait()
}

// We do flag parsing in init so we can
// Unshare if needed while we are still
// single threaded.
func init() {
	flag.Parse()
	if *dump && *debug {
		log.Fatalf("You can only set either dump OR debug")
	}
	if *debug {
		v = log.Printf
	}
	if *dump {
		var err error
		dumpWriter, err = ioutil.TempFile("", "cpu")
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("Logging to %s", dumpWriter.Name())
		*dbg9p = true
		ulog.Log = log.New(dumpWriter, "", log.Ltime|log.Lmicroseconds)
		v = ulog.Log.Printf
	}
}

func setWinsize(f *os.File, w, h int) {
	syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ),
		uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0})))
}

// TODO: we've been tryinmg to figure out the right way to do usage for years.
// If this is a good way, it belongs in the uroot package.
func usage() {
	var b bytes.Buffer
	flag.CommandLine.SetOutput(&b)
	flag.PrintDefaults()
	log.Fatalf("Usage: cpu [options] host [shell command]:\n%v", b.String())
}

func main() {
	args := flag.Args()
	if len(args) == 0 {
		usage()
	}
	host := args[0]
	a := strings.Join(args[1:], " ")
	verbose("Running as client with server 9p deadline of %v", *timeout9P)
	if a == "" {
		a = os.Getenv("SHELL")
	}
	t, err := termios.GetTermios(0)
	if err != nil {
		log.Printf("Getting Termios: %v. No job control/raw mode in this shell. Don't type passwords!", err)
	}
	if err := runClient(host, a); err != nil {
		e := 1
		log.Printf("SSH error %s", err)
		if x, ok := err.(*ossh.ExitError); ok {
			e = x.ExitStatus()
		}
		defer os.Exit(e)
	}
	if t != nil {
		if err := termios.SetTermios(0, t); err != nil {
			// Never make this a log.Fatal, it might
			// interfere with the exit handling
			// for errors from the remote process.
			log.Print(err)
		}
	}
}
<|endoftext|>