<commit_before>package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

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

// submitCmd lets people upload a solution to the website.
var submitCmd = &cobra.Command{
	Use:     "submit FILE1 [FILE2 ...]",
	Aliases: []string{"s"},
	Short:   "Submit your solution to an exercise.",
	Long: `Submit your solution to an Exercism exercise.

    Call the command with the list of files you want to submit.
`,
	RunE: func(cmd *cobra.Command, args []string) error {
		cfg := config.NewConfig()

		usrCfg := viper.New()
		usrCfg.AddConfigPath(cfg.Dir)
		usrCfg.SetConfigName("user")
		usrCfg.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = usrCfg.ReadInConfig()
		cfg.UserViperConfig = usrCfg

		v := viper.New()
		v.AddConfigPath(cfg.Dir)
		v.SetConfigName("cli")
		v.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = v.ReadInConfig()

		return runSubmit(cfg, cmd.Flags(), args)
	},
}

type submitContext struct {
	args   []string
	usrCfg *viper.Viper
}

func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
	usrCfg := cfg.UserViperConfig

	if err := validateUserConfig(usrCfg); err != nil {
		return err
	}

	ctx := &submitContext{args: args, usrCfg: usrCfg}

	if err := ctx.sanitizeArgs(); err != nil {
		return err
	}

	exercise, err := ctx.exercise()
	if err != nil {
		return err
	}

	migrationStatus, err := exercise.MigrateLegacyMetadataFile()
	if err != nil {
		return err
	}
	if verbose, _ := flags.GetBool("verbose"); verbose {
		fmt.Fprintf(Err, migrationStatus.String())
	}

	metadata, err := ctx.metadata(exercise.Filepath())
	if err != nil {
		return err
	}

	exercise.Documents, err = ctx.documents(exercise.Filepath())
	if err != nil {
		return err
	}

	if err := ctx.submitRequest(metadata.ID, exercise.Documents); err != nil {
		return err
	}

	ctx.printResult(metadata)
	return nil
}

func (ctx *submitContext) validateUserConfig() error {
	if ctx.usrCfg.GetString("token") == "" {
		return fmt.Errorf(msgWelcomePleaseConfigure, config.SettingsURL(ctx.usrCfg.GetString("apibaseurl")), BinaryName)
	}
	if ctx.usrCfg.GetString("workspace") == "" {
		return fmt.Errorf(msgRerunConfigure, BinaryName)
	}
	return nil
}

func (ctx *submitContext) sanitizeArgs() error {
	for i, arg := range ctx.args {
		var err error
		arg, err = filepath.Abs(arg)
		if err != nil {
			return err
		}

		info, err := os.Lstat(arg)
		if err != nil {
			if os.IsNotExist(err) {
				msg := `

    The file you are trying to submit cannot be found.

        %s

        `
				return fmt.Errorf(msg, arg)
			}
			return err
		}
		if info.IsDir() {
			msg := `

    You are submitting a directory, which is not currently supported.

        %s

    Please change into the directory and provide the path to the file(s) you wish to submit

        %s submit FILENAME

            `
			return fmt.Errorf(msg, arg, BinaryName)
		}

		src, err := filepath.EvalSymlinks(arg)
		if err != nil {
			return err
		}
		ctx.args[i] = src
	}
	return nil
}

func (ctx *submitContext) exercise() (workspace.Exercise, error) {
	ws, err := workspace.New(ctx.usrCfg.GetString("workspace"))
	if err != nil {
		return workspace.Exercise{}, err
	}

	var exerciseDir string
	for _, arg := range ctx.args {
		dir, err := ws.ExerciseDir(arg)
		if err != nil {
			if workspace.IsMissingMetadata(err) {
				return workspace.Exercise{}, errors.New(msgMissingMetadata)
			}
			return workspace.Exercise{}, err
		}
		if exerciseDir != "" && dir != exerciseDir {
			msg := `

    You are submitting files belonging to different solutions.
    Please submit the files for one solution at a time.

        `
			return workspace.Exercise{}, errors.New(msg)
		}
		exerciseDir = dir
	}

	return workspace.NewExerciseFromDir(exerciseDir), nil
}

func (ctx *submitContext) metadata(exerciseDir string) (*workspace.ExerciseMetadata, error) {
	metadata, err := workspace.NewExerciseMetadata(exerciseDir)
	if err != nil {
		return nil, err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)
	if exercise.Slug != metadata.Exercise {
		// TODO: error msg should suggest running future doctor command
		msg := `

	The exercise directory does not match exercise slug in metadata:

		expected '%[1]s' but got '%[2]s'

	Please rename the directory '%[1]s' to '%[2]s' and try again.

		`
		return nil, fmt.Errorf(msg, exercise.Slug, metadata.Exercise)
	}

	if !metadata.IsRequester {
		// TODO: add test
		msg := `

    The solution you are submitting is not connected to your account.
    Please re-download the exercise to make sure it has the data it needs.

        %s download --exercise=%s --track=%s

        `
		return nil, fmt.Errorf(msg, BinaryName, metadata.Exercise, metadata.Track)
	}
	return metadata, nil
}

func (ctx *submitContext) documents(exerciseDir string) ([]workspace.Document, error) {
	docs := make([]workspace.Document, 0, len(ctx.args))
	for _, file := range ctx.args {
		// Don't submit empty files
		info, err := os.Stat(file)
		if err != nil {
			return nil, err
		}
		const maxFileSize int64 = 65535
		if info.Size() >= maxFileSize {
			msg := `

      The submitted file '%s' is larger than the max allowed file size of %d bytes.
      Please reduce the size of the file and try again.

            `
			return nil, fmt.Errorf(msg, file, maxFileSize)
		}
		if info.Size() == 0 {

			msg := `

    WARNING: Skipping empty file
             %s

        `
			fmt.Fprintf(Err, msg, file)
			continue
		}
		doc, err := workspace.NewDocument(exerciseDir, file)
		if err != nil {
			return nil, err
		}
		docs = append(docs, doc)
	}
	if len(docs) == 0 {
		msg := `

    No files found to submit.

        `
		return nil, errors.New(msg)
	}
	return docs, nil
}

func (ctx *submitContext) submitRequest(id string, docs []workspace.Document) error {
	if id == "" {
		return errors.New("id is empty")
	}
	if len(docs) == 0 {
		return errors.New("docs is empty")
	}

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	for _, doc := range docs {
		file, err := os.Open(doc.Filepath())
		if err != nil {
			return err
		}
		defer file.Close()

		part, err := writer.CreateFormFile("files[]", doc.Path())
		if err != nil {
			return err
		}
		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}
	if err := writer.Close(); err != nil {
		return err
	}

	client, err := api.NewClient(ctx.usrCfg.GetString("token"), ctx.usrCfg.GetString("apibaseurl"))
	if err != nil {
		return err
	}
	url := fmt.Sprintf("%s/solutions/%s", ctx.usrCfg.GetString("apibaseurl"), id)
	req, err := client.NewRequest("PATCH", url, body)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

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

	if resp.StatusCode == http.StatusBadRequest {
		var jsonErrBody apiErrorMessage
		if err := json.NewDecoder(resp.Body).Decode(&jsonErrBody); err != nil {
			return fmt.Errorf("failed to parse error response - %s", err)
		}

		return fmt.Errorf(jsonErrBody.Error.Message)
	}

	bb := &bytes.Buffer{}
	_, err = bb.ReadFrom(resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func (ctx *submitContext) printResult(metadata *workspace.ExerciseMetadata) {
	msg := `

    Your solution has been submitted successfully.
    %s
`
	suffix := "View it at:\n\n    "
	if metadata.AutoApprove && metadata.Team == "" {
		suffix = "You can complete the exercise and unlock the next core exercise at:\n"
	}
	fmt.Fprintf(Err, msg, suffix)
	fmt.Fprintf(Out, "    %s\n\n", metadata.URL)
}

func init() {
	RootCmd.AddCommand(submitCmd)
}

type apiErrorMessage struct {
	Error struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error,omitempty"`
}
<commit_msg>Rename char receiver names<commit_after>package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

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

// submitCmd lets people upload a solution to the website.
var submitCmd = &cobra.Command{
	Use:     "submit FILE1 [FILE2 ...]",
	Aliases: []string{"s"},
	Short:   "Submit your solution to an exercise.",
	Long: `Submit your solution to an Exercism exercise.

    Call the command with the list of files you want to submit.
`,
	RunE: func(cmd *cobra.Command, args []string) error {
		cfg := config.NewConfig()

		usrCfg := viper.New()
		usrCfg.AddConfigPath(cfg.Dir)
		usrCfg.SetConfigName("user")
		usrCfg.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = usrCfg.ReadInConfig()
		cfg.UserViperConfig = usrCfg

		v := viper.New()
		v.AddConfigPath(cfg.Dir)
		v.SetConfigName("cli")
		v.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = v.ReadInConfig()

		return runSubmit(cfg, cmd.Flags(), args)
	},
}

type submitContext struct {
	args   []string
	usrCfg *viper.Viper
}

func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
	usrCfg := cfg.UserViperConfig

	if err := validateUserConfig(usrCfg); err != nil {
		return err
	}

	ctx := &submitContext{args: args, usrCfg: usrCfg}

	if err := ctx.sanitizeArgs(); err != nil {
		return err
	}

	exercise, err := ctx.exercise()
	if err != nil {
		return err
	}

	migrationStatus, err := exercise.MigrateLegacyMetadataFile()
	if err != nil {
		return err
	}
	if verbose, _ := flags.GetBool("verbose"); verbose {
		fmt.Fprintf(Err, migrationStatus.String())
	}

	metadata, err := ctx.metadata(exercise.Filepath())
	if err != nil {
		return err
	}

	exercise.Documents, err = ctx.documents(exercise.Filepath())
	if err != nil {
		return err
	}

	if err := ctx.submitRequest(metadata.ID, exercise.Documents); err != nil {
		return err
	}

	ctx.printResult(metadata)
	return nil
}

func (s *submitContext) validateUserConfig() error {
	if s.usrCfg.GetString("token") == "" {
		return fmt.Errorf(msgWelcomePleaseConfigure, config.SettingsURL(s.usrCfg.GetString("apibaseurl")), BinaryName)
	}
	if s.usrCfg.GetString("workspace") == "" {
		return fmt.Errorf(msgRerunConfigure, BinaryName)
	}
	return nil
}

func (s *submitContext) sanitizeArgs() error {
	for i, arg := range s.args {
		var err error
		arg, err = filepath.Abs(arg)
		if err != nil {
			return err
		}

		info, err := os.Lstat(arg)
		if err != nil {
			if os.IsNotExist(err) {
				msg := `

    The file you are trying to submit cannot be found.

        %s

        `
				return fmt.Errorf(msg, arg)
			}
			return err
		}
		if info.IsDir() {
			msg := `

    You are submitting a directory, which is not currently supported.

        %s

    Please change into the directory and provide the path to the file(s) you wish to submit

        %s submit FILENAME

            `
			return fmt.Errorf(msg, arg, BinaryName)
		}

		src, err := filepath.EvalSymlinks(arg)
		if err != nil {
			return err
		}
		s.args[i] = src
	}
	return nil
}

func (s *submitContext) exercise() (workspace.Exercise, error) {
	ws, err := workspace.New(s.usrCfg.GetString("workspace"))
	if err != nil {
		return workspace.Exercise{}, err
	}

	var exerciseDir string
	for _, arg := range s.args {
		dir, err := ws.ExerciseDir(arg)
		if err != nil {
			if workspace.IsMissingMetadata(err) {
				return workspace.Exercise{}, errors.New(msgMissingMetadata)
			}
			return workspace.Exercise{}, err
		}
		if exerciseDir != "" && dir != exerciseDir {
			msg := `

    You are submitting files belonging to different solutions.
    Please submit the files for one solution at a time.

        `
			return workspace.Exercise{}, errors.New(msg)
		}
		exerciseDir = dir
	}

	return workspace.NewExerciseFromDir(exerciseDir), nil
}

func (s *submitContext) metadata(exerciseDir string) (*workspace.ExerciseMetadata, error) {
	metadata, err := workspace.NewExerciseMetadata(exerciseDir)
	if err != nil {
		return nil, err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)
	if exercise.Slug != metadata.Exercise {
		// TODO: error msg should suggest running future doctor command
		msg := `

	The exercise directory does not match exercise slug in metadata:

		expected '%[1]s' but got '%[2]s'

	Please rename the directory '%[1]s' to '%[2]s' and try again.

		`
		return nil, fmt.Errorf(msg, exercise.Slug, metadata.Exercise)
	}

	if !metadata.IsRequester {
		// TODO: add test
		msg := `

    The solution you are submitting is not connected to your account.
    Please re-download the exercise to make sure it has the data it needs.

        %s download --exercise=%s --track=%s

        `
		return nil, fmt.Errorf(msg, BinaryName, metadata.Exercise, metadata.Track)
	}
	return metadata, nil
}

func (s *submitContext) documents(exerciseDir string) ([]workspace.Document, error) {
	docs := make([]workspace.Document, 0, len(s.args))
	for _, file := range s.args {
		// Don't submit empty files
		info, err := os.Stat(file)
		if err != nil {
			return nil, err
		}
		const maxFileSize int64 = 65535
		if info.Size() >= maxFileSize {
			msg := `

      The submitted file '%s' is larger than the max allowed file size of %d bytes.
      Please reduce the size of the file and try again.

            `
			return nil, fmt.Errorf(msg, file, maxFileSize)
		}
		if info.Size() == 0 {

			msg := `

    WARNING: Skipping empty file
             %s

        `
			fmt.Fprintf(Err, msg, file)
			continue
		}
		doc, err := workspace.NewDocument(exerciseDir, file)
		if err != nil {
			return nil, err
		}
		docs = append(docs, doc)
	}
	if len(docs) == 0 {
		msg := `

    No files found to submit.

        `
		return nil, errors.New(msg)
	}
	return docs, nil
}

func (s *submitContext) submitRequest(id string, docs []workspace.Document) error {
	if id == "" {
		return errors.New("id is empty")
	}
	if len(docs) == 0 {
		return errors.New("docs is empty")
	}

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	for _, doc := range docs {
		file, err := os.Open(doc.Filepath())
		if err != nil {
			return err
		}
		defer file.Close()

		part, err := writer.CreateFormFile("files[]", doc.Path())
		if err != nil {
			return err
		}
		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}
	if err := writer.Close(); err != nil {
		return err
	}

	client, err := api.NewClient(s.usrCfg.GetString("token"), s.usrCfg.GetString("apibaseurl"))
	if err != nil {
		return err
	}
	url := fmt.Sprintf("%s/solutions/%s", s.usrCfg.GetString("apibaseurl"), id)
	req, err := client.NewRequest("PATCH", url, body)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

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

	if resp.StatusCode == http.StatusBadRequest {
		var jsonErrBody apiErrorMessage
		if err := json.NewDecoder(resp.Body).Decode(&jsonErrBody); err != nil {
			return fmt.Errorf("failed to parse error response - %s", err)
		}

		return fmt.Errorf(jsonErrBody.Error.Message)
	}

	bb := &bytes.Buffer{}
	_, err = bb.ReadFrom(resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func (s *submitContext) printResult(metadata *workspace.ExerciseMetadata) {
	msg := `

    Your solution has been submitted successfully.
    %s
`
	suffix := "View it at:\n\n    "
	if metadata.AutoApprove && metadata.Team == "" {
		suffix = "You can complete the exercise and unlock the next core exercise at:\n"
	}
	fmt.Fprintf(Err, msg, suffix)
	fmt.Fprintf(Out, "    %s\n\n", metadata.URL)
}

func init() {
	RootCmd.AddCommand(submitCmd)
}

type apiErrorMessage struct {
	Error struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error,omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

var CmdStatus = &Cmd{
	Name: "status",
	Desc: "prints some debug status informations",
	Fn: func(env Env, args []string) error {
		config, err := LoadConfig(env)
		if err != nil {
			return err
		}

		fmt.Println("direnv exec path", config.SelfPath)
		fmt.Println("DIRENV_CONFIG", config.ConfDir)

		loadedRC := config.LoadedRC()
		foundRC := config.FindRC()

		if loadedRC != nil {
			fmt.Println("Loaded RC path", loadedRC.path)
			fmt.Println("Loaded RC mtime", loadedRC.mtime)
			fmt.Println("Loaded RC allowed", loadedRC.Allowed())
			fmt.Println("Loaded RC allowPath", loadedRC.allowPath)
		} else {
			fmt.Println("No .envrc loaded")
		}

		if foundRC != nil {
			fmt.Println("Found RC path", foundRC.path)
			fmt.Println("Found RC mtime", foundRC.mtime)
			fmt.Println("Found RC allowed", foundRC.Allowed())
			fmt.Println("Found RC allowPath", foundRC.allowPath)
		} else {
			fmt.Println("No .envrc found")
		}

		return nil
	},
}
<commit_msg>typo: informations -> information<commit_after>package main

import (
	"fmt"
)

var CmdStatus = &Cmd{
	Name: "status",
	Desc: "prints some debug status information",
	Fn: func(env Env, args []string) error {
		config, err := LoadConfig(env)
		if err != nil {
			return err
		}

		fmt.Println("direnv exec path", config.SelfPath)
		fmt.Println("DIRENV_CONFIG", config.ConfDir)

		loadedRC := config.LoadedRC()
		foundRC := config.FindRC()

		if loadedRC != nil {
			fmt.Println("Loaded RC path", loadedRC.path)
			fmt.Println("Loaded RC mtime", loadedRC.mtime)
			fmt.Println("Loaded RC allowed", loadedRC.Allowed())
			fmt.Println("Loaded RC allowPath", loadedRC.allowPath)
		} else {
			fmt.Println("No .envrc loaded")
		}

		if foundRC != nil {
			fmt.Println("Found RC path", foundRC.path)
			fmt.Println("Found RC mtime", foundRC.mtime)
			fmt.Println("Found RC allowed", foundRC.Allowed())
			fmt.Println("Found RC allowPath", foundRC.allowPath)
		} else {
			fmt.Println("No .envrc found")
		}

		return nil
	},
}
<|endoftext|>


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

// Dump the headers of a PE file.
//
// Synopsis:
//     pe [FILENAME]
//
// Description:
//     Windows and EFI executables are in the portable executable (PE) format.
//     This command prints the headers in a JSON format.
package main

import (
	"debug/pe"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
)

func openPE() (*pe.File, error) {
	switch flag.NArg() {
	case 0:
		return pe.NewFile(os.Stdin)
	case 1:
		filename := flag.Arg(0)
		return pe.Open(filename)
	default:
		return nil, errors.New("Usage: pe [FILENAME]")
	}
}

func main() {
	flag.Parse()

	f, err := openPE()
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	json, err := json.MarshalIndent(f, "", "\t")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(json))
}
<commit_msg>Cleanup pe command<commit_after>// Copyright 2017 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.

// Dump the headers of a PE file.
//
// Synopsis:
//     pe [FILENAME]
//
// Description:
//     Windows and EFI executables are in the portable executable (PE) format.
//     This command prints the headers in a JSON format.
package main

import (
	"debug/pe"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
)

func main() {
	// Parse flags
	flag.Parse()
	var (
		f   *pe.File
		err error
	)
	switch flag.NArg() {
	case 0:
		f, err = pe.NewFile(os.Stdin)
	case 1:
		filename := flag.Arg(0)
		f, err = pe.Open(filename)
	default:
		log.Fatal("Usage: pe [FILENAME]")
	}
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	// Convert to JSON
	j, err := json.MarshalIndent(f, "", "\t")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(j))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/fabiofalci/sconsify/events"
	"github.com/fabiofalci/sconsify/spotify"
	"github.com/fabiofalci/sconsify/ui"
	"github.com/howeyc/gopass"
)

func main() {
	providedUsername := flag.String("username", "", "Spotify username.")
	providedUi := flag.Bool("ui", true, "Run Sconsify with Console User Interface. If false then no User Interface will be presented and it'll only random between Playlists.")
	providedNoUiSilent := flag.Bool("noui-silent", false, "Silent mode when no User Interface is used.")
	flag.Parse()

	username, pass := credentials(providedUsername)
	events := events.InitialiseEvents()

	go spotify.Initialise(username, pass, events)

	if *providedUi {
		ui.StartConsoleUserInterface(events)
	} else {
		ui.StartNoUserInterface(events, providedNoUiSilent)
	}
}

func credentials(providedUsername *string) (*string, *[]byte) {
	username := ""
	if *providedUsername == "" {
		fmt.Print("Username: ")
		reader := bufio.NewReader(os.Stdin)
		username, _ = reader.ReadString('\n')
	} else {
		username = *providedUsername
	}
	username = strings.Trim(username, " \n\r")
	fmt.Print("Password: ")
	pass := gopass.GetPasswd()
	return &username, &pass
}
<commit_msg>If available read password from environment<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/fabiofalci/sconsify/events"
	"github.com/fabiofalci/sconsify/spotify"
	"github.com/fabiofalci/sconsify/ui"
	"github.com/howeyc/gopass"
)

func main() {
	providedUsername := flag.String("username", "", "Spotify username.")
	providedUi := flag.Bool("ui", true, "Run Sconsify with Console User Interface. If false then no User Interface will be presented and it'll only random between Playlists.")
	providedNoUiSilent := flag.Bool("noui-silent", false, "Silent mode when no User Interface is used.")
	flag.Parse()

	username, pass := credentials(providedUsername)
	events := events.InitialiseEvents()

	go spotify.Initialise(username, pass, events)

	if *providedUi {
		ui.StartConsoleUserInterface(events)
	} else {
		ui.StartNoUserInterface(events, providedNoUiSilent)
	}
}

func credentials(providedUsername *string) (*string, *[]byte) {
	username := ""
	if *providedUsername == "" {
		fmt.Print("Username: ")
		reader := bufio.NewReader(os.Stdin)
		username, _ = reader.ReadString('\n')
	} else {
		username = *providedUsername
	}
	username = strings.Trim(username, " \n\r")
	return &username, getPassword()
}

func getPassword() *[]byte {
	passFromEnv := os.Getenv("SCONSIFY_PASSWORD")
	if passFromEnv != "" {
		fmt.Println("Password from environment variable SCONSIFY_PASSWORD.")
		fmt.Println("Unset if you don't want to use it (unset SCONSIFY_PASSWORD).")
		b := []byte(passFromEnv)
		return &b
	}
	fmt.Print("Password: ")
	b := gopass.GetPasswd()
	return &b
}
<|endoftext|>


<commit_before>package steps

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/pivotal-golang/lager"
)

func invalidInterval(field string, interval time.Duration) error {
	return fmt.Errorf("The %s interval, %s, is not positive.", field, interval.String())
}

type monitorStep struct {
	check             Step
	hasStartedRunning chan<- struct{}

	logger       lager.Logger
	timeProvider timeprovider.TimeProvider

	startTimeout      time.Duration
	healthyInterval   time.Duration
	unhealthyInterval time.Duration

	cancelled int32
	cancel    chan struct{}
}

func NewMonitor(
	check Step,
	hasStartedRunning chan<- struct{},
	logger lager.Logger,
	timeProvider timeprovider.TimeProvider,
	startTimeout time.Duration,
	healthyInterval time.Duration,
	unhealthyInterval time.Duration,
) Step {
	logger = logger.Session("monitor-step")

	return &monitorStep{
		check:             check,
		hasStartedRunning: hasStartedRunning,
		logger:            logger,
		timeProvider:      timeProvider,
		startTimeout:      startTimeout,
		healthyInterval:   healthyInterval,
		unhealthyInterval: unhealthyInterval,
		cancel:            make(chan struct{}),
	}
}

func (step *monitorStep) Perform() error {

	if step.healthyInterval <= 0 {
		return invalidInterval("healthy", step.healthyInterval)
	}

	if step.unhealthyInterval <= 0 {
		return invalidInterval("unhealthy", step.unhealthyInterval)
	}

	healthy := false
	interval := step.unhealthyInterval

	var startBy *time.Time
	if step.startTimeout > 0 {
		t := step.timeProvider.Now().Add(step.startTimeout)
		startBy = &t
	}

	timer := step.timeProvider.NewTimer(interval)
	defer timer.Stop()

	for {
		select {
		case now := <-timer.C():
			stepErr := step.check.Perform()
			nowHealthy := stepErr == nil

			if healthy && !nowHealthy {
				step.logger.Info("transitioned-to-unhealthy")
				return stepErr
			} else if !healthy && nowHealthy {
				step.logger.Info("transitioned-to-healthy")
				healthy = true
				step.hasStartedRunning <- struct{}{}
				interval = step.healthyInterval
				startBy = nil
			}

			if startBy != nil && now.After(*startBy) {
				if !healthy {
					step.logger.Info("timed-out-before-healthy")
					return stepErr
				}
				startBy = nil
			}
		case <-step.cancel:
			return nil
		}

		timer.Reset(interval)
	}

	return nil
}

func (step *monitorStep) Cancel() {
	if !atomic.CompareAndSwapInt32(&step.cancelled, 0, 1) {
		return
	}

	step.logger.Info("cancelling")
	close(step.cancel)
}
<commit_msg>simplify monitor action cancel detection<commit_after>package steps

import (
	"fmt"
	"time"

	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/pivotal-golang/lager"
)

func invalidInterval(field string, interval time.Duration) error {
	return fmt.Errorf("The %s interval, %s, is not positive.", field, interval.String())
}

type monitorStep struct {
	check             Step
	hasStartedRunning chan<- struct{}

	logger       lager.Logger
	timeProvider timeprovider.TimeProvider

	startTimeout      time.Duration
	healthyInterval   time.Duration
	unhealthyInterval time.Duration

	cancel chan struct{}
}

func NewMonitor(
	check Step,
	hasStartedRunning chan<- struct{},
	logger lager.Logger,
	timeProvider timeprovider.TimeProvider,
	startTimeout time.Duration,
	healthyInterval time.Duration,
	unhealthyInterval time.Duration,
) Step {
	logger = logger.Session("monitor-step")

	return &monitorStep{
		check:             check,
		hasStartedRunning: hasStartedRunning,
		logger:            logger,
		timeProvider:      timeProvider,
		startTimeout:      startTimeout,
		healthyInterval:   healthyInterval,
		unhealthyInterval: unhealthyInterval,
		cancel:            make(chan struct{}),
	}
}

func (step *monitorStep) Perform() error {

	if step.healthyInterval <= 0 {
		return invalidInterval("healthy", step.healthyInterval)
	}

	if step.unhealthyInterval <= 0 {
		return invalidInterval("unhealthy", step.unhealthyInterval)
	}

	healthy := false
	interval := step.unhealthyInterval

	var startBy *time.Time
	if step.startTimeout > 0 {
		t := step.timeProvider.Now().Add(step.startTimeout)
		startBy = &t
	}

	timer := step.timeProvider.NewTimer(interval)
	defer timer.Stop()

	for {
		select {
		case now := <-timer.C():
			stepErr := step.check.Perform()
			nowHealthy := stepErr == nil

			if healthy && !nowHealthy {
				step.logger.Info("transitioned-to-unhealthy")
				return stepErr
			} else if !healthy && nowHealthy {
				step.logger.Info("transitioned-to-healthy")
				healthy = true
				step.hasStartedRunning <- struct{}{}
				interval = step.healthyInterval
				startBy = nil
			}

			if startBy != nil && now.After(*startBy) {
				if !healthy {
					step.logger.Info("timed-out-before-healthy")
					return stepErr
				}
				startBy = nil
			}
		case <-step.cancel:
			return nil
		}

		timer.Reset(interval)
	}

	return nil
}

func (step *monitorStep) Cancel() {
	step.logger.Info("cancelling")

	select {
	case <-step.cancel:
	default:
		close(step.cancel)
	}
}
<|endoftext|>


<commit_before>package util

import (
	// "fmt"
	"io"
	// "log"
	"fmt"
	"strings"
)

type TextPreview struct {
	Offset   int `json:"offset"`
	previews []string
	Preview  string `json:"preview"`
	Hits     []int  `json:"hits"`
}

func FilterTextPreview(r io.Reader, filter func(line string) bool, before int, after int) []TextPreview {
	scanner := NewLineScanner(r, 1024, before, after)

	previews := []TextPreview{}

	for scanner.HasNext() {
		lineNum, line, ok := scanner.FindLine(filter)

		var beforePreview *TextPreview
		hasPreview := len(previews) > 0

		if hasPreview {
			beforePreview = &previews[len(previews)-1]
		}

		if ok {
			before := scanner.GetBefore()
			offset := lineNum - len(before)

			// Checking need to merge with previous preview

			if hasPreview {
				lastLineNum := beforePreview.Offset + len(beforePreview.previews) - 1
				lastHitNum := beforePreview.Hits[len(beforePreview.Hits)-1]

				// concat
				if (lineNum - lastHitNum) <= scanner.GetAfterSize() {
					appendPreview(beforePreview, lineNum, line)
					continue
				}

				if offset <= (lastLineNum + 1) {
					// reduce duplication
					start := (lastLineNum + 1) - offset
					// fmt.Println("before", len(before), lineNum, line, lastLineNum, offset, start)

					lines := append(before[start:], line)

					appendPreview(beforePreview, lineNum, lines...)
					continue
				}
				// fmt.Println("assert", lineNum, lastHitNum, offset)
			}

			// New preview
			lines := append(before, line)
			preview := TextPreview{Offset: offset, Hits: []int{lineNum}, previews: lines}

			previews = append(previews, preview)

		} else {
			if hasPreview {
				lastHitNum := beforePreview.Hits[len(beforePreview.Hits)-1]
				if (lineNum - lastHitNum) <= scanner.GetAfterSize() {
					beforePreview.previews = append(beforePreview.previews, line)
					// fmt.Println("-----", line, scanner.GetLineNum())
				}
			}
		}
	}

	for i := range previews {
		previews[i].Preview = strings.Join(previews[i].previews, "\n")
		previews[i].previews = nil
	}
	return previews
}

func appendPreview(preview *TextPreview, hitLinuNum int, line ...string) {
	preview.Hits = append(preview.Hits, hitLinuNum)
	preview.previews = append(preview.previews, line...)
}

func Must(e error) {
	if e != nil {
		panic(e)
	}
}
<commit_msg>unused<commit_after>package util

import (
	// "fmt"
	"io"
	// "log"
	// "fmt"
	"strings"
)

type TextPreview struct {
	Offset   int `json:"offset"`
	previews []string
	Preview  string `json:"preview"`
	Hits     []int  `json:"hits"`
}

func FilterTextPreview(r io.Reader, filter func(line string) bool, before int, after int) []TextPreview {
	scanner := NewLineScanner(r, 1024, before, after)

	previews := []TextPreview{}

	for scanner.HasNext() {
		lineNum, line, ok := scanner.FindLine(filter)

		var beforePreview *TextPreview
		hasPreview := len(previews) > 0

		if hasPreview {
			beforePreview = &previews[len(previews)-1]
		}

		if ok {
			before := scanner.GetBefore()
			offset := lineNum - len(before)

			// Checking need to merge with previous preview

			if hasPreview {
				lastLineNum := beforePreview.Offset + len(beforePreview.previews) - 1
				lastHitNum := beforePreview.Hits[len(beforePreview.Hits)-1]

				// concat
				if (lineNum - lastHitNum) <= scanner.GetAfterSize() {
					appendPreview(beforePreview, lineNum, line)
					continue
				}

				if offset <= (lastLineNum + 1) {
					// reduce duplication
					start := (lastLineNum + 1) - offset
					// fmt.Println("before", len(before), lineNum, line, lastLineNum, offset, start)

					lines := append(before[start:], line)

					appendPreview(beforePreview, lineNum, lines...)
					continue
				}
				// fmt.Println("assert", lineNum, lastHitNum, offset)
			}

			// New preview
			lines := append(before, line)
			preview := TextPreview{Offset: offset, Hits: []int{lineNum}, previews: lines}

			previews = append(previews, preview)

		} else {
			if hasPreview {
				lastHitNum := beforePreview.Hits[len(beforePreview.Hits)-1]
				if (lineNum - lastHitNum) <= scanner.GetAfterSize() {
					beforePreview.previews = append(beforePreview.previews, line)
					// fmt.Println("-----", line, scanner.GetLineNum())
				}
			}
		}
	}

	for i := range previews {
		previews[i].Preview = strings.Join(previews[i].previews, "\n")
		previews[i].previews = nil
	}
	return previews
}

func appendPreview(preview *TextPreview, hitLinuNum int, line ...string) {
	preview.Hits = append(preview.Hits, hitLinuNum)
	preview.previews = append(preview.previews, line...)
}

func Must(e error) {
	if e != nil {
		panic(e)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Chromium 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 tsmon

import (
	"sync"

	"golang.org/x/net/context"

	"github.com/luci/luci-go/common/tsmon/monitor"
	"github.com/luci/luci-go/common/tsmon/store"
	"github.com/luci/luci-go/common/tsmon/types"
)

// State holds the configuration of the tsmon library.  There is one global
// instance of State, but it can be overridden in a Context by tests.
type State struct {
	S       store.Store
	M       monitor.Monitor
	Flusher *autoFlusher

	RegisteredMetrics     map[string]types.Metric
	RegisteredMetricsLock sync.RWMutex

	CallbacksMutex sync.RWMutex
	Callbacks      []Callback
}

// GetState returns the State instance held in the context (if set) or else
// returns the global state.
func GetState(c context.Context) *State {
	if ret := c.Value(stateKey); ret != nil {
		return ret.(*State)
	}
	return globalState
}

// WithState returns a new context holding the given State instance.
func WithState(c context.Context, s *State) context.Context {
	return context.WithValue(c, stateKey, s)
}

// WithFakes returns a new context holding a new State with a fake store and a
// fake monitor.
func WithFakes(c context.Context) (context.Context, *store.Fake, *monitor.Fake) {
	s := &store.Fake{}
	m := &monitor.Fake{}
	return WithState(c, &State{
		S:                 s,
		M:                 m,
		RegisteredMetrics: map[string]types.Metric{},
	}), s, m
}

type key int

var (
	globalState = &State{
		S:                 store.NewNilStore(),
		M:                 monitor.NewNilMonitor(),
		RegisteredMetrics: map[string]types.Metric{},
	}
	stateKey key = 1
)
<commit_msg>Add a WithDummyInMemory function - useful for tests that want a fake metric store<commit_after>// Copyright 2016 The Chromium 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 tsmon

import (
	"sync"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"github.com/luci/luci-go/common/tsmon/monitor"
	"github.com/luci/luci-go/common/tsmon/store"
	"github.com/luci/luci-go/common/tsmon/target"
	"github.com/luci/luci-go/common/tsmon/types"
)

// State holds the configuration of the tsmon library.  There is one global
// instance of State, but it can be overridden in a Context by tests.
type State struct {
	S       store.Store
	M       monitor.Monitor
	Flusher *autoFlusher

	RegisteredMetrics     map[string]types.Metric
	RegisteredMetricsLock sync.RWMutex

	CallbacksMutex sync.RWMutex
	Callbacks      []Callback
}

// GetState returns the State instance held in the context (if set) or else
// returns the global state.
func GetState(c context.Context) *State {
	if ret := c.Value(stateKey); ret != nil {
		return ret.(*State)
	}
	return globalState
}

// WithState returns a new context holding the given State instance.
func WithState(c context.Context, s *State) context.Context {
	return context.WithValue(c, stateKey, s)
}

// WithFakes returns a new context holding a new State with a fake store and a
// fake monitor.
func WithFakes(c context.Context) (context.Context, *store.Fake, *monitor.Fake) {
	s := &store.Fake{}
	m := &monitor.Fake{}
	return WithState(c, &State{
		S:                 s,
		M:                 m,
		RegisteredMetrics: map[string]types.Metric{},
	}), s, m
}

// WithDummyInMemory returns a new context holding a new State with a new in-
// memory store and a fake monitor.
func WithDummyInMemory(c context.Context) (context.Context, *monitor.Fake) {
	s := store.NewInMemory(&target.Task{ServiceName: proto.String("")})
	m := &monitor.Fake{}
	return WithState(c, &State{
		S:                 s,
		M:                 m,
		RegisteredMetrics: map[string]types.Metric{},
	}), m
}

type key int

var (
	globalState = &State{
		S:                 store.NewNilStore(),
		M:                 monitor.NewNilMonitor(),
		RegisteredMetrics: map[string]types.Metric{},
	}
	stateKey key = 1
)
<|endoftext|>


<commit_before>package aws

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Figure out user data
	userData := ""
	if attr, ok := d.Attributes["user_data"]; ok {
		userData = attr.NewExtra.(string)
	}

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
		UserData:     []byte(userData),
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "running",
		Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout: 10 * time.Minute,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Initialize the connection info
	rs.ConnInfo["type"] = "ssh"
	rs.ConnInfo["host"] = instance.PublicIpAddress

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:  "terminated",
		Refresh: InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout: 10 * time.Minute,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
			"user_data":         diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"key_name",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
			"security_groups",
			"subnet_id",
		},

		PreProcess: map[string]diff.PreProcessFunc{
			"user_data": func(v string) string {
				hash := sha1.Sum([]byte(v))
				return hex.EncodeToString(hash[:])
			},
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<commit_msg>provider/aws: Less aggressive API rate<commit_after>package aws

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Figure out user data
	userData := ""
	if attr, ok := d.Attributes["user_data"]; ok {
		userData = attr.NewExtra.(string)
	}

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
		UserData:     []byte(userData),
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending"},
		Target:     "running",
		Refresh:    InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Initialize the connection info
	rs.ConnInfo["type"] = "ssh"
	rs.ConnInfo["host"] = instance.PublicIpAddress

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:     "terminated",
		Refresh:    InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
			"user_data":         diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"key_name",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
			"security_groups",
			"subnet_id",
		},

		PreProcess: map[string]diff.PreProcessFunc{
			"user_data": func(v string) string {
				hash := sha1.Sum([]byte(v))
				return hex.EncodeToString(hash[:])
			},
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"hermes/stats/responses"

	"github.com/go-playground/validator"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
)

var Schema = `
schema {
    query: Stats
}

enum Operator {
    EQUAL
}

enum Condition {
    OR
    AND
}

type Stats {
    count: Count,
    average: Average
}

type Count {
    ratings(field: Field): Int!
}

type Average {
    ratings(field: Field): Float!
}

input Field {
    name: String!
    operator: Operator
    int: Int
    float: Float
    string: String
    bool: Boolean
    next: Operation
}

input Operation {
    condition: Condition!
    field: Field
}
`

type stats struct {
	Count   *graphql.ID
	Average *graphql.ID
}

type field struct {
	Name     string
	Operator *graphql.ID
	Int      *int
	Float    *float64
	String   *string
	Bool     *bool
	Next     *graphql.ID
}

type operation struct {
	Condition graphql.ID
	Field     *graphql.ID
}

type RequestValidator struct {
	validator *validator.Validate
}

func (rv *RequestValidator) Validate(request interface{}) error {
	return rv.validator.Struct(request)
}

func badRequestMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !hasAcceptHeader(context) {
			message = "Accept header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.OPTIONS && hasContentTypeHeader(context) {
			message = "OPTIONS requests must have no body"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.POST && !hasContentTypeHeader(context) {
			message = "Content-Type header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		return next(context)
	}
}

func notAcceptableMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !isValidAcceptHeader(context) {
			message = "JSON responses must be accepted"

			return echo.NewHTTPError(http.StatusNotAcceptable, []string{message})
		}

		return next(context)
	}
}

func unsupportedMediaTypeMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if context.Request().Method == echo.POST {
			if !isValidContentTypeHeader(context) || !isValidCharacterEncoding(context) {
				message = "Request body must be UTF-8 encoded JSON"

				return echo.NewHTTPError(http.StatusUnsupportedMediaType, []string{message})
			}
		}

		return next(context)
	}
}

func notImplementedMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		if context.Request().Method != echo.POST && context.Request().Method != echo.OPTIONS {
			return echo.NewHTTPError(http.StatusNotImplemented)
		}

		return next(context)
	}
}

func corsMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		context.Response().Header().Set("Access-Control-Allow-Origin", "*")
		context.Response().Header().Set("Access-Control-Allow-Methods", "OPTIONS, POST")
		context.Response().Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")

		return next(context)
	}
}

func hasAcceptHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Accept"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidAcceptHeader(context echo.Context) bool {
	accepted := "application/json"

	if header := context.Request().Header.Get("Accept"); strings.Contains(strings.ToLower(header), accepted) || header == "*/*" {
		return true
	}

	return false
}

func hasContentTypeHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Content-Type"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidContentTypeHeader(context echo.Context) bool {
	text := "text/plain"
	json := "application/json"

	if header := context.Request().Header.Get("Content-Type"); strings.Contains(strings.ToLower(header), text) || strings.Contains(strings.ToLower(header), json) {
		return true
	}

	return false
}

func isValidCharacterEncoding(context echo.Context) bool {
	charset := "charset=utf-8"

	if header := context.Request().Header.Get("Content-Type"); strings.HasSuffix(strings.ToLower(header), charset) {
		return true
	}

	return false
}

func loadSchema() {

}

func Handler(port int, handlers map[string]echo.HandlerFunc) http.Handler {
	e := echo.New()
	validate := validator.New()
	env := os.Getenv("HERMES_STATS_ENV")

	if env == "DEV" {
		e.Logger.SetLevel(log.DEBUG)
		e.Debug = true
	} else {
		e.Pre(middleware.HTTPSRedirect())
		e.Logger.SetLevel(log.ERROR)
	}

	e.Use(middleware.Secure())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.BodyLimit("20K"))
	e.Use(notImplementedMiddleware)
	e.Use(notAcceptableMiddleware)
	e.Use(badRequestMiddleware)
	e.Use(unsupportedMediaTypeMiddleware)
	e.Use(corsMiddleware)

	e.POST("/stats", handlers["PostStats"])

	e.HTTPErrorHandler = responses.ErrorHandler
	e.Validator = &RequestValidator{validator: validate}
	e.Server.Addr = ":" + strconv.Itoa(port)

	return e
}
<commit_msg>Added Parse()<commit_after>package handler

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"hermes/stats/responses"

	"github.com/go-playground/validator"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
)

// SCHEMA --- Extract this into another package
var schema *graphql.Schema

var Schema = `
schema {
    query: Stats
}

enum Operator {
    EQUAL
}

enum Condition {
    OR
    AND
}

type Stats {
    count: Count,
    average: Average
}

type Count {
    ratings(field: Field): Int!
}

type Average {
    ratings(field: Field): Float!
}

input Field {
    name: String!
    operator: Operator
    int: Int
    float: Float
    string: String
    bool: Boolean
    next: Operation
}

input Operation {
    condition: Condition!
    field: Field
}
`

type stats struct {
	Count   *graphql.ID
	Average *graphql.ID
}

type field struct {
	Name     string
	Operator *graphql.ID
	Int      *int
	Float    *float64
	String   *string
	Bool     *bool
	Next     *graphql.ID
}

type operation struct {
	Condition graphql.ID
	Field     *graphql.ID
}

func Parse() {
	var err error

	schema, err = graphql.ParseSchema(starwars.Schema, &starwars.Resolver{})

	if err != nil {
		panic(err)
	}
}

// END SCHEMA --- Extract this into another package

type RequestValidator struct {
	validator *validator.Validate
}

func (rv *RequestValidator) Validate(request interface{}) error {
	return rv.validator.Struct(request)
}

func badRequestMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !hasAcceptHeader(context) {
			message = "Accept header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.OPTIONS && hasContentTypeHeader(context) {
			message = "OPTIONS requests must have no body"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.POST && !hasContentTypeHeader(context) {
			message = "Content-Type header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		return next(context)
	}
}

func notAcceptableMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !isValidAcceptHeader(context) {
			message = "JSON responses must be accepted"

			return echo.NewHTTPError(http.StatusNotAcceptable, []string{message})
		}

		return next(context)
	}
}

func unsupportedMediaTypeMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if context.Request().Method == echo.POST {
			if !isValidContentTypeHeader(context) || !isValidCharacterEncoding(context) {
				message = "Request body must be UTF-8 encoded JSON"

				return echo.NewHTTPError(http.StatusUnsupportedMediaType, []string{message})
			}
		}

		return next(context)
	}
}

func notImplementedMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		if context.Request().Method != echo.POST && context.Request().Method != echo.OPTIONS {
			return echo.NewHTTPError(http.StatusNotImplemented)
		}

		return next(context)
	}
}

func corsMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		context.Response().Header().Set("Access-Control-Allow-Origin", "*")
		context.Response().Header().Set("Access-Control-Allow-Methods", "OPTIONS, POST")
		context.Response().Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")

		return next(context)
	}
}

func hasAcceptHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Accept"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidAcceptHeader(context echo.Context) bool {
	accepted := "application/json"

	if header := context.Request().Header.Get("Accept"); strings.Contains(strings.ToLower(header), accepted) || header == "*/*" {
		return true
	}

	return false
}

func hasContentTypeHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Content-Type"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidContentTypeHeader(context echo.Context) bool {
	text := "text/plain"
	json := "application/json"

	if header := context.Request().Header.Get("Content-Type"); strings.Contains(strings.ToLower(header), text) || strings.Contains(strings.ToLower(header), json) {
		return true
	}

	return false
}

func isValidCharacterEncoding(context echo.Context) bool {
	charset := "charset=utf-8"

	if header := context.Request().Header.Get("Content-Type"); strings.HasSuffix(strings.ToLower(header), charset) {
		return true
	}

	return false
}

func loadSchema() {

}

func Handler(port int, handlers map[string]echo.HandlerFunc) http.Handler {
	e := echo.New()
	validate := validator.New()
	env := os.Getenv("HERMES_STATS_ENV")

	if env == "DEV" {
		e.Logger.SetLevel(log.DEBUG)
		e.Debug = true
	} else {
		e.Pre(middleware.HTTPSRedirect())
		e.Logger.SetLevel(log.ERROR)
	}

	e.Use(middleware.Secure())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.BodyLimit("20K"))
	e.Use(notImplementedMiddleware)
	e.Use(notAcceptableMiddleware)
	e.Use(badRequestMiddleware)
	e.Use(unsupportedMediaTypeMiddleware)
	e.Use(corsMiddleware)

	e.POST("/stats", handlers["PostStats"])

	e.HTTPErrorHandler = responses.ErrorHandler
	e.Validator = &RequestValidator{validator: validate}
	e.Server.Addr = ":" + strconv.Itoa(port)

	return e
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"hermes/database"
	"hermes/stats/responses"

	"github.com/go-playground/validator"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
	"github.com/jinzhu/gorm"
)

// SCHEMA --- Extract this into another package

var (
	schema *graphql.Schema
)

type (
	field struct {
		Name     string
		Operator *string
		Int      *int
		Float    *float64
		String   *string
		Bool     *bool
		Next     *operation
	}

	operation struct {
		Condition string
		Field     *field
	}

	Resolver struct {
		db: *gorm.DB
	}

	CountResolver struct {
		db: *gorm.DB
	}

	AverageResolver struct {
		db: *gorm.DB
	}
)

func (cr *CountResolver) Ratings(args struct{ Field field }) int {
	return 0
}

func (ar *AverageResolver) Ratings(args struct{ Field field }) float {
	return 0
}

func NewResolver(db *gorm.DB) *Resolver {
	return &Resolver{db: db}
}

func ParseSchema() {
	var err error
	var db = database.GetReadDB()

	defer db.Close()

	rawSchema, readErr := ioutil.ReadFile("../schema/schema.graphql")

	if !readOk {
		panic("Could not load Graphql schema")
	}

	schema, err = graphql.ParseSchema(string(rawSchema), NewResolver(db))

	if err != nil {
		panic(err)
	}
}

// END SCHEMA --- Extract this into another package

type RequestValidator struct {
	validator *validator.Validate
}

func (rv *RequestValidator) Validate(request interface{}) error {
	return rv.validator.Struct(request)
}

func badRequestMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !hasAcceptHeader(context) {
			message = "Accept header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.OPTIONS && hasContentTypeHeader(context) {
			message = "OPTIONS requests must have no body"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.POST && !hasContentTypeHeader(context) {
			message = "Content-Type header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		return next(context)
	}
}

func notAcceptableMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !isValidAcceptHeader(context) {
			message = "JSON responses must be accepted"

			return echo.NewHTTPError(http.StatusNotAcceptable, []string{message})
		}

		return next(context)
	}
}

func notImplementedMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		if context.Request().Method != echo.POST && context.Request().Method != echo.OPTIONS {
			return echo.NewHTTPError(http.StatusNotImplemented)
		}

		return next(context)
	}
}

func corsMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		context.Response().Header().Set("Access-Control-Allow-Origin", "*")
		context.Response().Header().Set("Access-Control-Allow-Methods", "POST")
		context.Response().Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")

		return next(context)
	}
}

func hasAcceptHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Accept"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidAcceptHeader(context echo.Context) bool {
	accepted := "application/json"

	if header := context.Request().Header.Get("Accept"); strings.Contains(strings.ToLower(header), accepted) || header == "*/*" {
		return true
	}

	return false
}

func hasContentTypeHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Content-Type"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func Handler(port int, handlers map[string]echo.HandlerFunc) http.Handler {
	e := echo.New()
	validate := validator.New()
	env := os.Getenv("HERMES_STATS_ENV")

	if env == "DEV" {
		e.Logger.SetLevel(log.DEBUG)
		e.Debug = true
	} else {
		e.Pre(middleware.HTTPSRedirect())
		e.Logger.SetLevel(log.ERROR)
	}

	e.Use(middleware.Secure())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.BodyLimit("20K"))
	e.Use(notImplementedMiddleware)
	e.Use(notAcceptableMiddleware)
	e.Use(badRequestMiddleware)
	e.Use(corsMiddleware)

	e.POST("/stats", handlers["PostStats"])

	e.HTTPErrorHandler = responses.ErrorHandler
	e.Validator = &RequestValidator{validator: validate}
	e.Server.Addr = ":" + strconv.Itoa(port)

	return e
}
<commit_msg>Fixed error management<commit_after>package handler

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"hermes/database"
	"hermes/stats/responses"

	"github.com/go-playground/validator"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
	"github.com/labstack/gommon/log"
	"github.com/jinzhu/gorm"
)

// SCHEMA --- Extract this into another package

var (
	schema *graphql.Schema
)

type (
	field struct {
		Name     string
		Operator *string
		Int      *int
		Float    *float64
		String   *string
		Bool     *bool
		Next     *operation
	}

	operation struct {
		Condition string
		Field     *field
	}

	Resolver struct {
		db: *gorm.DB
	}

	CountResolver struct {
		db: *gorm.DB
	}

	AverageResolver struct {
		db: *gorm.DB
	}
)

func (cr *CountResolver) Ratings(args struct{ Field field }) int {
	return 0
}

func (ar *AverageResolver) Ratings(args struct{ Field field }) float {
	return 0
}

func NewResolver(db *gorm.DB) *Resolver {
	return &Resolver{db: db}
}

func ParseSchema() {
	var rawSchema []byte
	var err error
	var db = database.GetReadDB()

	defer db.Close()

	rawSchema, err = ioutil.ReadFile("../schema/schema.graphql")

	if err != nil {
		panic(err)
	}

	schema, err = graphql.ParseSchema(string(rawSchema), NewResolver(db))

	if err != nil {
		panic(err)
	}
}

// END SCHEMA --- Extract this into another package

type RequestValidator struct {
	validator *validator.Validate
}

func (rv *RequestValidator) Validate(request interface{}) error {
	return rv.validator.Struct(request)
}

func badRequestMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !hasAcceptHeader(context) {
			message = "Accept header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.OPTIONS && hasContentTypeHeader(context) {
			message = "OPTIONS requests must have no body"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		if context.Request().Method == echo.POST && !hasContentTypeHeader(context) {
			message = "Content-Type header is missing"

			return echo.NewHTTPError(http.StatusBadRequest, []string{message})
		}

		return next(context)
	}
}

func notAcceptableMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		var message string

		if !isValidAcceptHeader(context) {
			message = "JSON responses must be accepted"

			return echo.NewHTTPError(http.StatusNotAcceptable, []string{message})
		}

		return next(context)
	}
}

func notImplementedMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		if context.Request().Method != echo.POST && context.Request().Method != echo.OPTIONS {
			return echo.NewHTTPError(http.StatusNotImplemented)
		}

		return next(context)
	}
}

func corsMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
	return func(context echo.Context) error {
		context.Response().Header().Set("Access-Control-Allow-Origin", "*")
		context.Response().Header().Set("Access-Control-Allow-Methods", "POST")
		context.Response().Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")

		return next(context)
	}
}

func hasAcceptHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Accept"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func isValidAcceptHeader(context echo.Context) bool {
	accepted := "application/json"

	if header := context.Request().Header.Get("Accept"); strings.Contains(strings.ToLower(header), accepted) || header == "*/*" {
		return true
	}

	return false
}

func hasContentTypeHeader(context echo.Context) bool {
	if header := context.Request().Header.Get("Content-Type"); strings.TrimSpace(header) != "" {
		return true
	}

	return false
}

func Handler(port int, handlers map[string]echo.HandlerFunc) http.Handler {
	e := echo.New()
	validate := validator.New()
	env := os.Getenv("HERMES_STATS_ENV")

	if env == "DEV" {
		e.Logger.SetLevel(log.DEBUG)
		e.Debug = true
	} else {
		e.Pre(middleware.HTTPSRedirect())
		e.Logger.SetLevel(log.ERROR)
	}

	e.Use(middleware.Secure())
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.BodyLimit("20K"))
	e.Use(notImplementedMiddleware)
	e.Use(notAcceptableMiddleware)
	e.Use(badRequestMiddleware)
	e.Use(corsMiddleware)

	e.POST("/stats", handlers["PostStats"])

	e.HTTPErrorHandler = responses.ErrorHandler
	e.Validator = &RequestValidator{validator: validate}
	e.Server.Addr = ":" + strconv.Itoa(port)

	return e
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"time"
	"crypto/tls"
)

// Host:port to listen from
var from string

// Host:port to forward to
var to string

// If true, use SSL/TLS connections
var ssl bool

// Count the connections to make them easily identifiable
var nextConnId = make(chan int)

// Timestamp format for logging
const stamp = "15:04:05.000"

// Special Writer which writes head + nicely formatted binary / textual chunks + tail
type transferLog struct {
	head string
	tail string
}

// Write nicely formatted binary / textual chunk
func (l *transferLog) Write(p []byte) (n int, err error) {
	logPrint(l.head)

	binChunk := false
	chunkStart := 0
	printableCount := 0

	for i, b := range p {
		if isPrintable(b) {
			printableCount++

			// char chunks have a minimum length
			if binChunk && printableCount >= 5 {
				// Write the previous binary chunk
				chunkEnd := i - printableCount + 1
				writeHexChunk(p[chunkStart:chunkEnd])

				binChunk = false
				chunkStart = chunkEnd
			}
		} else {
			printableCount = 0

			if !binChunk {
				// Write the previous char chunk
				os.Stdout.Write(p[chunkStart:i])

				binChunk = true
				chunkStart = i
			}
		}
	}

	// Final chunk
	if binChunk {
		writeHexChunk(p[chunkStart:])
	} else {
		os.Stdout.Write(p[chunkStart:])
	}

	os.Stdout.WriteString(l.tail)
	return len(p), nil
}

func writeHexChunk(p []byte) {
	dumper := hex.Dumper(os.Stdout)
	dumper.Write(p)
	dumper.Close()
}

func isPrintable(b byte) bool {
	return b == 0x0d || b == 0x0a || (b >= 0x20 && b <= 0x7e)
}

// Log with optimized timestamp
func logPrintf(s string, a ...interface{}) {
	os.Stdout.WriteString(time.Now().Format(stamp))
	os.Stdout.WriteString(" ")
	os.Stdout.WriteString(fmt.Sprintf(s, a...))
	os.Stdout.WriteString("\n")
}

// Log with optimized timestamp
func logPrint(s string) {
	os.Stdout.WriteString(time.Now().Format(stamp))
	os.Stdout.WriteString(" ")
	os.Stdout.WriteString(s)
	os.Stdout.WriteString("\n")
}

// Copy to dst and to logger
func copyWithLog(dst io.Writer, src io.Reader, head string, tail string) {
	logger := &transferLog{head: head, tail: tail}
	multi := io.MultiWriter(dst, logger)
	if _, err := io.Copy(multi, src); err != nil {
		logPrintf("Error copying: %v", err)
	}
}

func handleConnection(src net.Conn) {
	connId := <-nextConnId
	logPrint(fmt.Sprintf("New connection: %v", connId))

	var dst net.Conn
	var err error
	if ssl {
		dst, err = tls.Dial("tcp", to, tlsClientConfig())
	} else {
		dst, err = net.Dial("tcp", to)
	}

	if err != nil {
		logPrintf("Error connecting to dest: %v", err)
		panic(err)
	}

	// Copy & log in both directions
	go copyWithLog(dst, src, fmt.Sprintf("->%v", connId), "\n")
	go copyWithLog(src, dst, fmt.Sprintf("<-%v", connId), "\n")
}

func genConnectionIds() {
	i := 1
	for {
		nextConnId <- i
		i++
	}
}

func tlsServerConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
	if err != nil {
		logPrintf("Could not read server certificate (cert.pem, key.pem): %v", err)
		os.Exit(1)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}

func tlsClientConfig() *tls.Config {
	// Simply accept everything
	return &tls.Config{InsecureSkipVerify: true}
}

func init() {
	flag.StringVar(&from, "from", ":8081", "Source host/port to listen to")
	flag.StringVar(&to, "to", "localhost:8080", "Destination host/port to forward to")
	flag.BoolVar(&ssl, "ssl", false, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
}

func main() {
	flag.Parse()

	logPrintf("Listening to [%v], forwarding to [%v]", from, to)

	var ln net.Listener
	var err error
	if ssl {
		ln, err = tls.Listen("tcp", from, tlsServerConfig())
	} else {
		ln, err = net.Listen("tcp", from)
	}

	if err != nil {
		logPrintf("Could not open port: %v", err)
		os.Exit(1)
	}

	go genConnectionIds()

	for {
		conn, err := ln.Accept()
		if err != nil {
			logPrintf("Error accepting: %v", err)
			continue
		}
		go handleConnection(conn)
	}
}
<commit_msg>Minor improvements in log output<commit_after>package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"time"
	"crypto/tls"
)

// Host:port to listen from
var from string

// Host:port to forward to
var to string

// If true, use SSL/TLS connections
var ssl bool

// Count the connections to make them easily identifiable
var nextConnId = make(chan int)

// Timestamp format for logging
const stamp = "15:04:05.000"

// Special Writer which writes head + nicely formatted binary / textual chunks + tail
type transferLog struct {
	head string
	tail string
}

// Write nicely formatted binary / textual chunk
func (l *transferLog) Write(p []byte) (n int, err error) {
	logPrint(l.head)

	binChunk := false
	chunkStart := 0
	printableCount := 0

	for i, b := range p {
		if isPrintable(b) {
			printableCount++

			// char chunks have a minimum length
			if binChunk && printableCount >= 5 {
				// Write the previous binary chunk
				chunkEnd := i - printableCount + 1
				writeHexChunk(p[chunkStart:chunkEnd])

				binChunk = false
				chunkStart = chunkEnd
			}
		} else {
			printableCount = 0

			if !binChunk {
				// Write the previous char chunk
				os.Stdout.Write(p[chunkStart:i])

				binChunk = true
				chunkStart = i
			}
		}
	}

	// Final chunk
	if binChunk {
		writeHexChunk(p[chunkStart:])
	} else {
		os.Stdout.Write(p[chunkStart:])
	}

	os.Stdout.WriteString(l.tail)
	return len(p), nil
}

func writeHexChunk(p []byte) {
	dumper := hex.Dumper(os.Stdout)
	dumper.Write(p)
	dumper.Close()
}

func isPrintable(b byte) bool {
	return b == 0x0d || b == 0x0a || (b >= 0x20 && b <= 0x7e)
}

// Log with optimized timestamp
func logPrintf(s string, a ...interface{}) {
	os.Stdout.WriteString(time.Now().Format(stamp))
	os.Stdout.WriteString(" ")
	os.Stdout.WriteString(fmt.Sprintf(s, a...))
	os.Stdout.WriteString("\n")
}

// Log with optimized timestamp
func logPrint(s string) {
	os.Stdout.WriteString(time.Now().Format(stamp))
	os.Stdout.WriteString(" ")
	os.Stdout.WriteString(s)
	os.Stdout.WriteString("\n")
}

// Copy to dst and to logger
func copyWithLog(dst io.Writer, src io.Reader, head string, tail string) {
	logger := &transferLog{head: head, tail: tail}
	multi := io.MultiWriter(dst, logger)
	if _, err := io.Copy(multi, src); err != nil {
		logPrintf("Closed connection: %v", err)
	}
}

func handleConnection(src net.Conn) {
	connId := <-nextConnId
	logPrint(fmt.Sprintf("New connection: %v (from %v)", connId, src.RemoteAddr()))

	var dst net.Conn
	var err error
	if ssl {
		dst, err = tls.Dial("tcp", to, tlsClientConfig())
	} else {
		dst, err = net.Dial("tcp", to)
	}

	if err != nil {
		logPrintf("Error connecting to dest: %v", err)
		panic(err)
	}

	// Copy & log in both directions
	go copyWithLog(dst, src, fmt.Sprintf("->%v", connId), "")
	go copyWithLog(src, dst, fmt.Sprintf("<-%v", connId), "")
}

func genConnectionIds() {
	i := 1
	for {
		nextConnId <- i
		i++
	}
}

func tlsServerConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
	if err != nil {
		logPrintf("Could not read server certificate (cert.pem, key.pem): %v", err)
		os.Exit(1)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}

func tlsClientConfig() *tls.Config {
	// Simply accept everything
	return &tls.Config{InsecureSkipVerify: true}
}

func init() {
	flag.StringVar(&from, "from", "", "Source host/port to listen to. Example: ':8081'")
	flag.StringVar(&to, "to", "", "Destination host/port to forward to. Example: 'localhost:8080'")
	flag.BoolVar(&ssl, "ssl", false, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
}

func main() {
	flag.Parse()
	if len(from) == 0 || len(to) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	logPrintf("Listening to [%v], forwarding to [%v]", from, to)

	var ln net.Listener
	var err error
	if ssl {
		ln, err = tls.Listen("tcp", from, tlsServerConfig())
	} else {
		ln, err = net.Listen("tcp", from)
	}

	if err != nil {
		logPrintf("Could not open port: %v", err)
		os.Exit(1)
	}

	go genConnectionIds()

	for {
		conn, err := ln.Accept()
		if err != nil {
			logPrintf("Error accepting: %v", err)
			continue
		}
		go handleConnection(conn)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"lupo/printer"
	"lupo/server"
	"os"
)

// Usage examples
// lupo -from :8080 -to myserver:80
// lupo -from :8443 -to myserver:443 -ssl
// lupo -style full -from :8080 -to myserver:80

var style string

func init() {
	flag.StringVar(&style, "style", "short", "Style of output. 'short' prints one line per transfer. 'full' prints everything. 'stats' prints a csv with stats.")
	flag.StringVar(&server.From, "from", server.From, "Source host/port to listen to. Example: ':8081'")
	flag.StringVar(&server.To, "to", server.To, "Destination host/port to forward to. Example: 'localhost:8080'")
	flag.BoolVar(&server.Ssl, "ssl", server.Ssl, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
	//flag.IntVar(&printer.MaxPayloadCharsToPrint, "trunc", printer.MaxPayloadCharsToPrint, "Truncate content (number of chars to print)")
	//flag.BoolVar(&printer.Headers, "headers", printer.Headers, "Print HTTP headers")
	// TODO out.Out
}

func main() {
	flag.Parse()
	if len(server.From) == 0 || len(server.To) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if style == "short" {
		go printer.Short()
	} else if style == "full" {
		go printer.Full()
	} else if style == "stats" {
		go printer.Stats()
	} else {
		panic("Unknown style")
	}

	server.Listen()
}
<commit_msg>Improved usage output<commit_after>package main

import (
	"flag"
	"lupo/printer"
	"lupo/server"
	"os"
	"fmt"
)

const version = "v0.2.0"

var style string

func appHeader() {
	fmt.Printf("lupo %v\n\n", version)
}

func usageExamples() {
	fmt.Println("Examples:")
	fmt.Println("  lupo -from :8080 -to myserver:80")
	fmt.Println("  lupo -from :8443 -to myserver:443 -ssl")
	fmt.Println("  lupo -style full -from :8080 -to myserver:80")
	fmt.Println("  lupo -style stats -from :8080 -to myserver:80")
}

func init() {
	flag.StringVar(&style, "style", "short", "Style of output. 'short' prints one line per transfer. 'full' prints everything. 'stats' prints a csv with stats")
	flag.StringVar(&server.From, "from", server.From, "Source host/port to listen to")
	flag.StringVar(&server.To, "to", server.To, "Destination host/port to forward to")
	flag.BoolVar(&server.Ssl, "ssl", server.Ssl, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
	//flag.IntVar(&printer.MaxPayloadCharsToPrint, "trunc", printer.MaxPayloadCharsToPrint, "Truncate content (number of chars to print)")
	//flag.BoolVar(&printer.Headers, "headers", printer.Headers, "Print HTTP headers")
	// TODO out.Out
}

func main() {
	flag.Parse()
	if len(server.From) == 0 || len(server.To) == 0 {
		appHeader()
		flag.Usage()
		fmt.Println()
		usageExamples()
		os.Exit(1)
	}

	if style == "short" {
		go printer.Short()
	} else if style == "full" {
		go printer.Full()
	} else if style == "stats" {
		go printer.Stats()
	} else {
		panic("Unknown style")
	}

	server.Listen()
}
<|endoftext|>


<commit_before>package storagenode

import (
	"encoding/json"
	"io/ioutil"
	"testing"

	"github.com/Sirupsen/logrus"

	"github.com/jacksontj/dataman/src/storage_node/metadata"

	"gopkg.in/yaml.v2"
)

func getMetaStore() (*MetadataStore, error) {
	config := &Config{}
	configBytes, err := ioutil.ReadFile("storagenode/config.yaml")
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(configBytes), &config)
	if err != nil {
		return nil, err
	}

	var datasourceInstanceConfig *DatasourceInstanceConfig
	for _, c := range config.Datasources {
		datasourceInstanceConfig = c
		break
	}

	return NewMetadataStore(datasourceInstanceConfig)
}

func resetMetaStore(metaStore *MetadataStore) error {
	meta := metaStore.GetMeta()

	for dbname, _ := range meta.Databases {
		if err := metaStore.EnsureDoesntExistDatabase(dbname); err != nil {
			return err
		}
	}

	return nil
}

// We have a variety of smaller internal fields which we don't care about for
// the use of comparison. So we'll just json dump and compare
func metaEqual(a, b interface{}) bool {
	aBytes, _ := json.MarshalIndent(a, "", "  ")
	bBytes, _ := json.MarshalIndent(b, "", "  ")

	ioutil.WriteFile("/home/jacksontj/Desktop/tmp/a", aBytes, 0644)
	ioutil.WriteFile("/home/jacksontj/Desktop/tmp/b", bBytes, 0644)

	if len(aBytes) != len(bBytes) {
		return false
	}

	for i, b := range aBytes {
		if b != bBytes[i] {
			return false
		}
	}
	return true
}

func getTestMeta() (*metadata.Meta, error) {
	testMeta := &metadata.Meta{}
	metaString, err := ioutil.ReadFile("test_metadata.json")
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal([]byte(metaString), &testMeta); err != nil {
		return nil, err
	}
	return testMeta, nil
}

func TestMetaStore_Database(t *testing.T) {
	metaStore, err := getMetaStore()
	if err != nil {
		t.Fatalf("Unable to get metaStore: %v", err)
	}

	if err := resetMetaStore(metaStore); err != nil {
		t.Fatalf("Unable to reset meta store: %v", err)
	}

	testMeta, err := getTestMeta()
	if err != nil {
		logrus.Fatalf("Error loading test meta: %v", err)
	}

	// Insert the meta -- here the provision state is all 0
	if err := metaStore.EnsureExistsDatabase(testMeta.Databases["example_forum"]); err != nil {
		t.Fatalf("Error ensuring DB: %v", err)
	}

	// Ensure that the one we had and the one stored are the same
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Now lets update the provision state for stuff
	db := metaStore.GetMeta().Databases["example_forum"]
	db.ProvisionState = metadata.Provision
	if err := metaStore.EnsureExistsDatabase(db); err != nil {
		t.Fatalf("Error ensuring DB 2: %v", err)
	}

	// Make sure it changed
	if !metaEqual(db, metaStore.GetMeta().Databases["example_forum"]) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Remove it all
	if err := metaStore.EnsureDoesntExistDatabase("example_forum"); err != nil {
		t.Fatalf("Error EnsureDoesntExistDatabase: %v", err)
	}

	// TODO: check
}

func TestMetaStore_ShardInstance(t *testing.T) {
	metaStore, err := getMetaStore()
	if err != nil {
		t.Fatalf("Unable to get metaStore: %v", err)
	}

	if err := resetMetaStore(metaStore); err != nil {
		t.Fatalf("Unable to reset meta store: %v", err)
	}

	testMeta, err := getTestMeta()
	if err != nil {
		logrus.Fatalf("Error loading test meta: %v", err)
	}

	db := &metadata.Database{Name: "example_forum"}
	// Insert the db
	if err := metaStore.EnsureExistsDatabase(db); err != nil {
		t.Fatalf("Error ensuring DB: %v", err)
	}

	// set the DB id -- so the compare works
	testMeta.Databases["example_forum"].ID = db.ID

	shardInstance := testMeta.Databases["example_forum"].ShardInstances["dbshard_example_forum_2"]

	// Ensure the shardInstance
	if err := metaStore.EnsureExistsShardInstance(db, shardInstance); err != nil {
		t.Fatalf("Error ensuring shardInstance: %v", err)
	}

	// Check
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Update the shardInstance
	shardInstance.ProvisionState = metadata.Provision
	if err := metaStore.EnsureExistsShardInstance(db, shardInstance); err != nil {
		t.Fatalf("Error ensuring shardInstance: %v", err)
	}

	// Check
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Remove the shardInstance
	if err := metaStore.EnsureDoesntExistShardInstance(db.Name, shardInstance.Name); err != nil {
		t.Fatalf("Error EnsureDoesntExistShardInstance: %v", err)
	}

	// TODO: check
}
<commit_msg>Relative paths<commit_after>package storagenode

import (
	"encoding/json"
	"io/ioutil"
	"testing"

	"github.com/Sirupsen/logrus"

	"github.com/jacksontj/dataman/src/storage_node/metadata"

	"gopkg.in/yaml.v2"
)

func getMetaStore() (*MetadataStore, error) {
	config := &Config{}
	configBytes, err := ioutil.ReadFile("storagenode/config.yaml")
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(configBytes), &config)
	if err != nil {
		return nil, err
	}

	var datasourceInstanceConfig *DatasourceInstanceConfig
	for _, c := range config.Datasources {
		datasourceInstanceConfig = c
		break
	}

	return NewMetadataStore(datasourceInstanceConfig)
}

func resetMetaStore(metaStore *MetadataStore) error {
	meta := metaStore.GetMeta()

	for dbname, _ := range meta.Databases {
		if err := metaStore.EnsureDoesntExistDatabase(dbname); err != nil {
			return err
		}
	}

	return nil
}

// We have a variety of smaller internal fields which we don't care about for
// the use of comparison. So we'll just json dump and compare
func metaEqual(a, b interface{}) bool {
	aBytes, _ := json.MarshalIndent(a, "", "  ")
	bBytes, _ := json.MarshalIndent(b, "", "  ")

	ioutil.WriteFile("a", aBytes, 0644)
	ioutil.WriteFile("b", bBytes, 0644)

	if len(aBytes) != len(bBytes) {
		return false
	}

	for i, b := range aBytes {
		if b != bBytes[i] {
			return false
		}
	}
	return true
}

func getTestMeta() (*metadata.Meta, error) {
	testMeta := &metadata.Meta{}
	metaString, err := ioutil.ReadFile("test_metadata.json")
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal([]byte(metaString), &testMeta); err != nil {
		return nil, err
	}
	return testMeta, nil
}

func TestMetaStore_Database(t *testing.T) {
	metaStore, err := getMetaStore()
	if err != nil {
		t.Fatalf("Unable to get metaStore: %v", err)
	}

	if err := resetMetaStore(metaStore); err != nil {
		t.Fatalf("Unable to reset meta store: %v", err)
	}

	testMeta, err := getTestMeta()
	if err != nil {
		logrus.Fatalf("Error loading test meta: %v", err)
	}

	// Insert the meta -- here the provision state is all 0
	if err := metaStore.EnsureExistsDatabase(testMeta.Databases["example_forum"]); err != nil {
		t.Fatalf("Error ensuring DB: %v", err)
	}

	// Ensure that the one we had and the one stored are the same
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Now lets update the provision state for stuff
	db := metaStore.GetMeta().Databases["example_forum"]
	db.ProvisionState = metadata.Provision
	if err := metaStore.EnsureExistsDatabase(db); err != nil {
		t.Fatalf("Error ensuring DB 2: %v", err)
	}

	// Make sure it changed
	if !metaEqual(db, metaStore.GetMeta().Databases["example_forum"]) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Remove it all
	if err := metaStore.EnsureDoesntExistDatabase("example_forum"); err != nil {
		t.Fatalf("Error EnsureDoesntExistDatabase: %v", err)
	}

	// TODO: check
}

func TestMetaStore_ShardInstance(t *testing.T) {
	metaStore, err := getMetaStore()
	if err != nil {
		t.Fatalf("Unable to get metaStore: %v", err)
	}

	if err := resetMetaStore(metaStore); err != nil {
		t.Fatalf("Unable to reset meta store: %v", err)
	}

	testMeta, err := getTestMeta()
	if err != nil {
		logrus.Fatalf("Error loading test meta: %v", err)
	}

	db := &metadata.Database{Name: "example_forum"}
	// Insert the db
	if err := metaStore.EnsureExistsDatabase(db); err != nil {
		t.Fatalf("Error ensuring DB: %v", err)
	}

	// set the DB id -- so the compare works
	testMeta.Databases["example_forum"].ID = db.ID

	shardInstance := testMeta.Databases["example_forum"].ShardInstances["dbshard_example_forum_2"]

	// Ensure the shardInstance
	if err := metaStore.EnsureExistsShardInstance(db, shardInstance); err != nil {
		t.Fatalf("Error ensuring shardInstance: %v", err)
	}

	// Check
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Update the shardInstance
	shardInstance.ProvisionState = metadata.Provision
	if err := metaStore.EnsureExistsShardInstance(db, shardInstance); err != nil {
		t.Fatalf("Error ensuring shardInstance: %v", err)
	}

	// Check
	if !metaEqual(testMeta, metaStore.GetMeta()) {
		t.Fatalf("not equal %v != %v", testMeta, metaStore.GetMeta())
	}

	// Remove the shardInstance
	if err := metaStore.EnsureDoesntExistShardInstance(db.Name, shardInstance.Name); err != nil {
		t.Fatalf("Error EnsureDoesntExistShardInstance: %v", err)
	}

	// TODO: check
}
<|endoftext|>


<commit_before>package colonycore

import (
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

type DataSource struct {
	orm.ModelBase
	ID           string `json:"_id",bson:"_id"`
	ConnectionID string
	QueryInfo    toolkit.M
	MetaData     []*FieldInfo
}

func (ds *DataSource) TableName() string {
	return "datasources"
}

func (ds *DataSource) RecordID() interface{} {
	return ds.ID
}

type FieldInfo struct {
	ID     string `json:"_id",bson:"_id"`
	Label  string
	Type   string
	Format string
	Lookup *Lookup
}

type Lookup struct {
	orm.ModelBase
	ID                    string `json:"_id",bson:"_id"`
	DataSourceID          string
	IDField, DisplayField string
	LookupFields          []string
}

func (l *Lookup) TableName() string {
	return "lookups"
}

func (l *Lookup) RecordID() interface{} {
	return l.ID
}
<commit_msg>no message<commit_after>package colonycore

import (
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

type DataSource struct {
	orm.ModelBase
	ID           string `json:"_id",bson:"_id"`
	ConnectionID string
	QueryInfo    toolkit.M
	MetaData     []*FieldInfo
}

func (ds *DataSource) TableName() string {
	return "datasources"
}

func (ds *DataSource) RecordID() interface{} {
	return ds.ID
}

type FieldInfo struct {
	ID     string `json:"_id",bson:"_id"`
	Label  string
	Type   string
	Format string
	Sub    []*FieldInfo
	Lookup *Lookup
}

type Lookup struct {
	orm.ModelBase
	ID                    string `json:"_id",bson:"_id"`
	DataSourceID          string
	IDField, DisplayField string
	LookupFields          []string
}

func (l *Lookup) TableName() string {
	return "lookups"
}

func (l *Lookup) RecordID() interface{} {
	return l.ID
}
<|endoftext|>