<commit_before>package common

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

// CommandPropertySet is a generic function that will set a property for a given plugin/app combination
func CommandPropertySet(pluginName, appName, property, value string, properties map[string]string) {
	if err := VerifyAppName(appName); err != nil {
		LogFail(err.Error())
	}
	if property == "" {
		LogFail("No property specified")
	}

	if _, ok := properties[property]; !ok {
		properties := reflect.ValueOf(properties).MapKeys()
		validPropertyList := make([]string, len(properties))
		for i := 0; i < len(properties); i++ {
			validPropertyList[i] = properties[i].String()
		}

		LogFail(fmt.Sprintf("Invalid property specified, valid properties include: %s", strings.Join(validPropertyList, ", ")))
	}

	if value != "" {
		LogInfo2Quiet(fmt.Sprintf("Setting %s to %s", property, value))
		PropertyWrite(pluginName, appName, property, value)
	} else {
		LogInfo2Quiet(fmt.Sprintf("Unsetting %s", property))
		err := PropertyDelete(pluginName, appName, property)
		if err != nil {
			LogFail(err.Error())
		}
	}
}

// PropertyDelete deletes a property from the plugin properties for an app
func PropertyDelete(pluginName string, appName string, property string) error {
	propertyPath := getPropertyPath(pluginName, appName, property)
	if err := os.Remove(propertyPath); err != nil {
		return fmt.Errorf("Unable to remove %s property %s.%s", pluginName, appName, property)
	}

	return nil
}

// PropertyDestroy destroys the plugin properties for an app
func PropertyDestroy(pluginName string, appName string) error {
	if appName == "_all_" {
		pluginConfigPath := getPluginConfigPath(pluginName)
		return os.RemoveAll(pluginConfigPath)
	}

	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	return os.RemoveAll(pluginAppConfigRoot)
}

// PropertyExists returns whether a property exists or not
func PropertyExists(pluginName string, appName string, property string) bool {
	propertyPath := getPropertyPath(pluginName, appName, property)
	_, err := os.Stat(propertyPath)
	return !os.IsNotExist(err)
}

// PropertyGet returns the value for a given property
func PropertyGet(pluginName string, appName string, property string) string {
	return PropertyGetDefault(pluginName, appName, property, "")
}

// PropertyGetAll returns a map of all properties for a given app
func PropertyGetAll(pluginName string, appName string) (map[string]string, error) {
	properties := make(map[string]string)
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	files, err := ioutil.ReadDir(pluginAppConfigRoot)
	if err != nil {
		return properties, err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		property := file.Name()
		properties[property] = PropertyGet(pluginName, appName, property)
	}

	return properties, nil
}

// PropertyGetDefault returns the value for a given property with a specified default value
func PropertyGetDefault(pluginName, appName, property, defaultValue string) (val string) {
	if !PropertyExists(pluginName, appName, property) {
		return
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	b, err := ioutil.ReadFile(propertyPath)
	if err != nil {
		LogWarn(fmt.Sprintf("Unable to read %s property %s.%s", pluginName, appName, property))
		return
	}
	val = string(b)
	return
}

// PropertyListAdd adds a property to a list at an optionally specified index
func PropertyListAdd(pluginName string, appName string, property string, value string, index int) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	scannedLines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	value = strings.TrimSpace(value)

	var lines []string
	for i, line := range scannedLines {
		if index != 0 && i == (index-1) {
			lines = append(lines, value)
		}
		lines = append(lines, line)
	}

	if index == 0 || index > len(scannedLines) {
		lines = append(lines, value)
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// PropertyListGet returns a property list
func PropertyListGet(pluginName string, appName string, property string) (lines []string, err error) {
	if !PropertyExists(pluginName, appName, property) {
		return lines, nil
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Open(propertyPath)
	if err != nil {
		return lines, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	if err = scanner.Err(); err != nil {
		return lines, fmt.Errorf("Unable to read %s config value for %s.%s: %s", pluginName, appName, property, err.Error())
	}

	return lines, nil
}

// PropertyListLength returns the length of a property list
func PropertyListLength(pluginName string, appName string, property string) (length int, err error) {
	if !PropertyExists(pluginName, appName, property) {
		return length, nil
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Open(propertyPath)
	if err != nil {
		return length, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	if err = scanner.Err(); err != nil {
		return length, fmt.Errorf("Unable to read %s config value for %s.%s: %s", pluginName, appName, property, err.Error())
	}

	length = len(lines)
	return length, nil
}

// PropertyListGetByIndex returns an entry within property list by index
func PropertyListGetByIndex(pluginName string, appName string, property string, index int) (propertyValue string, err error) {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return
	}

	found := false
	for i, line := range lines {
		if i == index {
			propertyValue = line
			found = true
		}
	}

	if !found {
		err = errors.New("Index not found")
	}

	return
}

// PropertyListGetByValue returns an entry within property list by value
func PropertyListGetByValue(pluginName string, appName string, property string, value string) (propertyValue string, err error) {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return
	}

	found := false
	for _, line := range lines {
		if line == value {
			propertyValue = line
			found = true
		}
	}

	if !found {
		err = errors.New("Value not found")
	}

	return
}

// PropertyListRemove removes a value from a property list
func PropertyListRemove(pluginName string, appName string, property string, value string) error {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	found := false
	w := bufio.NewWriter(file)
	for _, line := range lines {
		if line == value {
			found = true
			continue
		}
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)

	if !found {
		return errors.New("Property not found, nothing was removed")
	}

	return nil
}

// PropertyListRemoveByPrefix removes a value by prefix from a property list
func PropertyListRemoveByPrefix(pluginName string, appName string, property string, prefix string) error {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	found := false
	w := bufio.NewWriter(file)
	for _, line := range lines {
		if strings.HasPrefix(line, prefix) {
			found = true
			continue
		}
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)

	if !found {
		return errors.New("Property not found, nothing was removed")
	}

	return nil
}

// PropertyListSet sets a value within a property list at a specified index
func PropertyListSet(pluginName string, appName string, property string, value string, index int) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	scannedLines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	value = strings.TrimSpace(value)

	var lines []string
	if index >= len(scannedLines) {
		for _, line := range scannedLines {
			lines = append(lines, line)
		}
		lines = append(lines, value)
	} else {
		for i, line := range scannedLines {
			if i == index {
				lines = append(lines, value)
			} else {
				lines = append(lines, line)
			}
		}
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// propertyTouch ensures a given application property file exists
func propertyTouch(pluginName string, appName string, property string) error {
	if err := makePluginAppPropertyPath(pluginName, appName); err != nil {
		return fmt.Errorf("Unable to create %s config directory for %s: %s", pluginName, appName, err.Error())
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	if PropertyExists(pluginName, appName, property) {
		return nil
	}

	file, err := os.Create(propertyPath)
	if err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}
	defer file.Close()

	return nil
}

// PropertyWrite writes a value for a given application property
func PropertyWrite(pluginName string, appName string, property string, value string) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Create(propertyPath)
	if err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}
	defer file.Close()

	fmt.Fprintf(file, value)
	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// PropertySetup creates the plugin config root
func PropertySetup(pluginName string) error {
	pluginConfigRoot := getPluginConfigPath(pluginName)
	if err := os.MkdirAll(pluginConfigRoot, 0755); err != nil {
		return err
	}
	if err := setPermissions(path.Join(MustGetEnv("DOKKU_LIB_ROOT"), "config"), 0755); err != nil {
		return err
	}
	return setPermissions(pluginConfigRoot, 0755)
}

func getPropertyPath(pluginName string, appName string, property string) string {
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	return path.Join(pluginAppConfigRoot, property)
}

// getPluginAppPropertyPath returns the plugin property path for a given plugin/app combination
func getPluginAppPropertyPath(pluginName string, appName string) string {
	return path.Join(getPluginConfigPath(pluginName), appName)
}

// getPluginConfigPath returns the plugin property path for a given plugin
func getPluginConfigPath(pluginName string) string {
	return path.Join(MustGetEnv("DOKKU_LIB_ROOT"), "config", pluginName)
}

// makePluginAppPropertyPath ensures that a property path exists
func makePluginAppPropertyPath(pluginName string, appName string) error {
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	if err := os.MkdirAll(pluginAppConfigRoot, 0755); err != nil {
		return err
	}
	return setPermissions(pluginAppConfigRoot, 0755)
}

// setPermissions sets the proper owner and filemode for a given file
func setPermissions(path string, fileMode os.FileMode) error {
	if err := os.Chmod(path, fileMode); err != nil {
		return err
	}

	systemGroup := GetenvWithDefault("DOKKU_SYSTEM_GROUP", "dokku")
	systemUser := GetenvWithDefault("DOKKU_SYSTEM_USER", "dokku")

	group, err := user.LookupGroup(systemGroup)
	if err != nil {
		return err
	}
	user, err := user.Lookup(systemUser)
	if err != nil {
		return err
	}

	uid, err := strconv.Atoi(user.Uid)
	if err != nil {
		return err
	}

	gid, err := strconv.Atoi(group.Gid)
	if err != nil {
		return err
	}
	return os.Chown(path, uid, gid)
}
<commit_msg>fix: handle case where defaultValue was not properly returned by get-with-default<commit_after>package common

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

// CommandPropertySet is a generic function that will set a property for a given plugin/app combination
func CommandPropertySet(pluginName, appName, property, value string, properties map[string]string) {
	if err := VerifyAppName(appName); err != nil {
		LogFail(err.Error())
	}
	if property == "" {
		LogFail("No property specified")
	}

	if _, ok := properties[property]; !ok {
		properties := reflect.ValueOf(properties).MapKeys()
		validPropertyList := make([]string, len(properties))
		for i := 0; i < len(properties); i++ {
			validPropertyList[i] = properties[i].String()
		}

		LogFail(fmt.Sprintf("Invalid property specified, valid properties include: %s", strings.Join(validPropertyList, ", ")))
	}

	if value != "" {
		LogInfo2Quiet(fmt.Sprintf("Setting %s to %s", property, value))
		PropertyWrite(pluginName, appName, property, value)
	} else {
		LogInfo2Quiet(fmt.Sprintf("Unsetting %s", property))
		err := PropertyDelete(pluginName, appName, property)
		if err != nil {
			LogFail(err.Error())
		}
	}
}

// PropertyDelete deletes a property from the plugin properties for an app
func PropertyDelete(pluginName string, appName string, property string) error {
	propertyPath := getPropertyPath(pluginName, appName, property)
	if err := os.Remove(propertyPath); err != nil {
		return fmt.Errorf("Unable to remove %s property %s.%s", pluginName, appName, property)
	}

	return nil
}

// PropertyDestroy destroys the plugin properties for an app
func PropertyDestroy(pluginName string, appName string) error {
	if appName == "_all_" {
		pluginConfigPath := getPluginConfigPath(pluginName)
		return os.RemoveAll(pluginConfigPath)
	}

	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	return os.RemoveAll(pluginAppConfigRoot)
}

// PropertyExists returns whether a property exists or not
func PropertyExists(pluginName string, appName string, property string) bool {
	propertyPath := getPropertyPath(pluginName, appName, property)
	_, err := os.Stat(propertyPath)
	return !os.IsNotExist(err)
}

// PropertyGet returns the value for a given property
func PropertyGet(pluginName string, appName string, property string) string {
	return PropertyGetDefault(pluginName, appName, property, "")
}

// PropertyGetAll returns a map of all properties for a given app
func PropertyGetAll(pluginName string, appName string) (map[string]string, error) {
	properties := make(map[string]string)
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	files, err := ioutil.ReadDir(pluginAppConfigRoot)
	if err != nil {
		return properties, err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		property := file.Name()
		properties[property] = PropertyGet(pluginName, appName, property)
	}

	return properties, nil
}

// PropertyGetDefault returns the value for a given property with a specified default value
func PropertyGetDefault(pluginName, appName, property, defaultValue string) (val string) {
	if !PropertyExists(pluginName, appName, property) {
		val = defaultValue
		return
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	b, err := ioutil.ReadFile(propertyPath)
	if err != nil {
		LogWarn(fmt.Sprintf("Unable to read %s property %s.%s", pluginName, appName, property))
		return
	}
	val = string(b)
	return
}

// PropertyListAdd adds a property to a list at an optionally specified index
func PropertyListAdd(pluginName string, appName string, property string, value string, index int) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	scannedLines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	value = strings.TrimSpace(value)

	var lines []string
	for i, line := range scannedLines {
		if index != 0 && i == (index-1) {
			lines = append(lines, value)
		}
		lines = append(lines, line)
	}

	if index == 0 || index > len(scannedLines) {
		lines = append(lines, value)
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// PropertyListGet returns a property list
func PropertyListGet(pluginName string, appName string, property string) (lines []string, err error) {
	if !PropertyExists(pluginName, appName, property) {
		return lines, nil
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Open(propertyPath)
	if err != nil {
		return lines, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	if err = scanner.Err(); err != nil {
		return lines, fmt.Errorf("Unable to read %s config value for %s.%s: %s", pluginName, appName, property, err.Error())
	}

	return lines, nil
}

// PropertyListLength returns the length of a property list
func PropertyListLength(pluginName string, appName string, property string) (length int, err error) {
	if !PropertyExists(pluginName, appName, property) {
		return length, nil
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Open(propertyPath)
	if err != nil {
		return length, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}

	if err = scanner.Err(); err != nil {
		return length, fmt.Errorf("Unable to read %s config value for %s.%s: %s", pluginName, appName, property, err.Error())
	}

	length = len(lines)
	return length, nil
}

// PropertyListGetByIndex returns an entry within property list by index
func PropertyListGetByIndex(pluginName string, appName string, property string, index int) (propertyValue string, err error) {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return
	}

	found := false
	for i, line := range lines {
		if i == index {
			propertyValue = line
			found = true
		}
	}

	if !found {
		err = errors.New("Index not found")
	}

	return
}

// PropertyListGetByValue returns an entry within property list by value
func PropertyListGetByValue(pluginName string, appName string, property string, value string) (propertyValue string, err error) {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return
	}

	found := false
	for _, line := range lines {
		if line == value {
			propertyValue = line
			found = true
		}
	}

	if !found {
		err = errors.New("Value not found")
	}

	return
}

// PropertyListRemove removes a value from a property list
func PropertyListRemove(pluginName string, appName string, property string, value string) error {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	found := false
	w := bufio.NewWriter(file)
	for _, line := range lines {
		if line == value {
			found = true
			continue
		}
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)

	if !found {
		return errors.New("Property not found, nothing was removed")
	}

	return nil
}

// PropertyListRemoveByPrefix removes a value by prefix from a property list
func PropertyListRemoveByPrefix(pluginName string, appName string, property string, prefix string) error {
	lines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	found := false
	w := bufio.NewWriter(file)
	for _, line := range lines {
		if strings.HasPrefix(line, prefix) {
			found = true
			continue
		}
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)

	if !found {
		return errors.New("Property not found, nothing was removed")
	}

	return nil
}

// PropertyListSet sets a value within a property list at a specified index
func PropertyListSet(pluginName string, appName string, property string, value string, index int) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	scannedLines, err := PropertyListGet(pluginName, appName, property)
	if err != nil {
		return err
	}

	value = strings.TrimSpace(value)

	var lines []string
	if index >= len(scannedLines) {
		for _, line := range scannedLines {
			lines = append(lines, line)
		}
		lines = append(lines, value)
	} else {
		for i, line := range scannedLines {
			if i == index {
				lines = append(lines, value)
			} else {
				lines = append(lines, line)
			}
		}
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.OpenFile(propertyPath, os.O_RDWR|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	if err = w.Flush(); err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}

	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// propertyTouch ensures a given application property file exists
func propertyTouch(pluginName string, appName string, property string) error {
	if err := makePluginAppPropertyPath(pluginName, appName); err != nil {
		return fmt.Errorf("Unable to create %s config directory for %s: %s", pluginName, appName, err.Error())
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	if PropertyExists(pluginName, appName, property) {
		return nil
	}

	file, err := os.Create(propertyPath)
	if err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}
	defer file.Close()

	return nil
}

// PropertyWrite writes a value for a given application property
func PropertyWrite(pluginName string, appName string, property string, value string) error {
	if err := propertyTouch(pluginName, appName, property); err != nil {
		return err
	}

	propertyPath := getPropertyPath(pluginName, appName, property)
	file, err := os.Create(propertyPath)
	if err != nil {
		return fmt.Errorf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error())
	}
	defer file.Close()

	fmt.Fprintf(file, value)
	file.Chmod(0600)
	setPermissions(propertyPath, 0600)
	return nil
}

// PropertySetup creates the plugin config root
func PropertySetup(pluginName string) error {
	pluginConfigRoot := getPluginConfigPath(pluginName)
	if err := os.MkdirAll(pluginConfigRoot, 0755); err != nil {
		return err
	}
	if err := setPermissions(path.Join(MustGetEnv("DOKKU_LIB_ROOT"), "config"), 0755); err != nil {
		return err
	}
	return setPermissions(pluginConfigRoot, 0755)
}

func getPropertyPath(pluginName string, appName string, property string) string {
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	return path.Join(pluginAppConfigRoot, property)
}

// getPluginAppPropertyPath returns the plugin property path for a given plugin/app combination
func getPluginAppPropertyPath(pluginName string, appName string) string {
	return path.Join(getPluginConfigPath(pluginName), appName)
}

// getPluginConfigPath returns the plugin property path for a given plugin
func getPluginConfigPath(pluginName string) string {
	return path.Join(MustGetEnv("DOKKU_LIB_ROOT"), "config", pluginName)
}

// makePluginAppPropertyPath ensures that a property path exists
func makePluginAppPropertyPath(pluginName string, appName string) error {
	pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
	if err := os.MkdirAll(pluginAppConfigRoot, 0755); err != nil {
		return err
	}
	return setPermissions(pluginAppConfigRoot, 0755)
}

// setPermissions sets the proper owner and filemode for a given file
func setPermissions(path string, fileMode os.FileMode) error {
	if err := os.Chmod(path, fileMode); err != nil {
		return err
	}

	systemGroup := GetenvWithDefault("DOKKU_SYSTEM_GROUP", "dokku")
	systemUser := GetenvWithDefault("DOKKU_SYSTEM_USER", "dokku")

	group, err := user.LookupGroup(systemGroup)
	if err != nil {
		return err
	}
	user, err := user.Lookup(systemUser)
	if err != nil {
		return err
	}

	uid, err := strconv.Atoi(user.Uid)
	if err != nil {
		return err
	}

	gid, err := strconv.Atoi(group.Gid)
	if err != nil {
		return err
	}
	return os.Chown(path, uid, gid)
}
<|endoftext|>


<commit_before>package dupelink

import (
	"net/url"
	"strconv"
	"time"
	"log"

	"github.com/tucnak/telebot"
	"github.com/asdine/storm"

	"github.com/focusshifter/muxgoob/registry"
)

type DupeLinkPlugin struct {
}

type DupeLink struct {
	ID int `storm:"id,increment"`
	URL string `storm:"index"`
	MessageID int
	Sender telebot.User
	Unixtime int
}

var db *storm.DB

func init() {
	registry.RegisterPlugin(&DupeLinkPlugin{})
}

func (p *DupeLinkPlugin) Start(sharedDb *storm.DB) {
	db = sharedDb
}

func (p *DupeLinkPlugin) Process(message telebot.Message) {
	messageURLs := getURLs(message)
	var validURLs []string

	newURL := func(currentURL string, validURLs []string) bool {
		for _, existingURL := range validURLs {
			if existingURL == currentURL {
				return false
			}
		}

		return true
	}

	for _, messageURL := range messageURLs {
		parsedURL, err := url.Parse(messageURL)

		if err != nil {
			continue
		}

		currentURL := parsedURL.Hostname() + parsedURL.RequestURI()

		if newURL(currentURL, validURLs) {
			validURLs = append(validURLs, currentURL)
			reactToURL(currentURL, message)
		}
	}
}

func getURLs(message telebot.Message) []string {
	var urls []string

	for _, entity := range message.Entities {
		if entity.Type == "url" {
			urls = append(urls, message.Text[entity.Offset:(entity.Offset + entity.Length)])
		}
	}

	return urls
}

func reactToURL(currentURL string, message telebot.Message) {
	chat := db.From(strconv.FormatInt(message.Chat.ID, 10))

	var existingLink DupeLink
	err := chat.One("URL", currentURL, &existingLink);

	if err == nil {
		log.Println("Found dupe, reporting: " + currentURL)

		bot := registry.Bot
		formattedTime := time.Unix(int64(existingLink.Unixtime), 0).Format(time.RFC1123)
		formattedUser := existingLink.Sender.FirstName + " " + existingLink.Sender.LastName
		bot.SendMessage(message.Chat, "That was already posted on " + formattedTime + " by " + formattedUser,
						&telebot.SendOptions{ReplyTo: message})
	} else {
		log.Println("Link not found, saving: " + currentURL)

		newLink := DupeLink{URL: currentURL,
							MessageID: message.ID,
							Sender: message.Sender,
							Unixtime: message.Unixtime}
		chat.Save(&newLink)
	}
}
<commit_msg>Use runes, not string slices when extracting the URL<commit_after>package dupelink

import (
	"net/url"
	"strconv"
	"time"
	"log"

	"github.com/tucnak/telebot"
	"github.com/asdine/storm"

	"github.com/focusshifter/muxgoob/registry"
)

type DupeLinkPlugin struct {
}

type DupeLink struct {
	ID int `storm:"id,increment"`
	URL string `storm:"index"`
	MessageID int
	Sender telebot.User
	Unixtime int
}

var db *storm.DB

func init() {
	registry.RegisterPlugin(&DupeLinkPlugin{})
}

func (p *DupeLinkPlugin) Start(sharedDb *storm.DB) {
	db = sharedDb
}

func (p *DupeLinkPlugin) Process(message telebot.Message) {
	messageURLs := getURLs(message)
	var validURLs []string

	newURL := func(currentURL string, validURLs []string) bool {
		for _, existingURL := range validURLs {
			if existingURL == currentURL {
				return false
			}
		}

		return true
	}

	for _, messageURL := range messageURLs {
		parsedURL, err := url.Parse(messageURL)

		if err != nil {
			continue
		}

		currentURL := parsedURL.Hostname() + parsedURL.RequestURI()

		if newURL(currentURL, validURLs) {
			validURLs = append(validURLs, currentURL)
			reactToURL(currentURL, message)
		}
	}
}

func getURLs(message telebot.Message) []string {
	var urls []string

	for _, entity := range message.Entities {
		if entity.Type == "url" {
			urls = append(urls, string([]rune(message.Text)[entity.Offset:(entity.Offset + entity.Length)]))
		}
	}

	return urls
}

func reactToURL(currentURL string, message telebot.Message) {
	chat := db.From(strconv.FormatInt(message.Chat.ID, 10))

	var existingLink DupeLink
	err := chat.One("URL", currentURL, &existingLink);

	if err == nil {
		log.Println("Found dupe, reporting: " + currentURL)

		bot := registry.Bot
		formattedTime := time.Unix(int64(existingLink.Unixtime), 0).Format(time.RFC1123)
		formattedUser := existingLink.Sender.FirstName + " " + existingLink.Sender.LastName
		bot.SendMessage(message.Chat, "That was already posted on " + formattedTime + " by " + formattedUser,
						&telebot.SendOptions{ReplyTo: message})
	} else {
		log.Println("Link not found, saving: " + currentURL)

		newLink := DupeLink{URL: currentURL,
							MessageID: message.ID,
							Sender: message.Sender,
							Unixtime: message.Unixtime}
		chat.Save(&newLink)
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"math/rand"
	"reflect"
	"testing"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	clientgotesting "k8s.io/client-go/testing"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
	informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
	"k8s.io/kubernetes/pkg/controller"
)

func TestDockercfgDeletion(t *testing.T) {
	testcases := map[string]struct {
		ClientObjects []runtime.Object

		DeletedSecret *api.Secret

		ExpectedActions []clientgotesting.Action
	}{
		"deleted dockercfg secret without serviceaccount": {
			DeletedSecret: createdDockercfgSecret(),

			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
		"deleted dockercfg secret with serviceaccount with reference": {
			ClientObjects: []runtime.Object{serviceAccount(addTokenSecretReference(tokenSecretReferences()), imagePullSecretReferences()), createdDockercfgSecret()},

			DeletedSecret: createdDockercfgSecret(),
			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewUpdateAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", serviceAccount(tokenSecretReferences(), emptyImagePullSecretReferences())),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
		"deleted dockercfg secret with serviceaccount without reference": {
			ClientObjects: []runtime.Object{serviceAccount(addTokenSecretReference(tokenSecretReferences()), imagePullSecretReferences()), createdDockercfgSecret()},

			DeletedSecret: createdDockercfgSecret(),
			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewUpdateAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", serviceAccount(tokenSecretReferences(), emptyImagePullSecretReferences())),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
	}

	for k, tc := range testcases {
		// Re-seed to reset name generation
		rand.Seed(1)

		client := fake.NewSimpleClientset(tc.ClientObjects...)
		informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
		controller := NewDockercfgDeletedController(
			informerFactory.Core().InternalVersion().Secrets(),
			client,
			DockercfgDeletedControllerOptions{},
		)
		stopCh := make(chan struct{})
		informerFactory.Start(stopCh)

		if tc.DeletedSecret != nil {
			controller.secretDeleted(tc.DeletedSecret)
		}

		for i, action := range client.Actions() {
			if len(tc.ExpectedActions) < i+1 {
				t.Errorf("%s: %d unexpected actions: %+v", k, len(client.Actions())-len(tc.ExpectedActions), client.Actions()[i:])
				break
			}

			expectedAction := tc.ExpectedActions[i]
			if !reflect.DeepEqual(expectedAction, action) {
				t.Errorf("%s: Expected %v, got %v", k, expectedAction, action)
				continue
			}
		}

		if len(tc.ExpectedActions) > len(client.Actions()) {
			t.Errorf("%s: %d additional expected actions:%+v", k, len(tc.ExpectedActions)-len(client.Actions()), tc.ExpectedActions[len(client.Actions()):])
		}
		close(stopCh)
	}
}
<commit_msg>Wait for controller startup in test<commit_after>package controllers

import (
	"math/rand"
	"reflect"
	"testing"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	clientgotesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
	informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
	"k8s.io/kubernetes/pkg/controller"
)

func TestDockercfgDeletion(t *testing.T) {
	testcases := map[string]struct {
		ClientObjects []runtime.Object

		DeletedSecret *api.Secret

		ExpectedActions []clientgotesting.Action
	}{
		"deleted dockercfg secret without serviceaccount": {
			DeletedSecret: createdDockercfgSecret(),

			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
		"deleted dockercfg secret with serviceaccount with reference": {
			ClientObjects: []runtime.Object{serviceAccount(addTokenSecretReference(tokenSecretReferences()), imagePullSecretReferences()), createdDockercfgSecret()},

			DeletedSecret: createdDockercfgSecret(),
			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewUpdateAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", serviceAccount(tokenSecretReferences(), emptyImagePullSecretReferences())),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
		"deleted dockercfg secret with serviceaccount without reference": {
			ClientObjects: []runtime.Object{serviceAccount(addTokenSecretReference(tokenSecretReferences()), imagePullSecretReferences()), createdDockercfgSecret()},

			DeletedSecret: createdDockercfgSecret(),
			ExpectedActions: []clientgotesting.Action{
				clientgotesting.NewGetAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", "default"),
				clientgotesting.NewUpdateAction(schema.GroupVersionResource{Resource: "serviceaccounts"}, "default", serviceAccount(tokenSecretReferences(), emptyImagePullSecretReferences())),
				clientgotesting.NewDeleteAction(schema.GroupVersionResource{Resource: "secrets"}, "default", "token-secret-1"),
			},
		},
	}

	for k, tc := range testcases {
		// Re-seed to reset name generation
		rand.Seed(1)

		client := fake.NewSimpleClientset(tc.ClientObjects...)
		informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
		controller := NewDockercfgDeletedController(
			informerFactory.Core().InternalVersion().Secrets(),
			client,
			DockercfgDeletedControllerOptions{},
		)
		stopCh := make(chan struct{})
		informerFactory.Start(stopCh)
		if !cache.WaitForCacheSync(stopCh, controller.secretController.HasSynced) {
			t.Fatalf("unable to reach cache sync")
		}
		client.ClearActions()

		if tc.DeletedSecret != nil {
			controller.secretDeleted(tc.DeletedSecret)
		}

		for i, action := range client.Actions() {
			if len(tc.ExpectedActions) < i+1 {
				t.Errorf("%s: %d unexpected actions: %+v", k, len(client.Actions())-len(tc.ExpectedActions), client.Actions()[i:])
				break
			}

			expectedAction := tc.ExpectedActions[i]
			if !reflect.DeepEqual(expectedAction, action) {
				t.Errorf("%s: Expected %v, got %v", k, expectedAction, action)
				continue
			}
		}

		if len(tc.ExpectedActions) > len(client.Actions()) {
			t.Errorf("%s: %d additional expected actions:%+v", k, len(tc.ExpectedActions)-len(client.Actions()), tc.ExpectedActions[len(client.Actions()):])
		}
		close(stopCh)
	}
}
<|endoftext|>


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

package app

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/api/auth"
	"github.com/globocom/tsuru/api/bind"
	"github.com/globocom/tsuru/api/service"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/repository"
	"io"
	"labix.org/v2/mgo/bson"
	"launchpad.net/goyaml"
	"os"
	"os/exec"
	"path"
	"sort"
	"strings"
	"time"
)

const confSep = "========"

type App struct {
	Env       map[string]bind.EnvVar
	Framework string
	Logs      []applog
	Name      string
	State     string
	Units     []Unit
	Teams     []string
}

func (a *App) MarshalJSON() ([]byte, error) {
	result := make(map[string]interface{})
	result["Name"] = a.Name
	result["State"] = a.State
	result["Framework"] = a.Framework
	result["Teams"] = a.Teams
	result["Units"] = a.Units
	result["Repository"] = repository.GetUrl(a.Name)
	return json.Marshal(&result)
}

type applog struct {
	Date    time.Time
	Message string
}

type conf struct {
	PreRestart []string `yaml:"pre-restart"`
	PosRestart []string `yaml:"pos-restart"`
}

func (a *App) Get() error {
	return db.Session.Apps().Find(bson.M{"name": a.Name}).One(a)
}

// createApp creates a new app.
//
// Creating a new app is a process composed of two steps:
//
//       1. Saves the app in the database
//       2. Deploys juju charm
func createApp(a *App) error {
	a.State = "pending"
	err := db.Session.Apps().Insert(a)
	if err != nil {
		return err
	}
	return deploy(a)
}

// Deploys an app.
func deploy(a *App) error {
	a.log(fmt.Sprintf("creating app %s", a.Name))
	cmd := exec.Command("juju", "deploy", "--repository=/home/charms", "local:"+a.Framework, a.Name)
	log.Printf("deploying %s with name %s", a.Framework, a.Name)
	out, err := cmd.CombinedOutput()
	outStr := string(out)
	a.log(outStr)
	log.Printf("executing %s", outStr)
	if err != nil {
		a.log(fmt.Sprintf("juju finished with exit status: %s", err))
		db.Session.Apps().Remove(bson.M{"name": a.Name})
		return errors.New(outStr)
	}
	return nil
}

func (a *App) unbind() error {
	var instances []service.ServiceInstance
	err := db.Session.ServiceInstances().Find(bson.M{"apps": bson.M{"$in": []string{a.Name}}}).All(&instances)
	if err != nil {
		return err
	}
	var msg string
	var addMsg = func(instanceName string, reason error) {
		if msg == "" {
			msg = "Failed to unbind the following instances:\n"
		}
		msg += fmt.Sprintf("- %s (%s)", instanceName, reason.Error())
	}
	for _, instance := range instances {
		err = instance.Unbind(a)
		if err != nil {
			addMsg(instance.Name, err)
		}
	}
	if msg != "" {
		return errors.New(msg)
	}
	return nil
}

func (a *App) destroy() error {
	out, err := a.unit().destroy()
	msg := string(out)
	log.Print(msg)
	if err != nil {
		return errors.New(msg)
	}
	err = a.unbind()
	if err != nil {
		return err
	}
	return db.Session.Apps().Remove(bson.M{"name": a.Name})
}

func (a *App) AddUnit(u *Unit) {
	for i, unt := range a.Units {
		if unt.Machine == u.Machine {
			a.Units[i] = *u
			return
		}
	}
	a.Units = append(a.Units, *u)
}

func (a *App) find(team *auth.Team) (int, bool) {
	pos := sort.Search(len(a.Teams), func(i int) bool {
		return a.Teams[i] >= team.Name
	})
	return pos, pos < len(a.Teams) && a.Teams[pos] == team.Name
}

func (a *App) grant(team *auth.Team) error {
	pos, found := a.find(team)
	if found {
		return errors.New("This team already has access to this app")
	}
	a.Teams = append(a.Teams, "")
	tmp := a.Teams[pos]
	for i := pos; i < len(a.Teams)-1; i++ {
		a.Teams[i+1], tmp = tmp, a.Teams[i]
	}
	a.Teams[pos] = team.Name
	return nil
}

func (a *App) revoke(team *auth.Team) error {
	index, found := a.find(team)
	if !found {
		return errors.New("This team does not have access to this app")
	}
	copy(a.Teams[index:], a.Teams[index+1:])
	a.Teams = a.Teams[:len(a.Teams)-1]
	return nil
}

func (a *App) teams() []auth.Team {
	var teams []auth.Team
	db.Session.Teams().Find(bson.M{"_id": bson.M{"$in": a.Teams}}).All(&teams)
	return teams
}

func (a *App) setTeams(teams []auth.Team) {
	a.Teams = make([]string, len(teams))
	for i, team := range teams {
		a.Teams[i] = team.Name
	}
	sort.Strings(a.Teams)
}

func (a *App) setEnv(env bind.EnvVar) {
	if a.Env == nil {
		a.Env = make(map[string]bind.EnvVar)
	}
	a.Env[env.Name] = env
	a.log(fmt.Sprintf("setting env %s with value %s", env.Name, env.Value))
}

func (a *App) getEnv(name string) (bind.EnvVar, error) {
	var (
		env bind.EnvVar
		err error
		ok  bool
	)
	if env, ok = a.Env[name]; !ok {
		err = errors.New("Environment variable not declared for this app.")
	}
	return env, err
}

func (a *App) InstanceEnv(name string) map[string]bind.EnvVar {
	envs := make(map[string]bind.EnvVar)
	for k, env := range a.Env {
		if env.InstanceName == name {
			envs[k] = bind.EnvVar(env)
		}
	}
	return envs
}

func deployHookAbsPath(p string) (string, error) {
	repoPath, err := config.GetString("git:unit-repo")
	if err != nil {
		return "", nil
	}
	cmdArgs := strings.Fields(p)
	abs := path.Join(repoPath, cmdArgs[0])
	_, err = os.Stat(abs)
	if os.IsNotExist(err) {
		return p, nil
	}
	cmdArgs[0] = abs
	return strings.Join(cmdArgs, " "), nil
}

// Returns app.conf located at app's git repository
func (a *App) conf() (conf, error) {
	var c conf
	uRepo, err := repository.GetPath()
	if err != nil {
		a.log(fmt.Sprintf("Got error while getting repository path: %s", err))
		return c, err
	}
	cPath := path.Join(uRepo, "app.conf")
	cmd := fmt.Sprintf(`echo "%s";cat %s`, confSep, cPath)
	o, err := a.unit().Command(nil, nil, cmd)
	if err != nil {
		a.log(fmt.Sprintf("Got error while executing command: %s... Skipping hooks execution", err))
		return c, nil
	}
	data := strings.Split(string(o), confSep)[1]
	err = goyaml.Unmarshal([]byte(data), &c)
	if err != nil {
		a.log(fmt.Sprintf("Got error while parsing yaml: %s", err))
		return c, err
	}
	return c, nil
}

func (a *App) runHook(cmds []string, kind string) ([]byte, error) {
	var (
		buf bytes.Buffer
		err error
	)
	a.log(fmt.Sprintf("Executing %s hook...", kind))
	for _, cmd := range cmds {
		p, err := deployHookAbsPath(cmd)
		if err != nil {
			a.log(fmt.Sprintf("Error obtaining absolute path to hook: %s.", err))
			continue
		}
		err = a.run(p, &buf)
		if err != nil {
			return nil, err
		}
	}
	a.log(fmt.Sprintf("Output of %s hooks: %s", kind, buf.Bytes()))
	return buf.Bytes(), err
}

// preRestart is responsible for running user's pre-restart script.
//
// The path to this script can be found at the app.conf file, at the root of user's app repository.
func (a *App) preRestart(c conf) ([]byte, error) {
	if !a.hasRestartHooks(c) {
		a.log("app.conf file does not exists or is in the right place. Skipping pre-restart hook...")
		return []byte(nil), nil
	}
	if len(c.PreRestart) == 0 {
		a.log("pre-restart hook section in app conf does not exists... Skipping pre-restart hook...")
		return []byte(nil), nil
	}
	return a.runHook(c.PreRestart, "pre-restart")
}

// posRestart is responsible for running user's pos-restart script.
//
// The path to this script can be found at the app.conf file, at the root of user's app repository.
func (a *App) posRestart(c conf) ([]byte, error) {
	if !a.hasRestartHooks(c) {
		a.log("app.conf file does not exists or is in the right place. Skipping pos-restart hook...")
		return []byte(nil), nil
	}
	if len(c.PosRestart) == 0 {
		a.log("pos-restart hook section in app conf does not exists... Skipping pos-restart hook...")
		return []byte(nil), nil
	}
	return a.runHook(c.PosRestart, "pos-restart")
}

func (a *App) hasRestartHooks(c conf) bool {
	return len(c.PreRestart) > 0 || len(c.PosRestart) > 0
}

// run executes the command in app units
func (a *App) run(cmd string, w io.Writer) error {
	a.log(fmt.Sprintf("running '%s'", cmd))
	cmd = fmt.Sprintf("[ -f /home/application/apprc ] && source /home/application/apprc; [ -d /home/application/current ] && cd /home/application/current; %s", cmd)
	out, err := a.unit().Command(w, w, cmd)
	a.log(string(out))
	return err
}

// restart runs the restart hook for the app
// and returns your output.
func restart(a *App, w io.Writer) ([]byte, error) {
	u := a.unit()
	a.log("executting hook to restarting")
	if w != nil {
		content := []byte("\n ---> Restarting your app\n")
		n, err := w.Write(content)
		if err != nil {
			return nil, err
		}
		if len(content) != n {
			return nil, io.ErrShortWrite
		}
	}
	out, err := u.executeHook("restart", w, w)
	if err != nil {
		return out, err
	}
	a.log(string(out))
	return out, nil
}

// installDeps runs the dependencies hook for the app
// and returns your output.
func installDeps(a *App, w io.Writer) ([]byte, error) {
	u := a.unit()
	a.log("executting hook dependencies")
	out, err := u.executeHook("dependencies", w, w)
	a.log(string(out))
	if err != nil {
		return out, err
	}
	return out, nil
}

func (a *App) unit() *Unit {
	if len(a.Units) > 0 {
		unit := a.Units[0]
		unit.app = a
		return &unit
	}
	return &Unit{app: a}
}

func (a *App) GetUnits() []bind.Unit {
	var units []bind.Unit
	for _, u := range a.Units {
		u.app = a
		units = append(units, &u)
	}
	return units
}

func (a *App) GetName() string {
	return a.Name
}

func (a *App) SetEnvs(envs []bind.EnvVar, publicOnly bool) error {
	e := make([]bind.EnvVar, len(envs))
	for i, env := range envs {
		e[i] = bind.EnvVar(env)
	}
	return setEnvsToApp(a, e, publicOnly)
}

func (a *App) UnsetEnvs(envs []string, publicOnly bool) error {
	return unsetEnvFromApp(a, envs, publicOnly)
}

func (a *App) log(message string) error {
	log.Printf(message)
	l := applog{Date: time.Now(), Message: message}
	a.Logs = append(a.Logs, l)
	return db.Session.Apps().Update(bson.M{"name": a.Name}, a)
}
<commit_msg>api/app: fix log message<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/api/auth"
	"github.com/globocom/tsuru/api/bind"
	"github.com/globocom/tsuru/api/service"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/repository"
	"io"
	"labix.org/v2/mgo/bson"
	"launchpad.net/goyaml"
	"os"
	"os/exec"
	"path"
	"sort"
	"strings"
	"time"
)

const confSep = "========"

type App struct {
	Env       map[string]bind.EnvVar
	Framework string
	Logs      []applog
	Name      string
	State     string
	Units     []Unit
	Teams     []string
}

func (a *App) MarshalJSON() ([]byte, error) {
	result := make(map[string]interface{})
	result["Name"] = a.Name
	result["State"] = a.State
	result["Framework"] = a.Framework
	result["Teams"] = a.Teams
	result["Units"] = a.Units
	result["Repository"] = repository.GetUrl(a.Name)
	return json.Marshal(&result)
}

type applog struct {
	Date    time.Time
	Message string
}

type conf struct {
	PreRestart []string `yaml:"pre-restart"`
	PosRestart []string `yaml:"pos-restart"`
}

func (a *App) Get() error {
	return db.Session.Apps().Find(bson.M{"name": a.Name}).One(a)
}

// createApp creates a new app.
//
// Creating a new app is a process composed of two steps:
//
//       1. Saves the app in the database
//       2. Deploys juju charm
func createApp(a *App) error {
	a.State = "pending"
	err := db.Session.Apps().Insert(a)
	if err != nil {
		return err
	}
	return deploy(a)
}

// Deploys an app.
func deploy(a *App) error {
	a.log(fmt.Sprintf("creating app %s", a.Name))
	cmd := exec.Command("juju", "deploy", "--repository=/home/charms", "local:"+a.Framework, a.Name)
	log.Printf("deploying %s with name %s", a.Framework, a.Name)
	out, err := cmd.CombinedOutput()
	outStr := string(out)
	a.log(outStr)
	log.Printf("executing %s", outStr)
	if err != nil {
		a.log(fmt.Sprintf("juju finished with exit status: %s", err))
		db.Session.Apps().Remove(bson.M{"name": a.Name})
		return errors.New(outStr)
	}
	return nil
}

func (a *App) unbind() error {
	var instances []service.ServiceInstance
	err := db.Session.ServiceInstances().Find(bson.M{"apps": bson.M{"$in": []string{a.Name}}}).All(&instances)
	if err != nil {
		return err
	}
	var msg string
	var addMsg = func(instanceName string, reason error) {
		if msg == "" {
			msg = "Failed to unbind the following instances:\n"
		}
		msg += fmt.Sprintf("- %s (%s)", instanceName, reason.Error())
	}
	for _, instance := range instances {
		err = instance.Unbind(a)
		if err != nil {
			addMsg(instance.Name, err)
		}
	}
	if msg != "" {
		return errors.New(msg)
	}
	return nil
}

func (a *App) destroy() error {
	out, err := a.unit().destroy()
	msg := string(out)
	log.Print(msg)
	if err != nil {
		return errors.New(msg)
	}
	err = a.unbind()
	if err != nil {
		return err
	}
	return db.Session.Apps().Remove(bson.M{"name": a.Name})
}

func (a *App) AddUnit(u *Unit) {
	for i, unt := range a.Units {
		if unt.Machine == u.Machine {
			a.Units[i] = *u
			return
		}
	}
	a.Units = append(a.Units, *u)
}

func (a *App) find(team *auth.Team) (int, bool) {
	pos := sort.Search(len(a.Teams), func(i int) bool {
		return a.Teams[i] >= team.Name
	})
	return pos, pos < len(a.Teams) && a.Teams[pos] == team.Name
}

func (a *App) grant(team *auth.Team) error {
	pos, found := a.find(team)
	if found {
		return errors.New("This team already has access to this app")
	}
	a.Teams = append(a.Teams, "")
	tmp := a.Teams[pos]
	for i := pos; i < len(a.Teams)-1; i++ {
		a.Teams[i+1], tmp = tmp, a.Teams[i]
	}
	a.Teams[pos] = team.Name
	return nil
}

func (a *App) revoke(team *auth.Team) error {
	index, found := a.find(team)
	if !found {
		return errors.New("This team does not have access to this app")
	}
	copy(a.Teams[index:], a.Teams[index+1:])
	a.Teams = a.Teams[:len(a.Teams)-1]
	return nil
}

func (a *App) teams() []auth.Team {
	var teams []auth.Team
	db.Session.Teams().Find(bson.M{"_id": bson.M{"$in": a.Teams}}).All(&teams)
	return teams
}

func (a *App) setTeams(teams []auth.Team) {
	a.Teams = make([]string, len(teams))
	for i, team := range teams {
		a.Teams[i] = team.Name
	}
	sort.Strings(a.Teams)
}

func (a *App) setEnv(env bind.EnvVar) {
	if a.Env == nil {
		a.Env = make(map[string]bind.EnvVar)
	}
	a.Env[env.Name] = env
	a.log(fmt.Sprintf("setting env %s with value %s", env.Name, env.Value))
}

func (a *App) getEnv(name string) (bind.EnvVar, error) {
	var (
		env bind.EnvVar
		err error
		ok  bool
	)
	if env, ok = a.Env[name]; !ok {
		err = errors.New("Environment variable not declared for this app.")
	}
	return env, err
}

func (a *App) InstanceEnv(name string) map[string]bind.EnvVar {
	envs := make(map[string]bind.EnvVar)
	for k, env := range a.Env {
		if env.InstanceName == name {
			envs[k] = bind.EnvVar(env)
		}
	}
	return envs
}

func deployHookAbsPath(p string) (string, error) {
	repoPath, err := config.GetString("git:unit-repo")
	if err != nil {
		return "", nil
	}
	cmdArgs := strings.Fields(p)
	abs := path.Join(repoPath, cmdArgs[0])
	_, err = os.Stat(abs)
	if os.IsNotExist(err) {
		return p, nil
	}
	cmdArgs[0] = abs
	return strings.Join(cmdArgs, " "), nil
}

// Returns app.conf located at app's git repository
func (a *App) conf() (conf, error) {
	var c conf
	uRepo, err := repository.GetPath()
	if err != nil {
		a.log(fmt.Sprintf("Got error while getting repository path: %s", err))
		return c, err
	}
	cPath := path.Join(uRepo, "app.conf")
	cmd := fmt.Sprintf(`echo "%s";cat %s`, confSep, cPath)
	o, err := a.unit().Command(nil, nil, cmd)
	if err != nil {
		a.log(fmt.Sprintf("Got error while executing command: %s... Skipping hooks execution", err))
		return c, nil
	}
	data := strings.Split(string(o), confSep)[1]
	err = goyaml.Unmarshal([]byte(data), &c)
	if err != nil {
		a.log(fmt.Sprintf("Got error while parsing yaml: %s", err))
		return c, err
	}
	return c, nil
}

func (a *App) runHook(cmds []string, kind string) ([]byte, error) {
	var (
		buf bytes.Buffer
		err error
	)
	a.log(fmt.Sprintf("Executing %s hook...", kind))
	for _, cmd := range cmds {
		p, err := deployHookAbsPath(cmd)
		if err != nil {
			a.log(fmt.Sprintf("Error obtaining absolute path to hook: %s.", err))
			continue
		}
		err = a.run(p, &buf)
		if err != nil {
			return nil, err
		}
	}
	a.log(fmt.Sprintf("Output of %s hooks: %s", kind, buf.Bytes()))
	return buf.Bytes(), err
}

// preRestart is responsible for running user's pre-restart script.
//
// The path to this script can be found at the app.conf file, at the root of user's app repository.
func (a *App) preRestart(c conf) ([]byte, error) {
	if !a.hasRestartHooks(c) {
		a.log("app.conf file does not exists or is in the right place. Skipping pre-restart hook...")
		return []byte(nil), nil
	}
	if len(c.PreRestart) == 0 {
		a.log("pre-restart hook section in app conf does not exists... Skipping pre-restart hook...")
		return []byte(nil), nil
	}
	return a.runHook(c.PreRestart, "pre-restart")
}

// posRestart is responsible for running user's pos-restart script.
//
// The path to this script can be found at the app.conf file, at the root of user's app repository.
func (a *App) posRestart(c conf) ([]byte, error) {
	if !a.hasRestartHooks(c) {
		a.log("app.conf file does not exists or is in the right place. Skipping pos-restart hook...")
		return []byte(nil), nil
	}
	if len(c.PosRestart) == 0 {
		a.log("pos-restart hook section in app conf does not exists... Skipping pos-restart hook...")
		return []byte(nil), nil
	}
	return a.runHook(c.PosRestart, "pos-restart")
}

func (a *App) hasRestartHooks(c conf) bool {
	return len(c.PreRestart) > 0 || len(c.PosRestart) > 0
}

// run executes the command in app units
func (a *App) run(cmd string, w io.Writer) error {
	a.log(fmt.Sprintf("running '%s'", cmd))
	cmd = fmt.Sprintf("[ -f /home/application/apprc ] && source /home/application/apprc; [ -d /home/application/current ] && cd /home/application/current; %s", cmd)
	out, err := a.unit().Command(w, w, cmd)
	a.log(string(out))
	return err
}

// restart runs the restart hook for the app
// and returns your output.
func restart(a *App, w io.Writer) ([]byte, error) {
	u := a.unit()
	a.log("executing hook to restart")
	if w != nil {
		content := []byte("\n ---> Restarting your app\n")
		n, err := w.Write(content)
		if err != nil {
			return nil, err
		}
		if len(content) != n {
			return nil, io.ErrShortWrite
		}
	}
	out, err := u.executeHook("restart", w, w)
	if err != nil {
		return out, err
	}
	a.log(string(out))
	return out, nil
}

// installDeps runs the dependencies hook for the app
// and returns your output.
func installDeps(a *App, w io.Writer) ([]byte, error) {
	u := a.unit()
	a.log("executting hook dependencies")
	out, err := u.executeHook("dependencies", w, w)
	a.log(string(out))
	if err != nil {
		return out, err
	}
	return out, nil
}

func (a *App) unit() *Unit {
	if len(a.Units) > 0 {
		unit := a.Units[0]
		unit.app = a
		return &unit
	}
	return &Unit{app: a}
}

func (a *App) GetUnits() []bind.Unit {
	var units []bind.Unit
	for _, u := range a.Units {
		u.app = a
		units = append(units, &u)
	}
	return units
}

func (a *App) GetName() string {
	return a.Name
}

func (a *App) SetEnvs(envs []bind.EnvVar, publicOnly bool) error {
	e := make([]bind.EnvVar, len(envs))
	for i, env := range envs {
		e[i] = bind.EnvVar(env)
	}
	return setEnvsToApp(a, e, publicOnly)
}

func (a *App) UnsetEnvs(envs []string, publicOnly bool) error {
	return unsetEnvFromApp(a, envs, publicOnly)
}

func (a *App) log(message string) error {
	log.Printf(message)
	l := applog{Date: time.Now(), Message: message}
	a.Logs = append(a.Logs, l)
	return db.Session.Apps().Update(bson.M{"name": a.Name}, a)
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/thermokarst/bactdb/helpers"
	"github.com/thermokarst/bactdb/payloads"
	"github.com/thermokarst/bactdb/types"
)

// HandleCompare is a HTTP handler for comparision.
// Comparision requires a list of strain ids and a list of characteristic ids.
// The id order dictates the presentation order.
func HandleCompare(w http.ResponseWriter, r *http.Request) *types.AppError {
	// types
	type Comparisions map[string]map[string]string
	type ComparisionsJSON [][]string

	// vars
	mimeType := r.FormValue("mimeType")
	if mimeType == "" {
		mimeType = "json"
	}
	claims := helpers.GetClaims(r)
	var header string
	var data []byte

	// Get measurements for comparision
	measService := MeasurementService{}
	opt := r.URL.Query()
	opt.Del("mimeType")
	opt.Del("token")
	opt.Add("Genus", mux.Vars(r)["genus"])
	measurementsEntity, appErr := measService.List(&opt, &claims)
	if appErr != nil {
		return appErr
	}
	measurementsPayload := (measurementsEntity).(*payloads.Measurements)

	// Assemble matrix
	characteristicIDs := strings.Split(opt.Get("characteristic_ids"), ",")
	strainIDs := strings.Split(opt.Get("strain_ids"), ",")

	comparisions := make(Comparisions)
	for _, characteristicID := range characteristicIDs {
		characteristicIDInt, _ := strconv.ParseInt(characteristicID, 10, 0)
		values := make(map[string]string)
		for _, strainID := range strainIDs {
			strainIDInt, _ := strconv.ParseInt(strainID, 10, 0)
			for _, m := range *measurementsPayload.Measurements {
				if (m.CharacteristicID == characteristicIDInt) && (m.StrainID == strainIDInt) {
					if m.Notes.Valid {
						values[strainID] = fmt.Sprintf("%s (%s)", m.Value(), m.Notes.String)
					} else {
						if values[strainID] != "" {
							values[strainID] = fmt.Sprintf("%s, %s", values[strainID], m.Value())
						} else {
							values[strainID] = m.Value()
						}
					}
				}
			}
			// If the strain doesn't have a measurement for this characteristic,
			// stick an empty value in anyway (for CSV).
			if _, ok := values[strainID]; !ok {
				values[strainID] = ""
			}
		}

		comparisions[characteristicID] = values
	}

	// Return, based on mimetype
	switch mimeType {
	case "json":
		header = "application/json"

		comparisionsJSON := make(ComparisionsJSON, 0)
		for _, characteristicID := range characteristicIDs {
			row := []string{characteristicID}
			for _, strainID := range strainIDs {
				row = append(row, comparisions[characteristicID][strainID])
			}
			comparisionsJSON = append(comparisionsJSON, row)
		}

		data, _ = json.Marshal(comparisionsJSON)
	case "csv":
		header = "text/csv"

		// maps to translate ids
		strains := make(map[string]string)
		for _, strain := range *measurementsPayload.Strains {
			var t string
			if strain.TypeStrain {
				t = "T"
			}
			strains[fmt.Sprintf("%d", strain.ID)] = fmt.Sprintf("%s %s %s", strain.SpeciesName(), strain.StrainName, t)
		}
		characteristics := make(map[string]string)
		for _, characteristic := range *measurementsPayload.Characteristics {
			characteristics[fmt.Sprintf("%d", characteristic.ID)] = characteristic.CharacteristicName
		}

		b := &bytes.Buffer{}
		wr := csv.NewWriter(b)

		// Write header row
		r := []string{"Characteristic"}
		for _, strainID := range strainIDs {
			r = append(r, strains[strainID])
		}
		wr.Write(r)

		// Write data
		for _, characteristicID := range characteristicIDs {
			r := []string{characteristics[characteristicID]}
			for _, strainID := range strainIDs {
				r = append(r, comparisions[characteristicID][strainID])
			}
			wr.Write(r)
		}
		wr.Flush()

		data = b.Bytes()

		w.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="compare-%d.csv"`, int32(time.Now().Unix())))
	}

	// Wrap it up
	w.Header().Set("Content-Type", header)
	w.Write(data)
	return nil
}
<commit_msg>Use semicolon in compare so that csv doesn't break<commit_after>package api

import (
	"bytes"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/thermokarst/bactdb/helpers"
	"github.com/thermokarst/bactdb/payloads"
	"github.com/thermokarst/bactdb/types"
)

// HandleCompare is a HTTP handler for comparision.
// Comparision requires a list of strain ids and a list of characteristic ids.
// The id order dictates the presentation order.
func HandleCompare(w http.ResponseWriter, r *http.Request) *types.AppError {
	// types
	type Comparisions map[string]map[string]string
	type ComparisionsJSON [][]string

	// vars
	mimeType := r.FormValue("mimeType")
	if mimeType == "" {
		mimeType = "json"
	}
	claims := helpers.GetClaims(r)
	var header string
	var data []byte

	// Get measurements for comparision
	measService := MeasurementService{}
	opt := r.URL.Query()
	opt.Del("mimeType")
	opt.Del("token")
	opt.Add("Genus", mux.Vars(r)["genus"])
	measurementsEntity, appErr := measService.List(&opt, &claims)
	if appErr != nil {
		return appErr
	}
	measurementsPayload := (measurementsEntity).(*payloads.Measurements)

	// Assemble matrix
	characteristicIDs := strings.Split(opt.Get("characteristic_ids"), ",")
	strainIDs := strings.Split(opt.Get("strain_ids"), ",")

	comparisions := make(Comparisions)
	for _, characteristicID := range characteristicIDs {
		characteristicIDInt, _ := strconv.ParseInt(characteristicID, 10, 0)
		values := make(map[string]string)
		for _, strainID := range strainIDs {
			strainIDInt, _ := strconv.ParseInt(strainID, 10, 0)
			for _, m := range *measurementsPayload.Measurements {
				if (m.CharacteristicID == characteristicIDInt) && (m.StrainID == strainIDInt) {
					if m.Notes.Valid {
						values[strainID] = fmt.Sprintf("%s (%s)", m.Value(), m.Notes.String)
					} else {
						if values[strainID] != "" {
							values[strainID] = fmt.Sprintf("%s; %s", values[strainID], m.Value())
						} else {
							values[strainID] = m.Value()
						}
					}
				}
			}
			// If the strain doesn't have a measurement for this characteristic,
			// stick an empty value in anyway (for CSV).
			if _, ok := values[strainID]; !ok {
				values[strainID] = ""
			}
		}

		comparisions[characteristicID] = values
	}

	// Return, based on mimetype
	switch mimeType {
	case "json":
		header = "application/json"

		comparisionsJSON := make(ComparisionsJSON, 0)
		for _, characteristicID := range characteristicIDs {
			row := []string{characteristicID}
			for _, strainID := range strainIDs {
				row = append(row, comparisions[characteristicID][strainID])
			}
			comparisionsJSON = append(comparisionsJSON, row)
		}

		data, _ = json.Marshal(comparisionsJSON)
	case "csv":
		header = "text/csv"

		// maps to translate ids
		strains := make(map[string]string)
		for _, strain := range *measurementsPayload.Strains {
			var t string
			if strain.TypeStrain {
				t = "T"
			}
			strains[fmt.Sprintf("%d", strain.ID)] = fmt.Sprintf("%s %s %s", strain.SpeciesName(), strain.StrainName, t)
		}
		characteristics := make(map[string]string)
		for _, characteristic := range *measurementsPayload.Characteristics {
			characteristics[fmt.Sprintf("%d", characteristic.ID)] = characteristic.CharacteristicName
		}

		b := &bytes.Buffer{}
		wr := csv.NewWriter(b)

		// Write header row
		r := []string{"Characteristic"}
		for _, strainID := range strainIDs {
			r = append(r, strains[strainID])
		}
		wr.Write(r)

		// Write data
		for _, characteristicID := range characteristicIDs {
			r := []string{characteristics[characteristicID]}
			for _, strainID := range strainIDs {
				r = append(r, comparisions[characteristicID][strainID])
			}
			wr.Write(r)
		}
		wr.Flush()

		data = b.Bytes()

		w.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="compare-%d.csv"`, int32(time.Now().Unix())))
	}

	// Wrap it up
	w.Header().Set("Content-Type", header)
	w.Write(data)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>golint fixes<commit_after><|endoftext|>


<commit_before>package api

import (
	"fmt"
    "github.com/tsuru/config"
    "github.com/nu7hatch/gouuid"
	"io/ioutil"
    "net/http"
    "time"
)

const (
	IMAGE_TYPES       = "image/(gif|p?jpeg|(x-)?png)"
	VIDEO_TYPES       = "(video|realmedia)"
)

func UploadFileHandler(w http.ResponseWriter, req *http.Request) {
    var pathToSave, err = config.GetString("photo_storage_path")
    now := time.Now()
    var directory = mountDirectoryPathFromTime(now)
    check(err)

	file, _, err := req.FormFile("file")
	check(err)

	data, err := ioutil.ReadAll(file)
	check(err)

    directory = pathToSave + directory
	err = CreateDir(directory)
	check(err)

	base, _ := uuid.NewV4()

	var path_file = directory + base.String()
	err = ioutil.WriteFile(path_file, data, 0777)
	check(err)

	fmt.Fprintf(w, "SUCCESS")
}

func PostFormUploadFile(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "<form enctype=\"multipart/form-data\" action=\"http://localhost:4321/upload\" method=\"post\">")
	fmt.Fprintf(w, "  <input type=\"file\" name=\"file\" />")
	fmt.Fprintf(w, "  <input type=\"submit\" value=\"upload\" />")
	fmt.Fprintf(w, "</form>")
	fmt.Fprintf(w, "")
}

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "WORKING")
}
<commit_msg>Fixing typo: take off blank space<commit_after>package api

import (
	"fmt"
    "github.com/tsuru/config"
    "github.com/nu7hatch/gouuid"
	"io/ioutil"
    "net/http"
    "time"
)

const (
	IMAGE_TYPES       = "image/(gif|p?jpeg|(x-)?png)"
	VIDEO_TYPES       = "(video|realmedia)"
)

func UploadFileHandler(w http.ResponseWriter, req *http.Request) {
    var pathToSave, err = config.GetString("photo_storage_path")
    now := time.Now()
    var directory = mountDirectoryPathFromTime(now)
    check(err)

	file, _, err := req.FormFile("file")
	check(err)

	data, err := ioutil.ReadAll(file)
	check(err)

    directory = pathToSave + directory
	err = CreateDir(directory)
	check(err)

	base, _ := uuid.NewV4()

	var path_file = directory + base.String()
	err = ioutil.WriteFile(path_file, data, 0777)
	check(err)

	fmt.Fprintf(w, "SUCCESS")
}

func PostFormUploadFile(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "<form enctype=\"multipart/form-data\" action=\"http://localhost:4321/upload\" method=\"post\">")
	fmt.Fprintf(w, "  <input type=\"file\" name=\"file\" />")
	fmt.Fprintf(w, "  <input type=\"submit\" value=\"upload\" />")
	fmt.Fprintf(w, "</form>")
	fmt.Fprintf(w, "")
}

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "WORKING")
}
<|endoftext|>


<commit_before>package cmd

import (
"fmt"
"net/http"
"github.com/spf13/cobra"
)

var httpClient *http.Client

var meCmd = &cobra.Command{
	Use:   "me",
	Short: "A brief description of your command",
	Long: `to quickly create a Cobra application.`,

	Run: func(cmd *cobra.Command, args []string) {

		apiUrl:= "/api/v2/users/myself"
		endpoint:= Endpoint(apiUrl)

		fmt.Println(endpoint)
	},
}

func init() {
	RootCmd.AddCommand(meCmd)
}
<commit_msg>Added git2go dependency<commit_after>package cmd

import (
	"fmt"
	"net/http"
	"github.com/spf13/cobra"
	git "gopkg.in/libgit2/git2go.v25"
)

var httpClient *http.Client

var meCmd = &cobra.Command{
	Use:   "me",
	Short: "A brief description of your command",
	Long: `to quickly create a Cobra application.`,

	Run: func(cmd *cobra.Command, args []string) {

		apiUrl:= "/api/v2/users/myself"
		endpoint:= Endpoint(apiUrl)

		fmt.Println(endpoint)
		fmt.Println(git.Name())
	},
}

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


<commit_before>// combat utility functions

package main

import "math"

func (g *game) Absorb(armor int) int {
	absorb := 0
	for i := 0; i < 2; i++ {
		absorb += RandInt(armor + 1)
	}
	return int(math.Round(float64(absorb) / 3))
}

func (g *game) HitDamage(dt dmgType, base int, armor int) (attack int, clang bool) {
	min := base / 2
	attack = min + RandInt(base-min+1)
	if dt == DmgPhysical {
		absorb := g.Absorb(armor)
		if absorb > 0 && absorb >= 2*armor/3 && RandInt(2) == 0 {
			clang = true
		}
		attack -= absorb
	}
	if attack < 0 {
		attack = 0
	}
	return attack, clang
}

func (m *monster) InflictDamage(g *game, damage, max int) {
	oldHP := g.Player.HP
	g.Player.HP -= damage
	g.ui.WoundedAnimation(g)
	if oldHP > max && g.Player.HP <= max {
		g.StoryPrintf("Critical HP: %d (hit by %s)", g.Player.HP, m.Kind.Indefinite(false))
		g.ui.CriticalHPWarning(g)
	}
}

func (g *game) MakeMonstersAware() {
	for _, m := range g.Monsters {
		if m.HP <= 0 {
			continue
		}
		if g.Player.LOS[m.Pos] {
			m.MakeAware(g)
			if m.State != Resting {
				m.GatherBand(g)
			}
		}
	}
}

func (g *game) MakeNoise(noise int, at position) {
	dij := &normalPath{game: g}
	nm := Dijkstra(dij, []position{at}, noise)
	for _, m := range g.Monsters {
		if !m.Exists() {
			continue
		}
		if m.State == Hunting {
			continue
		}
		n, ok := nm[m.Pos]
		if !ok {
			continue
		}
		d := n.Cost
		v := noise - d
		if v <= 0 {
			continue
		}
		if v > 25 {
			v = 25
		}
		r := RandInt(30)
		if m.State == Resting {
			v /= 2
		}
		if v > r {
			if g.Player.LOS[m.Pos] {
				m.MakeHunt(g)
			} else {
				m.Target = at
				m.State = Wandering
			}
			m.GatherBand(g)
		}
	}
}

func (g *game) AttackMonster(mons *monster, ev event) {
	switch {
	case g.Player.HasStatus(StatusSwap) && !g.Player.HasStatus(StatusLignification):
		g.SwapWithMonster(mons)
	case g.Player.Weapon == Frundis:
		if !g.HitMonster(DmgPhysical, mons, ev) {
			break
		}
		if RandInt(4) == 0 {
			mons.EnterConfusion(g, ev)
			g.PrintfStyled("Frundis glows… %s appears confused.", logPlayerHit, mons.Kind.Definite(false))
		}
	case g.Player.Weapon.Cleave():
		var neighbors []position
		if g.Player.HasStatus(StatusConfusion) {
			neighbors = g.Dungeon.CardinalFreeNeighbors(g.Player.Pos)
		} else {
			neighbors = g.Dungeon.FreeNeighbors(g.Player.Pos)
		}
		for _, pos := range neighbors {
			mons := g.MonsterAt(pos)
			if mons.Exists() {
				g.HitMonster(DmgPhysical, mons, ev)
			}
		}
	case g.Player.Weapon.Pierce():
		g.HitMonster(DmgPhysical, mons, ev)
		dir := mons.Pos.Dir(g.Player.Pos)
		behind := g.Player.Pos.To(dir).To(dir)
		if behind.valid() {
			mons := g.MonsterAt(behind)
			if mons.Exists() {
				g.HitMonster(DmgPhysical, mons, ev)
			}
		}
	case g.Player.Weapon == ElecWhip:
		g.HitConnected(mons.Pos, DmgMagical, ev)
	case g.Player.Weapon == DancingRapier:
		g.HitMonster(DmgPhysical, mons, ev)
		if mons.Exists() {
			dir := mons.Pos.Dir(g.Player.Pos)
			behind := g.Player.Pos.To(dir).To(dir)
			if behind.valid() {
				mons := g.MonsterAt(behind)
				if mons.Exists() {
					g.HitMonster(DmgPhysical, mons, ev)
				}
			}
			if !g.Player.HasStatus(StatusLignification) {
				ompos := mons.Pos
				mons.MoveTo(g, g.Player.Pos)
				g.PlacePlayerAt(ompos)
			}
		} else if !g.Player.HasStatus(StatusLignification) {
			g.PlacePlayerAt(mons.Pos)
		}
	case g.Player.Weapon == HarKarGauntlets:
		g.HarKarAttack(mons, ev)
	case g.Player.Weapon == BerserkSword:
		g.HitMonster(DmgPhysical, mons, ev)
		if RandInt(20) == 0 && !g.Player.HasStatus(StatusExhausted) && !g.Player.HasStatus(StatusBerserk) {
			g.Player.Statuses[StatusBerserk] = 1
			g.PushEvent(&simpleEvent{ERank: ev.Rank() + 65 + RandInt(20), EAction: BerserkEnd})
			g.Printf("Your sword insurges you to kill things.", BerserkPotion)
		}
	default:
		g.HitMonster(DmgPhysical, mons, ev)
	}
}

func (g *game) HarKarAttack(mons *monster, ev event) {
	dir := mons.Pos.Dir(g.Player.Pos)
	pos := g.Player.Pos
	for {
		pos = pos.To(dir)
		if !pos.valid() || g.Dungeon.Cell(pos).T != FreeCell {
			break
		}
		m := g.MonsterAt(pos)
		if !m.Exists() {
			break
		}
	}
	if pos.valid() && g.Dungeon.Cell(pos).T == FreeCell {
		pos = g.Player.Pos
		for {
			pos = pos.To(dir)
			if !pos.valid() || g.Dungeon.Cell(pos).T != FreeCell {
				break
			}
			m := g.MonsterAt(pos)
			if !m.Exists() {
				break
			}
			g.HitMonster(DmgPhysical, m, ev)
		}
		if !g.Player.HasStatus(StatusLignification) {
			g.PlacePlayerAt(pos)
		}
	} else {
		g.HitMonster(DmgPhysical, mons, ev)
	}
}

func (g *game) HitConnected(pos position, dt dmgType, ev event) {
	d := g.Dungeon
	conn := map[position]bool{}
	stack := []position{pos}
	conn[pos] = true
	nb := make([]position, 0, 8)
	for len(stack) > 0 {
		pos = stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		mons := g.MonsterAt(pos)
		if !mons.Exists() {
			continue
		}
		g.HitMonster(dt, mons, ev)
		nb = pos.Neighbors(nb, func(npos position) bool {
			return npos.valid() && d.Cell(npos).T != WallCell
		})
		for _, npos := range nb {
			if !conn[npos] {
				conn[npos] = true
				stack = append(stack, npos)
			}
		}
	}
}

func (g *game) HitNoise(clang bool) int {
	noise := BaseHitNoise
	if g.Player.Weapon == Frundis {
		noise -= 4
	}
	if g.Player.Armour == HarmonistRobe {
		noise -= 2
	}
	if g.Player.Armour == Robe {
		noise -= 1
	}
	if clang {
		arnoise := g.Player.Armor()
		if arnoise > 7 {
			arnoise = 7
		}
		noise += arnoise
	}
	return noise
}

type dmgType int

const (
	DmgPhysical dmgType = iota
	DmgMagical
)

func (g *game) HitMonster(dt dmgType, mons *monster, ev event) (hit bool) {
	maxacc := g.Player.Accuracy()
	if g.Player.Weapon == Sabre && mons.HP > 0 {
		maxacc += int(6 * (-1 + float64(mons.HPmax)/float64(mons.HP)))
	}
	acc := RandInt(maxacc)
	evasion := RandInt(mons.Evasion)
	if mons.State == Resting {
		evasion /= 2 + 1
	}
	if acc > evasion {
		hit = true
		noise := BaseHitNoise
		if g.Player.Weapon == Dagger {
			noise -= 2
		}
		if g.Player.Armour == HarmonistRobe {
			noise -= 2
		}
		if g.Player.Weapon == Frundis {
			noise -= 4
		}
		bonus := 0
		if g.Player.HasStatus(StatusBerserk) {
			bonus += 2 + RandInt(4)
		}
		attack, clang := g.HitDamage(dt, g.Player.Attack()+bonus, mons.Armor)
		if clang {
			noise += mons.Armor
		}
		g.MakeNoise(noise, mons.Pos)
		if mons.State == Resting {
			if g.Player.Weapon == Dagger {
				attack *= 4
			} else {
				attack *= 2
			}
		}
		var sclang string
		if clang {
			if mons.Armor > 3 {
				sclang = " ♫ Clang!"
			} else {
				sclang = " ♪ Clang!"
			}
		}
		oldHP := mons.HP
		mons.HP -= attack
		g.ui.HitAnimation(g, mons.Pos, false)
		if mons.HP > 0 {
			g.PrintfStyled("You hit %s (%d dmg).%s", logPlayerHit, mons.Kind.Definite(false), attack, sclang)
		} else if oldHP > 0 {
			// test oldHP > 0 because of sword special attack
			g.PrintfStyled("You kill %s (%d dmg).%s", logPlayerHit, mons.Kind.Definite(false), attack, sclang)
			g.HandleKill(mons, ev)
		}
		if mons.Kind == MonsBrizzia && RandInt(4) == 0 && !g.Player.HasStatus(StatusNausea) &&
			mons.Pos.Distance(g.Player.Pos) == 1 {
			g.Player.Statuses[StatusNausea]++
			g.PushEvent(&simpleEvent{ERank: ev.Rank() + 30 + RandInt(20), EAction: NauseaEnd})
			g.Print("The brizzia's corpse releases a nauseous gas. You feel sick.")
		}
		g.Stats.Hits++
	} else {
		g.Printf("You miss %s.", mons.Kind.Definite(false))
		g.Stats.Misses++
	}
	mons.MakeHuntIfHurt(g)
	return hit
}

func (g *game) HandleKill(mons *monster, ev event) {
	g.Stats.Killed++
	g.Stats.KilledMons[mons.Kind]++
	if mons.Kind == MonsExplosiveNadre {
		mons.Explode(g, ev)
	}
	if g.Doors[mons.Pos] {
		g.ComputeLOS()
	}
	if mons.Kind.Dangerousness() > 10 {
		g.StoryPrintf("You killed %s.", mons.Kind.Indefinite(false))
	}
}

const (
	WallNoise           = 18
	TemporalWallNoise   = 16
	ExplosionHitNoise   = 13
	ExplosionNoise      = 18
	MagicHitNoise       = 15
	BarkNoise           = 13
	MagicExplosionNoise = 16
	MagicCastNoise      = 16
	BaseHitNoise        = 11
	ShieldBlockNoise    = 15
)

func (g *game) ArmourClang() (sclang string) {
	if g.Player.Armor() > 3 {
		sclang = " Clang!"
	} else {
		sclang = " Smash!"
	}
	return sclang
}

func (g *game) BlockEffects(m *monster) {
	switch g.Player.Shield {
	case EarthShield:
		dir := m.Pos.Dir(g.Player.Pos)
		lat := g.Player.Pos.Laterals(dir)
		for _, pos := range lat {
			if !pos.valid() {
				continue
			}
			if RandInt(4) == 0 && g.Dungeon.Cell(pos).T == WallCell {
				g.Dungeon.SetCell(pos, FreeCell)
				g.Stats.Digs++
				g.MakeNoise(WallNoise, pos)
				g.Fog(pos, 1, g.Ev)
			}
		}
	case BashingShield:
		if m.Kind == MonsSatowalgaPlant || m.Pos.Distance(g.Player.Pos) > 1 {
			break
		}
		if RandInt(3) == 0 {
			break
		}
		dir := m.Pos.Dir(g.Player.Pos)
		pos := m.Pos
		for i := 0; i < 3; i++ {
			npos := pos.To(dir)
			if !npos.valid() || g.Dungeon.Cell(npos).T == WallCell {
				break
			}
			mons := g.MonsterAt(npos)
			if mons.Exists() {
				break
			}
			pos = npos
		}
		if !m.Status(MonsExhausted) {
			m.Statuses[MonsExhausted] = 1
			g.PushEvent(&monsterEvent{ERank: g.Ev.Rank() + 100 + RandInt(50), NMons: m.Index, EAction: MonsExhaustionEnd})
		}
		if pos != m.Pos {
			m.MoveTo(g, pos)
		}
	case ConfusingShield:
		if m.Pos.Distance(g.Player.Pos) > 1 {
			break
		}
		if RandInt(4) == 0 {
			m.EnterConfusion(g, g.Ev)
			g.Printf("%s appears confused.", m.Kind.Definite(true))
		}
	}
}
<commit_msg>fix bug with armour absorbing formula<commit_after>// combat utility functions

package main

import "math"

func (g *game) Absorb(armor int) int {
	absorb := 0
	for i := 0; i <= 2; i++ {
		absorb += RandInt(armor + 1)
	}
	return int(math.Round(float64(absorb) / 3))
}

func (g *game) HitDamage(dt dmgType, base int, armor int) (attack int, clang bool) {
	min := base / 2
	attack = min + RandInt(base-min+1)
	if dt == DmgPhysical {
		absorb := g.Absorb(armor)
		if absorb > 0 && absorb >= 2*armor/3 && RandInt(2) == 0 {
			clang = true
		}
		attack -= absorb
	}
	if attack < 0 {
		attack = 0
	}
	return attack, clang
}

func (m *monster) InflictDamage(g *game, damage, max int) {
	oldHP := g.Player.HP
	g.Player.HP -= damage
	g.ui.WoundedAnimation(g)
	if oldHP > max && g.Player.HP <= max {
		g.StoryPrintf("Critical HP: %d (hit by %s)", g.Player.HP, m.Kind.Indefinite(false))
		g.ui.CriticalHPWarning(g)
	}
}

func (g *game) MakeMonstersAware() {
	for _, m := range g.Monsters {
		if m.HP <= 0 {
			continue
		}
		if g.Player.LOS[m.Pos] {
			m.MakeAware(g)
			if m.State != Resting {
				m.GatherBand(g)
			}
		}
	}
}

func (g *game) MakeNoise(noise int, at position) {
	dij := &normalPath{game: g}
	nm := Dijkstra(dij, []position{at}, noise)
	for _, m := range g.Monsters {
		if !m.Exists() {
			continue
		}
		if m.State == Hunting {
			continue
		}
		n, ok := nm[m.Pos]
		if !ok {
			continue
		}
		d := n.Cost
		v := noise - d
		if v <= 0 {
			continue
		}
		if v > 25 {
			v = 25
		}
		r := RandInt(30)
		if m.State == Resting {
			v /= 2
		}
		if v > r {
			if g.Player.LOS[m.Pos] {
				m.MakeHunt(g)
			} else {
				m.Target = at
				m.State = Wandering
			}
			m.GatherBand(g)
		}
	}
}

func (g *game) AttackMonster(mons *monster, ev event) {
	switch {
	case g.Player.HasStatus(StatusSwap) && !g.Player.HasStatus(StatusLignification):
		g.SwapWithMonster(mons)
	case g.Player.Weapon == Frundis:
		if !g.HitMonster(DmgPhysical, mons, ev) {
			break
		}
		if RandInt(4) == 0 {
			mons.EnterConfusion(g, ev)
			g.PrintfStyled("Frundis glows… %s appears confused.", logPlayerHit, mons.Kind.Definite(false))
		}
	case g.Player.Weapon.Cleave():
		var neighbors []position
		if g.Player.HasStatus(StatusConfusion) {
			neighbors = g.Dungeon.CardinalFreeNeighbors(g.Player.Pos)
		} else {
			neighbors = g.Dungeon.FreeNeighbors(g.Player.Pos)
		}
		for _, pos := range neighbors {
			mons := g.MonsterAt(pos)
			if mons.Exists() {
				g.HitMonster(DmgPhysical, mons, ev)
			}
		}
	case g.Player.Weapon.Pierce():
		g.HitMonster(DmgPhysical, mons, ev)
		dir := mons.Pos.Dir(g.Player.Pos)
		behind := g.Player.Pos.To(dir).To(dir)
		if behind.valid() {
			mons := g.MonsterAt(behind)
			if mons.Exists() {
				g.HitMonster(DmgPhysical, mons, ev)
			}
		}
	case g.Player.Weapon == ElecWhip:
		g.HitConnected(mons.Pos, DmgMagical, ev)
	case g.Player.Weapon == DancingRapier:
		g.HitMonster(DmgPhysical, mons, ev)
		if mons.Exists() {
			dir := mons.Pos.Dir(g.Player.Pos)
			behind := g.Player.Pos.To(dir).To(dir)
			if behind.valid() {
				mons := g.MonsterAt(behind)
				if mons.Exists() {
					g.HitMonster(DmgPhysical, mons, ev)
				}
			}
			if !g.Player.HasStatus(StatusLignification) {
				ompos := mons.Pos
				mons.MoveTo(g, g.Player.Pos)
				g.PlacePlayerAt(ompos)
			}
		} else if !g.Player.HasStatus(StatusLignification) {
			g.PlacePlayerAt(mons.Pos)
		}
	case g.Player.Weapon == HarKarGauntlets:
		g.HarKarAttack(mons, ev)
	case g.Player.Weapon == BerserkSword:
		g.HitMonster(DmgPhysical, mons, ev)
		if RandInt(20) == 0 && !g.Player.HasStatus(StatusExhausted) && !g.Player.HasStatus(StatusBerserk) {
			g.Player.Statuses[StatusBerserk] = 1
			g.PushEvent(&simpleEvent{ERank: ev.Rank() + 65 + RandInt(20), EAction: BerserkEnd})
			g.Printf("Your sword insurges you to kill things.", BerserkPotion)
		}
	default:
		g.HitMonster(DmgPhysical, mons, ev)
	}
}

func (g *game) HarKarAttack(mons *monster, ev event) {
	dir := mons.Pos.Dir(g.Player.Pos)
	pos := g.Player.Pos
	for {
		pos = pos.To(dir)
		if !pos.valid() || g.Dungeon.Cell(pos).T != FreeCell {
			break
		}
		m := g.MonsterAt(pos)
		if !m.Exists() {
			break
		}
	}
	if pos.valid() && g.Dungeon.Cell(pos).T == FreeCell {
		pos = g.Player.Pos
		for {
			pos = pos.To(dir)
			if !pos.valid() || g.Dungeon.Cell(pos).T != FreeCell {
				break
			}
			m := g.MonsterAt(pos)
			if !m.Exists() {
				break
			}
			g.HitMonster(DmgPhysical, m, ev)
		}
		if !g.Player.HasStatus(StatusLignification) {
			g.PlacePlayerAt(pos)
		}
	} else {
		g.HitMonster(DmgPhysical, mons, ev)
	}
}

func (g *game) HitConnected(pos position, dt dmgType, ev event) {
	d := g.Dungeon
	conn := map[position]bool{}
	stack := []position{pos}
	conn[pos] = true
	nb := make([]position, 0, 8)
	for len(stack) > 0 {
		pos = stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		mons := g.MonsterAt(pos)
		if !mons.Exists() {
			continue
		}
		g.HitMonster(dt, mons, ev)
		nb = pos.Neighbors(nb, func(npos position) bool {
			return npos.valid() && d.Cell(npos).T != WallCell
		})
		for _, npos := range nb {
			if !conn[npos] {
				conn[npos] = true
				stack = append(stack, npos)
			}
		}
	}
}

func (g *game) HitNoise(clang bool) int {
	noise := BaseHitNoise
	if g.Player.Weapon == Frundis {
		noise -= 4
	}
	if g.Player.Armour == HarmonistRobe {
		noise -= 2
	}
	if g.Player.Armour == Robe {
		noise -= 1
	}
	if clang {
		arnoise := g.Player.Armor()
		if arnoise > 7 {
			arnoise = 7
		}
		noise += arnoise
	}
	return noise
}

type dmgType int

const (
	DmgPhysical dmgType = iota
	DmgMagical
)

func (g *game) HitMonster(dt dmgType, mons *monster, ev event) (hit bool) {
	maxacc := g.Player.Accuracy()
	if g.Player.Weapon == Sabre && mons.HP > 0 {
		maxacc += int(6 * (-1 + float64(mons.HPmax)/float64(mons.HP)))
	}
	acc := RandInt(maxacc)
	evasion := RandInt(mons.Evasion)
	if mons.State == Resting {
		evasion /= 2 + 1
	}
	if acc > evasion {
		hit = true
		noise := BaseHitNoise
		if g.Player.Weapon == Dagger {
			noise -= 2
		}
		if g.Player.Armour == HarmonistRobe {
			noise -= 2
		}
		if g.Player.Weapon == Frundis {
			noise -= 4
		}
		bonus := 0
		if g.Player.HasStatus(StatusBerserk) {
			bonus += 2 + RandInt(4)
		}
		attack, clang := g.HitDamage(dt, g.Player.Attack()+bonus, mons.Armor)
		if clang {
			noise += mons.Armor
		}
		g.MakeNoise(noise, mons.Pos)
		if mons.State == Resting {
			if g.Player.Weapon == Dagger {
				attack *= 4
			} else {
				attack *= 2
			}
		}
		var sclang string
		if clang {
			if mons.Armor > 3 {
				sclang = " ♫ Clang!"
			} else {
				sclang = " ♪ Clang!"
			}
		}
		oldHP := mons.HP
		mons.HP -= attack
		g.ui.HitAnimation(g, mons.Pos, false)
		if mons.HP > 0 {
			g.PrintfStyled("You hit %s (%d dmg).%s", logPlayerHit, mons.Kind.Definite(false), attack, sclang)
		} else if oldHP > 0 {
			// test oldHP > 0 because of sword special attack
			g.PrintfStyled("You kill %s (%d dmg).%s", logPlayerHit, mons.Kind.Definite(false), attack, sclang)
			g.HandleKill(mons, ev)
		}
		if mons.Kind == MonsBrizzia && RandInt(4) == 0 && !g.Player.HasStatus(StatusNausea) &&
			mons.Pos.Distance(g.Player.Pos) == 1 {
			g.Player.Statuses[StatusNausea]++
			g.PushEvent(&simpleEvent{ERank: ev.Rank() + 30 + RandInt(20), EAction: NauseaEnd})
			g.Print("The brizzia's corpse releases a nauseous gas. You feel sick.")
		}
		g.Stats.Hits++
	} else {
		g.Printf("You miss %s.", mons.Kind.Definite(false))
		g.Stats.Misses++
	}
	mons.MakeHuntIfHurt(g)
	return hit
}

func (g *game) HandleKill(mons *monster, ev event) {
	g.Stats.Killed++
	g.Stats.KilledMons[mons.Kind]++
	if mons.Kind == MonsExplosiveNadre {
		mons.Explode(g, ev)
	}
	if g.Doors[mons.Pos] {
		g.ComputeLOS()
	}
	if mons.Kind.Dangerousness() > 10 {
		g.StoryPrintf("You killed %s.", mons.Kind.Indefinite(false))
	}
}

const (
	WallNoise           = 18
	TemporalWallNoise   = 16
	ExplosionHitNoise   = 13
	ExplosionNoise      = 18
	MagicHitNoise       = 15
	BarkNoise           = 13
	MagicExplosionNoise = 16
	MagicCastNoise      = 16
	BaseHitNoise        = 11
	ShieldBlockNoise    = 15
)

func (g *game) ArmourClang() (sclang string) {
	if g.Player.Armor() > 3 {
		sclang = " Clang!"
	} else {
		sclang = " Smash!"
	}
	return sclang
}

func (g *game) BlockEffects(m *monster) {
	switch g.Player.Shield {
	case EarthShield:
		dir := m.Pos.Dir(g.Player.Pos)
		lat := g.Player.Pos.Laterals(dir)
		for _, pos := range lat {
			if !pos.valid() {
				continue
			}
			if RandInt(4) == 0 && g.Dungeon.Cell(pos).T == WallCell {
				g.Dungeon.SetCell(pos, FreeCell)
				g.Stats.Digs++
				g.MakeNoise(WallNoise, pos)
				g.Fog(pos, 1, g.Ev)
			}
		}
	case BashingShield:
		if m.Kind == MonsSatowalgaPlant || m.Pos.Distance(g.Player.Pos) > 1 {
			break
		}
		if RandInt(3) == 0 {
			break
		}
		dir := m.Pos.Dir(g.Player.Pos)
		pos := m.Pos
		for i := 0; i < 3; i++ {
			npos := pos.To(dir)
			if !npos.valid() || g.Dungeon.Cell(npos).T == WallCell {
				break
			}
			mons := g.MonsterAt(npos)
			if mons.Exists() {
				break
			}
			pos = npos
		}
		if !m.Status(MonsExhausted) {
			m.Statuses[MonsExhausted] = 1
			g.PushEvent(&monsterEvent{ERank: g.Ev.Rank() + 100 + RandInt(50), NMons: m.Index, EAction: MonsExhaustionEnd})
		}
		if pos != m.Pos {
			m.MoveTo(g, pos)
		}
	case ConfusingShield:
		if m.Pos.Distance(g.Player.Pos) > 1 {
			break
		}
		if RandInt(4) == 0 {
			m.EnterConfusion(g, g.Ev)
			g.Printf("%s appears confused.", m.Kind.Definite(true))
		}
	}
}
<|endoftext|>


<commit_before>package auditlog

import (
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"time"
)

// A Certification contains a snapshot an audit chain, errors that
// occurred in the range of events, and a nanosecond-resolution timestamp
// of when the certification was built.
type Certification struct {
	When   int64         `json:"when"`
	Chain  []*Event      `json:"chain"`
	Errors []*ErrorEvent `json:"errors"`
}

// Certify returns a certification for the requested range of events;
// start and end are event serial numbers. The certification is
// returned in JSON.
func (l *Logger) Certify(start, end uint64) ([]byte, error) {
	l.lock.Lock()
	defer l.lock.Unlock()
	if end <= 0 {
		end = l.counter - 1
	}

	attributes := []Attribute{
		{"start", fmt.Sprintf("%d", start)},
		{"end", fmt.Sprintf("%d", end)},
	}
	l.Info("auditlog", "certify", attributes)
	var certification Certification
	var err error

	tx, err := l.db.Begin()
	if err != nil {
		return nil, err
	}

	defer func() {
		if err == nil {
			tx.Commit()
		} else {
			tx.Rollback()
		}
	}()
	certification.Chain, err = loadEvents(tx, start, end)
	if err != nil {
		return nil, err
	}

	certification.Errors, err = loadErrors(tx, start, end)
	if err != nil {
		return nil, err
	}

	certification.When = time.Now().UnixNano()

	return json.Marshal(certification)
}

// VerifyCertification verifies a JSON-encoded certification against
// the signer's public key.
func VerifyCertification(in []byte, signer *ecdsa.PublicKey) (*Certification, bool) {
	var cl Certification
	err := json.Unmarshal(in, &cl)
	if err != nil {
		return nil, false
	}

	if len(cl.Chain) > 0 && cl.Chain[0].Serial == 0 {
		if !cl.Chain[0].Verify(signer, nil) {
			return nil, false
		}
	}

	if len(cl.Chain) > 1 {
		for i := 1; i < len(cl.Chain); i++ {
			if !cl.Chain[i].Verify(signer, cl.Chain[i-1].Signature) {
				return nil, false
			}
		}
	}
	return &cl, true
}

func publicFingerprint(signer *ecdsa.PublicKey) []byte {
	h := sha256.New()
	h.Write(signer.X.Bytes())
	h.Write(signer.Y.Bytes())
	return h.Sum(nil)
}
<commit_msg>Add RootSignature to verify integrity of root event.<commit_after>package auditlog

import (
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"time"
)

// A Certification contains a snapshot an audit chain, errors that
// occurred in the range of events, and a nanosecond-resolution timestamp
// of when the certification was built.
type Certification struct {
	When   int64         `json:"when"`
	Chain  []*Event      `json:"chain"`
	Errors []*ErrorEvent `json:"errors"`
}

// Certify returns a certification for the requested range of events;
// start and end are event serial numbers. The certification is
// returned in JSON.
func (l *Logger) Certify(start, end uint64) ([]byte, error) {
	l.lock.Lock()
	defer l.lock.Unlock()
	if end <= 0 {
		end = l.counter - 1
	}

	attributes := []Attribute{
		{"start", fmt.Sprintf("%d", start)},
		{"end", fmt.Sprintf("%d", end)},
	}
	l.Info("auditlog", "certify", attributes)
	var certification Certification
	var err error

	tx, err := l.db.Begin()
	if err != nil {
		return nil, err
	}

	defer func() {
		if err == nil {
			tx.Commit()
		} else {
			tx.Rollback()
		}
	}()
	certification.Chain, err = loadEvents(tx, start, end)
	if err != nil {
		return nil, err
	}

	certification.Errors, err = loadErrors(tx, start, end)
	if err != nil {
		return nil, err
	}

	certification.When = time.Now().UnixNano()

	return json.Marshal(certification)
}

// VerifyCertification verifies a JSON-encoded certification against
// the signer's public key.
func VerifyCertification(in []byte, signer *ecdsa.PublicKey) (*Certification, bool) {
	var cl Certification
	err := json.Unmarshal(in, &cl)
	if err != nil {
		return nil, false
	}

	if len(cl.Chain) > 0 && cl.Chain[0].Serial == 0 {
		if !cl.Chain[0].Verify(signer, nil) {
			return nil, false
		}
	}

	if len(cl.Chain) > 1 {
		for i := 1; i < len(cl.Chain); i++ {
			if !cl.Chain[i].Verify(signer, cl.Chain[i-1].Signature) {
				return nil, false
			}
		}
	}
	return &cl, true
}

func publicFingerprint(signer *ecdsa.PublicKey) []byte {
	h := sha256.New()
	h.Write(signer.X.Bytes())
	h.Write(signer.Y.Bytes())
	return h.Sum(nil)
}

// RootSignature returns the signature of the root event (i.e. the
// event with serial = 0). The user can store a copy of this, and use
// it to ensure the root of the chain has not been tampered with.
func (l *Logger) RootSignature() ([]byte, error) {
	tx, err := l.db.Begin()
	if err != nil {
		return nil, err
	}

	signature, err := getSignature(tx, 0)
	if err != nil {
		tx.Rollback()
		signature = nil
	} else {
		tx.Commit()
	}

	return signature, err
}
<|endoftext|>


<commit_before>// package waddell implements a low-latency signaling server that allows peers
// to exchange small messages (up to around 64kB) over TCP.  It is named after
// William B. Waddell, one of the founders of the Pony Express.
//
// Peers are identified by randomly assigned peer ids (type 4 UUIDs), which are
// used to address messages to the peers.  For the scheme to work, peers must
// have some out-of-band mechanism by which they can exchange peer ids.  Note
// that as soon as one peer contacts another via waddell, the 2nd peer will have
// the 1st peer's address and be able to reply using it.
//
// Peers can obtain new ids simply by reconnecting to waddell, and depending on
// security requirements it may be a good idea to do so periodically.
//
//
// Here is an example exchange between two peers:
//
//   peer 1 -> waddell server : connect
//
//   waddell server -> peer 1 : send newly assigned peer id
//
//   peer 2 -> waddell server : connect
//
//   waddell server -> peer 2 : send newly assigned peer id
//
//   (out of band)            : peer 1 lets peer 2 know about its id
//
//   peer 2 -> waddell server : send message to peer 1
//
//   waddell server -> peer 1 : deliver message from peer 2 (includes peer 2's id)
//
//   peer 1 -> waddell server : send message to peer 2
//
//   etc ..
//
//
// Message structure on the wire (bits):
//
//   0-15    Frame Length    - waddell uses github.com/getlantern/framed to
//                             frame messages. framed uses the first 16 bits of
//                             the message to indicate the length of the frame
//                             (Little Endian).
//
//   16-79   Address Part 1  - 64-bit integer in Little Endian byte order for
//                             first half of peer id identifying recipient (on
//                             messages to waddell) or sender (on messages from
//                             waddell).
//
//   80-143  Address Part 2  - 64-bit integer in Little Endian byte order for
//                             second half of peer id
//
//   144+    Message Body    - whatever data the client sent
//
package waddell

import (
	"github.com/getlantern/buuid"
	"github.com/getlantern/golog"
)

const (
	PEER_ID_LENGTH   = buuid.EncodedLength
	WADDELL_OVERHEAD = 18 // bytes of overhead imposed by waddell
)

var (
	log = golog.LoggerFor("waddell.client")

	keepAlive = []byte{'k'}
)

// PeerId is an identifier for a waddell peer
type PeerId buuid.ID

// PeerIdFromString constructs a PeerId from the string-encoded version of a
// uuid.UUID.
func PeerIdFromString(s string) (PeerId, error) {
	id, err := buuid.FromString(s)
	return PeerId(id), err
}

func readPeerId(b []byte) (PeerId, error) {
	id, err := buuid.Read(b)
	return PeerId(id), err
}

func randomPeerId() PeerId {
	return PeerId(buuid.Random())
}

func (id PeerId) write(b []byte) error {
	return buuid.ID(id).Write(b)
}

func (id PeerId) toBytes() []byte {
	return buuid.ID(id).ToBytes()
}
<commit_msg>Added back PeerID.String() method<commit_after>// package waddell implements a low-latency signaling server that allows peers
// to exchange small messages (up to around 64kB) over TCP.  It is named after
// William B. Waddell, one of the founders of the Pony Express.
//
// Peers are identified by randomly assigned peer ids (type 4 UUIDs), which are
// used to address messages to the peers.  For the scheme to work, peers must
// have some out-of-band mechanism by which they can exchange peer ids.  Note
// that as soon as one peer contacts another via waddell, the 2nd peer will have
// the 1st peer's address and be able to reply using it.
//
// Peers can obtain new ids simply by reconnecting to waddell, and depending on
// security requirements it may be a good idea to do so periodically.
//
//
// Here is an example exchange between two peers:
//
//   peer 1 -> waddell server : connect
//
//   waddell server -> peer 1 : send newly assigned peer id
//
//   peer 2 -> waddell server : connect
//
//   waddell server -> peer 2 : send newly assigned peer id
//
//   (out of band)            : peer 1 lets peer 2 know about its id
//
//   peer 2 -> waddell server : send message to peer 1
//
//   waddell server -> peer 1 : deliver message from peer 2 (includes peer 2's id)
//
//   peer 1 -> waddell server : send message to peer 2
//
//   etc ..
//
//
// Message structure on the wire (bits):
//
//   0-15    Frame Length    - waddell uses github.com/getlantern/framed to
//                             frame messages. framed uses the first 16 bits of
//                             the message to indicate the length of the frame
//                             (Little Endian).
//
//   16-79   Address Part 1  - 64-bit integer in Little Endian byte order for
//                             first half of peer id identifying recipient (on
//                             messages to waddell) or sender (on messages from
//                             waddell).
//
//   80-143  Address Part 2  - 64-bit integer in Little Endian byte order for
//                             second half of peer id
//
//   144+    Message Body    - whatever data the client sent
//
package waddell

import (
	"github.com/getlantern/buuid"
	"github.com/getlantern/golog"
)

const (
	PEER_ID_LENGTH   = buuid.EncodedLength
	WADDELL_OVERHEAD = 18 // bytes of overhead imposed by waddell
)

var (
	log = golog.LoggerFor("waddell.client")

	keepAlive = []byte{'k'}
)

// PeerId is an identifier for a waddell peer
type PeerId buuid.ID

// PeerIdFromString constructs a PeerId from the string-encoded version of a
// uuid.UUID.
func PeerIdFromString(s string) (PeerId, error) {
	id, err := buuid.FromString(s)
	return PeerId(id), err
}

func (id PeerId) String() string {
	return buuid.ID(id).String()
}

func readPeerId(b []byte) (PeerId, error) {
	id, err := buuid.Read(b)
	return PeerId(id), err
}

func randomPeerId() PeerId {
	return PeerId(buuid.Random())
}

func (id PeerId) write(b []byte) error {
	return buuid.ID(id).Write(b)
}

func (id PeerId) toBytes() []byte {
	return buuid.ID(id).ToBytes()
}
<|endoftext|>