<commit_before>package clustering

import (
	"github.com/sjwhitworth/golearn/base"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestExpectationMaximization(t *testing.T) {
	Convey("Doing EM-based clustering", t, func() {
		em, _ := NewExpectationMaximization(2)

		// Initialization tests
		// Trying to create NewExpectationMaximization with < 1 component
		Convey("With less than one component", func() {
			Convey("Creating a new instance", func() {
				_, err := NewExpectationMaximization(0)
				Convey("Should result in a InsufficientComponentsError", func() {
					So(err, ShouldEqual, InsufficientComponentsError)
				})
			})
		})

		// Data tests
		// Trying to Fit with fewer samples than components
		Convey("With insufficient training data", func() {
			Convey("Fitting", func() {
				testData, err := base.ParseCSVToInstances("./gaussian_mixture_single_obs.csv", false)
				So(err, ShouldBeNil)

				err = em.Fit(testData)

				Convey("Should result in a InsufficientDataError", func() {
					So(err, ShouldEqual, InsufficientDataError)
				})
			})
		})

		// Trying to Predict before having Fit
		Convey("With no training data", func() {
			Convey("Predicting", func() {
				testData, err := base.ParseCSVToInstances("./gaussian_mixture.csv", false)
				So(err, ShouldBeNil)

				_, err = em.Predict(testData)

				Convey("Should result in a NoTrainingDataError", func() {
					So(err, ShouldEqual, NoTrainingDataError)
				})
			})
		})

		// Computation tests
		// Test the predictions are resonable
		Convey("With sufficient training data", func() {
			instances, err := base.ParseCSVToInstances("./gaussian_mixture.csv", true)
			So(err, ShouldBeNil)

			Convey("Fitting", func() {
				err := em.Fit(instances)
				So(err, ShouldBeNil)

				first_mean := em.Params.Means.At(0, 0)

				Convey("It converges to reasonable a value", func() {
					So(first_mean, ShouldAlmostEqual, -5.973, .1)
				})
			})
		})
	})
}

func BenchmarkExpectationMaximizationOneRow(b *testing.B) {
	// Omits error handling in favor of brevity
	trainData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)
	testData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)

	em, err := NewExpectationMaximization(2)
	if err != nil {
		panic(err)
	}
	em.Fit(trainData)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		em.Predict(testData)
	}
}
<commit_msg>Add Convey "Test more code"<commit_after>package clustering

import (
	"github.com/sjwhitworth/golearn/base"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
)

func TestExpectationMaximization(t *testing.T) {
	Convey("Doing EM-based clustering", t, func() {
		em, _ := NewExpectationMaximization(2)

		// Initialization tests
		// Trying to create NewExpectationMaximization with < 1 component
		Convey("With less than one component", func() {
			Convey("Creating a new instance", func() {
				_, err := NewExpectationMaximization(0)
				Convey("Should result in a InsufficientComponentsError", func() {
					So(err, ShouldEqual, InsufficientComponentsError)
				})
			})
		})

		// Data tests
		// Trying to Fit with fewer samples than components
		Convey("With insufficient training data", func() {
			Convey("Fitting", func() {
				testData, err := base.ParseCSVToInstances("./gaussian_mixture_single_obs.csv", false)
				So(err, ShouldBeNil)

				err = em.Fit(testData)

				Convey("Should result in a InsufficientDataError", func() {
					So(err, ShouldEqual, InsufficientDataError)
				})
			})
		})

		// Trying to Predict before having Fit
		Convey("With no training data", func() {
			Convey("Predicting", func() {
				testData, err := base.ParseCSVToInstances("./gaussian_mixture.csv", false)
				So(err, ShouldBeNil)

				_, err = em.Predict(testData)

				Convey("Should result in a NoTrainingDataError", func() {
					So(err, ShouldEqual, NoTrainingDataError)
				})
			})
		})

		// Computation tests
		// Test the predictions are resonable
		Convey("With sufficient training data", func() {
			instances, err := base.ParseCSVToInstances("./gaussian_mixture.csv", true)
			So(err, ShouldBeNil)

			Convey("Fitting", func() {
				err := em.Fit(instances)
				So(err, ShouldBeNil)

				first_mean := em.Params.Means.At(0, 0)

				Convey("It converges to reasonable a value", func() {
					So(first_mean, ShouldAlmostEqual, -5.973, .1)
				})
			})
		})

		Convey("Test more code", func() {
			trainData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)
			testData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)

			em, err := NewExpectationMaximization(1)
			if err != nil {
				panic(err)
			}
			em.Fit(trainData)

			em.Predict(testData)
		})
	})
}

func BenchmarkExpectationMaximizationOneRow(b *testing.B) {
	// Omits error handling in favor of brevity
	trainData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)
	testData, _ := base.ParseCSVToInstances("./gaussian_mixture.csv", false)

	em, err := NewExpectationMaximization(2)
	if err != nil {
		panic(err)
	}
	em.Fit(trainData)

	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		em.Predict(testData)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Reborndb Org. All Rights Reserved.
// Licensed under the MIT (MIT-LICENSE.txt) license.

package main

import (
	"fmt"
	"path"

	log "github.com/ngaut/logging"
)

type qdbArgs struct {
	Addr   string `json:"addr"`
	DBType string `json:"dbtype"`
	CPUNum string `json:"cpu_num"`
}

// qdb-server
func startQDB(args *qdbArgs) (*process, error) {
	p := newDefaultProcess("qdb-server", qdbType)

	if len(args.Addr) == 0 {
		return nil, fmt.Errorf("qdb must have an address, not empty")
	}

	if len(args.CPUNum) == 0 {
		args.CPUNum = "2"
	}

	p.Ctx["addr"] = args.Addr

	if len(qdbConfigFile) > 0 {
		p.addCmdArgs(fmt.Sprintf("--config=%s", qdbConfigFile))
	}

	p.addCmdArgs("-L", path.Join(p.baseLogDir(), "qdb.log"))
	p.addCmdArgs(fmt.Sprintf("--ncpu=%s", args.CPUNum))
	p.addCmdArgs(fmt.Sprintf("--dbtype=%s", args.DBType))
	p.addCmdArgs(fmt.Sprintf("--dbpath=%s", path.Join(p.baseDataDir(), "db")))
	p.addCmdArgs(fmt.Sprintf("--addr=%s", args.Addr))
	p.addCmdArgs(fmt.Sprintf("--pidfile=%s", p.pidPath()))
	p.addCmdArgs(fmt.Sprintf("--dump_path=%s", path.Join(p.baseDataDir(), "dump.rdb")))
	p.addCmdArgs(fmt.Sprintf("--sync_file_path=%s", path.Join(p.baseDataDir(), "sync.pipe")))
	p.addCmdArgs(fmt.Sprintf("--repl_backlog_file_path=%s", path.Join(p.baseDataDir(), "repl_backlog")))

	// below we use fixed config, later maybe passed from args
	p.addCmdArgs(fmt.Sprintf("--conn_timeout=900"))
	p.addCmdArgs(fmt.Sprintf("--sync_file_size=34359738368"))
	p.addCmdArgs(fmt.Sprintf("--sync_buff_size=8388608"))
	p.addCmdArgs(fmt.Sprintf("--repl_backlog_size=10737418240"))

	bindRedisProcHandler(p)

	log.Infof("%s %v", p.Cmd, p.Args)

	if err := p.start(); err != nil {
		log.Errorf("start redis err %v", err)
		return nil, err
	}

	addCheckProc(p)

	return p, nil
}
<commit_msg>remove unnecessary log<commit_after>// Copyright 2015 Reborndb Org. All Rights Reserved.
// Licensed under the MIT (MIT-LICENSE.txt) license.

package main

import (
	"fmt"
	"path"

	log "github.com/ngaut/logging"
)

type qdbArgs struct {
	Addr   string `json:"addr"`
	DBType string `json:"dbtype"`
	CPUNum string `json:"cpu_num"`
}

// qdb-server
func startQDB(args *qdbArgs) (*process, error) {
	p := newDefaultProcess("qdb-server", qdbType)

	if len(args.Addr) == 0 {
		return nil, fmt.Errorf("qdb must have an address, not empty")
	}

	if len(args.CPUNum) == 0 {
		args.CPUNum = "2"
	}

	p.Ctx["addr"] = args.Addr

	if len(qdbConfigFile) > 0 {
		p.addCmdArgs(fmt.Sprintf("--config=%s", qdbConfigFile))
	}

	p.addCmdArgs("-L", path.Join(p.baseLogDir(), "qdb.log"))
	p.addCmdArgs(fmt.Sprintf("--ncpu=%s", args.CPUNum))
	p.addCmdArgs(fmt.Sprintf("--dbtype=%s", args.DBType))
	p.addCmdArgs(fmt.Sprintf("--dbpath=%s", path.Join(p.baseDataDir(), "db")))
	p.addCmdArgs(fmt.Sprintf("--addr=%s", args.Addr))
	p.addCmdArgs(fmt.Sprintf("--pidfile=%s", p.pidPath()))
	p.addCmdArgs(fmt.Sprintf("--dump_path=%s", path.Join(p.baseDataDir(), "dump.rdb")))
	p.addCmdArgs(fmt.Sprintf("--sync_file_path=%s", path.Join(p.baseDataDir(), "sync.pipe")))
	p.addCmdArgs(fmt.Sprintf("--repl_backlog_file_path=%s", path.Join(p.baseDataDir(), "repl_backlog")))

	// below we use fixed config, later maybe passed from args
	p.addCmdArgs(fmt.Sprintf("--conn_timeout=900"))
	p.addCmdArgs(fmt.Sprintf("--sync_file_size=34359738368"))
	p.addCmdArgs(fmt.Sprintf("--sync_buff_size=8388608"))
	p.addCmdArgs(fmt.Sprintf("--repl_backlog_size=10737418240"))

	bindRedisProcHandler(p)

	if err := p.start(); err != nil {
		log.Errorf("start redis err %v", err)
		return nil, err
	}

	addCheckProc(p)

	return p, nil
}
<|endoftext|>


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

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	"golang.org/x/build/buildlet"
	"golang.org/x/build/internal/gomote/protos"
)

func legacyDestroy(args []string) error {
	if activeGroup != nil {
		return fmt.Errorf("command does not support groups")
	}

	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
	fs.Usage = func() {
		fmt.Fprintln(os.Stderr, "destroy usage: gomote destroy <instance>")
		fs.PrintDefaults()
		if fs.NArg() == 0 {
			// List buildlets that you might want to destroy.
			cc, err := buildlet.NewCoordinatorClientFromFlags()
			if err != nil {
				log.Fatal(err)
			}
			rbs, err := cc.RemoteBuildlets()
			if err != nil {
				log.Fatal(err)
			}
			if len(rbs) > 0 {
				fmt.Printf("possible instances:\n")
				for _, rb := range rbs {
					fmt.Printf("\t%s\n", rb.Name)
				}
			}
		}
		os.Exit(1)
	}

	fs.Parse(args)
	if fs.NArg() != 1 {
		fs.Usage()
	}
	name := fs.Arg(0)
	bc, err := remoteClient(name)
	if err != nil {
		return err
	}
	return bc.Close()
}

func destroy(args []string) error {
	if activeGroup != nil {
		return fmt.Errorf("command does not yet support groups")
	}

	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
	fs.Usage = func() {
		fmt.Fprintln(os.Stderr, "destroy usage: gomote destroy <instance>")
		fs.PrintDefaults()
		if fs.NArg() == 0 {
			// List buildlets that you might want to destroy.
			client := gomoteServerClient(context.Background())
			resp, err := client.ListInstances(context.Background(), &protos.ListInstancesRequest{})
			if err != nil {
				log.Fatalf("unable to list possible instances to destroy: %s", statusFromError(err))
			}
			if len(resp.GetInstances()) > 0 {
				fmt.Printf("possible instances:\n")
				for _, inst := range resp.GetInstances() {
					fmt.Printf("\t%s\n", inst.GetGomoteId())
				}
			}
		}
		os.Exit(1)
	}

	fs.Parse(args)
	if fs.NArg() != 1 {
		fs.Usage()
	}
	name := fs.Arg(0)
	ctx := context.Background()
	client := gomoteServerClient(ctx)
	if _, err := client.DestroyInstance(ctx, &protos.DestroyInstanceRequest{
		GomoteId: name,
	}); err != nil {
		return fmt.Errorf("unable to destroy instance: %s", statusFromError(err))
	}
	return nil
}
<commit_msg>cmd/gomote: add support for groups to destroy<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	"golang.org/x/build/buildlet"
	"golang.org/x/build/internal/gomote/protos"
)

func legacyDestroy(args []string) error {
	if activeGroup != nil {
		return fmt.Errorf("command does not support groups")
	}

	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
	fs.Usage = func() {
		fmt.Fprintln(os.Stderr, "destroy usage: gomote destroy <instance>")
		fs.PrintDefaults()
		if fs.NArg() == 0 {
			// List buildlets that you might want to destroy.
			cc, err := buildlet.NewCoordinatorClientFromFlags()
			if err != nil {
				log.Fatal(err)
			}
			rbs, err := cc.RemoteBuildlets()
			if err != nil {
				log.Fatal(err)
			}
			if len(rbs) > 0 {
				fmt.Printf("possible instances:\n")
				for _, rb := range rbs {
					fmt.Printf("\t%s\n", rb.Name)
				}
			}
		}
		os.Exit(1)
	}

	fs.Parse(args)
	if fs.NArg() != 1 {
		fs.Usage()
	}
	name := fs.Arg(0)
	bc, err := remoteClient(name)
	if err != nil {
		return err
	}
	return bc.Close()
}

func destroy(args []string) error {
	fs := flag.NewFlagSet("destroy", flag.ContinueOnError)
	fs.Usage = func() {
		fmt.Fprintln(os.Stderr, "destroy usage: gomote destroy [instance]")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "Destroys a single instance, or all instances in a group.")
		fmt.Fprintln(os.Stderr, "Instance argument is optional with a group.")
		fs.PrintDefaults()
		if fs.NArg() == 0 {
			// List buildlets that you might want to destroy.
			client := gomoteServerClient(context.Background())
			resp, err := client.ListInstances(context.Background(), &protos.ListInstancesRequest{})
			if err != nil {
				log.Fatalf("unable to list possible instances to destroy: %s", statusFromError(err))
			}
			if len(resp.GetInstances()) > 0 {
				fmt.Printf("possible instances:\n")
				for _, inst := range resp.GetInstances() {
					fmt.Printf("\t%s\n", inst.GetGomoteId())
				}
			}
		}
		os.Exit(1)
	}

	fs.Parse(args)

	var destroySet []string
	if fs.NArg() == 1 {
		destroySet = append(destroySet, fs.Arg(0))
	} else if activeGroup != nil {
		for _, inst := range activeGroup.Instances {
			destroySet = append(destroySet, inst)
		}
	} else {
		fs.Usage()
	}
	for _, name := range destroySet {
		fmt.Fprintf(os.Stderr, "# Destroying %s\n", name)
		ctx := context.Background()
		client := gomoteServerClient(ctx)
		if _, err := client.DestroyInstance(ctx, &protos.DestroyInstanceRequest{
			GomoteId: name,
		}); err != nil {
			return fmt.Errorf("unable to destroy instance: %s", statusFromError(err))
		}
	}
	if activeGroup != nil {
		activeGroup.Instances = nil
		if err := storeGroup(activeGroup); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/flynn/json5"
	"github.com/zyedidia/glob"
)

type optionValidator func(string, interface{}) error

// The options that the user can set
var globalSettings map[string]interface{}

var invalidSettings bool

// Options with validators
var optionValidators = map[string]optionValidator{
	"tabsize":      validatePositiveValue,
	"scrollmargin": validateNonNegativeValue,
	"scrollspeed":  validateNonNegativeValue,
	"colorscheme":  validateColorscheme,
	"colorcolumn":  validateNonNegativeValue,
	"fileformat":   validateLineEnding,
}

// InitGlobalSettings initializes the options map and sets all options to their default values
func InitGlobalSettings() {
	invalidSettings = false
	defaults := DefaultGlobalSettings()
	var parsed map[string]interface{}

	filename := configDir + "/settings.json"
	writeSettings := false
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if !strings.HasPrefix(string(input), "null") {
			if err != nil {
				TermMessage("Error reading settings.json file: " + err.Error())
				invalidSettings = true
				return
			}

			err = json5.Unmarshal(input, &parsed)
			if err != nil {
				TermMessage("Error reading settings.json:", err.Error())
				invalidSettings = true
			}
		} else {
			writeSettings = true
		}
	}

	globalSettings = make(map[string]interface{})
	for k, v := range defaults {
		globalSettings[k] = v
	}
	for k, v := range parsed {
		if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
			globalSettings[k] = v
		}
	}

	if _, err := os.Stat(filename); os.IsNotExist(err) || writeSettings {
		err := WriteSettings(filename)
		if err != nil {
			TermMessage("Error writing settings.json file: " + err.Error())
		}
	}
}

// InitLocalSettings scans the json in settings.json and sets the options locally based
// on whether the buffer matches the glob
func InitLocalSettings(buf *Buffer) {
	invalidSettings = false
	var parsed map[string]interface{}

	filename := configDir + "/settings.json"
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if err != nil {
			TermMessage("Error reading settings.json file: " + err.Error())
			invalidSettings = true
			return
		}

		err = json5.Unmarshal(input, &parsed)
		if err != nil {
			TermMessage("Error reading settings.json:", err.Error())
			invalidSettings = true
		}
	}

	for k, v := range parsed {
		if strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
			if strings.HasPrefix(k, "ft:") {
				if buf.Settings["filetype"].(string) == k[3:] {
					for k1, v1 := range v.(map[string]interface{}) {
						buf.Settings[k1] = v1
					}
				}
			} else {
				g, err := glob.Compile(k)
				if err != nil {
					TermMessage("Error with glob setting ", k, ": ", err)
					continue
				}

				if g.MatchString(buf.Path) {
					for k1, v1 := range v.(map[string]interface{}) {
						buf.Settings[k1] = v1
					}
				}
			}
		}
	}
}

// WriteSettings writes the settings to the specified filename as JSON
func WriteSettings(filename string) error {
	if invalidSettings {
		// Do not write the settings if there was an error when reading them
		return nil
	}

	var err error
	if _, e := os.Stat(configDir); e == nil {
		parsed := make(map[string]interface{})

		filename := configDir + "/settings.json"
		for k, v := range globalSettings {
			parsed[k] = v
		}
		if _, e := os.Stat(filename); e == nil {
			input, err := ioutil.ReadFile(filename)
			if string(input) != "null" {
				if err != nil {
					return err
				}

				err = json5.Unmarshal(input, &parsed)
				if err != nil {
					TermMessage("Error reading settings.json:", err.Error())
					invalidSettings = true
				}

				for k, v := range parsed {
					if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
						if _, ok := globalSettings[k]; ok {
							parsed[k] = globalSettings[k]
						}
					}
				}
			}
		}

		txt, _ := json.MarshalIndent(parsed, "", "    ")
		err = ioutil.WriteFile(filename, append(txt, '\n'), 0644)
	}
	return err
}

// AddOption creates a new option. This is meant to be called by plugins to add options.
func AddOption(name string, value interface{}) {
	globalSettings[name] = value
	err := WriteSettings(configDir + "/settings.json")
	if err != nil {
		TermMessage("Error writing settings.json file: " + err.Error())
	}
}

// GetGlobalOption returns the global value of the given option
func GetGlobalOption(name string) interface{} {
	return globalSettings[name]
}

// GetLocalOption returns the local value of the given option
func GetLocalOption(name string, buf *Buffer) interface{} {
	return buf.Settings[name]
}

// GetOption returns the value of the given option
// If there is a local version of the option, it returns that
// otherwise it will return the global version
func GetOption(name string) interface{} {
	if GetLocalOption(name, CurView().Buf) != nil {
		return GetLocalOption(name, CurView().Buf)
	}
	return GetGlobalOption(name)
}

// DefaultGlobalSettings returns the default global settings for micro
// Note that colorscheme is a global only option
func DefaultGlobalSettings() map[string]interface{} {
	return map[string]interface{}{
		"autoindent":     true,
		"autosave":       false,
		"basename":       false,
		"colorcolumn":    float64(0),
		"colorscheme":    "default",
		"cursorline":     true,
		"eofnewline":     false,
		"fastdirty":      true,
		"fileformat":     "unix",
		"ignorecase":     false,
		"indentchar":     " ",
		"infobar":        true,
		"keepautoindent": false,
		"keymenu":        false,
		"matchbrace":     false,
		"mouse":          true,
		"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
		"pluginrepos":    []string{},
		"rmtrailingws":   false,
		"ruler":          true,
		"savecursor":     false,
		"savehistory":    true,
		"saveundo":       false,
		"scrollbar":      false,
		"scrollmargin":   float64(3),
		"scrollspeed":    float64(2),
		"softwrap":       false,
		"splitbottom":    true,
		"splitright":     true,
		"statusline":     true,
		"sucmd":          "sudo",
		"syntax":         true,
		"tabmovement":    false,
		"tabsize":        float64(4),
		"tabstospaces":   false,
		"termtitle":      false,
		"useprimary":     true,
	}
}

// DefaultLocalSettings returns the default local settings
// Note that filetype is a local only option
func DefaultLocalSettings() map[string]interface{} {
	return map[string]interface{}{
		"autoindent":     true,
		"autosave":       false,
		"basename":       false,
		"colorcolumn":    float64(0),
		"cursorline":     true,
		"eofnewline":     false,
		"fastdirty":      true,
		"fileformat":     "unix",
		"filetype":       "Unknown",
		"ignorecase":     false,
		"indentchar":     " ",
		"keepautoindent": false,
		"matchbrace":     false,
		"rmtrailingws":   false,
		"ruler":          true,
		"savecursor":     false,
		"saveundo":       false,
		"scrollbar":      false,
		"scrollmargin":   float64(3),
		"scrollspeed":    float64(2),
		"softwrap":       false,
		"splitbottom":    true,
		"splitright":     true,
		"statusline":     true,
		"syntax":         true,
		"tabmovement":    false,
		"tabsize":        float64(4),
		"tabstospaces":   false,
		"useprimary":     true,
	}
}

// SetOption attempts to set the given option to the value
// By default it will set the option as global, but if the option
// is local only it will set the local version
// Use setlocal to force an option to be set locally
func SetOption(option, value string) error {
	if _, ok := globalSettings[option]; !ok {
		if _, ok := CurView().Buf.Settings[option]; !ok {
			return errors.New("Invalid option")
		}
		SetLocalOption(option, value, CurView())
		return nil
	}

	var nativeValue interface{}

	kind := reflect.TypeOf(globalSettings[option]).Kind()
	if kind == reflect.Bool {
		b, err := ParseBool(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = b
	} else if kind == reflect.String {
		nativeValue = value
	} else if kind == reflect.Float64 {
		i, err := strconv.Atoi(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = float64(i)
	} else {
		return errors.New("Option has unsupported value type")
	}

	if err := optionIsValid(option, nativeValue); err != nil {
		return err
	}

	globalSettings[option] = nativeValue

	if option == "colorscheme" {
		// LoadSyntaxFiles()
		InitColorscheme()
		for _, tab := range tabs {
			for _, view := range tab.views {
				view.Buf.UpdateRules()
			}
		}
	}

	if option == "infobar" || option == "keymenu" {
		for _, tab := range tabs {
			tab.Resize()
		}
	}

	if option == "mouse" {
		if !nativeValue.(bool) {
			screen.DisableMouse()
		} else {
			screen.EnableMouse()
		}
	}

	if len(tabs) != 0 {
		if _, ok := CurView().Buf.Settings[option]; ok {
			for _, tab := range tabs {
				for _, view := range tab.views {
					SetLocalOption(option, value, view)
				}
			}
		}
	}

	return nil
}

// SetLocalOption sets the local version of this option
func SetLocalOption(option, value string, view *View) error {
	buf := view.Buf
	if _, ok := buf.Settings[option]; !ok {
		return errors.New("Invalid option")
	}

	var nativeValue interface{}

	kind := reflect.TypeOf(buf.Settings[option]).Kind()
	if kind == reflect.Bool {
		b, err := ParseBool(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = b
	} else if kind == reflect.String {
		nativeValue = value
	} else if kind == reflect.Float64 {
		i, err := strconv.Atoi(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = float64(i)
	} else {
		return errors.New("Option has unsupported value type")
	}

	if err := optionIsValid(option, nativeValue); err != nil {
		return err
	}

	if option == "fastdirty" {
		// If it is being turned off, we have to hash every open buffer
		var empty [16]byte
		for _, tab := range tabs {
			for _, v := range tab.views {
				if !nativeValue.(bool) {
					if v.Buf.origHash == empty {
						data, err := ioutil.ReadFile(v.Buf.AbsPath)
						if err != nil {
							data = []byte{}
						}
						v.Buf.origHash = md5.Sum(data)
					}
				} else {
					v.Buf.IsModified = v.Buf.Modified()
				}
			}
		}
	}

	buf.Settings[option] = nativeValue

	if option == "statusline" {
		view.ToggleStatusLine()
	}

	if option == "filetype" {
		// LoadSyntaxFiles()
		InitColorscheme()
		buf.UpdateRules()
	}

	if option == "fileformat" {
		buf.IsModified = true
	}

	if option == "syntax" {
		if !nativeValue.(bool) {
			buf.ClearMatches()
		} else {
			buf.highlighter.HighlightStates(buf)
		}
	}

	return nil
}

// SetOptionAndSettings sets the given option and saves the option setting to the settings config file
func SetOptionAndSettings(option, value string) {
	filename := configDir + "/settings.json"

	err := SetOption(option, value)

	if err != nil {
		messenger.Error(err.Error())
		return
	}

	err = WriteSettings(filename)
	if err != nil {
		messenger.Error("Error writing to settings.json: " + err.Error())
		return
	}
}

func optionIsValid(option string, value interface{}) error {
	if validator, ok := optionValidators[option]; ok {
		return validator(option, value)
	}

	return nil
}

// Option validators

func validatePositiveValue(option string, value interface{}) error {
	tabsize, ok := value.(float64)

	if !ok {
		return errors.New("Expected numeric type for " + option)
	}

	if tabsize < 1 {
		return errors.New(option + " must be greater than 0")
	}

	return nil
}

func validateNonNegativeValue(option string, value interface{}) error {
	nativeValue, ok := value.(float64)

	if !ok {
		return errors.New("Expected numeric type for " + option)
	}

	if nativeValue < 0 {
		return errors.New(option + " must be non-negative")
	}

	return nil
}

func validateColorscheme(option string, value interface{}) error {
	colorscheme, ok := value.(string)

	if !ok {
		return errors.New("Expected string type for colorscheme")
	}

	if !ColorschemeExists(colorscheme) {
		return errors.New(colorscheme + " is not a valid colorscheme")
	}

	return nil
}

func validateLineEnding(option string, value interface{}) error {
	endingType, ok := value.(string)

	if !ok {
		return errors.New("Expected string type for file format")
	}

	if endingType != "unix" && endingType != "dos" {
		return errors.New("File format must be either 'unix' or 'dos'")
	}

	return nil
}
<commit_msg>Fix syntax highlighting on empty buffer<commit_after>package main

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/flynn/json5"
	"github.com/zyedidia/glob"
)

type optionValidator func(string, interface{}) error

// The options that the user can set
var globalSettings map[string]interface{}

var invalidSettings bool

// Options with validators
var optionValidators = map[string]optionValidator{
	"tabsize":      validatePositiveValue,
	"scrollmargin": validateNonNegativeValue,
	"scrollspeed":  validateNonNegativeValue,
	"colorscheme":  validateColorscheme,
	"colorcolumn":  validateNonNegativeValue,
	"fileformat":   validateLineEnding,
}

// InitGlobalSettings initializes the options map and sets all options to their default values
func InitGlobalSettings() {
	invalidSettings = false
	defaults := DefaultGlobalSettings()
	var parsed map[string]interface{}

	filename := configDir + "/settings.json"
	writeSettings := false
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if !strings.HasPrefix(string(input), "null") {
			if err != nil {
				TermMessage("Error reading settings.json file: " + err.Error())
				invalidSettings = true
				return
			}

			err = json5.Unmarshal(input, &parsed)
			if err != nil {
				TermMessage("Error reading settings.json:", err.Error())
				invalidSettings = true
			}
		} else {
			writeSettings = true
		}
	}

	globalSettings = make(map[string]interface{})
	for k, v := range defaults {
		globalSettings[k] = v
	}
	for k, v := range parsed {
		if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
			globalSettings[k] = v
		}
	}

	if _, err := os.Stat(filename); os.IsNotExist(err) || writeSettings {
		err := WriteSettings(filename)
		if err != nil {
			TermMessage("Error writing settings.json file: " + err.Error())
		}
	}
}

// InitLocalSettings scans the json in settings.json and sets the options locally based
// on whether the buffer matches the glob
func InitLocalSettings(buf *Buffer) {
	invalidSettings = false
	var parsed map[string]interface{}

	filename := configDir + "/settings.json"
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if err != nil {
			TermMessage("Error reading settings.json file: " + err.Error())
			invalidSettings = true
			return
		}

		err = json5.Unmarshal(input, &parsed)
		if err != nil {
			TermMessage("Error reading settings.json:", err.Error())
			invalidSettings = true
		}
	}

	for k, v := range parsed {
		if strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
			if strings.HasPrefix(k, "ft:") {
				if buf.Settings["filetype"].(string) == k[3:] {
					for k1, v1 := range v.(map[string]interface{}) {
						buf.Settings[k1] = v1
					}
				}
			} else {
				g, err := glob.Compile(k)
				if err != nil {
					TermMessage("Error with glob setting ", k, ": ", err)
					continue
				}

				if g.MatchString(buf.Path) {
					for k1, v1 := range v.(map[string]interface{}) {
						buf.Settings[k1] = v1
					}
				}
			}
		}
	}
}

// WriteSettings writes the settings to the specified filename as JSON
func WriteSettings(filename string) error {
	if invalidSettings {
		// Do not write the settings if there was an error when reading them
		return nil
	}

	var err error
	if _, e := os.Stat(configDir); e == nil {
		parsed := make(map[string]interface{})

		filename := configDir + "/settings.json"
		for k, v := range globalSettings {
			parsed[k] = v
		}
		if _, e := os.Stat(filename); e == nil {
			input, err := ioutil.ReadFile(filename)
			if string(input) != "null" {
				if err != nil {
					return err
				}

				err = json5.Unmarshal(input, &parsed)
				if err != nil {
					TermMessage("Error reading settings.json:", err.Error())
					invalidSettings = true
				}

				for k, v := range parsed {
					if !strings.HasPrefix(reflect.TypeOf(v).String(), "map") {
						if _, ok := globalSettings[k]; ok {
							parsed[k] = globalSettings[k]
						}
					}
				}
			}
		}

		txt, _ := json.MarshalIndent(parsed, "", "    ")
		err = ioutil.WriteFile(filename, append(txt, '\n'), 0644)
	}
	return err
}

// AddOption creates a new option. This is meant to be called by plugins to add options.
func AddOption(name string, value interface{}) {
	globalSettings[name] = value
	err := WriteSettings(configDir + "/settings.json")
	if err != nil {
		TermMessage("Error writing settings.json file: " + err.Error())
	}
}

// GetGlobalOption returns the global value of the given option
func GetGlobalOption(name string) interface{} {
	return globalSettings[name]
}

// GetLocalOption returns the local value of the given option
func GetLocalOption(name string, buf *Buffer) interface{} {
	return buf.Settings[name]
}

// GetOption returns the value of the given option
// If there is a local version of the option, it returns that
// otherwise it will return the global version
func GetOption(name string) interface{} {
	if GetLocalOption(name, CurView().Buf) != nil {
		return GetLocalOption(name, CurView().Buf)
	}
	return GetGlobalOption(name)
}

// DefaultGlobalSettings returns the default global settings for micro
// Note that colorscheme is a global only option
func DefaultGlobalSettings() map[string]interface{} {
	return map[string]interface{}{
		"autoindent":     true,
		"autosave":       false,
		"basename":       false,
		"colorcolumn":    float64(0),
		"colorscheme":    "default",
		"cursorline":     true,
		"eofnewline":     false,
		"fastdirty":      true,
		"fileformat":     "unix",
		"ignorecase":     false,
		"indentchar":     " ",
		"infobar":        true,
		"keepautoindent": false,
		"keymenu":        false,
		"matchbrace":     false,
		"mouse":          true,
		"pluginchannels": []string{"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"},
		"pluginrepos":    []string{},
		"rmtrailingws":   false,
		"ruler":          true,
		"savecursor":     false,
		"savehistory":    true,
		"saveundo":       false,
		"scrollbar":      false,
		"scrollmargin":   float64(3),
		"scrollspeed":    float64(2),
		"softwrap":       false,
		"splitbottom":    true,
		"splitright":     true,
		"statusline":     true,
		"sucmd":          "sudo",
		"syntax":         true,
		"tabmovement":    false,
		"tabsize":        float64(4),
		"tabstospaces":   false,
		"termtitle":      false,
		"useprimary":     true,
	}
}

// DefaultLocalSettings returns the default local settings
// Note that filetype is a local only option
func DefaultLocalSettings() map[string]interface{} {
	return map[string]interface{}{
		"autoindent":     true,
		"autosave":       false,
		"basename":       false,
		"colorcolumn":    float64(0),
		"cursorline":     true,
		"eofnewline":     false,
		"fastdirty":      true,
		"fileformat":     "unix",
		"filetype":       "Unknown",
		"ignorecase":     false,
		"indentchar":     " ",
		"keepautoindent": false,
		"matchbrace":     false,
		"rmtrailingws":   false,
		"ruler":          true,
		"savecursor":     false,
		"saveundo":       false,
		"scrollbar":      false,
		"scrollmargin":   float64(3),
		"scrollspeed":    float64(2),
		"softwrap":       false,
		"splitbottom":    true,
		"splitright":     true,
		"statusline":     true,
		"syntax":         true,
		"tabmovement":    false,
		"tabsize":        float64(4),
		"tabstospaces":   false,
		"useprimary":     true,
	}
}

// SetOption attempts to set the given option to the value
// By default it will set the option as global, but if the option
// is local only it will set the local version
// Use setlocal to force an option to be set locally
func SetOption(option, value string) error {
	if _, ok := globalSettings[option]; !ok {
		if _, ok := CurView().Buf.Settings[option]; !ok {
			return errors.New("Invalid option")
		}
		SetLocalOption(option, value, CurView())
		return nil
	}

	var nativeValue interface{}

	kind := reflect.TypeOf(globalSettings[option]).Kind()
	if kind == reflect.Bool {
		b, err := ParseBool(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = b
	} else if kind == reflect.String {
		nativeValue = value
	} else if kind == reflect.Float64 {
		i, err := strconv.Atoi(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = float64(i)
	} else {
		return errors.New("Option has unsupported value type")
	}

	if err := optionIsValid(option, nativeValue); err != nil {
		return err
	}

	globalSettings[option] = nativeValue

	if option == "colorscheme" {
		// LoadSyntaxFiles()
		InitColorscheme()
		for _, tab := range tabs {
			for _, view := range tab.views {
				view.Buf.UpdateRules()
			}
		}
	}

	if option == "infobar" || option == "keymenu" {
		for _, tab := range tabs {
			tab.Resize()
		}
	}

	if option == "mouse" {
		if !nativeValue.(bool) {
			screen.DisableMouse()
		} else {
			screen.EnableMouse()
		}
	}

	if len(tabs) != 0 {
		if _, ok := CurView().Buf.Settings[option]; ok {
			for _, tab := range tabs {
				for _, view := range tab.views {
					SetLocalOption(option, value, view)
				}
			}
		}
	}

	return nil
}

// SetLocalOption sets the local version of this option
func SetLocalOption(option, value string, view *View) error {
	buf := view.Buf
	if _, ok := buf.Settings[option]; !ok {
		return errors.New("Invalid option")
	}

	var nativeValue interface{}

	kind := reflect.TypeOf(buf.Settings[option]).Kind()
	if kind == reflect.Bool {
		b, err := ParseBool(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = b
	} else if kind == reflect.String {
		nativeValue = value
	} else if kind == reflect.Float64 {
		i, err := strconv.Atoi(value)
		if err != nil {
			return errors.New("Invalid value")
		}
		nativeValue = float64(i)
	} else {
		return errors.New("Option has unsupported value type")
	}

	if err := optionIsValid(option, nativeValue); err != nil {
		return err
	}

	if option == "fastdirty" {
		// If it is being turned off, we have to hash every open buffer
		var empty [16]byte
		for _, tab := range tabs {
			for _, v := range tab.views {
				if !nativeValue.(bool) {
					if v.Buf.origHash == empty {
						data, err := ioutil.ReadFile(v.Buf.AbsPath)
						if err != nil {
							data = []byte{}
						}
						v.Buf.origHash = md5.Sum(data)
					}
				} else {
					v.Buf.IsModified = v.Buf.Modified()
				}
			}
		}
	}

	buf.Settings[option] = nativeValue

	if option == "statusline" {
		view.ToggleStatusLine()
	}

	if option == "filetype" {
		// LoadSyntaxFiles()
		InitColorscheme()
		buf.UpdateRules()
	}

	if option == "fileformat" {
		buf.IsModified = true
	}

	if option == "syntax" {
		if !nativeValue.(bool) {
			buf.ClearMatches()
		} else {
			if buf.highlighter != nil {
				buf.highlighter.HighlightStates(buf)
			}
		}
	}

	return nil
}

// SetOptionAndSettings sets the given option and saves the option setting to the settings config file
func SetOptionAndSettings(option, value string) {
	filename := configDir + "/settings.json"

	err := SetOption(option, value)

	if err != nil {
		messenger.Error(err.Error())
		return
	}

	err = WriteSettings(filename)
	if err != nil {
		messenger.Error("Error writing to settings.json: " + err.Error())
		return
	}
}

func optionIsValid(option string, value interface{}) error {
	if validator, ok := optionValidators[option]; ok {
		return validator(option, value)
	}

	return nil
}

// Option validators

func validatePositiveValue(option string, value interface{}) error {
	tabsize, ok := value.(float64)

	if !ok {
		return errors.New("Expected numeric type for " + option)
	}

	if tabsize < 1 {
		return errors.New(option + " must be greater than 0")
	}

	return nil
}

func validateNonNegativeValue(option string, value interface{}) error {
	nativeValue, ok := value.(float64)

	if !ok {
		return errors.New("Expected numeric type for " + option)
	}

	if nativeValue < 0 {
		return errors.New(option + " must be non-negative")
	}

	return nil
}

func validateColorscheme(option string, value interface{}) error {
	colorscheme, ok := value.(string)

	if !ok {
		return errors.New("Expected string type for colorscheme")
	}

	if !ColorschemeExists(colorscheme) {
		return errors.New(colorscheme + " is not a valid colorscheme")
	}

	return nil
}

func validateLineEnding(option string, value interface{}) error {
	endingType, ok := value.(string)

	if !ok {
		return errors.New("Expected string type for file format")
	}

	if endingType != "unix" && endingType != "dos" {
		return errors.New("File format must be either 'unix' or 'dos'")
	}

	return nil
}
<|endoftext|>


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

package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"

	lumberjack "gopkg.in/natefinch/lumberjack.v2"

	"github.com/xenolf/lego/acme"

	"github.com/mholt/caddy"
	// plug in the HTTP server type
	_ "github.com/mholt/caddy/caddyhttp"
	"github.com/mholt/caddy/caddytls"

	// This is where other plugins get plugged in (imported)
	_ "github.com/mholt/caddy/caddyhttp/proxy"
	_ "github.com/namsral/multipass"
)

func init() {
	caddy.TrapSignals()
	setVersion()

	flag.BoolVar(&caddytls.Agreed, "agree", false, "Agree to the CA's Subscriber Agreement")
	flag.StringVar(&caddytls.DefaultCAUrl, "ca", "https://acme-v01.api.letsencrypt.org/directory", "URL to certificate authority's ACME server directory")
	flag.StringVar(&conf, "conf", "", "Caddyfile to load (default \""+caddy.DefaultConfigFile+"\")")
	flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
	flag.BoolVar(&plugins, "plugins", false, "List installed plugins")
	flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
	flag.StringVar(&logfile, "log", "stdout", "Process log file")
	flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
	flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
	flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
	flag.StringVar(&serverType, "type", "http", "Type of server to run")
	flag.BoolVar(&version, "version", false, "Show version")

	caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))
	caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
}

// Run is Caddy's main() function.
func main() {
	flag.Parse()

	caddy.AppName = appName
	caddy.AppVersion = appVersion
	acme.UserAgent = appName + "/" + appVersion

	// Set up process log before anything bad happens
	switch logfile {
	case "stdout":
		log.SetOutput(os.Stdout)
	case "stderr":
		log.SetOutput(os.Stderr)
	case "":
		log.SetOutput(ioutil.Discard)
	default:
		log.SetOutput(&lumberjack.Logger{
			Filename:   logfile,
			MaxSize:    100,
			MaxAge:     14,
			MaxBackups: 10,
		})
	}

	// Check for one-time actions
	if revoke != "" {
		err := caddytls.Revoke(revoke)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Revoked certificate for %s\n", revoke)
		os.Exit(0)
	}
	if version {
		fmt.Printf("%s %s\n", appName, appVersion)
		if devBuild && gitShortStat != "" {
			fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified)
		}
		os.Exit(0)
	}
	if plugins {
		fmt.Println(caddy.DescribePlugins())
		os.Exit(0)
	}

	// Set CPU cap
	err := setCPU(cpu)
	if err != nil {
		mustLogFatal(err)
	}

	// Get Caddyfile input
	caddyfile, err := caddy.LoadCaddyfile(serverType)
	if err != nil {
		mustLogFatal(err)
	}

	// Start your engines
	instance, err := caddy.Start(caddyfile)
	if err != nil {
		mustLogFatal(err)
	}

	// Twiddle your thumbs
	instance.Wait()
}

// mustLogFatal wraps log.Fatal() in a way that ensures the
// output is always printed to stderr so the user can see it
// if the user is still there, even if the process log was not
// enabled. If this process is an upgrade, however, and the user
// might not be there anymore, this just logs to the process
// log and exits.
func mustLogFatal(args ...interface{}) {
	if !caddy.IsUpgrade() {
		log.SetOutput(os.Stderr)
	}
	log.Fatal(args...)
}

// confLoader loads the Caddyfile using the -conf flag.
func confLoader(serverType string) (caddy.Input, error) {
	if conf == "" {
		return nil, nil
	}

	if conf == "stdin" {
		return caddy.CaddyfileFromPipe(os.Stdin)
	}

	contents, err := ioutil.ReadFile(conf)
	if err != nil {
		return nil, err
	}
	return caddy.CaddyfileInput{
		Contents:       contents,
		Filepath:       conf,
		ServerTypeName: serverType,
	}, nil
}

// defaultLoader loads the Caddyfile from the current working directory.
func defaultLoader(serverType string) (caddy.Input, error) {
	contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	return caddy.CaddyfileInput{
		Contents:       contents,
		Filepath:       caddy.DefaultConfigFile,
		ServerTypeName: serverType,
	}, nil
}

// setVersion figures out the version information
// based on variables set by -ldflags.
func setVersion() {
	// A development build is one that's not at a tag or has uncommitted changes
	devBuild = gitTag == "" || gitShortStat != ""

	// Only set the appVersion if -ldflags was used
	if gitNearestTag != "" || gitTag != "" {
		if devBuild && gitNearestTag != "" {
			appVersion = fmt.Sprintf("%s (+%s %s)",
				strings.TrimPrefix(gitNearestTag, "v"), gitCommit, buildDate)
		} else if gitTag != "" {
			appVersion = strings.TrimPrefix(gitTag, "v")
		}
	}
}

// setCPU parses string cpu and sets GOMAXPROCS
// according to its value. It accepts either
// a number (e.g. 3) or a percent (e.g. 50%).
func setCPU(cpu string) error {
	var numCPU int

	availCPU := runtime.NumCPU()

	if strings.HasSuffix(cpu, "%") {
		// Percent
		var percent float32
		pctStr := cpu[:len(cpu)-1]
		pctInt, err := strconv.Atoi(pctStr)
		if err != nil || pctInt < 1 || pctInt > 100 {
			return errors.New("invalid CPU value: percentage must be between 1-100")
		}
		percent = float32(pctInt) / 100
		numCPU = int(float32(availCPU) * percent)
	} else {
		// Number
		num, err := strconv.Atoi(cpu)
		if err != nil || num < 1 {
			return errors.New("invalid CPU value: provide a number or percent greater than 0")
		}
		numCPU = num
	}

	if numCPU > availCPU {
		numCPU = availCPU
	}

	runtime.GOMAXPROCS(numCPU)
	return nil
}

const appName = "Caddy"

// Flags that control program flow or startup
var (
	serverType string
	conf       string
	cpu        string
	logfile    string
	revoke     string
	version    bool
	plugins    bool
)

// Build information obtained with the help of -ldflags
var (
	appVersion = "(untracked dev build)" // inferred at startup
	devBuild   = true                    // inferred at startup

	buildDate        string // date -u
	gitTag           string // git describe --exact-match HEAD 2> /dev/null
	gitNearestTag    string // git describe --abbrev=0 --tags HEAD
	gitCommit        string // git rev-parse HEAD
	gitShortStat     string // git diff-index --shortstat
	gitFilesModified string // git diff-index --name-only HEAD
)
<commit_msg>Fix constant appName to Multipass<commit_after>// Copyright 2016 Lars Wiegman. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.

package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"strings"

	lumberjack "gopkg.in/natefinch/lumberjack.v2"

	"github.com/xenolf/lego/acme"

	"github.com/mholt/caddy"
	// plug in the HTTP server type
	_ "github.com/mholt/caddy/caddyhttp"
	"github.com/mholt/caddy/caddytls"

	// This is where other plugins get plugged in (imported)
	_ "github.com/mholt/caddy/caddyhttp/proxy"
	_ "github.com/namsral/multipass"
)

func init() {
	caddy.TrapSignals()
	setVersion()

	flag.BoolVar(&caddytls.Agreed, "agree", false, "Agree to the CA's Subscriber Agreement")
	flag.StringVar(&caddytls.DefaultCAUrl, "ca", "https://acme-v01.api.letsencrypt.org/directory", "URL to certificate authority's ACME server directory")
	flag.StringVar(&conf, "conf", "", "Caddyfile to load (default \""+caddy.DefaultConfigFile+"\")")
	flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
	flag.BoolVar(&plugins, "plugins", false, "List installed plugins")
	flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
	flag.StringVar(&logfile, "log", "stdout", "Process log file")
	flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
	flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
	flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
	flag.StringVar(&serverType, "type", "http", "Type of server to run")
	flag.BoolVar(&version, "version", false, "Show version")

	caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))
	caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
}

// Run is Caddy's main() function.
func main() {
	flag.Parse()

	caddy.AppName = appName
	caddy.AppVersion = appVersion
	acme.UserAgent = appName + "/" + appVersion

	// Set up process log before anything bad happens
	switch logfile {
	case "stdout":
		log.SetOutput(os.Stdout)
	case "stderr":
		log.SetOutput(os.Stderr)
	case "":
		log.SetOutput(ioutil.Discard)
	default:
		log.SetOutput(&lumberjack.Logger{
			Filename:   logfile,
			MaxSize:    100,
			MaxAge:     14,
			MaxBackups: 10,
		})
	}

	// Check for one-time actions
	if revoke != "" {
		err := caddytls.Revoke(revoke)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Revoked certificate for %s\n", revoke)
		os.Exit(0)
	}
	if version {
		fmt.Printf("%s %s\n", appName, appVersion)
		if devBuild && gitShortStat != "" {
			fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified)
		}
		os.Exit(0)
	}
	if plugins {
		fmt.Println(caddy.DescribePlugins())
		os.Exit(0)
	}

	// Set CPU cap
	err := setCPU(cpu)
	if err != nil {
		mustLogFatal(err)
	}

	// Get Caddyfile input
	caddyfile, err := caddy.LoadCaddyfile(serverType)
	if err != nil {
		mustLogFatal(err)
	}

	// Start your engines
	instance, err := caddy.Start(caddyfile)
	if err != nil {
		mustLogFatal(err)
	}

	// Twiddle your thumbs
	instance.Wait()
}

// mustLogFatal wraps log.Fatal() in a way that ensures the
// output is always printed to stderr so the user can see it
// if the user is still there, even if the process log was not
// enabled. If this process is an upgrade, however, and the user
// might not be there anymore, this just logs to the process
// log and exits.
func mustLogFatal(args ...interface{}) {
	if !caddy.IsUpgrade() {
		log.SetOutput(os.Stderr)
	}
	log.Fatal(args...)
}

// confLoader loads the Caddyfile using the -conf flag.
func confLoader(serverType string) (caddy.Input, error) {
	if conf == "" {
		return nil, nil
	}

	if conf == "stdin" {
		return caddy.CaddyfileFromPipe(os.Stdin)
	}

	contents, err := ioutil.ReadFile(conf)
	if err != nil {
		return nil, err
	}
	return caddy.CaddyfileInput{
		Contents:       contents,
		Filepath:       conf,
		ServerTypeName: serverType,
	}, nil
}

// defaultLoader loads the Caddyfile from the current working directory.
func defaultLoader(serverType string) (caddy.Input, error) {
	contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	return caddy.CaddyfileInput{
		Contents:       contents,
		Filepath:       caddy.DefaultConfigFile,
		ServerTypeName: serverType,
	}, nil
}

// setVersion figures out the version information
// based on variables set by -ldflags.
func setVersion() {
	// A development build is one that's not at a tag or has uncommitted changes
	devBuild = gitTag == "" || gitShortStat != ""

	// Only set the appVersion if -ldflags was used
	if gitNearestTag != "" || gitTag != "" {
		if devBuild && gitNearestTag != "" {
			appVersion = fmt.Sprintf("%s (+%s %s)",
				strings.TrimPrefix(gitNearestTag, "v"), gitCommit, buildDate)
		} else if gitTag != "" {
			appVersion = strings.TrimPrefix(gitTag, "v")
		}
	}
}

// setCPU parses string cpu and sets GOMAXPROCS
// according to its value. It accepts either
// a number (e.g. 3) or a percent (e.g. 50%).
func setCPU(cpu string) error {
	var numCPU int

	availCPU := runtime.NumCPU()

	if strings.HasSuffix(cpu, "%") {
		// Percent
		var percent float32
		pctStr := cpu[:len(cpu)-1]
		pctInt, err := strconv.Atoi(pctStr)
		if err != nil || pctInt < 1 || pctInt > 100 {
			return errors.New("invalid CPU value: percentage must be between 1-100")
		}
		percent = float32(pctInt) / 100
		numCPU = int(float32(availCPU) * percent)
	} else {
		// Number
		num, err := strconv.Atoi(cpu)
		if err != nil || num < 1 {
			return errors.New("invalid CPU value: provide a number or percent greater than 0")
		}
		numCPU = num
	}

	if numCPU > availCPU {
		numCPU = availCPU
	}

	runtime.GOMAXPROCS(numCPU)
	return nil
}

const appName = "Multipass"

// Flags that control program flow or startup
var (
	serverType string
	conf       string
	cpu        string
	logfile    string
	revoke     string
	version    bool
	plugins    bool
)

// Build information obtained with the help of -ldflags
var (
	appVersion = "(untracked dev build)" // inferred at startup
	devBuild   = true                    // inferred at startup

	buildDate        string // date -u
	gitTag           string // git describe --exact-match HEAD 2> /dev/null
	gitNearestTag    string // git describe --abbrev=0 --tags HEAD
	gitCommit        string // git rev-parse HEAD
	gitShortStat     string // git diff-index --shortstat
	gitFilesModified string // git diff-index --name-only HEAD
)
<|endoftext|>


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

package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/minio/cli"
	"github.com/minio/mc/pkg/probe"
	minio "github.com/minio/minio-go/v6"
	"github.com/minio/minio/pkg/console"
)

var retentionCmd = cli.Command{
	Name:   "retention",
	Usage:  "set object retention for objects with a given prefix",
	Action: mainRetention,
	Before: setGlobalsFromContext,
	Flags:  globalFlags,
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET [governance | compliance] [VALIDITY]

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
VALIDITY:
  This argument must be formatted like Nd or Ny where 'd' denotes days and 'y' denotes years e.g. 10d, 3y.

EXAMPLES:
   1. Set object retention for objects in a given prefix
     $ {{.HelpName}} myminio/mybucket/prefix compliance 30d
`,
}

// Structured message depending on the type of console.
type retentionCmdMessage struct {
	Mode     minio.RetentionMode `json:"mode"`
	Validity *string             `json:"validity"`
	URLPath  string              `json:"urlpath"`
	Status   string              `json:"status"`
	Err      error               `json:"error"`
}

// Colorized message for console printing.
func (m retentionCmdMessage) String() string {
	if m.Err != nil {
		return console.Colorize("RetentionMessageFailure", "Cannot set object retention on `"+m.URLPath+"`."+m.Err.Error())
	}
	return ""
}

// JSON'ified message for scripting.
func (m retentionCmdMessage) JSON() string {
	msgBytes, e := json.MarshalIndent(m, "", " ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
	return string(msgBytes)
}

// setRetention - Set Retention for all objects within a given prefix.
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit) error {
	clnt, err := newClient(urlStr)
	if err != nil {
		fatalIf(err.Trace(), "Cannot parse the provided url.")
	}

	// Quit early if urlStr does not point to an S3 server
	switch clnt.(type) {
	case *fsClient:
		fatal(errDummy().Trace(), "Retention for filesystem not supported.")
	}

	alias, _, _ := mustExpandAlias(urlStr)
	retainUntilDate := func() (time.Time, error) {
		if validity == nil {
			return timeSentinel, fmt.Errorf("invalid validity '%v'", validity)
		}
		t := UTCNow()
		if *unit == minio.Years {
			t = t.AddDate(int(*validity), 0, 0)
		} else {
			t = t.AddDate(0, 0, int(*validity))
		}
		timeStr := t.Format(time.RFC3339)

		t1, e := time.Parse(
			time.RFC3339,
			timeStr)
		if e != nil {
			return timeSentinel, e
		}
		return t1, nil
	}
	validityStr := func() *string {
		if validity == nil {
			return nil
		}

		unitStr := "d"
		if *unit == minio.Years {
			unitStr = "y"
		}
		s := fmt.Sprint(*validity, unitStr)
		return &s
	}

	var cErr error
	errorsFound := false
	for content := range clnt.List(true, false, false, DirNone) {
		if content.Err != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.")
			cErr = exitStatus(globalErrorExitStatus) // Set the exit status.
			continue
		}
		retainUntil, err := retainUntilDate()
		if err != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid retention date")
			continue
		}
		newClnt, perr := newClientFromAlias(alias, content.URL.String())
		if perr != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid URL")
			continue
		}
		probeErr := newClnt.PutObjectRetention(mode, &retainUntil)
		if probeErr != nil {
			errorsFound = true
			printMsg(retentionCmdMessage{
				Mode:     *mode,
				Validity: validityStr(),
				Status:   "failure",
				URLPath:  content.URL.Path,
				Err:      probeErr.ToGoError(),
			})
		} else {
			if globalJSON {
				printMsg(retentionCmdMessage{
					Mode:     *mode,
					Validity: validityStr(),
					Status:   "success",
					URLPath:  content.URL.Path,
				})
			}
		}
	}
	if cErr == nil && !globalJSON {
		if errorsFound {
			console.Print(console.Colorize("RetentionPartialFailure", fmt.Sprintf("Errors found while setting retention on objects with prefix `%s`.\n", urlStr)))
		} else {
			console.Print(console.Colorize("RetentionSuccess", fmt.Sprintf("Object retention successfully set for prefix `%s`.\n", urlStr)))
		}
	}
	return cErr
}

// main for retention command.
func mainRetention(ctx *cli.Context) error {
	console.SetColor("RetentionSuccess", color.New(color.FgGreen, color.Bold))
	console.SetColor("RetentionPartialFailure", color.New(color.FgRed, color.Bold))
	console.SetColor("RetentionMessageFailure", color.New(color.FgYellow))

	// Parse encryption keys per command.
	_, err := getEncKeys(ctx)
	fatalIf(err, "Unable to parse encryption keys.")

	// lock specific flags.
	clearLock := ctx.Bool("clear")

	args := ctx.Args()

	var urlStr string
	var mode *minio.RetentionMode
	var validity *uint
	var unit *minio.ValidityUnit

	switch l := len(args); l {
	case 3:
		urlStr = args[0]
		if clearLock {
			fatalIf(probe.NewError(errors.New("invalid argument")), "clear flag must be passed with target alone")
		}

		m := minio.RetentionMode(strings.ToUpper(args[1]))
		if !m.IsValid() {
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid retention mode '%v'", m)
		}

		mode = &m

		validityStr := args[2]
		unitStr := string(validityStr[len(validityStr)-1])

		validityStr = validityStr[:len(validityStr)-1]
		ui64, err := strconv.ParseUint(validityStr, 10, 64)
		if err != nil {
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity '%v'", args[2])
		}
		u := uint(ui64)
		validity = &u

		switch unitStr {
		case "d", "D":
			d := minio.Days
			unit = &d
		case "y", "Y":
			y := minio.Years
			unit = &y
		default:
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity format '%v'", args[2])
		}
	default:
		cli.ShowCommandHelpAndExit(ctx, "retention", 1)
	}
	return setRetention(urlStr, mode, validity, unit)
}
<commit_msg>retention - cleanup unused code (#3094)<commit_after>/*
 * MinIO Client (C) 2019 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/minio/cli"
	"github.com/minio/mc/pkg/probe"
	minio "github.com/minio/minio-go/v6"
	"github.com/minio/minio/pkg/console"
)

var retentionCmd = cli.Command{
	Name:   "retention",
	Usage:  "set object retention for objects with a given prefix",
	Action: mainRetention,
	Before: setGlobalsFromContext,
	Flags:  globalFlags,
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET [governance | compliance] [VALIDITY]

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
VALIDITY:
  This argument must be formatted like Nd or Ny where 'd' denotes days and 'y' denotes years e.g. 10d, 3y.

EXAMPLES:
   1. Set object retention for objects in a given prefix
     $ {{.HelpName}} myminio/mybucket/prefix compliance 30d
`,
}

// Structured message depending on the type of console.
type retentionCmdMessage struct {
	Mode     minio.RetentionMode `json:"mode"`
	Validity *string             `json:"validity"`
	URLPath  string              `json:"urlpath"`
	Status   string              `json:"status"`
	Err      error               `json:"error"`
}

// Colorized message for console printing.
func (m retentionCmdMessage) String() string {
	if m.Err != nil {
		return console.Colorize("RetentionMessageFailure", "Cannot set object retention on `"+m.URLPath+"`."+m.Err.Error())
	}
	return ""
}

// JSON'ified message for scripting.
func (m retentionCmdMessage) JSON() string {
	msgBytes, e := json.MarshalIndent(m, "", " ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
	return string(msgBytes)
}

// setRetention - Set Retention for all objects within a given prefix.
func setRetention(urlStr string, mode *minio.RetentionMode, validity *uint, unit *minio.ValidityUnit) error {
	clnt, err := newClient(urlStr)
	if err != nil {
		fatalIf(err.Trace(), "Cannot parse the provided url.")
	}

	// Quit early if urlStr does not point to an S3 server
	switch clnt.(type) {
	case *fsClient:
		fatal(errDummy().Trace(), "Retention for filesystem not supported.")
	}

	alias, _, _ := mustExpandAlias(urlStr)
	retainUntilDate := func() (time.Time, error) {
		if validity == nil {
			return timeSentinel, fmt.Errorf("invalid validity '%v'", validity)
		}
		t := UTCNow()
		if *unit == minio.Years {
			t = t.AddDate(int(*validity), 0, 0)
		} else {
			t = t.AddDate(0, 0, int(*validity))
		}
		timeStr := t.Format(time.RFC3339)

		t1, e := time.Parse(
			time.RFC3339,
			timeStr)
		if e != nil {
			return timeSentinel, e
		}
		return t1, nil
	}
	validityStr := func() *string {
		if validity == nil {
			return nil
		}

		unitStr := "d"
		if *unit == minio.Years {
			unitStr = "y"
		}
		s := fmt.Sprint(*validity, unitStr)
		return &s
	}

	var cErr error
	errorsFound := false
	for content := range clnt.List(true, false, false, DirNone) {
		if content.Err != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.")
			cErr = exitStatus(globalErrorExitStatus) // Set the exit status.
			continue
		}
		retainUntil, err := retainUntilDate()
		if err != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid retention date")
			continue
		}
		newClnt, perr := newClientFromAlias(alias, content.URL.String())
		if perr != nil {
			errorIf(content.Err.Trace(clnt.GetURL().String()), "Invalid URL")
			continue
		}
		probeErr := newClnt.PutObjectRetention(mode, &retainUntil)
		if probeErr != nil {
			errorsFound = true
			printMsg(retentionCmdMessage{
				Mode:     *mode,
				Validity: validityStr(),
				Status:   "failure",
				URLPath:  content.URL.Path,
				Err:      probeErr.ToGoError(),
			})
		} else {
			if globalJSON {
				printMsg(retentionCmdMessage{
					Mode:     *mode,
					Validity: validityStr(),
					Status:   "success",
					URLPath:  content.URL.Path,
				})
			}
		}
	}
	if cErr == nil && !globalJSON {
		if errorsFound {
			console.Print(console.Colorize("RetentionPartialFailure", fmt.Sprintf("Errors found while setting retention on objects with prefix `%s`.\n", urlStr)))
		} else {
			console.Print(console.Colorize("RetentionSuccess", fmt.Sprintf("Object retention successfully set for prefix `%s`.\n", urlStr)))
		}
	}
	return cErr
}

// main for retention command.
func mainRetention(ctx *cli.Context) error {
	console.SetColor("RetentionSuccess", color.New(color.FgGreen, color.Bold))
	console.SetColor("RetentionPartialFailure", color.New(color.FgRed, color.Bold))
	console.SetColor("RetentionMessageFailure", color.New(color.FgYellow))
	args := ctx.Args()

	var urlStr string
	var mode *minio.RetentionMode
	var validity *uint
	var unit *minio.ValidityUnit

	switch l := len(args); l {
	case 3:
		urlStr = args[0]
		m := minio.RetentionMode(strings.ToUpper(args[1]))
		if !m.IsValid() {
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid retention mode '%v'", m)
		}

		mode = &m

		validityStr := args[2]
		unitStr := string(validityStr[len(validityStr)-1])

		validityStr = validityStr[:len(validityStr)-1]
		ui64, err := strconv.ParseUint(validityStr, 10, 64)
		if err != nil {
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity '%v'", args[2])
		}
		u := uint(ui64)
		validity = &u

		switch unitStr {
		case "d", "D":
			d := minio.Days
			unit = &d
		case "y", "Y":
			y := minio.Years
			unit = &y
		default:
			fatalIf(probe.NewError(errors.New("invalid argument")), "invalid validity format '%v'", args[2])
		}
	default:
		cli.ShowCommandHelpAndExit(ctx, "retention", 1)
	}
	return setRetention(urlStr, mode, validity, unit)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

var (
	stInsert *sql.Stmt
	stUpdate *sql.Stmt
	stDelete *sql.Stmt
)

func main() {
	db, err := sql.Open("mysql", "vagrant:db1234@tcp(127.0.0.1:3306)/vagrant")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	err = test(db)
	if err != nil {
		log.Printf("WARN: %s", err)
	}
}

func test(db *sql.DB) error {
	if err := test0(db); err != nil {
		return err
	}
	if err := test1(db); err != nil {
		return err
	}
	if err := test2(db); err != nil {
		return err
	}
	if err := test3(db); err != nil {
		return err
	}
	// TODO:
	if err := test99(db); err != nil {
		return err
	}
	return nil
}

func test0(db *sql.DB) error {
	rows, err := db.Query(`SHOW DATABASES`)
	if err != nil {
		return err
	}
	defer rows.Close()
	for rows.Next() {
		var name string
		err := rows.Scan(&name)
		if err != nil {
			return err
		}
		fmt.Printf("test0: table:%s found\n", name)
	}
	return nil
}

func test1(db *sql.DB) error {
	_, err := db.Exec(`CREATE TABLE IF NOT EXISTS users (
		id INT PRIMARY KEY AUTO_INCREMENT,
		name VARCHAR(255) UNIQUE,
		password VARCHAR(255)
	)`)
	if err != nil {
		return err
	}
	return nil
}

func test2(db *sql.DB) error {
	var err error
	stInsert, err = db.Prepare(
		`INSERT INTO users (name, password) VALUES (?, ?)`)
	if err != nil {
		return err
	}
	stUpdate, err = db.Prepare(
		`UPDATE users SET name = ?, password = ? WHERE id = ?`)
	if err != nil {
		return err
	}
	stDelete, err = db.Prepare(`DELETE FROM users WHERE id = ?`)
	if err != nil {
		return err
	}
	return nil
}

func test3(db *sql.DB) error {
	var err error
	_, err = db.Prepare(
		`INSERT INTO users (name, password) VALUES (?, ?`)
	if err == nil {
		panic("prepare in test3 should be failed")
	}
	fmt.Printf("test3: IGNORED ERROR: %s\n", err)
	return nil
}

func test99(db *sql.DB) error {
	if stDelete != nil {
		stDelete.Close()
	}
	if stUpdate != nil {
		stUpdate.Close()
	}
	if stInsert != nil {
		stInsert.Close()
	}
	_, err := db.Exec(`DROP TABLE users`)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>test more prepared statements<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

var (
	stInsert *sql.Stmt
	stSelect *sql.Stmt
	stUpdate *sql.Stmt
	stDelete *sql.Stmt
)

func main() {
	db, err := sql.Open("mysql", "vagrant:db1234@tcp(127.0.0.1:3306)/vagrant")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	err = test(db)
	if err != nil {
		log.Printf("WARN: %s", err)
	}
}

func test(db *sql.DB) error {
	if err := test0(db); err != nil {
		return err
	}
	if err := test1(db); err != nil {
		return err
	}
	if err := test2(db); err != nil {
		return err
	}
	if err := test3(db); err != nil {
		return err
	}
	if err := test4(db); err != nil {
		return err
	}
	if err := test5(db); err != nil {
		return err
	}
	// TODO:
	if err := test99(db); err != nil {
		return err
	}
	return nil
}

func test0(db *sql.DB) error {
	rows, err := db.Query(`SHOW DATABASES`)
	if err != nil {
		return err
	}
	defer rows.Close()
	for rows.Next() {
		var name string
		err := rows.Scan(&name)
		if err != nil {
			return err
		}
		fmt.Printf("test0: table:%s found\n", name)
	}
	return nil
}

func test1(db *sql.DB) error {
	_, err := db.Exec(`CREATE TABLE IF NOT EXISTS users (
		id INT PRIMARY KEY AUTO_INCREMENT,
		name VARCHAR(255) UNIQUE,
		password VARCHAR(255)
	)`)
	if err != nil {
		return err
	}
	return nil
}

func test2(db *sql.DB) error {
	var err error
	stInsert, err = db.Prepare(
		`INSERT INTO users (name, password) VALUES (?, ?)`)
	if err != nil {
		return err
	}
	stSelect, err = db.Prepare(`SELECT * FROM users WHERE name LIKE ?`)
	if err != nil {
		return err
	}
	stUpdate, err = db.Prepare(
		`UPDATE users SET name = ?, password = ? WHERE id = ?`)
	if err != nil {
		return err
	}
	stDelete, err = db.Prepare(`DELETE FROM users WHERE id = ?`)
	if err != nil {
		return err
	}
	return nil
}

func test3(db *sql.DB) error {
	var err error
	_, err = db.Prepare(
		`INSERT INTO users (name, password) VALUES (?, ?`)
	if err == nil {
		panic("prepare in test3 should be failed")
	}
	fmt.Printf("test3: IGNORED ERROR: %s\n", err)
	return nil
}

func test4(db *sql.DB) error {
	insert := func(u, p string) error {
		r, err := stInsert.Exec(u, p)
		if err != nil {
			return err
		}
		id, _ := r.LastInsertId()
		if err != nil {
			return err
		}
		fmt.Printf("test4: inserted %q as %d\n", u, id)
		return nil
	}
	if err := insert("foo", "pass1234"); err != nil {
		return err
	}
	if err := insert("baz", "pass1234"); err != nil {
		return err
	}
	if err := insert("bar", "pass1234"); err != nil {
		return err
	}
	if err := insert("user001", "pass1234"); err != nil {
		return err
	}
	if err := insert("user002", "pass1234"); err != nil {
		return err
	}
	if err := insert("user003", "pass1234"); err != nil {
		return err
	}
	return nil
}

func test5(db *sql.DB) error {
	rows, err := stSelect.Query("user%")
	if err != nil {
		return err
	}
	defer rows.Close()
	return nil
}

func test99(db *sql.DB) error {
	if stDelete != nil {
		stDelete.Close()
	}
	if stUpdate != nil {
		stUpdate.Close()
	}
	if stSelect != nil {
		stSelect.Close()
	}
	if stInsert != nil {
		stInsert.Close()
	}
	_, err := db.Exec(`DROP TABLE users`)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package cmdpolling

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"
	"errors"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/ingrammicro/concerto/api/polling"
	"github.com/ingrammicro/concerto/cmd"
	"github.com/ingrammicro/concerto/utils"
	"github.com/ingrammicro/concerto/utils/format"
)

const (
	ProcessIdFile = "imco-polling.pid"
)

var (
	commandProcessed = make(chan bool, 1)
)

// Handle signals
func handleSysSignals(cancelFunc context.CancelFunc) {
	log.Debug("handleSysSignals")

	gracefulStop := make(chan os.Signal, 1)
	signal.Notify(gracefulStop, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
	log.Debug("Ending, signal detected:", <-gracefulStop)
	cancelFunc()
}

// Start the polling process
func cmdStart(c *cli.Context) error {
	log.Debug("cmdStart")

	formatter := format.GetFormatter()
	if err := utils.SetProcessIdToFile(ProcessIdFile); err != nil {
		formatter.PrintFatal("cannot create the pid file", err)
	}

	pollingPingTimingInterval := c.Int64("time")
	if !(pollingPingTimingInterval > 0) {
		formatter.PrintFatal("invalid argument", errors.New("a positive value should be used"))
	}
	log.Debug("Ping time interval:", pollingPingTimingInterval)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go handleSysSignals(cancel)

	pingRoutine(ctx, c, pollingPingTimingInterval)

	return nil
}

// Stop the polling process
func cmdStop(c *cli.Context) error {
	log.Debug("cmdStop")

	formatter := format.GetFormatter()
	if err := utils.StopProcess(ProcessIdFile); err != nil {
		formatter.PrintFatal("cannot stop the polling process", err)
	}

	log.Info("concerto polling successfully stopped")
	return nil
}

// Main polling background routine
func pingRoutine(ctx context.Context, c *cli.Context, pollingPingTimingInterval int64) {
	log.Debug("pingRoutine")

	formatter := format.GetFormatter()
	pollingSvc := cmd.WireUpPolling(c)

	isRunningCommandRoutine := false
	t := time.NewTicker(time.Duration(pollingPingTimingInterval) * time.Second)
	for {
		log.Debug("Requesting for candidate commands status")
		ping, status, err := pollingSvc.Ping()
		if err != nil {
			formatter.PrintError("Couldn't receive polling ping data", err)
		} else {
			// One command is available, and no process running
			if status == 201 && ping.PendingCommands && !isRunningCommandRoutine {
				log.Debug("Detected a candidate command")
				isRunningCommandRoutine = true
				go processingCommandRoutine(pollingSvc, formatter)
			}
		}

		select {
		case <-commandProcessed:
			isRunningCommandRoutine = false
		default:
		}

		select {
		case <-t.C:
		case <-ctx.Done():
			log.Debug(ctx.Err())
			log.Debug("closing polling")
			return
		}
	}
}

// Subsidiary routine for commands processing
func processingCommandRoutine(pollingSvc *polling.PollingService, formatter format.Formatter) {
	log.Debug("processingCommandRoutine")

	// 1. Request for the new command available
	log.Debug("Retrieving available command")
	command, status, err := pollingSvc.GetNextCommand()
	if err != nil {
		formatter.PrintError("Couldn't receive polling command candidate data", err)
	}

	// 2. Execute the retrieved command
	if status == 200 {
		log.Debug("Running the retrieved command")
		command.Stdout, command.ExitCode, _, _ = utils.RunCmd(command.Script)
		command.Stderr = ""
		if command.ExitCode != 0 {
			command.Stderr = command.Stdout
			command.Stdout = ""
		}

		// 3. If command successfully executed, then status is propagated to IMCO
		if command.ExitCode == 0 {
			log.Debug("Reporting command execution status")
			commandIn, err := utils.ItemConvertParamsWithTagAsID(*command)
			if err != nil {
				formatter.PrintError("Couldn't send polling command report data; error parsing payload", err)
			}

			_, status, err := pollingSvc.UpdateCommand(commandIn, command.Id)
			if err != nil {
				formatter.PrintError("Couldn't send polling command report data", err)
			}

			if status == 200 {
				log.Debug("Command execution results successfully reported")
			} else {
				log.Error("Cannot report the command execution results")
			}
		} else {
			log.Error("Cannot run the retrieved command")
		}
	} else {
		log.Error("Cannot retrieve the next command")
	}

	commandProcessed <- true
}
<commit_msg>Use default time period in a bad command parameter case (issue #13)<commit_after>package cmdpolling

import (
	"context"
	"os"
	"os/signal"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/ingrammicro/concerto/api/polling"
	"github.com/ingrammicro/concerto/cmd"
	"github.com/ingrammicro/concerto/utils"
	"github.com/ingrammicro/concerto/utils/format"
)

const (
	DefaultPollingPingTimingInterval = 30
	ProcessIdFile                    = "imco-polling.pid"
)

var (
	commandProcessed = make(chan bool, 1)
)

// Handle signals
func handleSysSignals(cancelFunc context.CancelFunc) {
	log.Debug("handleSysSignals")

	gracefulStop := make(chan os.Signal, 1)
	signal.Notify(gracefulStop, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
	log.Debug("Ending, signal detected:", <-gracefulStop)
	cancelFunc()
}

// Start the polling process
func cmdStart(c *cli.Context) error {
	log.Debug("cmdStart")

	formatter := format.GetFormatter()
	if err := utils.SetProcessIdToFile(ProcessIdFile); err != nil {
		formatter.PrintFatal("cannot create the pid file", err)
	}

	pollingPingTimingInterval := c.Int64("time")
	if !(pollingPingTimingInterval > 0) {
		pollingPingTimingInterval = DefaultPollingPingTimingInterval
	}
	log.Debug("Ping time interval:", pollingPingTimingInterval)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go handleSysSignals(cancel)

	pingRoutine(ctx, c, pollingPingTimingInterval)

	return nil
}

// Stop the polling process
func cmdStop(c *cli.Context) error {
	log.Debug("cmdStop")

	formatter := format.GetFormatter()
	if err := utils.StopProcess(ProcessIdFile); err != nil {
		formatter.PrintFatal("cannot stop the polling process", err)
	}

	log.Info("concerto polling successfully stopped")
	return nil
}

// Main polling background routine
func pingRoutine(ctx context.Context, c *cli.Context, pollingPingTimingInterval int64) {
	log.Debug("pingRoutine")

	formatter := format.GetFormatter()
	pollingSvc := cmd.WireUpPolling(c)

	isRunningCommandRoutine := false
	t := time.NewTicker(time.Duration(pollingPingTimingInterval) * time.Second)
	for {
		log.Debug("Requesting for candidate commands status")
		ping, status, err := pollingSvc.Ping()
		if err != nil {
			formatter.PrintError("Couldn't receive polling ping data", err)
		} else {
			// One command is available, and no process running
			if status == 201 && ping.PendingCommands && !isRunningCommandRoutine {
				log.Debug("Detected a candidate command")
				isRunningCommandRoutine = true
				go processingCommandRoutine(pollingSvc, formatter)
			}
		}

		select {
		case <-commandProcessed:
			isRunningCommandRoutine = false
		default:
		}

		select {
		case <-t.C:
		case <-ctx.Done():
			log.Debug(ctx.Err())
			log.Debug("closing polling")
			return
		}
	}
}

// Subsidiary routine for commands processing
func processingCommandRoutine(pollingSvc *polling.PollingService, formatter format.Formatter) {
	log.Debug("processingCommandRoutine")

	// 1. Request for the new command available
	log.Debug("Retrieving available command")
	command, status, err := pollingSvc.GetNextCommand()
	if err != nil {
		formatter.PrintError("Couldn't receive polling command candidate data", err)
	}

	// 2. Execute the retrieved command
	if status == 200 {
		log.Debug("Running the retrieved command")
		command.Stdout, command.ExitCode, _, _ = utils.RunCmd(command.Script)
		command.Stderr = ""
		if command.ExitCode != 0 {
			command.Stderr = command.Stdout
			command.Stdout = ""
		}

		// 3. If command successfully executed, then status is propagated to IMCO
		if command.ExitCode == 0 {
			log.Debug("Reporting command execution status")
			commandIn, err := utils.ItemConvertParamsWithTagAsID(*command)
			if err != nil {
				formatter.PrintError("Couldn't send polling command report data; error parsing payload", err)
			}

			_, status, err := pollingSvc.UpdateCommand(commandIn, command.Id)
			if err != nil {
				formatter.PrintError("Couldn't send polling command report data", err)
			}

			if status == 200 {
				log.Debug("Command execution results successfully reported")
			} else {
				log.Error("Cannot report the command execution results")
			}
		} else {
			log.Error("Cannot run the retrieved command")
		}
	} else {
		log.Error("Cannot retrieve the next command")
	}

	commandProcessed <- true
}
<|endoftext|>


<commit_before>package command

import (
	"github.com/webdevops/go-stubfilegenerator"
	"fmt"
	"strconv"
	"path/filepath"
)

type Typo3Stubs struct {
	Options MysqlCommonOptions `group:"common"`
	Positional struct {
		Schema string `description:"Schema" required:"1"`
		Typo3Root string `description:"TYPO3 root path" required:"1"`
	} `positional-args:"true"`
	Force  bool   `short:"f"  long:"force"      description:"Overwrite existing files"`
}

type storage struct {
	Uid string
	Name string
	Path string
}

type storageFile struct {
	Uid string
	Path string
	RelPath string
	AbsPath string
	ImageWidth string
	ImageHeight string
}

func (conf *Typo3Stubs) Execute(args []string) error {
	fmt.Println("Starting TYPO3 fileadmin stub generator")
	conf.Options.Init()

	sql := `SELECT uid,
                   name,
                   ExtractValue(configuration, '//field[@index=\'basePath\']/value/text()') as storagepath
              FROM sys_file_storage
             WHERE deleted = 0
              AND driver = 'local'`
	result := conf.Options.ExecQuery(conf.Positional.Schema, sql)

	for _, val := range result {
		storage := storage{val[0], val[1], val[2]}
		conf.processStorage(storage)
	}

	return nil
}

func (conf *Typo3Stubs) processStorage(storage storage) {
	stubgen := stubfilegenerator.StubGenerator()

	if conf.Force {
		stubgen.Overwrite = true
	}

	sql := `SELECT f.uid,
                   f.identifier,
                   fm.width as meta_width,
                   fm.height as meta_height
              FROM sys_file f
                   LEFT JOIN sys_file_metadata fm
                     ON fm.file = f.uid
                    AND fm.t3ver_oid = 0
              WHERE f.storage = ` + storage.Uid;
	result := conf.Options.ExecQuery(conf.Positional.Schema, sql)

	for _, val := range result {
		file := storageFile{}
		file.ImageWidth = "800"
		file.ImageHeight = "400"

		switch len(val) {
		case 4:
			file.ImageWidth = val[2]
			file.ImageHeight = val[3]
			file.Uid = val[0]
			file.Path = val[1]
			fallthrough
		case 2:
			file.Uid = val[0]
			file.Path = filepath.Join(storage.Path, val[1])
			file.RelPath = filepath.Join(conf.Positional.Typo3Root, file.Path)
			file.AbsPath, _ = filepath.Abs(file.RelPath)
		}

		stubgen.TemplateVariables["PATH"] = file.Path
		stubgen.Image.Width, _ = strconv.Atoi(file.ImageWidth)
		stubgen.Image.Height, _ = strconv.Atoi(file.ImageHeight)
		stubgen.GenerateStub(file.AbsPath)
	}

}
<commit_msg>Add image size as text to stubs<commit_after>package command

import (
	"github.com/webdevops/go-stubfilegenerator"
	"fmt"
	"strconv"
	"path/filepath"
)

type Typo3Stubs struct {
	Options MysqlCommonOptions `group:"common"`
	Positional struct {
		Schema string `description:"Schema" required:"1"`
		Typo3Root string `description:"TYPO3 root path" required:"1"`
	} `positional-args:"true"`
	Force  bool   `short:"f"  long:"force"      description:"Overwrite existing files"`
}

type storage struct {
	Uid string
	Name string
	Path string
}

type storageFile struct {
	Uid string
	Path string
	RelPath string
	AbsPath string
	ImageWidth string
	ImageHeight string
}

func (conf *Typo3Stubs) Execute(args []string) error {
	fmt.Println("Starting TYPO3 fileadmin stub generator")
	conf.Options.Init()

	sql := `SELECT uid,
                   name,
                   ExtractValue(configuration, '//field[@index=\'basePath\']/value/text()') as storagepath
              FROM sys_file_storage
             WHERE deleted = 0
              AND driver = 'local'`
	result := conf.Options.ExecQuery(conf.Positional.Schema, sql)

	for _, val := range result {
		storage := storage{val[0], val[1], val[2]}
		conf.processStorage(storage)
	}

	return nil
}

func (conf *Typo3Stubs) processStorage(storage storage) {
	stubgen := stubfilegenerator.StubGenerator()
	stubgen.Image.Text = append(stubgen.Image.Text, "Size: %IMAGE_WIDTH% * %IMAGE_HEIGHT%")

	if conf.Force {
		stubgen.Overwrite = true
	}

	sql := `SELECT f.uid,
                   f.identifier,
                   fm.width as meta_width,
                   fm.height as meta_height
              FROM sys_file f
                   LEFT JOIN sys_file_metadata fm
                     ON fm.file = f.uid
                    AND fm.t3ver_oid = 0
              WHERE f.storage = ` + storage.Uid;
	result := conf.Options.ExecQuery(conf.Positional.Schema, sql)

	for _, val := range result {
		file := storageFile{}
		file.ImageWidth = "800"
		file.ImageHeight = "400"

		switch len(val) {
		case 4:
			file.ImageWidth = val[2]
			file.ImageHeight = val[3]
			file.Uid = val[0]
			file.Path = val[1]
			fallthrough
		case 2:
			file.Uid = val[0]
			file.Path = filepath.Join(storage.Path, val[1])
			file.RelPath = filepath.Join(conf.Positional.Typo3Root, file.Path)
			file.AbsPath, _ = filepath.Abs(file.RelPath)
		}

		stubgen.TemplateVariables["PATH"] = file.Path
		stubgen.TemplateVariables["IMAGE_WIDTH"] = file.ImageWidth
		stubgen.TemplateVariables["IMAGE_HEIGHT"] = file.ImageHeight
		stubgen.Image.Width, _ = strconv.Atoi(file.ImageWidth)
		stubgen.Image.Height, _ = strconv.Atoi(file.ImageHeight)
		stubgen.GenerateStub(file.AbsPath)
	}

}
<|endoftext|>


<commit_before>package fakeyagnats

import (
	"github.com/cloudfoundry/yagnats"
)

type FakeYagnats struct {
	Subscriptions     map[string][]yagnats.Subscription
	PublishedMessages map[string][]yagnats.Message
	Unsubscriptions   []int

	ConnectedConnectionProvider yagnats.ConnectionProvider

	ConnectError     error
	PublishError     error
	SubscribeError   error
	UnsubscribeError error

	DidUnsubscribeAll bool
	PingResponse      bool

	counter int
}

func New() *FakeYagnats {
	fake := &FakeYagnats{}
	fake.Reset()
	return fake
}

func (f *FakeYagnats) Reset() {
	f.PublishedMessages = map[string][]yagnats.Message{}
	f.Subscriptions = map[string][]yagnats.Subscription{}
	f.Unsubscriptions = []int{}

	f.ConnectedConnectionProvider = nil

	f.ConnectError = nil
	f.PublishError = nil
	f.SubscribeError = nil
	f.UnsubscribeError = nil

	f.DidUnsubscribeAll = false
	f.PingResponse = true

	f.counter = 0
}

func (f *FakeYagnats) Ping() bool {
	return f.PingResponse
}

func (f *FakeYagnats) Connect(connectionProvider yagnats.ConnectionProvider) error {
	f.ConnectedConnectionProvider = connectionProvider
	return f.ConnectError
}

func (f *FakeYagnats) Disconnect() {
	f.ConnectedConnectionProvider = nil
	return
}

func (f *FakeYagnats) Publish(subject, payload string) error {
	return f.PublishWithReplyTo(subject, payload, "")
}

func (f *FakeYagnats) PublishWithReplyTo(subject, payload, reply string) error {
	message := yagnats.Message{
		Subject: subject,
		Payload: payload,
		ReplyTo: reply,
	}

	f.PublishedMessages[subject] = append(f.PublishedMessages[subject], message)

	return f.PublishError
}

func (f *FakeYagnats) Subscribe(subject string, callback yagnats.Callback) (int, error) {
	return f.SubscribeWithQueue(subject, "", callback)
}

func (f *FakeYagnats) SubscribeWithQueue(subject, queue string, callback yagnats.Callback) (int, error) {
	f.counter++
	subscription := yagnats.Subscription{
		Subject:  subject,
		Queue:    queue,
		ID:       f.counter,
		Callback: callback,
	}

	f.Subscriptions[subject] = append(f.Subscriptions[subject], subscription)

	return subscription.ID, f.SubscribeError
}

func (f *FakeYagnats) Unsubscribe(subscription int) error {
	f.Unsubscriptions = append(f.Unsubscriptions, subscription)
	return f.UnsubscribeError
}

func (f *FakeYagnats) UnsubscribeAll() {
	f.DidUnsubscribeAll = true
}
<commit_msg>oops. fake yagnats didn't satisfy the interface.  fixed.<commit_after>package fakeyagnats

import (
	"github.com/cloudfoundry/yagnats"
)

type FakeYagnats struct {
	Subscriptions        map[string][]yagnats.Subscription
	PublishedMessages    map[string][]yagnats.Message
	Unsubscriptions      []int
	UnsubscribedSubjects []string

	ConnectedConnectionProvider yagnats.ConnectionProvider

	ConnectError     error
	PublishError     error
	SubscribeError   error
	UnsubscribeError error

	PingResponse bool

	counter int
}

func New() *FakeYagnats {
	fake := &FakeYagnats{}
	fake.Reset()
	return fake
}

func (f *FakeYagnats) Reset() {
	f.PublishedMessages = map[string][]yagnats.Message{}
	f.Subscriptions = map[string][]yagnats.Subscription{}
	f.Unsubscriptions = []int{}
	f.UnsubscribedSubjects = []string{}

	f.ConnectedConnectionProvider = nil

	f.ConnectError = nil
	f.PublishError = nil
	f.SubscribeError = nil
	f.UnsubscribeError = nil

	f.PingResponse = true

	f.counter = 0
}

func (f *FakeYagnats) Ping() bool {
	return f.PingResponse
}

func (f *FakeYagnats) Connect(connectionProvider yagnats.ConnectionProvider) error {
	f.ConnectedConnectionProvider = connectionProvider
	return f.ConnectError
}

func (f *FakeYagnats) Disconnect() {
	f.ConnectedConnectionProvider = nil
	return
}

func (f *FakeYagnats) Publish(subject, payload string) error {
	return f.PublishWithReplyTo(subject, payload, "")
}

func (f *FakeYagnats) PublishWithReplyTo(subject, payload, reply string) error {
	message := yagnats.Message{
		Subject: subject,
		Payload: payload,
		ReplyTo: reply,
	}

	f.PublishedMessages[subject] = append(f.PublishedMessages[subject], message)

	return f.PublishError
}

func (f *FakeYagnats) Subscribe(subject string, callback yagnats.Callback) (int, error) {
	return f.SubscribeWithQueue(subject, "", callback)
}

func (f *FakeYagnats) SubscribeWithQueue(subject, queue string, callback yagnats.Callback) (int, error) {
	f.counter++
	subscription := yagnats.Subscription{
		Subject:  subject,
		Queue:    queue,
		ID:       f.counter,
		Callback: callback,
	}

	f.Subscriptions[subject] = append(f.Subscriptions[subject], subscription)

	return subscription.ID, f.SubscribeError
}

func (f *FakeYagnats) Unsubscribe(subscription int) error {
	f.Unsubscriptions = append(f.Unsubscriptions, subscription)
	return f.UnsubscribeError
}

func (f *FakeYagnats) UnsubscribeAll(subject string) {
	f.UnsubscribedSubjects = append(f.UnsubscribedSubjects, subject)
}
<|endoftext|>