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

package engine

import (
	"errors"
	"fmt"
	"github.com/fatih/color"
	"log"
	"strconv"
	"strings"
)

const (
	// The following are all PHP breakpoint types
	// Each PHP breakpoint has an entry in the DebugEngineState.Breakpoints table
	// *and* within GDB internally, of course
	breakpointTypeLine        engineBreakpointType = "line"
	breakpointTypeCall        engineBreakpointType = "call"
	breakpointTypeReturn      engineBreakpointType = "return"
	breakpointTypeException   engineBreakpointType = "exception"
	breakpointTypeConditional engineBreakpointType = "conditional"
	breakpointTypeWatch       engineBreakpointType = "watch"
	// This is a non-PHP breakpoint, i.e. a pure GDB breakpoint
	// Usually internal breakpoints are not stored in the DebugEngineState.Breakpoints table
	// They are usually created and thrown away on demand
	breakpointTypeInternal engineBreakpointType = "internal"

	breakpointHitCondGtEq engineBreakpointCondition = ">="
	breakpointHitCondEq   engineBreakpointCondition = "=="
	breakpointHitCondMod  engineBreakpointCondition = "%"

	breakpointStateDisabled engineBreakpointState = "disabled"
	breakpointStateEnabled  engineBreakpointState = "enabled"

	// Error codes returned when a user (php) breakpoint cannot be set
	breakpointErrorCodeCouldNotSet      engineBreakpointErrorCode = 200
	breakpointErrorCodeTypeNotSupported engineBreakpointErrorCode = 201
)

type engineBreakpointError struct {
	code    engineBreakpointErrorCode
	message string
}

type engineBreakpointType string
type engineBreakpointState string
type engineBreakpointCondition string
type engineBreakpointErrorCode int

type engineBreakPoint struct {
	id           string
	bpType       engineBreakpointType
	filename     string
	lineno       int
	state        engineBreakpointState
	temporary    bool
	hitCount     int
	hitValue     int
	hitCondition engineBreakpointCondition
	exception    string
	expression   string
}

func stringToBreakpointType(t string) (engineBreakpointType, error) {
	switch t {
	case "line":
		return breakpointTypeLine, nil
	case "call":
		return breakpointTypeCall, nil
	case "return":
		return breakpointTypeReturn, nil
	case "exception":
		return breakpointTypeException, nil
	case "conditional":
		return breakpointTypeConditional, nil
	case "watch":
		return breakpointTypeWatch, nil
	// Deliberately omit the internal breakpoint type
	default:
		return "", errors.New("Unknown breakpoint type")
	}
}

// @TODO what about multiple breakpoints on the same c source code line?
func breakpointStopGetID(notification map[string]interface{}) (string, bool) {
	class, ok := notification["class"].(string)
	if !ok || class != "stopped" {
		return "", false
	}

	payload, ok := notification["payload"].(map[string]interface{})
	if !ok {
		return "", false
	}

	breakPointNumString, ok := payload["bkptno"].(string)
	if !ok {
		return "", false
	}

	reason, ok := payload["reason"].(string)
	if !ok || reason != "breakpoint-hit" {
		return "", false
	}

	return breakPointNumString, true
}

func handleBreakpointUpdate(es *engineState, dCmd dbgpCmd) string {
	d, ok := dCmd.options["d"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint number for breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["n"]
	if ok {
		panicWith(fmt.Sprint("Line number updates are currently unsupported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["h"]
	if ok {
		panicWith(fmt.Sprint("Hit condition/value update is currently not supported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["o"]
	if ok {
		panicWith(fmt.Sprint("Hit condition/value update is currently not supported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	s, ok := dCmd.options["s"]
	if !ok {
		panicWith(fmt.Sprint("Please provide new breakpoint status in breakpoint_update. Got:", dCmd.fullCommand))
	}

	if s == "disabled" {
		disableGdbBreakpoint(es, d)
	} else if s == "enabled" {
		enableGdbBreakpoint(es, d)
	} else {
		panicWith(fmt.Sprintf("Unknown breakpoint status %v for breakpoint_update", s))
	}

	return fmt.Sprintf(gBreakpointRemoveOrUpdateXMLResponseFormat, "breakpoint_update", dCmd.seqNum)
}

func handleBreakpointRemove(es *engineState, dCmd dbgpCmd) string {
	d, ok := dCmd.options["d"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint id to remove. Got:", dCmd.fullCommand))
	}

	removeGdbBreakpoint(es, d)

	return fmt.Sprintf(gBreakpointRemoveOrUpdateXMLResponseFormat, "breakpoint_remove", dCmd.seqNum)
}

func handleBreakpointSetLineBreakpoint(es *engineState, dCmd dbgpCmd) string {
	phpFilename, ok := dCmd.options["f"]
	if !ok {
		panicWith(fmt.Sprint("Please provide filename option -f in breakpoint_set. Got: ", dCmd.fullCommand))
	}

	status, ok := dCmd.options["s"]
	disabled := false
	if ok {
		if status == "disabled" {
			disabled = true
		} else if status != "enabled" {
			panicWith("Unknown breakpoint status: " + status)
		}
	} else {
		status = "enabled"
	}

	phpLinenoString, ok := dCmd.options["n"]
	if !ok {
		panicWith(fmt.Sprint("Please provide line number option -n in breakpoint_set. Got:", dCmd.fullCommand))
	}

	r, ok := dCmd.options["r"]
	temporary := false
	if ok && r == "1" {
		temporary = true
	}

	_, ok = dCmd.options["h"]
	if ok {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Hit condition/value is currently not supported")
	}

	_, ok = dCmd.options["o"]
	if ok {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Hit condition/value is currently not supported")
	}

	phpLineno, err := strconv.Atoi(phpLinenoString)
	panicIf(err)

	id, breakErr := setPhpBreakpointInGdb(es, phpFilename, phpLineno, disabled, temporary)
	if breakErr != nil {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakErr.code, breakErr.message)
	}

	return fmt.Sprintf(gBreakpointSetLineXMLResponseFormat, dCmd.seqNum, status, id)
}

func handleBreakpointSet(es *engineState, dCmd dbgpCmd) string {
	t, ok := dCmd.options["t"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint type option -t in breakpoint_set. Got:", dCmd.fullCommand))
	}

	tt, err := stringToBreakpointType(t)
	panicIf(err)

	switch tt {
	case breakpointTypeLine:
		return handleBreakpointSetLineBreakpoint(es, dCmd)
	default:
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Breakpoint type "+tt+" is not supported")
	}
}

func getEnabledPhpBreakpoints(es *engineState) []string {
	var enabledPhpBreakpoints []string
	for name, bp := range es.breakpoints {
		if bp.state == breakpointStateEnabled && bp.bpType != breakpointTypeInternal {
			enabledPhpBreakpoints = append(enabledPhpBreakpoints, name)
		}
	}

	return enabledPhpBreakpoints
}

func isEnabledPhpBreakpoint(es *engineState, id string) bool {
	for name, bp := range es.breakpoints {
		if name == id && bp.state == breakpointStateEnabled && bp.bpType != breakpointTypeInternal {
			return true
		}
	}

	return false
}

func isEnabledPhpTemporaryBreakpoint(es *engineState, id string) bool {
	for name, bp := range es.breakpoints {
		if name == id &&
			bp.state == breakpointStateEnabled &&
			bp.bpType != breakpointTypeInternal &&
			bp.temporary {
			return true
		}
	}

	return false
}

func disableGdbBreakpoints(es *engineState, bpList []string) {
	if len(bpList) > 0 {
		commandArgs := fmt.Sprintf("%v", strings.Join(bpList, " "))
		sendGdbCommand(es.gdbSession, "break-disable", commandArgs)
		for _, el := range bpList {
			bp, ok := es.breakpoints[el]
			if ok {
				bp.state = breakpointStateDisabled
			}
		}
	}
}

// convenience function
func disableGdbBreakpoint(es *engineState, bp string) {
	disableGdbBreakpoints(es, []string{bp})
}

// Note that not all "internal" breakpoints are stored in the breakpoints table
func disableAllGdbBreakpoints(es *engineState) {
	sendGdbCommand(es.gdbSession, "break-disable")
	for _, bp := range es.breakpoints {
		bp.state = breakpointStateDisabled
	}
}

func enableAllGdbBreakpoints(es *engineState) {
	sendGdbCommand(es.gdbSession, "break-enable")
	for _, bp := range es.breakpoints {
		bp.state = breakpointStateEnabled
	}
}

func enableGdbBreakpoints(es *engineState, bpList []string) {
	if len(bpList) > 0 {
		commandArgs := fmt.Sprintf("%v", strings.Join(bpList, " "))
		sendGdbCommand(es.gdbSession, "break-enable", commandArgs)
		for _, el := range bpList {
			bp, ok := es.breakpoints[el]
			if ok {
				bp.state = breakpointStateEnabled
			}
		}
	}
}

func getAssocEnabledPhpBreakpoint(es *engineState, filename string, lineno int) (string, bool) {
	for name, bp := range es.breakpoints {
		if bp.filename == filename &&
			bp.lineno == lineno &&
			bp.state == breakpointStateEnabled &&
			bp.bpType != breakpointTypeInternal {
			return name, true
		}
	}

	return "", false
}

// convenience function
func enableGdbBreakpoint(es *engineState, bp string) {
	enableGdbBreakpoints(es, []string{bp})
}

// Sets an equivalent breakpoint in gdb for PHP
// Also inserts the breakpoint into es.Breakpoints table
func setPhpBreakpointInGdb(es *engineState, phpFilename string, phpLineno int, disabled bool, temporary bool) (string, *engineBreakpointError) {
	internalLineno, ok := es.sourceMap[phpFilename]
	if !ok {
		warning := fmt.Sprintf("dontbug: Not able to find %v to add a breakpoint. The IDE is trying to set a breakpoint for a file from a different project or you have not specified the root directory command line parameter correctly. Ignoring", phpFilename)
		color.Yellow(warning)
		return "", &engineBreakpointError{breakpointErrorCodeCouldNotSet, warning}
	}

	breakpointState := breakpointStateEnabled
	disabledFlag := ""
	if disabled {
		disabledFlag = "-d " // Note the space after -d
		breakpointState = breakpointStateDisabled
	}

	temporaryFlag := ""
	if temporary {
		temporaryFlag = "-t " // Note the space after -t
	}

	// @TODO for some reason this break-insert command stops working if we break sendGdbCommand call into operation, argument params
	result := sendGdbCommand(es.gdbSession,
		fmt.Sprintf("break-insert %v%v-f -c \"lineno == %v\" --source dontbug_break.c --line %v", temporaryFlag, disabledFlag, phpLineno, internalLineno))

	if result["class"] != "done" {
		warning := fmt.Sprintf("dontbug: Could not set breakpoint in gdb backend at %v:%v. Something is probably wrong with breakpoint parameters", phpFilename, phpLineno)
		color.Red(warning)
		return "", &engineBreakpointError{breakpointErrorCodeCouldNotSet, warning}
	}

	payload := result["payload"].(map[string]interface{})
	bkpt := payload["bkpt"].(map[string]interface{})
	id := bkpt["number"].(string)

	_, ok = es.breakpoints[id]
	if ok {
		log.Fatal("Breakpoint number returned by gdb not unique: ", id)
	}

	es.breakpoints[id] = &engineBreakPoint{
		id:        id,
		filename:  phpFilename,
		lineno:    phpLineno,
		state:     breakpointState,
		temporary: temporary,
		bpType:    breakpointTypeLine,
	}

	return id, nil
}

// Does not make an entry in breakpoints table
func setPhpStackDepthLevelBreakpointInGdb(es *engineState, level int) string {
	if level > es.maxStackDepth {
		log.Fatalf("Max stack depth is %v but asked to set breakpoint at depth %v\n", es.maxStackDepth, level+1)
	}
	line := es.levelAr[level]

	params := fmt.Sprintf("-f --source dontbug_break.c --line %v", line)
	result := sendGdbCommand(es.gdbSession, "break-insert", params)

	if result["class"] != "done" {
		log.Fatal("breakpoint was not set successfully in gdb backend. Command was:", "break-insert", params)
	}

	payload := result["payload"].(map[string]interface{})
	bkpt := payload["bkpt"].(map[string]interface{})
	id := bkpt["number"].(string)

	return id
}

func removeGdbBreakpoint(es *engineState, id string) {
	sendGdbCommand(es.gdbSession, "break-delete", id)
	_, ok := es.breakpoints[id]
	if ok {
		delete(es.breakpoints, id)
	}
}

func gotoMasterBpLocation(es *engineState, reverse bool) (string, bool) {
	enableGdbBreakpoint(es, dontbugMasterBp)
	id, ok := continueExecution(es, reverse)
	disableGdbBreakpoint(es, dontbugMasterBp)
	return id, ok
}
<commit_msg>[#4] Make a warning less confusing<commit_after>// Copyright © 2016 Sidharth Kshatriya
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package engine

import (
	"errors"
	"fmt"
	"github.com/fatih/color"
	"log"
	"strconv"
	"strings"
)

const (
	// The following are all PHP breakpoint types
	// Each PHP breakpoint has an entry in the DebugEngineState.Breakpoints table
	// *and* within GDB internally, of course
	breakpointTypeLine        engineBreakpointType = "line"
	breakpointTypeCall        engineBreakpointType = "call"
	breakpointTypeReturn      engineBreakpointType = "return"
	breakpointTypeException   engineBreakpointType = "exception"
	breakpointTypeConditional engineBreakpointType = "conditional"
	breakpointTypeWatch       engineBreakpointType = "watch"
	// This is a non-PHP breakpoint, i.e. a pure GDB breakpoint
	// Usually internal breakpoints are not stored in the DebugEngineState.Breakpoints table
	// They are usually created and thrown away on demand
	breakpointTypeInternal engineBreakpointType = "internal"

	breakpointHitCondGtEq engineBreakpointCondition = ">="
	breakpointHitCondEq   engineBreakpointCondition = "=="
	breakpointHitCondMod  engineBreakpointCondition = "%"

	breakpointStateDisabled engineBreakpointState = "disabled"
	breakpointStateEnabled  engineBreakpointState = "enabled"

	// Error codes returned when a user (php) breakpoint cannot be set
	breakpointErrorCodeCouldNotSet      engineBreakpointErrorCode = 200
	breakpointErrorCodeTypeNotSupported engineBreakpointErrorCode = 201
)

type engineBreakpointError struct {
	code    engineBreakpointErrorCode
	message string
}

type engineBreakpointType string
type engineBreakpointState string
type engineBreakpointCondition string
type engineBreakpointErrorCode int

type engineBreakPoint struct {
	id           string
	bpType       engineBreakpointType
	filename     string
	lineno       int
	state        engineBreakpointState
	temporary    bool
	hitCount     int
	hitValue     int
	hitCondition engineBreakpointCondition
	exception    string
	expression   string
}

func stringToBreakpointType(t string) (engineBreakpointType, error) {
	switch t {
	case "line":
		return breakpointTypeLine, nil
	case "call":
		return breakpointTypeCall, nil
	case "return":
		return breakpointTypeReturn, nil
	case "exception":
		return breakpointTypeException, nil
	case "conditional":
		return breakpointTypeConditional, nil
	case "watch":
		return breakpointTypeWatch, nil
	// Deliberately omit the internal breakpoint type
	default:
		return "", errors.New("Unknown breakpoint type")
	}
}

// @TODO what about multiple breakpoints on the same c source code line?
func breakpointStopGetID(notification map[string]interface{}) (string, bool) {
	class, ok := notification["class"].(string)
	if !ok || class != "stopped" {
		return "", false
	}

	payload, ok := notification["payload"].(map[string]interface{})
	if !ok {
		return "", false
	}

	breakPointNumString, ok := payload["bkptno"].(string)
	if !ok {
		return "", false
	}

	reason, ok := payload["reason"].(string)
	if !ok || reason != "breakpoint-hit" {
		return "", false
	}

	return breakPointNumString, true
}

func handleBreakpointUpdate(es *engineState, dCmd dbgpCmd) string {
	d, ok := dCmd.options["d"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint number for breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["n"]
	if ok {
		panicWith(fmt.Sprint("Line number updates are currently unsupported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["h"]
	if ok {
		panicWith(fmt.Sprint("Hit condition/value update is currently not supported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	_, ok = dCmd.options["o"]
	if ok {
		panicWith(fmt.Sprint("Hit condition/value update is currently not supported in breakpoint_update. Got:", dCmd.fullCommand))
	}

	s, ok := dCmd.options["s"]
	if !ok {
		panicWith(fmt.Sprint("Please provide new breakpoint status in breakpoint_update. Got:", dCmd.fullCommand))
	}

	if s == "disabled" {
		disableGdbBreakpoint(es, d)
	} else if s == "enabled" {
		enableGdbBreakpoint(es, d)
	} else {
		panicWith(fmt.Sprintf("Unknown breakpoint status %v for breakpoint_update", s))
	}

	return fmt.Sprintf(gBreakpointRemoveOrUpdateXMLResponseFormat, "breakpoint_update", dCmd.seqNum)
}

func handleBreakpointRemove(es *engineState, dCmd dbgpCmd) string {
	d, ok := dCmd.options["d"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint id to remove. Got:", dCmd.fullCommand))
	}

	removeGdbBreakpoint(es, d)

	return fmt.Sprintf(gBreakpointRemoveOrUpdateXMLResponseFormat, "breakpoint_remove", dCmd.seqNum)
}

func handleBreakpointSetLineBreakpoint(es *engineState, dCmd dbgpCmd) string {
	phpFilename, ok := dCmd.options["f"]
	if !ok {
		panicWith(fmt.Sprint("Please provide filename option -f in breakpoint_set. Got: ", dCmd.fullCommand))
	}

	status, ok := dCmd.options["s"]
	disabled := false
	if ok {
		if status == "disabled" {
			disabled = true
		} else if status != "enabled" {
			panicWith("Unknown breakpoint status: " + status)
		}
	} else {
		status = "enabled"
	}

	phpLinenoString, ok := dCmd.options["n"]
	if !ok {
		panicWith(fmt.Sprint("Please provide line number option -n in breakpoint_set. Got:", dCmd.fullCommand))
	}

	r, ok := dCmd.options["r"]
	temporary := false
	if ok && r == "1" {
		temporary = true
	}

	_, ok = dCmd.options["h"]
	if ok {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Hit condition/value is currently not supported")
	}

	_, ok = dCmd.options["o"]
	if ok {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Hit condition/value is currently not supported")
	}

	phpLineno, err := strconv.Atoi(phpLinenoString)
	panicIf(err)

	id, breakErr := setPhpBreakpointInGdb(es, phpFilename, phpLineno, disabled, temporary)
	if breakErr != nil {
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakErr.code, breakErr.message)
	}

	return fmt.Sprintf(gBreakpointSetLineXMLResponseFormat, dCmd.seqNum, status, id)
}

func handleBreakpointSet(es *engineState, dCmd dbgpCmd) string {
	t, ok := dCmd.options["t"]
	if !ok {
		panicWith(fmt.Sprint("Please provide breakpoint type option -t in breakpoint_set. Got:", dCmd.fullCommand))
	}

	tt, err := stringToBreakpointType(t)
	panicIf(err)

	switch tt {
	case breakpointTypeLine:
		return handleBreakpointSetLineBreakpoint(es, dCmd)
	default:
		return fmt.Sprintf(gErrorXMLResponseFormat, "breakpoint_set", dCmd.seqNum, breakpointErrorCodeTypeNotSupported, "Breakpoint type "+tt+" is not supported")
	}
}

func getEnabledPhpBreakpoints(es *engineState) []string {
	var enabledPhpBreakpoints []string
	for name, bp := range es.breakpoints {
		if bp.state == breakpointStateEnabled && bp.bpType != breakpointTypeInternal {
			enabledPhpBreakpoints = append(enabledPhpBreakpoints, name)
		}
	}

	return enabledPhpBreakpoints
}

func isEnabledPhpBreakpoint(es *engineState, id string) bool {
	for name, bp := range es.breakpoints {
		if name == id && bp.state == breakpointStateEnabled && bp.bpType != breakpointTypeInternal {
			return true
		}
	}

	return false
}

func isEnabledPhpTemporaryBreakpoint(es *engineState, id string) bool {
	for name, bp := range es.breakpoints {
		if name == id &&
			bp.state == breakpointStateEnabled &&
			bp.bpType != breakpointTypeInternal &&
			bp.temporary {
			return true
		}
	}

	return false
}

func disableGdbBreakpoints(es *engineState, bpList []string) {
	if len(bpList) > 0 {
		commandArgs := fmt.Sprintf("%v", strings.Join(bpList, " "))
		sendGdbCommand(es.gdbSession, "break-disable", commandArgs)
		for _, el := range bpList {
			bp, ok := es.breakpoints[el]
			if ok {
				bp.state = breakpointStateDisabled
			}
		}
	}
}

// convenience function
func disableGdbBreakpoint(es *engineState, bp string) {
	disableGdbBreakpoints(es, []string{bp})
}

// Note that not all "internal" breakpoints are stored in the breakpoints table
func disableAllGdbBreakpoints(es *engineState) {
	sendGdbCommand(es.gdbSession, "break-disable")
	for _, bp := range es.breakpoints {
		bp.state = breakpointStateDisabled
	}
}

func enableAllGdbBreakpoints(es *engineState) {
	sendGdbCommand(es.gdbSession, "break-enable")
	for _, bp := range es.breakpoints {
		bp.state = breakpointStateEnabled
	}
}

func enableGdbBreakpoints(es *engineState, bpList []string) {
	if len(bpList) > 0 {
		commandArgs := fmt.Sprintf("%v", strings.Join(bpList, " "))
		sendGdbCommand(es.gdbSession, "break-enable", commandArgs)
		for _, el := range bpList {
			bp, ok := es.breakpoints[el]
			if ok {
				bp.state = breakpointStateEnabled
			}
		}
	}
}

func getAssocEnabledPhpBreakpoint(es *engineState, filename string, lineno int) (string, bool) {
	for name, bp := range es.breakpoints {
		if bp.filename == filename &&
			bp.lineno == lineno &&
			bp.state == breakpointStateEnabled &&
			bp.bpType != breakpointTypeInternal {
			return name, true
		}
	}

	return "", false
}

// convenience function
func enableGdbBreakpoint(es *engineState, bp string) {
	enableGdbBreakpoints(es, []string{bp})
}

// Sets an equivalent breakpoint in gdb for PHP
// Also inserts the breakpoint into es.Breakpoints table
func setPhpBreakpointInGdb(es *engineState, phpFilename string, phpLineno int, disabled bool, temporary bool) (string, *engineBreakpointError) {
	internalLineno, ok := es.sourceMap[phpFilename]
	if !ok {
		warning := fmt.Sprintf("dontbug: [This warning is usually harmless and can be ignored] Warning: Not able to find %v to add a breakpoint. The IDE is either trying to set a breakpoint for a file from a different project or the root directory command line parameter was not specified correctly.", phpFilename)
		color.Yellow(warning)
		return "", &engineBreakpointError{breakpointErrorCodeCouldNotSet, warning}
	}

	breakpointState := breakpointStateEnabled
	disabledFlag := ""
	if disabled {
		disabledFlag = "-d " // Note the space after -d
		breakpointState = breakpointStateDisabled
	}

	temporaryFlag := ""
	if temporary {
		temporaryFlag = "-t " // Note the space after -t
	}

	// @TODO for some reason this break-insert command stops working if we break sendGdbCommand call into operation, argument params
	result := sendGdbCommand(es.gdbSession,
		fmt.Sprintf("break-insert %v%v-f -c \"lineno == %v\" --source dontbug_break.c --line %v", temporaryFlag, disabledFlag, phpLineno, internalLineno))

	if result["class"] != "done" {
		warning := fmt.Sprintf("dontbug: Could not set breakpoint in gdb backend at %v:%v. Something is probably wrong with breakpoint parameters", phpFilename, phpLineno)
		color.Red(warning)
		return "", &engineBreakpointError{breakpointErrorCodeCouldNotSet, warning}
	}

	payload := result["payload"].(map[string]interface{})
	bkpt := payload["bkpt"].(map[string]interface{})
	id := bkpt["number"].(string)

	_, ok = es.breakpoints[id]
	if ok {
		log.Fatal("Breakpoint number returned by gdb not unique: ", id)
	}

	es.breakpoints[id] = &engineBreakPoint{
		id:        id,
		filename:  phpFilename,
		lineno:    phpLineno,
		state:     breakpointState,
		temporary: temporary,
		bpType:    breakpointTypeLine,
	}

	return id, nil
}

// Does not make an entry in breakpoints table
func setPhpStackDepthLevelBreakpointInGdb(es *engineState, level int) string {
	if level > es.maxStackDepth {
		log.Fatalf("Max stack depth is %v but asked to set breakpoint at depth %v\n", es.maxStackDepth, level+1)
	}
	line := es.levelAr[level]

	params := fmt.Sprintf("-f --source dontbug_break.c --line %v", line)
	result := sendGdbCommand(es.gdbSession, "break-insert", params)

	if result["class"] != "done" {
		log.Fatal("breakpoint was not set successfully in gdb backend. Command was:", "break-insert", params)
	}

	payload := result["payload"].(map[string]interface{})
	bkpt := payload["bkpt"].(map[string]interface{})
	id := bkpt["number"].(string)

	return id
}

func removeGdbBreakpoint(es *engineState, id string) {
	sendGdbCommand(es.gdbSession, "break-delete", id)
	_, ok := es.breakpoints[id]
	if ok {
		delete(es.breakpoints, id)
	}
}

func gotoMasterBpLocation(es *engineState, reverse bool) (string, bool) {
	enableGdbBreakpoint(es, dontbugMasterBp)
	id, ok := continueExecution(es, reverse)
	disableGdbBreakpoint(es, dontbugMasterBp)
	return id, ok
}
<|endoftext|>


<commit_before>package response

import (
	"encoding/xml"
	"errors"
	"net/http"
	"reflect"

	"github.com/codegangsta/inject"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/encoder"
)

type wrappedResponseWriter struct {
	http.ResponseWriter

	statusCode int
}

func newWrappedResponseWriter(w http.ResponseWriter) *wrappedResponseWriter {
	wr := &wrappedResponseWriter{ResponseWriter: w}
	return wr
}

func (wr *wrappedResponseWriter) WriteHeader(code int) {
	wr.WriteHeader(code)
	wr.statusCode = code
}

type errorResponse struct {
	XMLName xml.Name `json:"-" xml:"error"`
	Error   int      `json:"error" xml:"code"`
	Message string   `json:"message" xml:"message"`
}

func NewEncoder() martini.Handler {
	return func(c martini.Context, w http.ResponseWriter) {
		wrappedWriter := newWrappedResponseWriter(w)
		c.MapTo(wrappedWriter, (*http.ResponseWriter)(nil))

		returnHandler := func(ctx martini.Context, vals []reflect.Value) {
			rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
			res := rv.Interface().(http.ResponseWriter)
			var responseVal reflect.Value
			if len(vals) > 1 && vals[0].Kind() == reflect.Int {
				res.WriteHeader(int(vals[0].Int()))
				responseVal = vals[1]
			} else if len(vals) > 0 {
				responseVal = vals[0]
			}
			if isNil(responseVal) {
				wrappedRes := res.(*wrappedResponseWriter)
				code := wrappedRes.statusCode
				if code == 0 {
					panic(errors.New("No return code set for error"))
				}
				responseVal = reflect.ValueOf(errorResponse{Error: code, Message: http.StatusText(code)})
			}
			if canDeref(responseVal) {
				responseVal = responseVal.Elem()
			}
			if isByteSlice(responseVal) {
				res.Write(responseVal.Bytes())
			} else if isStruct(responseVal) || isStructSlice(responseVal) {
				encv := ctx.Get(inject.InterfaceOf((*encoder.Encoder)(nil)))
				enc := encv.Interface().(encoder.Encoder)
				res.Write(encoder.Must(enc.Encode(responseVal.Interface())))
			} else {
				res.Write([]byte(responseVal.String()))
			}
		}
		c.MapTo(returnHandler, (*martini.ReturnHandler)(nil))
	}
}

func isByteSlice(val reflect.Value) bool {
	return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
}

func isStruct(val reflect.Value) bool {
	return val.Kind() == reflect.Struct
}

func isStructSlice(val reflect.Value) bool {
	return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Struct
}

func isNil(val reflect.Value) bool {
	return val.Kind() == reflect.Invalid
}

func canDeref(val reflect.Value) bool {
	return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
}
<commit_msg>Had wrong mapping types for martini.ReturnHandler)<commit_after>package response

import (
	"encoding/xml"
	"errors"
	"net/http"
	"reflect"

	"github.com/codegangsta/inject"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/encoder"
)

type wrappedResponseWriter struct {
	http.ResponseWriter

	statusCode int
}

func newWrappedResponseWriter(w http.ResponseWriter) *wrappedResponseWriter {
	wr := &wrappedResponseWriter{ResponseWriter: w}
	return wr
}

func (wr *wrappedResponseWriter) WriteHeader(code int) {
	wr.WriteHeader(code)
	wr.statusCode = code
}

type errorResponse struct {
	XMLName xml.Name `json:"-" xml:"error"`
	Error   int      `json:"error" xml:"code"`
	Message string   `json:"message" xml:"message"`
}

func NewEncoder() martini.Handler {
	return func(c martini.Context, w http.ResponseWriter) {
		wrappedWriter := newWrappedResponseWriter(w)
		c.MapTo(wrappedWriter, (*http.ResponseWriter)(nil))

		var rtnHandler martini.ReturnHandler
		rtnHandler = func(ctx martini.Context, vals []reflect.Value) {
			rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
			res := rv.Interface().(http.ResponseWriter)
			var responseVal reflect.Value
			if len(vals) > 1 && vals[0].Kind() == reflect.Int {
				res.WriteHeader(int(vals[0].Int()))
				responseVal = vals[1]
			} else if len(vals) > 0 {
				responseVal = vals[0]
			}
			if isNil(responseVal) {
				wrappedRes := res.(*wrappedResponseWriter)
				code := wrappedRes.statusCode
				if code == 0 {
					panic(errors.New("No return code set for error"))
				}
				responseVal = reflect.ValueOf(errorResponse{Error: code, Message: http.StatusText(code)})
			}
			if canDeref(responseVal) {
				responseVal = responseVal.Elem()
			}
			if isByteSlice(responseVal) {
				res.Write(responseVal.Bytes())
			} else if isStruct(responseVal) || isStructSlice(responseVal) {
				encv := ctx.Get(inject.InterfaceOf((*encoder.Encoder)(nil)))
				enc := encv.Interface().(encoder.Encoder)
				res.Write(encoder.Must(enc.Encode(responseVal.Interface())))
			} else {
				res.Write([]byte(responseVal.String()))
			}
		}
		c.Map(rtnHandler)
	}
}

func isByteSlice(val reflect.Value) bool {
	return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
}

func isStruct(val reflect.Value) bool {
	return val.Kind() == reflect.Struct
}

func isStructSlice(val reflect.Value) bool {
	return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Struct
}

func isNil(val reflect.Value) bool {
	return val.Kind() == reflect.Invalid
}

func canDeref(val reflect.Value) bool {
	return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
}
<|endoftext|>


<commit_before>// Copyright ©2015 The gonum 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 lapack64 provides a set of convenient wrapper functions for LAPACK
// calls, as specified in the netlib standard (www.netlib.org).
//
// The native Go routines are used by default, and the Use function can be used
// to set an alternate implementation.
//
// If the type of matrix (General, Symmetric, etc.) is known and fixed, it is
// used in the wrapper signature. In many cases, however, the type of the matrix
// changes during the call to the routine, for example the matrix is symmetric on
// entry and is triangular on exit. In these cases the correct types should be checked
// in the documentation.
//
// The full set of Lapack functions is very large, and it is not clear that a
// full implementation is desirable, let alone feasible. Please open up an issue
// if there is a specific function you need and/or are willing to implement.
package lapack64

import (
	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/lapack"
	"github.com/gonum/lapack/native"
)

var lapack64 lapack.Float64 = native.Implementation{}

// Use sets the LAPACK float64 implementation to be used by subsequent BLAS calls.
// The default implementation is native.Implementation.
func Use(l lapack.Float64) {
	lapack64 = l
}

// Potrf computes the cholesky factorization of a.
//  A = U^T * U if ul == blas.Upper
//  A = L * L^T if ul == blas.Lower
// The underlying data between the input matrix and output matrix is shared.
func Potrf(a blas64.Symmetric) (t blas64.Triangular, ok bool) {
	ok = lapack64.Dpotrf(a.Uplo, a.N, a.Data, a.Stride)
	t.Uplo = a.Uplo
	t.N = a.N
	t.Data = a.Data
	t.Stride = a.Stride
	t.Diag = blas.NonUnit
	return
}

// Gels finds a minimum-norm solution based on the matrices A and B using the
// QR or LQ factorization. Dgels returns false if the matrix
// A is singular, and true if this solution was successfully found.
//
// The minimization problem solved depends on the input parameters.
//
//  1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2
//     is minimized.
//  2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of
//     A * X = B.
//  3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of
//     A^T * X = B.
//  4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2
//     is minimized.
// Note that the least-squares solutions (cases 1 and 3) perform the minimization
// per column of B. This is not the same as finding the minimum-norm matrix.
//
// The matrix A is a general matrix of size m×n and is modified during this call.
// The input matrix B is of size max(m,n)×nrhs, and serves two purposes. On entry,
// the elements of b specify the input matrix B. B has size m×nrhs if
// trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the
// leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans,
// this submatrix is of size n×nrhs, and of size m×nrhs otherwise.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic
// otherwise. A longer work will enable blocked algorithms to be called.
// In the special case that lwork == -1, work[0] will be set to the optimal working
// length.
func Gels(trans blas.Transpose, a blas64.General, b blas64.General, work []float64, lwork int) bool {
	return lapack64.Dgels(trans, a.Rows, a.Cols, b.Cols, a.Data, a.Stride, b.Data, b.Stride, work, lwork)
}

// Geqrf computes the QR factorization of the m×n matrix A using a blocked
// algorithm. A is modified to contain the information to construct Q and R.
// The upper triangle of a contains the matrix R. The lower triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length at least min(m,n), and
// this function will panic otherwise.
//
// The ith elementary reflector can be explicitly constructed by first extracting
// the
//  v[j] = 0           j < i
//  v[j] = i           j == i
//  v[j] = a[i*lda+j]  j > i
// and computing h_i = I - tau[i] * v * v^T.
//
// The orthonormal matrix Q can be constucted from a product of these elementary
// reflectors, Q = H_1*H_2 ... H_k, where k = min(m,n).
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m and this function will panic otherwise.
// Dgeqrf is a blocked QR factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Geqrf,
// the optimal work length will be stored into work[0].
func Geqrf(a blas64.General, tau, work []float64, lwork int) {
	lapack64.Dgeqrf(a.Rows, a.Cols, a.Data, a.Stride, tau, work, lwork)
}

// Gelqf computes the QR factorization of the m×n matrix A using a blocked
// algorithm. A is modified to contain the information to construct L and Q.
// The lower triangle of a contains the matrix L. The lower triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length at least min(m,n), and
// this function will panic otherwise.
//
// See Geqrf for a description of the elementary reflectors and orthonormal
// matrix Q. Q is constructed as a product of these elementary reflectors,
// Q = H_k ... H_2*H_1.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m and this function will panic otherwise.
// Dgeqrf is a blocked LQ factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Gelqf,
// the optimal work length will be stored into work[0].
func Gelqf(a blas64.General, tau, work []float64, lwork int) {
	lapack64.Dgelqf(a.Rows, a.Cols, a.Data, a.Stride, tau, work, lwork)
}

// Getrf computes the LU decomposition of the m×n matrix A.
// The LU decomposition is a factorization of A into
//  A = P * L * U
// where P is a permutation matrix, L is a unit lower triangular matrix, and
// U is a (usually) non-unit upper triangular matrix. On exit, L and U are stored
// in place into a.
//
// ipiv is a permutation vector. It indicates that row i of the matrix was
// changed with ipiv[i]. ipiv must have length at least min(m,n), and will panic
// otherwise. ipiv is zero-indexed.
//
// Dgetrf is the blocked version of the algorithm.
//
// Dgetrf returns whether the matrix A is singular. The LU decomposition will
// be computed regardless of the singularity of A, but division by zero
// will occur if the false is returned and the result is used to solve a
// system of equations.
func Getrf(a blas64.General, ipiv []int) bool {
	return lapack64.Dgetrf(a.Rows, a.Cols, a.Data, a.Stride, ipiv)
}

// Dgetrs solves a system of equations using an LU factorization.
// The system of equations solved is
//  A * X = B if trans == blas.Trans
//  A^T * X = B if trans == blas.NoTrans
// A is a general n×n matrix with stride lda. B is a general matrix of size n×nrhs.
//
// On entry b contains the elements of the matrix B. On exit, b contains the
// elements of X, the solution to the system of equations.
//
// a and ipiv contain the LU factorization of A and the permutation indices as
// computed by Getrf. ipiv is zero-indexed.
func Getrs(trans blas.Transpose, a blas64.General, b blas64.General, ipiv []int) {
	lapack64.Dgetrs(trans, a.Cols, b.Cols, a.Data, a.Stride, ipiv, b.Data, b.Stride)
}

// Ormlq multiplies the matrix C by the othogonal matrix Q defined by
// A and tau. A and tau are as returned from Gelqf.
//  C = Q * C    if side == blas.Left and trans == blas.NoTrans
//  C = Q^T * C  if side == blas.Left and trans == blas.Trans
//  C = C * Q    if side == blas.Right and trans == blas.NoTrans
//  C = C * Q^T  if side == blas.Right and trans == blas.Trans
// If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right
// A is of size k×n. This uses a blocked algorithm.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Ormlq uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Ormlq,
// the optimal work length will be stored into work[0].
//
// Tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
func Ormlq(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) {
	lapack64.Dormlq(side, trans, c.Rows, c.Cols, a.Rows, a.Data, a.Stride, tau, c.Data, c.Stride, work, lwork)
}

// Ormqr multiplies the matrix C by the othogonal matrix Q defined by
// A and tau. A and tau are as returned from Geqrf.
//  C = Q * C    if side == blas.Left and trans == blas.NoTrans
//  C = Q^T * C  if side == blas.Left and trans == blas.Trans
//  C = C * Q    if side == blas.Right and trans == blas.NoTrans
//  C = C * Q^T  if side == blas.Right and trans == blas.Trans
// If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right
// A is of size k×n. This uses a blocked algorithm.
//
// tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Ormqr uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Ormqr,
// the optimal work length will be stored into work[0].
func Ormqr(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) {
	lapack64.Dormqr(side, trans, c.Rows, c.Cols, a.Cols, a.Data, a.Stride, tau, c.Data, c.Stride, work, lwork)
}

// Trtrs solves a triangular system of the form A * X = B or A^T * X = B. Trtrs
// returns whether the solve completed successfully. If A is singular, no solve is performed.
func Trtrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, a blas64.Triangular, b blas64.General) (ok bool) {
	return lapack64.Dtrtrs(uplo, trans, diag, a.N, b.Cols, a.Data, a.Stride, b.Data, b.Stride)
}
<commit_msg>Remove unnecessary inputs to Trtrs in lapack64<commit_after>// Copyright ©2015 The gonum 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 lapack64 provides a set of convenient wrapper functions for LAPACK
// calls, as specified in the netlib standard (www.netlib.org).
//
// The native Go routines are used by default, and the Use function can be used
// to set an alternate implementation.
//
// If the type of matrix (General, Symmetric, etc.) is known and fixed, it is
// used in the wrapper signature. In many cases, however, the type of the matrix
// changes during the call to the routine, for example the matrix is symmetric on
// entry and is triangular on exit. In these cases the correct types should be checked
// in the documentation.
//
// The full set of Lapack functions is very large, and it is not clear that a
// full implementation is desirable, let alone feasible. Please open up an issue
// if there is a specific function you need and/or are willing to implement.
package lapack64

import (
	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/lapack"
	"github.com/gonum/lapack/native"
)

var lapack64 lapack.Float64 = native.Implementation{}

// Use sets the LAPACK float64 implementation to be used by subsequent BLAS calls.
// The default implementation is native.Implementation.
func Use(l lapack.Float64) {
	lapack64 = l
}

// Potrf computes the cholesky factorization of a.
//  A = U^T * U if ul == blas.Upper
//  A = L * L^T if ul == blas.Lower
// The underlying data between the input matrix and output matrix is shared.
func Potrf(a blas64.Symmetric) (t blas64.Triangular, ok bool) {
	ok = lapack64.Dpotrf(a.Uplo, a.N, a.Data, a.Stride)
	t.Uplo = a.Uplo
	t.N = a.N
	t.Data = a.Data
	t.Stride = a.Stride
	t.Diag = blas.NonUnit
	return
}

// Gels finds a minimum-norm solution based on the matrices A and B using the
// QR or LQ factorization. Dgels returns false if the matrix
// A is singular, and true if this solution was successfully found.
//
// The minimization problem solved depends on the input parameters.
//
//  1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2
//     is minimized.
//  2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of
//     A * X = B.
//  3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of
//     A^T * X = B.
//  4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2
//     is minimized.
// Note that the least-squares solutions (cases 1 and 3) perform the minimization
// per column of B. This is not the same as finding the minimum-norm matrix.
//
// The matrix A is a general matrix of size m×n and is modified during this call.
// The input matrix B is of size max(m,n)×nrhs, and serves two purposes. On entry,
// the elements of b specify the input matrix B. B has size m×nrhs if
// trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the
// leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans,
// this submatrix is of size n×nrhs, and of size m×nrhs otherwise.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic
// otherwise. A longer work will enable blocked algorithms to be called.
// In the special case that lwork == -1, work[0] will be set to the optimal working
// length.
func Gels(trans blas.Transpose, a blas64.General, b blas64.General, work []float64, lwork int) bool {
	return lapack64.Dgels(trans, a.Rows, a.Cols, b.Cols, a.Data, a.Stride, b.Data, b.Stride, work, lwork)
}

// Geqrf computes the QR factorization of the m×n matrix A using a blocked
// algorithm. A is modified to contain the information to construct Q and R.
// The upper triangle of a contains the matrix R. The lower triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length at least min(m,n), and
// this function will panic otherwise.
//
// The ith elementary reflector can be explicitly constructed by first extracting
// the
//  v[j] = 0           j < i
//  v[j] = i           j == i
//  v[j] = a[i*lda+j]  j > i
// and computing h_i = I - tau[i] * v * v^T.
//
// The orthonormal matrix Q can be constucted from a product of these elementary
// reflectors, Q = H_1*H_2 ... H_k, where k = min(m,n).
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m and this function will panic otherwise.
// Dgeqrf is a blocked QR factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Geqrf,
// the optimal work length will be stored into work[0].
func Geqrf(a blas64.General, tau, work []float64, lwork int) {
	lapack64.Dgeqrf(a.Rows, a.Cols, a.Data, a.Stride, tau, work, lwork)
}

// Gelqf computes the QR factorization of the m×n matrix A using a blocked
// algorithm. A is modified to contain the information to construct L and Q.
// The lower triangle of a contains the matrix L. The lower triangular elements
// (not including the diagonal) contain the elementary reflectors. Tau is modified
// to contain the reflector scales. Tau must have length at least min(m,n), and
// this function will panic otherwise.
//
// See Geqrf for a description of the elementary reflectors and orthonormal
// matrix Q. Q is constructed as a product of these elementary reflectors,
// Q = H_k ... H_2*H_1.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m and this function will panic otherwise.
// Dgeqrf is a blocked LQ factorization, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Gelqf,
// the optimal work length will be stored into work[0].
func Gelqf(a blas64.General, tau, work []float64, lwork int) {
	lapack64.Dgelqf(a.Rows, a.Cols, a.Data, a.Stride, tau, work, lwork)
}

// Getrf computes the LU decomposition of the m×n matrix A.
// The LU decomposition is a factorization of A into
//  A = P * L * U
// where P is a permutation matrix, L is a unit lower triangular matrix, and
// U is a (usually) non-unit upper triangular matrix. On exit, L and U are stored
// in place into a.
//
// ipiv is a permutation vector. It indicates that row i of the matrix was
// changed with ipiv[i]. ipiv must have length at least min(m,n), and will panic
// otherwise. ipiv is zero-indexed.
//
// Dgetrf is the blocked version of the algorithm.
//
// Dgetrf returns whether the matrix A is singular. The LU decomposition will
// be computed regardless of the singularity of A, but division by zero
// will occur if the false is returned and the result is used to solve a
// system of equations.
func Getrf(a blas64.General, ipiv []int) bool {
	return lapack64.Dgetrf(a.Rows, a.Cols, a.Data, a.Stride, ipiv)
}

// Dgetrs solves a system of equations using an LU factorization.
// The system of equations solved is
//  A * X = B if trans == blas.Trans
//  A^T * X = B if trans == blas.NoTrans
// A is a general n×n matrix with stride lda. B is a general matrix of size n×nrhs.
//
// On entry b contains the elements of the matrix B. On exit, b contains the
// elements of X, the solution to the system of equations.
//
// a and ipiv contain the LU factorization of A and the permutation indices as
// computed by Getrf. ipiv is zero-indexed.
func Getrs(trans blas.Transpose, a blas64.General, b blas64.General, ipiv []int) {
	lapack64.Dgetrs(trans, a.Cols, b.Cols, a.Data, a.Stride, ipiv, b.Data, b.Stride)
}

// Ormlq multiplies the matrix C by the othogonal matrix Q defined by
// A and tau. A and tau are as returned from Gelqf.
//  C = Q * C    if side == blas.Left and trans == blas.NoTrans
//  C = Q^T * C  if side == blas.Left and trans == blas.Trans
//  C = C * Q    if side == blas.Right and trans == blas.NoTrans
//  C = C * Q^T  if side == blas.Right and trans == blas.Trans
// If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right
// A is of size k×n. This uses a blocked algorithm.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Ormlq uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Ormlq,
// the optimal work length will be stored into work[0].
//
// Tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
func Ormlq(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) {
	lapack64.Dormlq(side, trans, c.Rows, c.Cols, a.Rows, a.Data, a.Stride, tau, c.Data, c.Stride, work, lwork)
}

// Ormqr multiplies the matrix C by the othogonal matrix Q defined by
// A and tau. A and tau are as returned from Geqrf.
//  C = Q * C    if side == blas.Left and trans == blas.NoTrans
//  C = Q^T * C  if side == blas.Left and trans == blas.Trans
//  C = C * Q    if side == blas.Right and trans == blas.NoTrans
//  C = C * Q^T  if side == blas.Right and trans == blas.Trans
// If side == blas.Left, A is a matrix of side k×m, and if side == blas.Right
// A is of size k×n. This uses a blocked algorithm.
//
// tau contains the householder scales and must have length at least k, and
// this function will panic otherwise.
//
// Work is temporary storage, and lwork specifies the usable memory length.
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
// and this function will panic otherwise.
// Ormqr uses a block algorithm, but the block size is limited
// by the temporary space available. If lwork == -1, instead of performing Ormqr,
// the optimal work length will be stored into work[0].
func Ormqr(side blas.Side, trans blas.Transpose, a blas64.General, tau []float64, c blas64.General, work []float64, lwork int) {
	lapack64.Dormqr(side, trans, c.Rows, c.Cols, a.Cols, a.Data, a.Stride, tau, c.Data, c.Stride, work, lwork)
}

// Trtrs solves a triangular system of the form A * X = B or A^T * X = B. Trtrs
// returns whether the solve completed successfully. If A is singular, no solve is performed.
func Trtrs(trans blas.Transpose, a blas64.Triangular, b blas64.General) (ok bool) {
	return lapack64.Dtrtrs(a.Uplo, trans, a.Diag, a.N, b.Cols, a.Data, a.Stride, b.Data, b.Stride)
}
<|endoftext|>


<commit_before>package sockjsclient

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"sync"
)

// the implementation of New() doesn't have any error to be returned yet it
// returns, so it's totally safe to neglect the error
var cookieJar, _ = cookiejar.New(nil)

type XHRSession struct {
	mu sync.Mutex

	client     *http.Client
	sessionURL string
	sessionID  string
	messages   []string
	opened     bool
}

// NewXHRSession returns a new XHRSession, a SockJS client which supports
// xhr-polling
// http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-74
func NewXHRSession(opts *DialOptions) (*XHRSession, error) {
	client := &http.Client{
		// never make it less than the heartbeat delay from the sockjs server.
		// If this is los, your requests to the server will time out, so you'll
		// never receive the heartbeat frames.
		Timeout: opts.Timeout,
		// add this so we can make use of load balancer's sticky session features,
		// such as AWS ELB
		Jar: cookieJar,
	}

	// following /server_id/session_id should always be the same for every session
	serverID := threeDigits()
	sessionID := randomStringLength(20)
	sessionURL := opts.BaseURL + "/" + serverID + "/" + sessionID

	// start the initial session handshake
	sessionResp, err := client.Post(sessionURL+"/xhr", "text/plain", nil)
	if err != nil {
		return nil, err
	}
	defer sessionResp.Body.Close()

	buf := bufio.NewReader(sessionResp.Body)
	frame, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}

	if frame != 'o' {
		return nil, fmt.Errorf("can't start session, invalid frame: %s", frame)
	}

	return &XHRSession{
		client:     client,
		sessionID:  sessionID,
		sessionURL: sessionURL,
		opened:     true,
	}, nil
}

func (x *XHRSession) ID() string {
	return x.sessionID
}

func (x *XHRSession) Recv() (string, error) {
	// Return previously received messages if there is any.
	if len(x.messages) > 0 {
		msg := x.messages[0]
		x.messages = x.messages[1:]
		return msg, nil
	}

	// start to poll from the server until we receive something
	for {
		resp, err := x.client.Post(x.sessionURL+"/xhr", "text/plain", nil)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()

		buf := bufio.NewReader(resp.Body)

		// returns an error if buffer is empty
		frame, err := buf.ReadByte()
		if err != nil {
			return "", err
		}

		switch frame {
		case 'o':
			// session started
			x.mu.Lock()
			x.opened = true
			x.mu.Unlock()
			continue
		case 'a':
			// received an array of messages
			data, err := ioutil.ReadAll(buf)
			if err != nil {
				return "", err
			}

			var messages []string
			err = json.Unmarshal(data, &messages)
			if err != nil {
				return "", err
			}

			x.messages = append(x.messages, messages...)

			if len(x.messages) == 0 {
				return "", errors.New("no message")
			}

			// Return first message in slice, and remove it from the slice, so
			// next time the others will be picked
			msg := x.messages[0]
			x.messages = x.messages[1:]

			return msg, nil
		case 'h':
			// heartbeat received
			continue
		case 'c':
			x.mu.Lock()
			x.opened = false
			x.mu.Unlock()
			return "", errors.New("session closed")
		default:
			return "", errors.New("invalid frame type")
		}
	}

	return "", errors.New("FATAL: If we get here, please revisit the logic again")
}

func (x *XHRSession) Send(frame string) error {
	x.mu.Lock()
	if !x.opened {
		x.mu.Unlock()
		return errors.New("session is not opened yet")
	}
	x.mu.Unlock()

	// Need's to be JSON encoded array of string messages (SockJS protocol
	// requirement)
	message := []string{frame}
	body, err := json.Marshal(&message)
	if err != nil {
		return err
	}

	resp, err := x.client.Post(x.sessionURL+"/xhr_send", "text/plain", bytes.NewReader(body))
	if err != nil {
		return err
	}

	if resp.StatusCode == 404 {
		return errors.New("XHR session doesn't exists")
	}

	if resp.StatusCode != 204 {
		return fmt.Errorf("Sending failed: %d", resp.StatusCode)
	}

	return nil
}

func (x *XHRSession) Close(status uint32, reason string) error {
	return nil
}
<commit_msg>sockjsclient: needs to be compliance with the protocol<commit_after>package sockjsclient

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"sync"
)

// the implementation of New() doesn't have any error to be returned yet it
// returns, so it's totally safe to neglect the error
var cookieJar, _ = cookiejar.New(nil)

type XHRSession struct {
	mu sync.Mutex

	client     *http.Client
	sessionURL string
	sessionID  string
	messages   []string
	opened     bool
}

// NewXHRSession returns a new XHRSession, a SockJS client which supports
// xhr-polling
// http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-74
func NewXHRSession(opts *DialOptions) (*XHRSession, error) {
	client := &http.Client{
		// never make it less than the heartbeat delay from the sockjs server.
		// If this is los, your requests to the server will time out, so you'll
		// never receive the heartbeat frames.
		Timeout: opts.Timeout,
		// add this so we can make use of load balancer's sticky session features,
		// such as AWS ELB
		Jar: cookieJar,
	}

	// following /server_id/session_id should always be the same for every session
	serverID := threeDigits()
	sessionID := randomStringLength(20)
	sessionURL := opts.BaseURL + "/" + serverID + "/" + sessionID

	// start the initial session handshake
	sessionResp, err := client.Post(sessionURL+"/xhr", "text/plain", nil)
	if err != nil {
		return nil, err
	}
	defer sessionResp.Body.Close()

	if sessionResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Starting new session failed. Want: %d Got: %d",
			http.StatusOK, sessionResp.StatusCode)
	}

	buf := bufio.NewReader(sessionResp.Body)
	frame, err := buf.ReadByte()
	if err != nil {
		return nil, err
	}

	if frame != 'o' {
		return nil, fmt.Errorf("can't start session, invalid frame: %s", frame)
	}

	return &XHRSession{
		client:     client,
		sessionID:  sessionID,
		sessionURL: sessionURL,
		opened:     true,
	}, nil
}

func (x *XHRSession) ID() string {
	return x.sessionID
}

func (x *XHRSession) Recv() (string, error) {
	// Return previously received messages if there is any.
	if len(x.messages) > 0 {
		msg := x.messages[0]
		x.messages = x.messages[1:]
		return msg, nil
	}

	// start to poll from the server until we receive something
	for {
		resp, err := x.client.Post(x.sessionURL+"/xhr", "text/plain", nil)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return "", fmt.Errorf("Receiving data failed. Want: %d Got: %d",
				http.StatusOK, resp.StatusCode)
		}

		buf := bufio.NewReader(resp.Body)

		// returns an error if buffer is empty
		frame, err := buf.ReadByte()
		if err != nil {
			return "", err
		}

		switch frame {
		case 'o':
			// session started
			x.mu.Lock()
			x.opened = true
			x.mu.Unlock()
			continue
		case 'a':
			// received an array of messages
			data, err := ioutil.ReadAll(buf)
			if err != nil {
				return "", err
			}

			var messages []string
			err = json.Unmarshal(data, &messages)
			if err != nil {
				return "", err
			}

			x.messages = append(x.messages, messages...)

			if len(x.messages) == 0 {
				return "", errors.New("no message")
			}

			// Return first message in slice, and remove it from the slice, so
			// next time the others will be picked
			msg := x.messages[0]
			x.messages = x.messages[1:]

			return msg, nil
		case 'h':
			// heartbeat received
			continue
		case 'c':
			x.mu.Lock()
			x.opened = false
			x.mu.Unlock()
			return "", errors.New("session closed")
		default:
			return "", errors.New("invalid frame type")
		}
	}

	return "", errors.New("FATAL: If we get here, please revisit the logic again")
}

func (x *XHRSession) Send(frame string) error {
	x.mu.Lock()
	if !x.opened {
		x.mu.Unlock()
		return errors.New("session is not opened yet")
	}
	x.mu.Unlock()

	// Need's to be JSON encoded array of string messages (SockJS protocol
	// requirement)
	message := []string{frame}
	body, err := json.Marshal(&message)
	if err != nil {
		return err
	}

	resp, err := x.client.Post(x.sessionURL+"/xhr_send", "text/plain", bytes.NewReader(body))
	if err != nil {
		return err
	}

	if resp.StatusCode == http.StatusNotFound {
		return errors.New("XHR session doesn't exists")
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Sending data failed. Want: %d Got: %d",
			http.StatusOK, resp.StatusCode)
	}

	return nil
}

func (x *XHRSession) Close(status uint32, reason string) error {
	return nil
}
<|endoftext|>


<commit_before>package solrmonitor

func NewMockSolrMonitor(state ClusterState, liveNodes []string) *SolrMonitor {
	collections := map[string]*collection{}
	for k, v := range state {
		collections[k] = &collection{
			collectionState: v,
		}
	}
	return &SolrMonitor{
		collections: collections,
		liveNodes:   liveNodes,
	}
}
<commit_msg>Improved mock solrmonitor to support GetLiveDataNodes which asks for the ZkCli state (#41)<commit_after>package solrmonitor

import "github.com/fullstorydev/zk"

func NewMockSolrMonitor(state ClusterState, liveNodes []string) *SolrMonitor {
	collections := map[string]*collection{}
	for k, v := range state {
		collections[k] = &collection{
			collectionState: v,
		}
	}
	return &SolrMonitor{
		zkCli:       newMockZkClient(),
		collections: collections,
		liveNodes:   liveNodes,
	}
}

func newMockZkClient() ZkCli {
	return mockZkClient{}
}

type mockZkClient struct {
}

func (m mockZkClient) ChildrenW(path string) ([]string, *zk.Stat, <-chan zk.Event, error) {
	panic("Not implemented")
}

func (m mockZkClient) Get(path string) ([]byte, *zk.Stat, error) {
	panic("Not implemented")
}

func (m mockZkClient) GetW(path string) ([]byte, *zk.Stat, <-chan zk.Event, error) {
	panic("Not implemented")
}

func (m mockZkClient) ExistsW(path string) (bool, *zk.Stat, <-chan zk.Event, error) {
	panic("Not implemented")
}

func (m mockZkClient) State() zk.State {
	return zk.StateHasSession
}

func (m mockZkClient) Close() {
}
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/cloudinit"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/storage"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/tools"
)

// A EnvironProvider represents a computing and storage provider.
type EnvironProvider interface {
	// Prepare prepares an environment for use. Any additional
	// configuration attributes in the returned environment should
	// be saved to be used later. If the environment is already
	// prepared, this call is equivalent to Open.
	Prepare(ctx BootstrapContext, cfg *config.Config) (Environ, error)

	// Open opens the environment and returns it.
	// The configuration must have come from a previously
	// prepared environment.
	Open(cfg *config.Config) (Environ, error)

	// Validate ensures that config is a valid configuration for this
	// provider, applying changes to it if necessary, and returns the
	// validated configuration.
	// If old is not nil, it holds the previous environment configuration
	// for consideration when validating changes.
	Validate(cfg, old *config.Config) (valid *config.Config, err error)

	// Boilerplate returns a default configuration for the environment in yaml format.
	// The text should be a key followed by some number of attributes:
	//    `environName:
	//        type: environTypeName
	//        attr1: val1
	//    `
	// The text is used as a template (see the template package) with one extra template
	// function available, rand, which expands to a random hexadecimal string when invoked.
	BoilerplateConfig() string

	// SecretAttrs filters the supplied configuration returning only values
	// which are considered sensitive. All of the values of these secret
	// attributes need to be strings.
	SecretAttrs(cfg *config.Config) (map[string]string, error)
}

// EnvironStorage implements storage access for an environment.
type EnvironStorage interface {
	// Storage returns storage specific to the environment.
	Storage() storage.Storage
}

// ConfigGetter implements access to an environment's configuration.
type ConfigGetter interface {
	// Config returns the configuration data with which the Environ was created.
	// Note that this is not necessarily current; the canonical location
	// for the configuration data is stored in the state.
	Config() *config.Config
}

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// environs.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a MachineConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *cloudinit.MachineConfig) error

// An Environ represents a juju environment as specified
// in the environments.yaml file.
//
// Due to the limitations of some providers (for example ec2), the
// results of the Environ methods may not be fully sequentially
// consistent. In particular, while a provider may retry when it
// gets an error for an operation, it will not retry when
// an operation succeeds, even if that success is not
// consistent with a previous operation.
//
// Even though Juju takes care not to share an Environ between concurrent
// workers, it does allow concurrent method calls into the provider
// implementation.  The typical provider implementation needs locking to
// avoid undefined behaviour when the configuration changes.
type Environ interface {
	// Bootstrap creates a new instance with the series and architecture
	// of its choice, constrained to those of the available tools, and
	// returns the instance's architecture, series, and a function that
	// must be called to finalize the bootstrap process by transferring
	// the tools and installing the initial Juju state server.
	//
	// It is possible to direct Bootstrap to use a specific architecture
	// (or fail if it cannot start an instance of that architecture) by
	// using an architecture constraint; this will have the effect of
	// limiting the available tools to just those matching the specified
	// architecture.
	Bootstrap(ctx BootstrapContext, params BootstrapParams) (arch, series string, _ BootstrapFinalizer, _ error)

	// InstanceBroker defines methods for starting and stopping
	// instances.
	InstanceBroker

	// AllocateAddress requests a specific address to be allocated for the
	// given instance on the given network.
	AllocateAddress(instId instance.Id, netId network.Id, addr network.Address) error

	// ListNetworks returns basic information about all networks known
	// by the provider for the environment, for a specific instance. A
	// provider may return all networks instead of just those for the
	// instance (provider specific). The networks may be unknown to juju
	// yet (i.e. when called initially or when a new network was created).
	ListNetworks(inst instance.Id) ([]network.BasicInfo, error)

	// ConfigGetter allows the retrieval of the configuration data.
	ConfigGetter

	// EnvironCapability allows access to this environment's capabilities.
	state.EnvironCapability

	// ConstraintsValidator returns a Validator instance which
	// is used to validate and merge constraints.
	ConstraintsValidator() (constraints.Validator, error)

	// SetConfig updates the Environ's configuration.
	//
	// Calls to SetConfig do not affect the configuration of
	// values previously obtained from Storage.
	SetConfig(cfg *config.Config) error

	// Instances returns a slice of instances corresponding to the
	// given instance ids.  If no instances were found, but there
	// was no other error, it will return ErrNoInstances.  If
	// some but not all the instances were found, the returned slice
	// will have some nil slots, and an ErrPartialInstances error
	// will be returned.
	Instances(ids []instance.Id) ([]instance.Instance, error)

	// StateServerInstances returns the IDs of instances corresponding
	// to Juju state servers. If there are no state server instances,
	// ErrNotBootstrapped is returned.
	StateServerInstances() ([]instance.Id, error)

	// Destroy shuts down all known machines and destroys the
	// rest of the environment. Note that on some providers,
	// very recently started instances may not be destroyed
	// because they are not yet visible.
	//
	// When Destroy has been called, any Environ referring to the
	// same remote environment may become invalid
	Destroy() error

	// OpenPorts opens the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	OpenPorts(ports []network.PortRange) error

	// ClosePorts closes the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	ClosePorts(ports []network.PortRange) error

	// Ports returns the port ranges opened for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	Ports() ([]network.PortRange, error)

	// Provider returns the EnvironProvider that created this Environ.
	Provider() EnvironProvider

	state.Prechecker
}

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<commit_msg>Remove old part of comment<commit_after>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/cloudinit"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/storage"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/tools"
)

// A EnvironProvider represents a computing and storage provider.
type EnvironProvider interface {
	// Prepare prepares an environment for use. Any additional
	// configuration attributes in the returned environment should
	// be saved to be used later. If the environment is already
	// prepared, this call is equivalent to Open.
	Prepare(ctx BootstrapContext, cfg *config.Config) (Environ, error)

	// Open opens the environment and returns it.
	// The configuration must have come from a previously
	// prepared environment.
	Open(cfg *config.Config) (Environ, error)

	// Validate ensures that config is a valid configuration for this
	// provider, applying changes to it if necessary, and returns the
	// validated configuration.
	// If old is not nil, it holds the previous environment configuration
	// for consideration when validating changes.
	Validate(cfg, old *config.Config) (valid *config.Config, err error)

	// Boilerplate returns a default configuration for the environment in yaml format.
	// The text should be a key followed by some number of attributes:
	//    `environName:
	//        type: environTypeName
	//        attr1: val1
	//    `
	// The text is used as a template (see the template package) with one extra template
	// function available, rand, which expands to a random hexadecimal string when invoked.
	BoilerplateConfig() string

	// SecretAttrs filters the supplied configuration returning only values
	// which are considered sensitive. All of the values of these secret
	// attributes need to be strings.
	SecretAttrs(cfg *config.Config) (map[string]string, error)
}

// EnvironStorage implements storage access for an environment.
type EnvironStorage interface {
	// Storage returns storage specific to the environment.
	Storage() storage.Storage
}

// ConfigGetter implements access to an environment's configuration.
type ConfigGetter interface {
	// Config returns the configuration data with which the Environ was created.
	// Note that this is not necessarily current; the canonical location
	// for the configuration data is stored in the state.
	Config() *config.Config
}

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// environs.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a MachineConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *cloudinit.MachineConfig) error

// An Environ represents a juju environment as specified
// in the environments.yaml file.
//
// Due to the limitations of some providers (for example ec2), the
// results of the Environ methods may not be fully sequentially
// consistent. In particular, while a provider may retry when it
// gets an error for an operation, it will not retry when
// an operation succeeds, even if that success is not
// consistent with a previous operation.
//
// Even though Juju takes care not to share an Environ between concurrent
// workers, it does allow concurrent method calls into the provider
// implementation.  The typical provider implementation needs locking to
// avoid undefined behaviour when the configuration changes.
type Environ interface {
	// Bootstrap creates a new instance with the series and architecture
	// of its choice, constrained to those of the available tools, and
	// returns the instance's architecture, series, and a function that
	// must be called to finalize the bootstrap process by transferring
	// the tools and installing the initial Juju state server.
	//
	// It is possible to direct Bootstrap to use a specific architecture
	// (or fail if it cannot start an instance of that architecture) by
	// using an architecture constraint; this will have the effect of
	// limiting the available tools to just those matching the specified
	// architecture.
	Bootstrap(ctx BootstrapContext, params BootstrapParams) (arch, series string, _ BootstrapFinalizer, _ error)

	// InstanceBroker defines methods for starting and stopping
	// instances.
	InstanceBroker

	// AllocateAddress requests a specific address to be allocated for the
	// given instance on the given network.
	AllocateAddress(instId instance.Id, netId network.Id, addr network.Address) error

	// ListNetworks returns basic information about all networks known
	// by the provider for the environment, for a specific instance. A
	// provider may return all networks instead of just those for the
	// instance (provider specific).
	ListNetworks(inst instance.Id) ([]network.BasicInfo, error)

	// ConfigGetter allows the retrieval of the configuration data.
	ConfigGetter

	// EnvironCapability allows access to this environment's capabilities.
	state.EnvironCapability

	// ConstraintsValidator returns a Validator instance which
	// is used to validate and merge constraints.
	ConstraintsValidator() (constraints.Validator, error)

	// SetConfig updates the Environ's configuration.
	//
	// Calls to SetConfig do not affect the configuration of
	// values previously obtained from Storage.
	SetConfig(cfg *config.Config) error

	// Instances returns a slice of instances corresponding to the
	// given instance ids.  If no instances were found, but there
	// was no other error, it will return ErrNoInstances.  If
	// some but not all the instances were found, the returned slice
	// will have some nil slots, and an ErrPartialInstances error
	// will be returned.
	Instances(ids []instance.Id) ([]instance.Instance, error)

	// StateServerInstances returns the IDs of instances corresponding
	// to Juju state servers. If there are no state server instances,
	// ErrNotBootstrapped is returned.
	StateServerInstances() ([]instance.Id, error)

	// Destroy shuts down all known machines and destroys the
	// rest of the environment. Note that on some providers,
	// very recently started instances may not be destroyed
	// because they are not yet visible.
	//
	// When Destroy has been called, any Environ referring to the
	// same remote environment may become invalid
	Destroy() error

	// OpenPorts opens the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	OpenPorts(ports []network.PortRange) error

	// ClosePorts closes the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	ClosePorts(ports []network.PortRange) error

	// Ports returns the port ranges opened for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	Ports() ([]network.PortRange, error)

	// Provider returns the EnvironProvider that created this Environ.
	Provider() EnvironProvider

	state.Prechecker
}

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<|endoftext|>


<commit_before>package easysftp

import (
	"errors"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
)

// ClientConfig maintains all of the configuration info to connect to a SSH host
type ClientConfig struct {
	Username string
	Host     string
	KeyPath  string
	Password string
	Timeout  time.Duration
	FileMode os.FileMode
}

// Client communicates with the SFTP to download files/pathes
type Client struct {
	sshClient *ssh.Client
	config    *ClientConfig
}

// Connect to a host with this given config
func Connect(config *ClientConfig) (*Client, error) {
	var auth []ssh.AuthMethod
	if config.KeyPath != "" {
		privKey, err := ioutil.ReadFile(config.KeyPath)
		if err != nil {
			return nil, err
		}
		signer, err := ssh.ParsePrivateKey(privKey)
		if err != nil {
			return nil, err
		}

		auth = append(auth, ssh.PublicKeys(signer))
	}

	if len(auth) == 0 {
		if config.Password == "" {
			return nil, errors.New("Missing password or key for SSH authentication")
		}

		auth = append(auth, ssh.Password(config.Password))
	}

	sshClient, err := ssh.Dial("tcp", config.Host, &ssh.ClientConfig{
		User:    config.Username,
		Auth:    auth,
		Timeout: config.Timeout,
	})
	if err != nil {
		return nil, err
	}

	return &Client{
		sshClient: sshClient,
		config:    config,
	}, nil
}

// Close the underlying SSH conection
func (c *Client) Close() error {
	return c.sshClient.Close()
}

func (c *Client) newSftpClient() (*sftp.Client, error) {
	return sftp.NewClient(c.sshClient)
}

// Stat gets information for the given path
func (c *Client) Stat(path string) (os.FileInfo, error) {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return nil, err
	}

	defer sftpClient.Close()

	return sftpClient.Stat(path)
}

// Lstat gets information for the given path, if it is a symbolic link, it will describe the symbolic link
func (c *Client) Lstat(path string) (os.FileInfo, error) {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return nil, err
	}

	defer sftpClient.Close()

	return sftpClient.Lstat(path)
}

// Download a file from the given path to the output writer
func (c *Client) Download(path string, output io.Writer) error {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return err
	}

	defer sftpClient.Close()

	info, err := sftpClient.Stat(path)
	if err != nil {
		return err
	}

	if info.IsDir() {
		return errors.New("Unable to use easysftp.Client.Download for dir: " + path)
	}

	remote, err := sftpClient.Open(path)
	if err != nil {
		return err
	}

	defer remote.Close()

	_, err = io.Copy(output, remote)
	return err
}

// Mirror downloads an entire folder (recursively) or file underneath the given localParentPath
func (c *Client) Mirror(path string, localParentPath string) error {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return err
	}

	defer sftpClient.Close()

	info, err := sftpClient.Stat(path)
	if err != nil {
		return err
	}

	// download the file
	if !info.IsDir() {
		sftpClient.Close()
		localPath := filepath.Join(localParentPath, info.Name())
		localInfo, err := os.Stat(localPath)
		if os.IsExist(err) && localInfo.IsDir() {
			err = os.RemoveAll(localPath)
			if err != nil {
				return err
			}
		}

		file, err := os.OpenFile(
			localPath,
			os.O_RDWR|os.O_CREATE|os.O_TRUNC,
			c.config.FileMode,
		)
		if err != nil {
			return err
		}

		defer file.Close()

		return c.Download(path, file)
	}

	// download the whole directory recursively
	walker := sftpClient.Walk(path)
	remoteParentPath := filepath.Dir(path)
	for walker.Step() {
		if err := walker.Err(); err != nil {
			return err
		}

		info := walker.Stat()

		relPath, err := filepath.Rel(remoteParentPath, walker.Path())
		if err != nil {
			return err
		}

		localPath := filepath.Join(localParentPath, relPath)

		// if we have something at the download path delete it if it is a directory
		// and the remote is a file and vice a versa
		localInfo, err := os.Stat(localPath)
		if os.IsExist(err) {
			if localInfo.IsDir() {
				if info.IsDir() {
					continue
				}

				err = os.RemoveAll(localPath)
				if err != nil {
					return err
				}
			} else if info.IsDir() {
				err = os.Remove(localPath)
				if err != nil {
					return err
				}
			}
		}

		if info.IsDir() {
			err = os.MkdirAll(localPath, c.config.FileMode)
			if err != nil {
				return err
			}

			continue
		}

		remoteFile, err := sftpClient.Open(walker.Path())
		if err != nil {
			return err
		}

		localFile, err := os.OpenFile(localPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, c.config.FileMode)
		if err != nil {
			remoteFile.Close()
			return err
		}

		_, err = io.Copy(localFile, remoteFile)
		remoteFile.Close()
		localFile.Close()

		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Add resume support to downloads<commit_after>package easysftp

import (
	"errors"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
)

// ClientConfig maintains all of the configuration info to connect to a SSH host
type ClientConfig struct {
	Username string
	Host     string
	KeyPath  string
	Password string
	Timeout  time.Duration
	FileMode os.FileMode
}

// Client communicates with the SFTP to download files/pathes
type Client struct {
	sshClient *ssh.Client
	config    *ClientConfig
}

// Connect to a host with this given config
func Connect(config *ClientConfig) (*Client, error) {
	var auth []ssh.AuthMethod
	if config.KeyPath != "" {
		privKey, err := ioutil.ReadFile(config.KeyPath)
		if err != nil {
			return nil, err
		}
		signer, err := ssh.ParsePrivateKey(privKey)
		if err != nil {
			return nil, err
		}

		auth = append(auth, ssh.PublicKeys(signer))
	}

	if len(auth) == 0 {
		if config.Password == "" {
			return nil, errors.New("Missing password or key for SSH authentication")
		}

		auth = append(auth, ssh.Password(config.Password))
	}

	sshClient, err := ssh.Dial("tcp", config.Host, &ssh.ClientConfig{
		User:    config.Username,
		Auth:    auth,
		Timeout: config.Timeout,
	})
	if err != nil {
		return nil, err
	}

	return &Client{
		sshClient: sshClient,
		config:    config,
	}, nil
}

// Close the underlying SSH conection
func (c *Client) Close() error {
	return c.sshClient.Close()
}

func (c *Client) newSftpClient() (*sftp.Client, error) {
	return sftp.NewClient(c.sshClient)
}

// Stat gets information for the given path
func (c *Client) Stat(path string) (os.FileInfo, error) {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return nil, err
	}

	defer sftpClient.Close()

	return sftpClient.Stat(path)
}

// Lstat gets information for the given path, if it is a symbolic link, it will describe the symbolic link
func (c *Client) Lstat(path string) (os.FileInfo, error) {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return nil, err
	}

	defer sftpClient.Close()

	return sftpClient.Lstat(path)
}

// Download a file from the given path to the output writer with the given offset of the remote file
func (c *Client) Download(path string, output io.Writer, offset int64) error {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return err
	}

	defer sftpClient.Close()

	info, err := sftpClient.Stat(path)
	if err != nil {
		return err
	}

	if info.IsDir() {
		return errors.New("Unable to use easysftp.Client.Download for dir: " + path)
	}

	remote, err := sftpClient.Open(path)
	if err != nil {
		return err
	}

	defer remote.Close()

	_, err = remote.Seek(offset, 0)
	if err != nil {
		return err
	}

	_, err = io.Copy(output, remote)
	return err
}

// Mirror downloads an entire folder (recursively) or file underneath the given localParentPath
// resume will continue downloading interrupted files
func (c *Client) Mirror(path string, localParentPath string, resume bool) error {
	sftpClient, err := c.newSftpClient()
	if err != nil {
		return err
	}

	defer sftpClient.Close()

	info, err := sftpClient.Stat(path)
	if err != nil {
		return err
	}

	// download the file
	if !info.IsDir() {
		sftpClient.Close()
		localPath := filepath.Join(localParentPath, info.Name())
		localInfo, err := os.Stat(localPath)
		if os.IsExist(err) && localInfo.IsDir() {
			err = os.RemoveAll(localPath)
			if err != nil {
				return err
			}
		}

		flags := os.O_RDWR | os.O_CREATE

		if resume {
			// append to the end of the file
			flags |= os.O_APPEND
		} else {
			// truncate the file
			flags |= os.O_TRUNC
		}

		file, err := os.OpenFile(
			localPath,
			flags,
			c.config.FileMode,
		)
		if err != nil {
			return err
		}

		defer file.Close()

		var offset int64
		if resume {
			info, err := file.Stat()
			if err != nil {
				return err
			}

			// we assume that the size of the file is the resume point
			offset = info.Size()
		}

		return c.Download(path, file, offset)
	}

	// download the whole directory recursively
	walker := sftpClient.Walk(path)
	remoteParentPath := filepath.Dir(path)
	for walker.Step() {
		if err := walker.Err(); err != nil {
			return err
		}

		info := walker.Stat()

		relPath, err := filepath.Rel(remoteParentPath, walker.Path())
		if err != nil {
			return err
		}

		localPath := filepath.Join(localParentPath, relPath)

		// if we have something at the download path delete it if it is a directory
		// and the remote is a file and vice a versa
		localInfo, err := os.Stat(localPath)
		if os.IsExist(err) {
			if localInfo.IsDir() {
				if info.IsDir() {
					continue
				}

				err = os.RemoveAll(localPath)
				if err != nil {
					return err
				}
			} else if info.IsDir() {
				err = os.Remove(localPath)
				if err != nil {
					return err
				}
			}
		}

		if info.IsDir() {
			err = os.MkdirAll(localPath, c.config.FileMode)
			if err != nil {
				return err
			}

			continue
		}

		remoteFile, err := sftpClient.Open(walker.Path())
		if err != nil {
			return err
		}

		localFile, err := os.OpenFile(localPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, c.config.FileMode)
		if err != nil {
			remoteFile.Close()
			return err
		}

		_, err = io.Copy(localFile, remoteFile)
		remoteFile.Close()
		localFile.Close()

		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Package upstream abstracts a upstream lookups so that plugins can handle them in an unified way.
package upstream

import (
	"context"
	"fmt"

	"github.com/coredns/coredns/core/dnsserver"
	"github.com/coredns/coredns/plugin/pkg/nonwriter"
	"github.com/coredns/coredns/request"

	"github.com/miekg/dns"
)

// Upstream is used to resolve CNAME or other external targets via CoreDNS itself.
type Upstream struct{}

// New creates a new Upstream to resolve names using the coredns process.
func New() *Upstream { return &Upstream{} }

// Lookup routes lookups to our selves or forward to a remote.
func (u *Upstream) Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error) {
	server, ok := ctx.Value(dnsserver.Key{}).(*dnsserver.Server)
	if !ok {
		return nil, fmt.Errorf("no full server is running")
	}
	req := state.NewWithQuestion(name, typ)

	nw := nonwriter.New(state.W)
	server.ServeDNS(ctx, nw, req.Req)

	return nw.Msg, nil
}
<commit_msg>Update upstream.Lookup method comment to reflect current state (#4832)<commit_after>// Package upstream abstracts a upstream lookups so that plugins can handle them in an unified way.
package upstream

import (
	"context"
	"fmt"

	"github.com/coredns/coredns/core/dnsserver"
	"github.com/coredns/coredns/plugin/pkg/nonwriter"
	"github.com/coredns/coredns/request"

	"github.com/miekg/dns"
)

// Upstream is used to resolve CNAME or other external targets via CoreDNS itself.
type Upstream struct{}

// New creates a new Upstream to resolve names using the coredns process.
func New() *Upstream { return &Upstream{} }

// Lookup routes lookups to our selves to make it follow the plugin chain *again*, but with a (possibly) new query. As
// we are doing the query against ourselves again, there is no actual new hop, as such RFC 6891 does not apply and we
// need the EDNS0 option present in the *original* query to be present here too.
func (u *Upstream) Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error) {
	server, ok := ctx.Value(dnsserver.Key{}).(*dnsserver.Server)
	if !ok {
		return nil, fmt.Errorf("no full server is running")
	}
	req := state.NewWithQuestion(name, typ)

	nw := nonwriter.New(state.W)
	server.ServeDNS(ctx, nw, req.Req)

	return nw.Msg, nil
}
<|endoftext|>