<commit_before>package ui

import (
	"fmt"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/termbox-go"
)

const (
	// Double clicks
	MouseLeftDbl termbox.Key = 0xFF00 + iota
	MouseRightDbl
)

// Evtstate stores some state about kb/mouse events
type EvtState struct {
	MovingView                    bool
	LastClickX, LastClickY        int
	LastLeftClick, LastRightClick int64 // timestamp
	DragLn, DragCol               int
	InDrag                        bool
}

// EventLoop is the main event loop that keeps waiting for events as long as
// the editor is running.
func (e *Editor) EventLoop() {

	e.term.SetMouseMode(termbox.MouseMotion)
	// Note: terminal might not support SGR mouse events, but trying anyway
	e.term.SetMouseMode(termbox.MouseSgr)

	e.term.SetInputMode(termbox.InputMouse)
	for {
		ev := termbox.PollEvent()
		switch ev.Type {
		case termbox.EventResize:
			actions.EdResize(ev.Height, ev.Width)
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyCtrlQ:
				if !actions.EdQuitCheck() {
					actions.EdSetStatusErr("Unsaved changes. Save or request close again.")
				} else {
					return // that's all falks, quit
				}
			case termbox.KeyEsc:
				actions.CmdbarToggle()
			default:
				if e.cmdOn {
					e.Cmdbar.Event(e, &ev)
				} else if e.CurView != nil {
					e.CurView().(*View).Event(e, &ev)
				}
			}
		case termbox.EventMouse:
			w := e.WidgetAt(ev.MouseY, ev.MouseX)
			if w != nil {
				w.Event(e, &ev)
			}
		}
		actions.EdRender()
	}
}

// ##################### CmdBar ########################################

// Event handler for Cmdbar
func (c *Cmdbar) Event(e *Editor, ev *termbox.Event) {
	switch ev.Type {
	case termbox.EventKey:
		switch ev.Key {
		case termbox.KeyBackspace, termbox.KeyBackspace2:
			if len(c.Cmd) > 0 {
				c.Cmd = c.Cmd[:len(c.Cmd)-1]
			}
		case termbox.KeyEnter:
			c.RunCmd()
		default:
			if ev.Ch != 0 && ev.Mod == 0 { // otherwise special key combo
				c.Cmd = append(c.Cmd, ev.Ch)
			}
		}

	case termbox.EventMouse:
		switch ev.Key {
		case termbox.MouseLeft:
			if isMouseUp(ev) && !e.cmdOn {
				actions.CmdbarToggle()
			}
		}
	}
}

// ##################### StatusBar ########################################

// Event handler for Statusbar
func (s *Statusbar) Event(e *Editor, ev *termbox.Event) {
	// Anything ??
}

// ##################### View       ########################################

// Event handler for View
func (v *View) Event(e *Editor, ev *termbox.Event) {
	dirty := false
	es := false //expand selection
	vid := v.Id()
	actions.ViewAutoScroll(vid, 0, 0, false)
	switch ev.Type {
	case termbox.EventKey:
		ln, col := actions.ViewCurPos(vid)
		e.evtState.InDrag = false

		// alt combos
		if ev.Mod == termbox.ModAlt {
			switch ev.Ch {
			case 'o':
				actions.ViewOpenSelection(vid, false)
				return
			}
			return
		}

		// Combos not supported directly by termbox
		if ev.Meta == termbox.Ctrl {
			switch ev.Key {
			case termbox.KeyArrowDown:
				actions.EdViewNavigate(core.CursorMvmtDown)
				return
			case termbox.KeyArrowUp:
				actions.EdViewNavigate(core.CursorMvmtUp)
				return
			case termbox.KeyArrowLeft:
				actions.EdViewNavigate(core.CursorMvmtLeft)
				return
			case termbox.KeyArrowRight:
				actions.EdViewNavigate(core.CursorMvmtRight)
				return
			}
		}

		switch ev.Key {
		// Ctrl combos
		case termbox.KeyCtrlA:
			actions.ViewSelectAll(vid)
			return
		case termbox.KeyCtrlC:
			switch v.backend.(type) {
			case *backend.BackendCmd:
				// CTRL+C process
				if v.backend.(*backend.BackendCmd).Running() {
					actions.ViewCmdStop(vid)
					return
				}
			}
			actions.ViewCopy(vid)
		//case termbox.KeyCtrlF:
		//	actions.External("search.ank")
		case termbox.KeyCtrlO:
			actions.ViewOpenSelection(vid, true)
		case termbox.KeyCtrlQ:
			return
		case termbox.KeyCtrlR:
			actions.ViewReload(vid)
		case termbox.KeyCtrlS:
			actions.ViewSave(vid)
		case termbox.KeyCtrlV:
			actions.ViewPaste(vid)
			dirty = true
		case termbox.KeyCtrlW:
			actions.EdDelViewCheck(e.curViewId)
			return
		case termbox.KeyCtrlX:
			actions.ViewCut(vid)
			dirty = true
		case termbox.KeyCtrlY:
			actions.ViewRedo(vid)
		case termbox.KeyCtrlZ:
			actions.ViewUndo(vid)
		// "Regular" keys
		case termbox.KeyArrowRight:
			actions.ViewCursorMvmt(vid, core.CursorMvmtRight)
			es = true
		case termbox.KeyArrowLeft:
			actions.ViewCursorMvmt(vid, core.CursorMvmtLeft)
			es = true
		case termbox.KeyArrowUp:
			actions.ViewCursorMvmt(vid, core.CursorMvmtUp)
			es = true
		case termbox.KeyArrowDown:
			actions.ViewCursorMvmt(vid, core.CursorMvmtDown)
			es = true
		case termbox.KeyPgdn:
			actions.ViewCursorMvmt(vid, core.CursorMvmtPgDown)
			es = true
		case termbox.KeyPgup:
			actions.ViewCursorMvmt(vid, core.CursorMvmtPgUp)
			es = true
		case termbox.KeyEnd:
			actions.ViewCursorMvmt(vid, core.CursorMvmtEnd)
			es = true
		case termbox.KeyHome:
			actions.ViewCursorMvmt(vid, core.CursorMvmtHome)
			es = true
		case termbox.KeyTab:
			actions.ViewInsertCur(vid, "\t")
			dirty = true
			es = true
		case termbox.KeyEnter:
			actions.ViewInsertNewLine(vid)
			dirty = true
		case termbox.KeyDelete:
			actions.ViewDeleteCur(vid)
			dirty = true
		case termbox.KeyBackspace, termbox.KeyBackspace2:
			actions.ViewBackspace(vid)
			dirty = true
		default:
			// insert the key
			if ev.Ch != 0 && ev.Mod == 0 && ev.Meta == 0 { // otherwise some special key combo
				actions.ViewInsertCur(vid, string(ev.Ch))
				dirty = true
			}
		}
		// extend keyboard selection
		if es && ev.Meta == termbox.Shift {
			actions.ViewStretchSelection(vid, ln, col)
		} else {
			actions.ViewClearSelections(vid)
		}
	case termbox.EventMouse:
		col := ev.MouseX - v.x1 + v.offx - 2
		ln := ev.MouseY - v.y1 + v.offy - 2
		if isMouseUp(ev) && ev.MouseX == e.evtState.LastClickX &&
			ev.MouseY == e.evtState.LastClickY &&
			time.Now().Unix()-e.evtState.LastLeftClick <= 2 {
			ev.Key = MouseLeftDbl
			e.evtState.LastClickX = -1
		}
		switch ev.Key {
		case MouseLeftDbl:
			if ev.MouseX == v.x1 && ev.MouseY == v.y1 {
				actions.EdSwapViews(e.CurViewId(), vid)
				actions.EdActivateView(vid, v.CurLine(), v.CurCol())
				e.evtState.MovingView = false
				actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				return
			}
			if selection := v.ExpandSelectionWord(ln, col); selection != nil {
				v.selections = []core.Selection{
					*selection,
				}
			}
			return
		case termbox.MouseScrollUp:
			actions.ViewMoveCursor(vid, -1, 0)
			return
		case termbox.MouseScrollDown:
			actions.ViewMoveCursor(vid, 1, 0)
			return
		case termbox.MouseRight:
			if isMouseUp(ev) {
				e.evtState.InDrag = false
				e.evtState.LastClickX, e.evtState.LastClickY = ev.MouseX, ev.MouseY
				e.evtState.LastRightClick = time.Now().Unix()
				actions.ViewClearSelections(vid)
				actions.ViewMoveCursor(vid, ev.MouseY-v.y1-2-v.CursorY, ev.MouseX-v.x1-2-v.CursorX)
				actions.ViewOpenSelection(vid, true)
			}
			return
		case termbox.MouseLeft:
			if e.evtState.MovingView && isMouseUp(ev) {
				e.evtState.MovingView = false
				actions.EdViewMove(vid, e.evtState.LastClickY, e.evtState.LastClickX, ev.MouseY, ev.MouseX)
				actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				return
			}
			if ev.MouseX == v.x2-1 && ev.MouseY == v.y1 && isMouseUp(ev) {
				actions.EdDelViewCheck(vid)
				return
			}
			if ev.MouseX == v.x1 && ev.MouseY == v.y1 && isMouseUp(ev) {
				// handle
				e.evtState.MovingView = true
				e.evtState.LastClickX = ev.MouseX
				e.evtState.LastClickY = ev.MouseY
				e.evtState.LastLeftClick = time.Now().Unix()
				actions.EdSetStatusErr("Starting move, click new position or dbl click to swap")
				return
			}
			if ev.MouseX <= v.x1 {
				return // scrollbar TBD
			}
			if ev.DragOn {
				if !e.evtState.InDrag {
					e.evtState.InDrag = true
					actions.ViewClearSelections(vid)
					actions.EdActivateView(vid, e.evtState.DragLn, e.evtState.DragCol)
				}
				// continued drag
				x1 := e.evtState.DragCol
				y1 := e.evtState.DragLn
				x2 := col
				y2 := ln

				actions.ViewClearSelections(vid)
				actions.ViewAddSelection(
					vid,
					y1,
					v.LineRunesTo(v.slice, y1, x1),
					y2,
					v.LineRunesTo(v.slice, y2, x2))

				// Handling scrolling while dragging
				if ln < v.offy { // scroll up
					actions.ViewAutoScroll(vid, -v.LineCount()/10, 0, true)
				} else if ln >= v.offy+(v.y2-v.y1)-2 { // scroll down
					actions.ViewAutoScroll(vid, v.LineCount()/10, 0, true)
				} else if col < v.offx { //scroll left
					actions.ViewAutoScroll(vid, 0, -5, true)
				} else if col >= v.offx+(v.x2-v.x1)-3 { // scroll right
					actions.ViewAutoScroll(vid, 0, 5, true)
				}
				return
			}

			if isMouseUp(ev) { // click
				if selected, _ := v.Selected(ln, col); selected {
					e.evtState.InDrag = false
					// otherwise it could be the mouseUp at the end of a drag.
				}
				if !e.evtState.InDrag {
					actions.ViewClearSelections(vid)
					actions.EdActivateView(vid, ln, col)
					e.evtState.LastLeftClick = time.Now().Unix()
					e.evtState.LastClickX, e.evtState.LastClickY = ev.MouseX, ev.MouseY
					actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				}
			}
			e.evtState.InDrag = false
			actions.CmdbarEnable(false)
			e.evtState.DragLn = ln
			e.evtState.DragCol = col
		} // end switch
	}

	if dirty {
		actions.ViewSetDirty(vid, true)
	}
}

func isMouseUp(ev *termbox.Event) bool {
	return ev.MouseBtnState == termbox.MouseBtnUp
}
<commit_msg>Make sure ctrl+C is copy if any selections, when in terminal<commit_after>package ui

import (
	"fmt"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/termbox-go"
)

const (
	// Double clicks
	MouseLeftDbl termbox.Key = 0xFF00 + iota
	MouseRightDbl
)

// Evtstate stores some state about kb/mouse events
type EvtState struct {
	MovingView                    bool
	LastClickX, LastClickY        int
	LastLeftClick, LastRightClick int64 // timestamp
	DragLn, DragCol               int
	InDrag                        bool
}

// EventLoop is the main event loop that keeps waiting for events as long as
// the editor is running.
func (e *Editor) EventLoop() {

	e.term.SetMouseMode(termbox.MouseMotion)
	// Note: terminal might not support SGR mouse events, but trying anyway
	e.term.SetMouseMode(termbox.MouseSgr)

	e.term.SetInputMode(termbox.InputMouse)
	for {
		ev := termbox.PollEvent()
		switch ev.Type {
		case termbox.EventResize:
			actions.EdResize(ev.Height, ev.Width)
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyCtrlQ:
				if !actions.EdQuitCheck() {
					actions.EdSetStatusErr("Unsaved changes. Save or request close again.")
				} else {
					return // that's all falks, quit
				}
			case termbox.KeyEsc:
				actions.CmdbarToggle()
			default:
				if e.cmdOn {
					e.Cmdbar.Event(e, &ev)
				} else if e.CurView != nil {
					e.CurView().(*View).Event(e, &ev)
				}
			}
		case termbox.EventMouse:
			w := e.WidgetAt(ev.MouseY, ev.MouseX)
			if w != nil {
				w.Event(e, &ev)
			}
		}
		actions.EdRender()
	}
}

// ##################### CmdBar ########################################

// Event handler for Cmdbar
func (c *Cmdbar) Event(e *Editor, ev *termbox.Event) {
	switch ev.Type {
	case termbox.EventKey:
		switch ev.Key {
		case termbox.KeyBackspace, termbox.KeyBackspace2:
			if len(c.Cmd) > 0 {
				c.Cmd = c.Cmd[:len(c.Cmd)-1]
			}
		case termbox.KeyEnter:
			c.RunCmd()
		default:
			if ev.Ch != 0 && ev.Mod == 0 { // otherwise special key combo
				c.Cmd = append(c.Cmd, ev.Ch)
			}
		}

	case termbox.EventMouse:
		switch ev.Key {
		case termbox.MouseLeft:
			if isMouseUp(ev) && !e.cmdOn {
				actions.CmdbarToggle()
			}
		}
	}
}

// ##################### StatusBar ########################################

// Event handler for Statusbar
func (s *Statusbar) Event(e *Editor, ev *termbox.Event) {
	// Anything ??
}

// ##################### View       ########################################

// Event handler for View
func (v *View) Event(e *Editor, ev *termbox.Event) {
	dirty := false
	es := false //expand selection
	vid := v.Id()
	actions.ViewAutoScroll(vid, 0, 0, false)
	switch ev.Type {
	case termbox.EventKey:
		ln, col := actions.ViewCurPos(vid)
		e.evtState.InDrag = false

		// alt combos
		if ev.Mod == termbox.ModAlt {
			switch ev.Ch {
			case 'o':
				actions.ViewOpenSelection(vid, false)
				return
			}
			return
		}

		// Combos not supported directly by termbox
		if ev.Meta == termbox.Ctrl {
			switch ev.Key {
			case termbox.KeyArrowDown:
				actions.EdViewNavigate(core.CursorMvmtDown)
				return
			case termbox.KeyArrowUp:
				actions.EdViewNavigate(core.CursorMvmtUp)
				return
			case termbox.KeyArrowLeft:
				actions.EdViewNavigate(core.CursorMvmtLeft)
				return
			case termbox.KeyArrowRight:
				actions.EdViewNavigate(core.CursorMvmtRight)
				return
			}
		}

		switch ev.Key {
		// Ctrl combos
		case termbox.KeyCtrlA:
			actions.ViewSelectAll(vid)
			return
		case termbox.KeyCtrlC:
			switch v.backend.(type) {
			case *backend.BackendCmd:
				if len(*v.Selections()) == 0 { // if selections, fallthrough to copy
					// CTRL+C process
					if v.backend.(*backend.BackendCmd).Running() {
						actions.ViewCmdStop(vid)
						return
					}
				}
			}
			actions.ViewCopy(vid)
		//case termbox.KeyCtrlF:
		//	actions.External("search.ank")
		case termbox.KeyCtrlO:
			actions.ViewOpenSelection(vid, true)
		case termbox.KeyCtrlQ:
			return
		case termbox.KeyCtrlR:
			actions.ViewReload(vid)
		case termbox.KeyCtrlS:
			actions.ViewSave(vid)
		case termbox.KeyCtrlT:
			execTerm([]string{core.Terminal})
		case termbox.KeyCtrlV:
			actions.ViewPaste(vid)
			dirty = true
		case termbox.KeyCtrlW:
			actions.EdDelViewCheck(e.curViewId)
			return
		case termbox.KeyCtrlX:
			actions.ViewCut(vid)
			dirty = true
		case termbox.KeyCtrlY:
			actions.ViewRedo(vid)
		case termbox.KeyCtrlZ:
			actions.ViewUndo(vid)
		// "Regular" keys
		case termbox.KeyArrowRight:
			actions.ViewCursorMvmt(vid, core.CursorMvmtRight)
			es = true
		case termbox.KeyArrowLeft:
			actions.ViewCursorMvmt(vid, core.CursorMvmtLeft)
			es = true
		case termbox.KeyArrowUp:
			actions.ViewCursorMvmt(vid, core.CursorMvmtUp)
			es = true
		case termbox.KeyArrowDown:
			actions.ViewCursorMvmt(vid, core.CursorMvmtDown)
			es = true
		case termbox.KeyPgdn:
			actions.ViewCursorMvmt(vid, core.CursorMvmtPgDown)
			es = true
		case termbox.KeyPgup:
			actions.ViewCursorMvmt(vid, core.CursorMvmtPgUp)
			es = true
		case termbox.KeyEnd:
			actions.ViewCursorMvmt(vid, core.CursorMvmtEnd)
			es = true
		case termbox.KeyHome:
			actions.ViewCursorMvmt(vid, core.CursorMvmtHome)
			es = true
		case termbox.KeyTab:
			actions.ViewInsertCur(vid, "\t")
			dirty = true
			es = true
		case termbox.KeyEnter:
			actions.ViewInsertNewLine(vid)
			dirty = true
		case termbox.KeyDelete:
			actions.ViewDeleteCur(vid)
			dirty = true
		case termbox.KeyBackspace, termbox.KeyBackspace2:
			actions.ViewBackspace(vid)
			dirty = true
		default:
			// insert the key
			if ev.Ch != 0 && ev.Mod == 0 && ev.Meta == 0 { // otherwise some special key combo
				actions.ViewInsertCur(vid, string(ev.Ch))
				dirty = true
			}
		}
		// extend keyboard selection
		if es && ev.Meta == termbox.Shift {
			actions.ViewStretchSelection(vid, ln, col)
		} else {
			actions.ViewClearSelections(vid)
		}
	case termbox.EventMouse:
		col := ev.MouseX - v.x1 + v.offx - 2
		ln := ev.MouseY - v.y1 + v.offy - 2
		if isMouseUp(ev) && ev.MouseX == e.evtState.LastClickX &&
			ev.MouseY == e.evtState.LastClickY &&
			time.Now().Unix()-e.evtState.LastLeftClick <= 2 {
			ev.Key = MouseLeftDbl
			e.evtState.LastClickX = -1
		}
		switch ev.Key {
		case MouseLeftDbl:
			if ev.MouseX == v.x1 && ev.MouseY == v.y1 {
				actions.EdSwapViews(e.CurViewId(), vid)
				actions.EdActivateView(vid, v.CurLine(), v.CurCol())
				e.evtState.MovingView = false
				actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				return
			}
			if selection := v.ExpandSelectionWord(ln, col); selection != nil {
				v.selections = []core.Selection{
					*selection,
				}
			}
			return
		case termbox.MouseScrollUp:
			actions.ViewMoveCursor(vid, -1, 0)
			return
		case termbox.MouseScrollDown:
			actions.ViewMoveCursor(vid, 1, 0)
			return
		case termbox.MouseRight:
			if isMouseUp(ev) {
				e.evtState.InDrag = false
				e.evtState.LastClickX, e.evtState.LastClickY = ev.MouseX, ev.MouseY
				e.evtState.LastRightClick = time.Now().Unix()
				actions.ViewClearSelections(vid)
				actions.ViewMoveCursor(vid, ev.MouseY-v.y1-2-v.CursorY, ev.MouseX-v.x1-2-v.CursorX)
				actions.ViewOpenSelection(vid, true)
			}
			return
		case termbox.MouseLeft:
			if e.evtState.MovingView && isMouseUp(ev) {
				e.evtState.MovingView = false
				actions.EdViewMove(vid, e.evtState.LastClickY, e.evtState.LastClickX, ev.MouseY, ev.MouseX)
				actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				return
			}
			if ev.MouseX == v.x2-1 && ev.MouseY == v.y1 && isMouseUp(ev) {
				actions.EdDelViewCheck(vid)
				return
			}
			if ev.MouseX == v.x1 && ev.MouseY == v.y1 && isMouseUp(ev) {
				// handle
				e.evtState.MovingView = true
				e.evtState.LastClickX = ev.MouseX
				e.evtState.LastClickY = ev.MouseY
				e.evtState.LastLeftClick = time.Now().Unix()
				actions.EdSetStatusErr("Starting move, click new position or dbl click to swap")
				return
			}
			if ev.MouseX <= v.x1 {
				return // scrollbar TBD
			}
			if ev.DragOn {
				if !e.evtState.InDrag {
					e.evtState.InDrag = true
					actions.ViewClearSelections(vid)
					actions.EdActivateView(vid, e.evtState.DragLn, e.evtState.DragCol)
				}
				// continued drag
				x1 := e.evtState.DragCol
				y1 := e.evtState.DragLn
				x2 := col
				y2 := ln

				actions.ViewClearSelections(vid)
				actions.ViewAddSelection(
					vid,
					y1,
					v.LineRunesTo(v.slice, y1, x1),
					y2,
					v.LineRunesTo(v.slice, y2, x2))

				// Handling scrolling while dragging
				if ln < v.offy { // scroll up
					actions.ViewAutoScroll(vid, -v.LineCount()/10, 0, true)
				} else if ln >= v.offy+(v.y2-v.y1)-2 { // scroll down
					actions.ViewAutoScroll(vid, v.LineCount()/10, 0, true)
				} else if col < v.offx { //scroll left
					actions.ViewAutoScroll(vid, 0, -5, true)
				} else if col >= v.offx+(v.x2-v.x1)-3 { // scroll right
					actions.ViewAutoScroll(vid, 0, 5, true)
				}
				return
			}

			if isMouseUp(ev) { // click
				if selected, _ := v.Selected(ln, col); selected {
					e.evtState.InDrag = false
					// otherwise it could be the mouseUp at the end of a drag.
				}
				if !e.evtState.InDrag {
					actions.ViewClearSelections(vid)
					actions.EdActivateView(vid, ln, col)
					e.evtState.LastLeftClick = time.Now().Unix()
					e.evtState.LastClickX, e.evtState.LastClickY = ev.MouseX, ev.MouseY
					actions.EdSetStatus(fmt.Sprintf("%s  [%d]", v.WorkDir(), vid))
				}
			}
			e.evtState.InDrag = false
			actions.CmdbarEnable(false)
			e.evtState.DragLn = ln
			e.evtState.DragCol = col
		} // end switch
	}

	if dirty {
		actions.ViewSetDirty(vid, true)
	}
}

func isMouseUp(ev *termbox.Event) bool {
	return ev.MouseBtnState == termbox.MouseBtnUp
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package strings

import (
	"errors"
	"math"
)

// ErrSyntax indicates that a value does not have the right syntax.
var ErrSyntax = errors.New("StringToInt: invalid syntax")

// ErrRange indicates that a value is out of range.
var ErrRange = errors.New("StringToInt: value out of range")

// StringToInt converts number represented by string with base 10 to integer.
func StringToInt(s string) (int64, error) {
	if len(s) == 0 {
		return 0, ErrSyntax
	}

	neg := false
	if s[0] == '+' {
		s = s[1:]
	} else if s[0] == '-' {
		neg = true
		s = s[1:]
	}

	var u uint64
	for _, c := range s {
		if c < '0' || c > '9' {
			return 0, ErrSyntax
		}

		u = u*10 + uint64(c-'0')
		if neg && u > -math.MinInt64 || !neg && u > math.MaxInt64 { // Check for overflows: -n < math.MinInt64 || n > math.MaxInt64
			return 0, ErrRange
		}
	}

	n := int64(u)
	if neg {
		n = -n
	}
	return n, nil
}

// IntToString converts integer to string.
func IntToString(n int64) string {
	if n == 0 {
		return "0"
	}

	var s [19 + 1]byte // 19 is max digits of int64; +1 for sign.
	i := len(s)

	neg := n < 0
	u := uint64(n)
	if neg {
		u = -u // uint64(^n + 1)
	}

	for u > 0 {
		i--
		s[i] = byte(u%10 + '0')
		u /= 10
	}

	if neg {
		i--
		s[i] = '-'
	}

	return string(s[i:])
}
<commit_msg>Add pre-check if multiplication will overflow in strings.StringToInt<commit_after>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package strings

import (
	"errors"
	"math"
)

// ErrSyntax indicates that a value does not have the right syntax.
var ErrSyntax = errors.New("StringToInt: invalid syntax")

// ErrRange indicates that a value is out of range.
var ErrRange = errors.New("StringToInt: value out of range")

// StringToInt converts number represented by string with base 10 to integer.
func StringToInt(s string) (int64, error) {
	const cutoff = math.MaxInt64/10 + 1 // The first smallest number such that cutoff*10 > MaxInt64.

	if len(s) == 0 {
		return 0, ErrSyntax
	}

	neg := false
	if s[0] == '+' {
		s = s[1:]
	} else if s[0] == '-' {
		neg = true
		s = s[1:]
	}

	var u uint64
	for _, c := range s {
		if c < '0' || c > '9' {
			return 0, ErrSyntax
		}

		if u >= cutoff { // Check if u*10 overflows.
			return 0, ErrRange
		}
		u *= 10

		u += uint64(c-'0')
		if neg && u > -math.MinInt64 || !neg && u > math.MaxInt64 { // Check for overflows: -n < math.MinInt64 || n > math.MaxInt64
			return 0, ErrRange
		}
	}

	n := int64(u)
	if neg {
		n = -n
	}
	return n, nil
}

// IntToString converts integer to string.
func IntToString(n int64) string {
	if n == 0 {
		return "0"
	}

	var s [19 + 1]byte // 19 is max digits of int64; +1 for sign.
	i := len(s)

	neg := n < 0
	u := uint64(n)
	if neg {
		u = -u // uint64(^n + 1)
	}

	for u > 0 {
		i--
		s[i] = byte(u%10 + '0')
		u /= 10
	}

	if neg {
		i--
		s[i] = '-'
	}

	return string(s[i:])
}
<|endoftext|>


<commit_before>package util

import (
	"golang.org/x/crypto/scrypt"
)

// DeriveKey derives a key from password and salt being keyLen bytes long.
// It uses an established password derivation function.
func DeriveKey(pwd, salt []byte, keyLen int) []byte {
	// Parameters to be changed in future
	// https://godoc.org/golang.org/x/crypto/scrypt

	// TODO: 16384 is awfully slow. Consider increasing it later
	//       or consider using argon2 or something if it's faster.
	// key, err := scrypt.Key(pwd, salt, 16384, 8, 1, keyLen)
	key, err := scrypt.Key(pwd, salt, 4096, 8, 1, keyLen)
	if err != nil {
		panic("Bad scrypt parameters: " + err.Error())
	}

	return key
}
<commit_msg>util: increase Scrypt size to 32768<commit_after>package util

import (
	"golang.org/x/crypto/scrypt"
)

// DeriveKey derives a key from password and salt being keyLen bytes long.
// It uses an established password derivation function.
func DeriveKey(pwd, salt []byte, keyLen int) []byte {
	// Parameters to be changed in future
	// https://godoc.org/golang.org/x/crypto/scrypt
	key, err := scrypt.Key(pwd, salt, 32768, 8, 1, keyLen)
	if err != nil {
		panic("Bad scrypt parameters: " + err.Error())
	}

	return key
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"html/template"
	"net/http"
	"path/filepath"
	"strconv"
)

//Precache all templates in folder templates at start
var templates = template.Must(template.ParseFiles(filepath.Join("templates", "miners.html"),
	filepath.Join("templates", "index.html"),
	filepath.Join("templates", "miner.html")))

//Starts the webserver
func webServerMain(port int) {
	r := mux.NewRouter()
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}", MinerHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}/onoff", EnableDisableHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}/gpu", GPUHandler)
	r.HandleFunc("/miners", MinersHandler)
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./web-root/")))
	http.Handle("/", r)
	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}

//Request handler for a single miner information
func MinerHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	miner := MinerWrapper{}
	miner.Name = key

	//Get the array that hold the information about the devs
	miners[key].DevsWrap.Mu.RLock()
	miner.Devs = miners[key].DevsWrap.Devs
	miners[key].DevsWrap.Mu.RUnlock()
	//fmt.Printf("Onoff: %s\n", miner.Devs.Devs[0].OnOff)

	err := templates.ExecuteTemplate(w, "miner.html", miner)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func EnableDisableHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	//Parse the values
	statusNumber, err := strconv.Atoi(r.FormValue("status"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	deviceNumber, err := strconv.Atoi(r.FormValue("device"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Printf("Status: %v, Device: %v\n", statusNumber, deviceNumber)
	enableDisable(statusNumber, deviceNumber, key)
	http.Redirect(w, r, "/miner/"+key, http.StatusFound)
}

//Request handler for a creatin summary for all miners
func MinersHandler(w http.ResponseWriter, r *http.Request) {
	//Generate the correct structure for the template
	tempMiners := createMinersTemplate()

	err := templates.ExecuteTemplate(w, "miners.html", tempMiners)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func createMinersTemplate() MinersTemplate {
	var rows []MinerRow

	for _, value := range miners {

		var minerStructTemp = *value

		//Lock it
		minerStructTemp.SumWrap.Mu.RLock()
		//Add it
		rows = append(rows, minerStructTemp.SumWrap.SummaryRow)
		//Unlock it
		minerStructTemp.SumWrap.Mu.RUnlock()
	}
	return MinersTemplate{rows}
}

//Default handler
func HomeHandler(w http.ResponseWriter, r *http.Request) {

	hw := HomeWrapper{}

	//Calculate the total hashrate
	for _, value := range miners {
		var minerStructTemp = *value

		hw.TotalMHS += minerStructTemp.SumWrap.SummaryRow.MHSAv
	}

	err := templates.ExecuteTemplate(w, "index.html", hw)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func GPUHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	http.Redirect(w, r, "/miner/"+key, http.StatusFound)
}

type MinerWrapper struct {
	Name string
	Devs DevsResponse
}

type HomeWrapper struct {
	TotalMHS float64
}

type MinersTemplate struct {
	Rows []MinerRow
}

type MinerRow struct {
	Name      string
	Accepted  int
	Rejected  int
	MHSAv     float64
	BestShare int
}
<commit_msg>Parsing form values in GPUHandler<commit_after>package main

import (
	"fmt"
	"github.com/gorilla/mux"
	"html/template"
	"net/http"
	"path/filepath"
	"strconv"
)

//Precache all templates in folder templates at start
var templates = template.Must(template.ParseFiles(filepath.Join("templates", "miners.html"),
	filepath.Join("templates", "index.html"),
	filepath.Join("templates", "miner.html")))

//Starts the webserver
func webServerMain(port int) {
	r := mux.NewRouter()
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}", MinerHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}/onoff", EnableDisableHandler)
	r.HandleFunc("/miner/{key:[a-zA-Z0-9]+}/gpu", GPUHandler)
	r.HandleFunc("/miners", MinersHandler)
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./web-root/")))
	http.Handle("/", r)
	http.ListenAndServe(":"+strconv.Itoa(port), nil)
}

//Request handler for a single miner information
func MinerHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	miner := MinerWrapper{}
	miner.Name = key

	//Get the array that hold the information about the devs
	miners[key].DevsWrap.Mu.RLock()
	miner.Devs = miners[key].DevsWrap.Devs
	miners[key].DevsWrap.Mu.RUnlock()
	//fmt.Printf("Onoff: %s\n", miner.Devs.Devs[0].OnOff)

	err := templates.ExecuteTemplate(w, "miner.html", miner)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func EnableDisableHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	//Parse the values
	statusNumber, err := strconv.Atoi(r.FormValue("status"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	deviceNumber, err := strconv.Atoi(r.FormValue("device"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Printf("Status: %v, Device: %v\n", statusNumber, deviceNumber)
	enableDisable(statusNumber, deviceNumber, key)
	http.Redirect(w, r, "/miner/"+key, http.StatusFound)
}

//Request handler for a creatin summary for all miners
func MinersHandler(w http.ResponseWriter, r *http.Request) {
	//Generate the correct structure for the template
	tempMiners := createMinersTemplate()

	err := templates.ExecuteTemplate(w, "miners.html", tempMiners)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func createMinersTemplate() MinersTemplate {
	var rows []MinerRow

	for _, value := range miners {

		var minerStructTemp = *value

		//Lock it
		minerStructTemp.SumWrap.Mu.RLock()
		//Add it
		rows = append(rows, minerStructTemp.SumWrap.SummaryRow)
		//Unlock it
		minerStructTemp.SumWrap.Mu.RUnlock()
	}
	return MinersTemplate{rows}
}

//Default handler
func HomeHandler(w http.ResponseWriter, r *http.Request) {

	hw := HomeWrapper{}

	//Calculate the total hashrate
	for _, value := range miners {
		var minerStructTemp = *value

		hw.TotalMHS += minerStructTemp.SumWrap.SummaryRow.MHSAv
	}

	err := templates.ExecuteTemplate(w, "index.html", hw)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func GPUHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	key := vars["key"]

	//Parse the values
	gpuClock, err := strconv.Atoi(r.FormValue("GPUClock"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	deviceNumber, err := strconv.Atoi(r.FormValue("device"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	gpuMemory, err := strconv.Atoi(r.FormValue("MemoryClock"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	http.Redirect(w, r, "/miner/"+key, http.StatusFound)
}

type MinerWrapper struct {
	Name string
	Devs DevsResponse
}

type HomeWrapper struct {
	TotalMHS float64
}

type MinersTemplate struct {
	Rows []MinerRow
}

type MinerRow struct {
	Name      string
	Accepted  int
	Rejected  int
	MHSAv     float64
	BestShare int
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 fs_test

import (
	"github.com/jacobsa/comeback/fs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"io"
	"io/ioutil"
	"os"
	"path"
	"testing"
)

func TestCreate(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// CreateFile
////////////////////////////////////////////////////////////////////////

type CreateFileTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	w   io.WriteCloser
	err error
}

func init() { RegisterTestSuite(&CreateFileTest{}) }

func (t *CreateFileTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *CreateFileTest) call() {
	t.w, t.err = t.fileSystem.CreateFile(t.path, t.perms)
}

func (t *CreateFileTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateFileTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateFileTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateFileTest) FileAlreadyExists() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateFileTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)
	defer t.w.Close()

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeFile, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

func (t *CreateFileTest) SavesDataToCorrectPlace() {
	// Call
	t.call()
	AssertEq(nil, t.err)

	// Write
	expected := []byte("taco")
	_, err := t.w.Write(expected)
	AssertEq(nil, err)

	// Close
	AssertEq(nil, t.w.Close())

	// Read
	data, err := ioutil.ReadFile(t.path)
	AssertEq(nil, err)

	ExpectThat(data, DeepEquals(expected))
}

////////////////////////////////////////////////////////////////////////
// Mkdir
////////////////////////////////////////////////////////////////////////

type MkdirTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&MkdirTest{}) }

func (t *MkdirTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *MkdirTest) call() {
	t.err = t.fileSystem.Mkdir(t.path, t.perms)
}

func (t *MkdirTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *MkdirTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *MkdirTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *MkdirTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *MkdirTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeDirectory, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateNamedPipe
////////////////////////////////////////////////////////////////////////

type CreateNamedPipeTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&CreateNamedPipeTest{}) }

func (t *CreateNamedPipeTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *CreateNamedPipeTest) call() {
	t.err = t.fileSystem.CreateNamedPipe(t.path, t.perms)
}

func (t *CreateNamedPipeTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateNamedPipeTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateNamedPipeTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateNamedPipeTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateNamedPipeTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeNamedPipe, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateSymlink
////////////////////////////////////////////////////////////////////////

type CreateSymlinkTest struct {
	fileSystemTest

	target  string
	source  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&CreateSymlinkTest{}) }

func (t *CreateSymlinkTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/foo/bar"
	t.perms = 0644
}

func (t *CreateSymlinkTest) call() {
	t.err = t.fileSystem.CreateSymlink(t.target, t.source, t.perms)
}

func (t *CreateSymlinkTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateSymlinkTest) NonExistentParent() {
	t.source = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateSymlinkTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.source = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateSymlinkTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.source, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateSymlinkTest) CreatesCorrectEntry() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/burrito"
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeSymlink, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq("/burrito", entry.Target)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateHardLink
////////////////////////////////////////////////////////////////////////

type CreateHardLinkTest struct {
	fileSystemTest

	target  string
	source  string

	err error
}

func init() { RegisterTestSuite(&CreateHardLinkTest{}) }

func (t *CreateHardLinkTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/foo/bar"
}

func (t *CreateHardLinkTest) call() {
	t.err = t.fileSystem.CreateHardLink(t.target, t.source)
}

func (t *CreateHardLinkTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateHardLinkTest) NonExistentParent() {
	t.source = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateHardLinkTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.source = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateHardLinkTest) TargetDoesntExist() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/burrito"

	// Call
	t.call()
	AssertEq(nil, t.err)

	ExpectThat(t.err, Error(HasSubstr("TODO")))
}

func (t *CreateHardLinkTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.source, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateHardLinkTest) CreatesCorrectEntry() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = path.Join(t.baseDir, "burrito")

	// Create target
	err := ioutil.WriteFile(t.target, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any(), Any()))

	entry0 := entries[0]
	ExpectEq(fs.TypeFile, entry0.Type)
	ExpectEq("burrito", entry0.Name)

	entry1 := entries[1]
	ExpectEq(fs.TypeFile, entry1.Type)
	ExpectEq("taco", entry1.Name)

	AssertNe(0, entry0.ContainingDevice)
	ExpectEq(entry1.ContainingDevice, entry0.ContainingDevice)

	AssertNe(0, entry0.Inode)
	ExpectEq(entry1.Inode, entry0.Inode)
}
<commit_msg>Fixed some test bugs.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 fs_test

import (
	"github.com/jacobsa/comeback/fs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"io"
	"io/ioutil"
	"os"
	"path"
	"testing"
)

func TestCreate(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// CreateFile
////////////////////////////////////////////////////////////////////////

type CreateFileTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	w   io.WriteCloser
	err error
}

func init() { RegisterTestSuite(&CreateFileTest{}) }

func (t *CreateFileTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *CreateFileTest) call() {
	t.w, t.err = t.fileSystem.CreateFile(t.path, t.perms)
}

func (t *CreateFileTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateFileTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateFileTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateFileTest) FileAlreadyExists() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateFileTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)
	defer t.w.Close()

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeFile, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

func (t *CreateFileTest) SavesDataToCorrectPlace() {
	// Call
	t.call()
	AssertEq(nil, t.err)

	// Write
	expected := []byte("taco")
	_, err := t.w.Write(expected)
	AssertEq(nil, err)

	// Close
	AssertEq(nil, t.w.Close())

	// Read
	data, err := ioutil.ReadFile(t.path)
	AssertEq(nil, err)

	ExpectThat(data, DeepEquals(expected))
}

////////////////////////////////////////////////////////////////////////
// Mkdir
////////////////////////////////////////////////////////////////////////

type MkdirTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&MkdirTest{}) }

func (t *MkdirTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *MkdirTest) call() {
	t.err = t.fileSystem.Mkdir(t.path, t.perms)
}

func (t *MkdirTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *MkdirTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *MkdirTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *MkdirTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *MkdirTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeDirectory, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateNamedPipe
////////////////////////////////////////////////////////////////////////

type CreateNamedPipeTest struct {
	fileSystemTest

	path  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&CreateNamedPipeTest{}) }

func (t *CreateNamedPipeTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0644
}

func (t *CreateNamedPipeTest) call() {
	t.err = t.fileSystem.CreateNamedPipe(t.path, t.perms)
}

func (t *CreateNamedPipeTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateNamedPipeTest) NonExistentParent() {
	t.path = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateNamedPipeTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.path = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateNamedPipeTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.path, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateNamedPipeTest) CreatesCorrectEntry() {
	t.path = path.Join(t.baseDir, "taco")
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeNamedPipe, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateSymlink
////////////////////////////////////////////////////////////////////////

type CreateSymlinkTest struct {
	fileSystemTest

	target  string
	source  string
	perms os.FileMode

	err error
}

func init() { RegisterTestSuite(&CreateSymlinkTest{}) }

func (t *CreateSymlinkTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/foo/bar"
	t.perms = 0644
}

func (t *CreateSymlinkTest) call() {
	t.err = t.fileSystem.CreateSymlink(t.target, t.source, t.perms)
}

func (t *CreateSymlinkTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateSymlinkTest) NonExistentParent() {
	t.source = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateSymlinkTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.source = path.Join(dirpath, "taco")

	// Parent
	err := os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateSymlinkTest) FileAlreadyExistsWithSameName() {
	// Create
	err := ioutil.WriteFile(t.source, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateSymlinkTest) CreatesCorrectEntry() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/burrito"
	t.perms = 0674  // Conflicts with default umask

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any()))
	entry := entries[0]

	ExpectEq(fs.TypeSymlink, entry.Type)
	ExpectEq("taco", entry.Name)
	ExpectEq("/burrito", entry.Target)
	ExpectEq(0674, entry.Permissions)
}

////////////////////////////////////////////////////////////////////////
// CreateHardLink
////////////////////////////////////////////////////////////////////////

type CreateHardLinkTest struct {
	fileSystemTest

	target  string
	source  string

	err error
}

func init() { RegisterTestSuite(&CreateHardLinkTest{}) }

func (t *CreateHardLinkTest) SetUp(i *TestInfo) {
	// Common
	t.fileSystemTest.SetUp(i)

	// Set up defaults.
	t.source = path.Join(t.baseDir, "taco")
	t.target = path.Join(t.baseDir, "burrito")
}

func (t *CreateHardLinkTest) call() {
	t.err = t.fileSystem.CreateHardLink(t.target, t.source)
}

func (t *CreateHardLinkTest) list() []*fs.DirectoryEntry {
	entries, err := t.fileSystem.ReadDir(t.baseDir)
	AssertEq(nil, err)
	return entries
}

func (t *CreateHardLinkTest) NonExistentParent() {
	t.source = "/foo/bar/baz/qux"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("qux")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
}

func (t *CreateHardLinkTest) NoPermissionsForParent() {
	dirpath := path.Join(t.baseDir, "foo")
	t.source = path.Join(dirpath, "taco")

	// Create target
	err := ioutil.WriteFile(t.target, []byte{}, 0644)
	AssertEq(nil, err)

	// Parent
	err = os.Mkdir(dirpath, 0100)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("foo")))
	ExpectThat(t.err, Error(HasSubstr("permission denied")))
}

func (t *CreateHardLinkTest) TargetDoesntExist() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = "/burrito"

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("burrito")))
	ExpectThat(t.err, Error(HasSubstr("no such")))
	ExpectThat(t.err, Error(HasSubstr("file")))
}

func (t *CreateHardLinkTest) FileAlreadyExistsWithSameName() {
	// Create source
	err := ioutil.WriteFile(t.source, []byte{}, 0644)
	AssertEq(nil, err)

	// Create target
	err = ioutil.WriteFile(t.target, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("file exists")))
}

func (t *CreateHardLinkTest) CreatesCorrectEntry() {
	t.source = path.Join(t.baseDir, "taco")
	t.target = path.Join(t.baseDir, "burrito")

	// Create target
	err := ioutil.WriteFile(t.target, []byte{}, 0644)
	AssertEq(nil, err)

	// Call
	t.call()
	AssertEq(nil, t.err)

	// List
	entries := t.list()

	AssertThat(entries, ElementsAre(Any(), Any()))

	entry0 := entries[0]
	ExpectEq(fs.TypeFile, entry0.Type)
	ExpectEq("burrito", entry0.Name)

	entry1 := entries[1]
	ExpectEq(fs.TypeFile, entry1.Type)
	ExpectEq("taco", entry1.Name)

	AssertNe(0, entry0.ContainingDevice)
	ExpectEq(entry1.ContainingDevice, entry0.ContainingDevice)

	AssertNe(0, entry0.Inode)
	ExpectEq(entry1.Inode, entry0.Inode)
}
<|endoftext|>


<commit_before>package conductor

import (
	"github.com/fsouza/go-dockerclient"
	"strings"
)

type Conductor struct {
	Client *docker.Client
}

type ConductorContainer struct {
	Conductor *Conductor
	Container *docker.Container
}

type ConductorContainerConfig struct {
	Name        string
	Image       string
	PortMap     map[string]string
	Environment []string
	Volumes     []string
	Dns         []string
}

func (c *ConductorContainer) ID() string {
	return c.Container.ID
}

func New(Host string) *Conductor {
	client, _ := docker.NewClient(Host)
	return &Conductor{Client: client}
}

func (c *Conductor) PullImage(image string) string {
	parsed := strings.Split(image, "/")
	registry := parsed[0]
	image_and_tag := strings.Join(parsed[1:], "")
	parsed_image := strings.Split(image_and_tag, ":")
	repository := parsed_image[0]
	tag := parsed_image[1]
	opts := docker.PullImageOptions{
		Repository: repository,
		Registry:   registry,
		Tag:        tag,
	}

	c.Client.PullImage(opts, docker.AuthConfiguration{})
	latest_image, _ := c.Client.InspectImage(image)
	return latest_image.ID
}

func (c *Conductor) CreateAndStartContainer(cfg ConductorContainerConfig) {

	portBindings := map[docker.Port][]docker.PortBinding{}

	for k, v := range cfg.PortMap {
		portBindings[docker.Port(k)] = []docker.PortBinding{{HostIP: "0.0.0.0", HostPort: v}}
	}

	hostConfig := &docker.HostConfig{PortBindings: portBindings, Binds: cfg.Volumes, DNS: cfg.Dns}

	container, err := c.Client.CreateContainer(docker.CreateContainerOptions{
		Name:       cfg.Name,
		Config:     &docker.Config{Image: cfg.Image, Env: cfg.Environment},
		HostConfig: hostConfig,
	})

	if err != nil {
		panic(err)
	}

	c.Client.StartContainer(container.ID, hostConfig)
}

func (c *Conductor) RemoveContainer(id string) error {
	return c.Client.RemoveContainer(docker.RemoveContainerOptions{ID: id, Force: true})
}

func (c *Conductor) FindContainer(needle string) *ConductorContainer {
	containers, _ := c.Client.ListContainers(docker.ListContainersOptions{All: true})
	for _, container := range containers {
		for _, name := range container.Names {
			if name == "/"+needle {
				real_container, _ := c.Client.InspectContainer(container.ID)
				return &ConductorContainer{Conductor: c, Container: real_container}
			}
		}
	}
	return &ConductorContainer{}
}
<commit_msg>Always restart containers<commit_after>package conductor

import (
	"github.com/fsouza/go-dockerclient"
	"strings"
)

type Conductor struct {
	Client *docker.Client
}

type ConductorContainer struct {
	Conductor *Conductor
	Container *docker.Container
}

type ConductorContainerConfig struct {
	Name        string
	Image       string
	PortMap     map[string]string
	Environment []string
	Volumes     []string
	Dns         []string
}

func (c *ConductorContainer) ID() string {
	return c.Container.ID
}

func New(Host string) *Conductor {
	client, _ := docker.NewClient(Host)
	return &Conductor{Client: client}
}

func (c *Conductor) PullImage(image string) string {
	parsed := strings.Split(image, "/")
	registry := parsed[0]
	image_and_tag := strings.Join(parsed[1:], "")
	parsed_image := strings.Split(image_and_tag, ":")
	repository := parsed_image[0]
	tag := parsed_image[1]
	opts := docker.PullImageOptions{
		Repository: repository,
		Registry:   registry,
		Tag:        tag,
	}

	c.Client.PullImage(opts, docker.AuthConfiguration{})
	latest_image, _ := c.Client.InspectImage(image)
	return latest_image.ID
}

func (c *Conductor) CreateAndStartContainer(cfg ConductorContainerConfig) {

	portBindings := map[docker.Port][]docker.PortBinding{}

	for k, v := range cfg.PortMap {
		portBindings[docker.Port(k)] = []docker.PortBinding{{HostIP: "0.0.0.0", HostPort: v}}
	}

	hostConfig := &docker.HostConfig{PortBindings: portBindings,
		Binds: cfg.Volumes, DNS: cfg.Dns,
		RestartPolicy: docker.AlwaysRestart()}

	container, err := c.Client.CreateContainer(docker.CreateContainerOptions{
		Name:       cfg.Name,
		Config:     &docker.Config{Image: cfg.Image, Env: cfg.Environment},
		HostConfig: hostConfig,
	})

	if err != nil {
		panic(err)
	}

	c.Client.StartContainer(container.ID, hostConfig)
}

func (c *Conductor) RemoveContainer(id string) error {
	return c.Client.RemoveContainer(docker.RemoveContainerOptions{ID: id, Force: true})
}

func (c *Conductor) FindContainer(needle string) *ConductorContainer {
	containers, _ := c.Client.ListContainers(docker.ListContainersOptions{All: true})
	for _, container := range containers {
		for _, name := range container.Names {
			if name == "/"+needle {
				real_container, _ := c.Client.InspectContainer(container.ID)
				return &ConductorContainer{Conductor: c, Container: real_container}
			}
		}
	}
	return &ConductorContainer{}
}
<|endoftext|>


<commit_before>// The unexport command unexports exported identifiers which are not imported
// by any other Go code.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/refactor/importgraph"
)

// Usage is a replacement usage function for the flags package.
func Usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\tunexport [flags] -identifier T [packages]\n")
	fmt.Fprintf(os.Stderr, "Flags:\n")
	flag.PrintDefaults()
}

func main() {
	var (
		flagIdentifier = flag.String("identifier", "", "comma-separated list of identifiers names; if empty all identifiers are unexported")
		flagDryRun     = flag.Bool("dryrun", false, "show the change, but do not apply")
		flagVerbose    = flag.Bool("verbose", false, "show more information. Useful for debugging.")
	)

	flag.Usage = Usage
	flag.Parse()
	log.SetPrefix("unexport:")

	args := flag.Args()

	if err := runMain(&config{
		importPath:  args[0],
		identifiers: strings.Split(*flagIdentifier, ","),
		dryRun:      *flagDryRun,
		verbose:     *flagVerbose,
	}); err != nil {
		fmt.Fprintf(os.Stderr, "unexport: %s\n", err)
		os.Exit(1)
	}
}

// config is used to define how unexport should be work
type config struct {
	// importPath defines the package defined with the importpath
	importPath string

	// identifiers is used to limit the changes of unexporting to certain identifiers
	identifiers []string

	// logging/development ...
	dryRun  bool
	verbose bool
}

// runMain runs the actual command. It's an helper function so we can easily
// calls defers or return errors.
func runMain(conf *config) error {
	path := conf.importPath

	ctxt := &build.Default
	prog, err := loadProgram(ctxt, map[string]bool{path: true})
	if err != nil {
		return err
	}

	_, rev, errors := importgraph.Build(ctxt)
	if len(errors) > 0 {
		// With a large GOPATH tree, errors are inevitable.
		// Report them but proceed.
		fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
		for path, err := range errors {
			fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
		}
	}

	// Enumerate the set of potentially affected packages.
	possiblePackages := make(map[string]bool)
	for _, obj := range findExportedObjects(prog, path) {
		// External test packages are never imported,
		// so they will never appear in the graph.
		for path := range rev.Search(obj.Pkg().Path()) {
			possiblePackages[path] = true
		}
	}

	fmt.Println("Possible affected packages:")
	for pkg := range possiblePackages {
		fmt.Println("\t", pkg)
	}

	// reload the program with all possible packages to fetch the packageinfo's
	globalProg, err := loadProgram(ctxt, possiblePackages)
	if err != nil {
		return err
	}

	objsToUpdate := make(map[types.Object]bool, 0)
	objects := findExportedObjects(globalProg, path)

	fmt.Println("Exported identififers are:")
	for _, obj := range objects {
		fmt.Println("\t", obj)
	}

	for _, info := range globalProg.Imported {
		safeObjects := filterObjects(info, objects)
		for _, obj := range safeObjects {
			objsToUpdate[obj] = true
		}
	}

	fmt.Println("Safe to unexport identifiers are:")
	for obj := range objsToUpdate {
		fmt.Println("\t", obj)
	}

	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range globalProg.Imported {
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
	}

	var nerrs, npkgs int
	for _, info := range globalProg.Imported {
		first := true
		for _, f := range info.Files {
			tokenFile := globalProg.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
				}
				if err := rewriteFile(globalProg.Fset, f, tokenFile.Name()); err != nil {
					fmt.Fprintf(os.Stderr, "unexport: %s\n", err)
					nerrs++
				}
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Unexported %d occurrence%s in %d file%s in %d package%s.\n",
		nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}
	return nil

}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

func rewriteFile(fset *token.FileSet, f *ast.File, filename string) error {
	fmt.Printf("filename = %+v\n", filename)
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		return fmt.Errorf("failed to pretty-print syntax tree: %v", err)
	}
	return ioutil.WriteFile(filename, buf.Bytes(), 0644)
}

// filterObjects filters the given objects and returns objects which are not in use by the given info package
func filterObjects(info *loader.PackageInfo, exported map[*ast.Ident]types.Object) map[*ast.Ident]types.Object {
	filtered := make(map[*ast.Ident]types.Object, 0)
	for id, ex := range exported {
		if !hasUse(info, ex) {
			filtered[id] = ex
		}
	}

	return filtered
}

// hasUse returns true if the given obj is part of the use in info
func hasUse(info *loader.PackageInfo, obj types.Object) bool {
	for _, o := range info.Uses {
		if o == obj {
			return true
		}
	}
	return false
}

// exportedObjects returns objects which are exported only
func exportedObjects(info *loader.PackageInfo) map[*ast.Ident]types.Object {
	objects := make(map[*ast.Ident]types.Object, 0)
	for id, obj := range info.Defs {
		if obj == nil {
			continue
		}

		if obj.Exported() {
			objects[id] = obj
		}
	}

	return objects
}

func findExportedObjects(prog *loader.Program, path string) map[*ast.Ident]types.Object {
	var pkgObj *types.Package
	for pkg := range prog.AllPackages {
		if pkg.Path() == path {
			pkgObj = pkg
			break
		}
	}

	info := prog.AllPackages[pkgObj]
	return exportedObjects(info)
}

func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:       ctxt,
		ParserMode:  parser.ParseComments,
		AllowErrors: false,
	}

	for pkg := range pkgs {
		conf.ImportWithTests(pkg)
	}
	return conf.Load()
}
<commit_msg>unexport: add build tags, and more cli changes<commit_after>// The unexport command unexports exported identifiers which are not imported
// by any other Go code.
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/refactor/importgraph"
)

func main() {
	var (
		flagPackage    = flag.String("package", "", "package import path to be unexported")
		flagIdentifier = flag.String("identifier", "", "comma-separated list of identifiers names; if empty all identifiers are unexported")
		flagDryRun     = flag.Bool("dryrun", false, "show the change, but do not apply")
		flagVerbose    = flag.Bool("verbose", false, "show more information. Useful for debugging.")
	)

	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)

	flag.Parse()
	log.SetPrefix("unexport:")

	if err := runMain(&config{
		importPath:   *flagPackage,
		identifiers:  strings.Split(*flagIdentifier, ","),
		buildContext: &build.Default,
		dryRun:       *flagDryRun,
		verbose:      *flagVerbose,
	}); err != nil {
		fmt.Fprintf(os.Stderr, "unexport: %s\n", err)
		os.Exit(1)
	}
}

// config is used to define how unexport should be work
type config struct {
	// importPath defines the package defined with the importpath
	importPath string

	// identifiers is used to limit the changes of unexporting to certain identifiers
	identifiers []string

	// build context
	buildContext *build.Context

	// logging/development ...
	dryRun  bool
	verbose bool
}

// runMain runs the actual command. It's an helper function so we can easily
// calls defers or return errors.
func runMain(conf *config) error {
	if conf.importPath == "" {
		return errors.New("import path of the package must be given")
	}

	path := conf.importPath

	prog, err := loadProgram(conf.buildContext, map[string]bool{path: true})
	if err != nil {
		return err
	}

	_, rev, errors := importgraph.Build(conf.buildContext)
	if len(errors) > 0 {
		// With a large GOPATH tree, errors are inevitable.
		// Report them but proceed.
		fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
		for path, err := range errors {
			fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
		}
	}

	// Enumerate the set of potentially affected packages.
	possiblePackages := make(map[string]bool)
	for _, obj := range findExportedObjects(prog, path) {
		// External test packages are never imported,
		// so they will never appear in the graph.
		for path := range rev.Search(obj.Pkg().Path()) {
			possiblePackages[path] = true
		}
	}

	if conf.verbose {
		fmt.Println("Possible affected packages:")
		for pkg := range possiblePackages {
			fmt.Println("\t", pkg)
		}
	}

	// reload the program with all possible packages to fetch the packageinfo's
	globalProg, err := loadProgram(conf.buildContext, possiblePackages)
	if err != nil {
		return err
	}

	objsToUpdate := make(map[types.Object]bool, 0)
	objects := findExportedObjects(globalProg, path)

	if conf.verbose {
		log.Println("Exported identififers are:")
		for _, obj := range objects {
			log.Println("\t", obj)
		}
	}

	for _, info := range globalProg.Imported {
		safeObjects := filterObjects(info, objects)
		for _, obj := range safeObjects {
			objsToUpdate[obj] = true
		}
	}

	if conf.verbose {
		log.Println("Safe to unexport identifiers are:")
		for obj := range objsToUpdate {
			log.Println("\t", obj)
		}
	}

	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range globalProg.Imported {
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
	}

	var nerrs, npkgs int
	for _, info := range globalProg.Imported {
		first := true
		for _, f := range info.Files {
			tokenFile := globalProg.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
				}
				if err := rewriteFile(globalProg.Fset, f, tokenFile.Name()); err != nil {
					log.Println(err)
					nerrs++
				}
			}
		}
	}

	log.Printf("Unexported %d occurrence%s in %d file%s in %d package%s.\n", nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}

	return nil
}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

func rewriteFile(fset *token.FileSet, f *ast.File, filename string) error {
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		return fmt.Errorf("failed to pretty-print syntax tree: %v", err)
	}
	return ioutil.WriteFile(filename, buf.Bytes(), 0644)
}

// filterObjects filters the given objects and returns objects which are not in use by the given info package
func filterObjects(info *loader.PackageInfo, exported map[*ast.Ident]types.Object) map[*ast.Ident]types.Object {
	filtered := make(map[*ast.Ident]types.Object, 0)
	for id, ex := range exported {
		if !hasUse(info, ex) {
			filtered[id] = ex
		}
	}

	return filtered
}

// hasUse returns true if the given obj is part of the use in info
func hasUse(info *loader.PackageInfo, obj types.Object) bool {
	for _, o := range info.Uses {
		if o == obj {
			return true
		}
	}
	return false
}

// exportedObjects returns objects which are exported only
func exportedObjects(info *loader.PackageInfo) map[*ast.Ident]types.Object {
	objects := make(map[*ast.Ident]types.Object, 0)
	for id, obj := range info.Defs {
		if obj == nil {
			continue
		}

		if obj.Exported() {
			objects[id] = obj
		}
	}

	return objects
}

func findExportedObjects(prog *loader.Program, path string) map[*ast.Ident]types.Object {
	var pkgObj *types.Package
	for pkg := range prog.AllPackages {
		if pkg.Path() == path {
			pkgObj = pkg
			break
		}
	}

	info := prog.AllPackages[pkgObj]
	return exportedObjects(info)
}

func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:       ctxt,
		ParserMode:  parser.ParseComments,
		AllowErrors: false,
	}

	for pkg := range pkgs {
		conf.ImportWithTests(pkg)
	}
	return conf.Load()
}
<|endoftext|>


<commit_before>// The unexport command unexports exported identifiers which are not imported
// by any other Go code.
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/refactor/importgraph"
)

func main() {
	var (
		flagPackage    = flag.String("package", "", "package import path to be unexported")
		flagIdentifier = flag.String("identifier", "", "comma-separated list of identifiers names; if empty all identifiers are unexported")
		flagDryRun     = flag.Bool("dryrun", false, "show the change, but do not apply")
		flagVerbose    = flag.Bool("verbose", false, "show more information. Useful for debugging.")
	)

	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)

	flag.Parse()
	log.SetPrefix("unexport:")

	if err := runMain(&config{
		importPath:   *flagPackage,
		identifiers:  strings.Split(*flagIdentifier, ","),
		buildContext: &build.Default,
		dryRun:       *flagDryRun,
		verbose:      *flagVerbose,
	}); err != nil {
		fmt.Fprintf(os.Stderr, "unexport: %s\n", err)
		os.Exit(1)
	}
}

// config is used to define how unexport should be work
type config struct {
	// importPath defines the package defined with the importpath
	importPath string

	// identifiers is used to limit the changes of unexporting to certain identifiers
	identifiers []string

	// build context
	buildContext *build.Context

	// logging/development ...
	dryRun  bool
	verbose bool
}

// runMain runs the actual command. It's an helper function so we can easily
// calls defers or return errors.
func runMain(conf *config) error {
	if conf.importPath == "" {
		return errors.New("import path of the package must be given")
	}

	path := conf.importPath

	prog, err := loadProgram(conf.buildContext, map[string]bool{path: true})
	if err != nil {
		return err
	}

	_, rev, errors := importgraph.Build(conf.buildContext)
	if len(errors) > 0 {
		// With a large GOPATH tree, errors are inevitable.
		// Report them but proceed.
		fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
		for path, err := range errors {
			fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
		}
	}

	// Enumerate the set of potentially affected packages.
	possiblePackages := make(map[string]bool)
	for _, obj := range findExportedObjects(prog, path) {
		// External test packages are never imported,
		// so they will never appear in the graph.
		for path := range rev.Search(obj.Pkg().Path()) {
			possiblePackages[path] = true
		}
	}

	if conf.verbose {
		fmt.Println("Possible affected packages:")
		for pkg := range possiblePackages {
			fmt.Println("\t", pkg)
		}
	}

	// reload the program with all possible packages to fetch the packageinfo's
	globalProg, err := loadProgram(conf.buildContext, possiblePackages)
	if err != nil {
		return err
	}

	objsToUpdate := make(map[types.Object]bool, 0)
	objects := findExportedObjects(globalProg, path)

	if conf.verbose {
		log.Println("Exported identififers are:")
		for _, obj := range objects {
			log.Println("\t", obj)
		}
	}

	for _, info := range globalProg.Imported {
		safeObjects := filterObjects(info, objects)
		for _, obj := range safeObjects {
			objsToUpdate[obj] = true
		}
	}

	if conf.verbose {
		log.Println("Safe to unexport identifiers are:")
		for obj := range objsToUpdate {
			log.Println("\t", obj)
		}
	}

	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range globalProg.Imported {
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
	}

	var nerrs, npkgs int
	for _, info := range globalProg.Imported {
		first := true
		for _, f := range info.Files {
			tokenFile := globalProg.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
				}
				if err := rewriteFile(globalProg.Fset, f, tokenFile.Name()); err != nil {
					log.Println(err)
					nerrs++
				}
			}
		}
	}

	log.Printf("Unexported %d occurrence%s in %d file%s in %d package%s.\n", nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}

	return nil
}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

func rewriteFile(fset *token.FileSet, f *ast.File, filename string) error {
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		return fmt.Errorf("failed to pretty-print syntax tree: %v", err)
	}
	return ioutil.WriteFile(filename, buf.Bytes(), 0644)
}

// filterObjects filters the given objects and returns objects which are not in use by the given info package
func filterObjects(info *loader.PackageInfo, exported map[*ast.Ident]types.Object) map[*ast.Ident]types.Object {
	filtered := make(map[*ast.Ident]types.Object, 0)
	for id, ex := range exported {
		if !hasUse(info, ex) {
			filtered[id] = ex
		}
	}

	return filtered
}

// hasUse returns true if the given obj is part of the use in info
func hasUse(info *loader.PackageInfo, obj types.Object) bool {
	for _, o := range info.Uses {
		if o == obj {
			return true
		}
	}
	return false
}

// exportedObjects returns objects which are exported only
func exportedObjects(info *loader.PackageInfo) map[*ast.Ident]types.Object {
	objects := make(map[*ast.Ident]types.Object, 0)
	for id, obj := range info.Defs {
		if obj == nil {
			continue
		}

		if obj.Exported() {
			objects[id] = obj
		}
	}

	return objects
}

func findExportedObjects(prog *loader.Program, path string) map[*ast.Ident]types.Object {
	var pkgObj *types.Package
	for pkg := range prog.AllPackages {
		if pkg.Path() == path {
			pkgObj = pkg
			break
		}
	}

	info := prog.AllPackages[pkgObj]
	return exportedObjects(info)
}

func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:       ctxt,
		ParserMode:  parser.ParseComments,
		AllowErrors: false,
	}

	for pkg := range pkgs {
		conf.ImportWithTests(pkg)
	}
	return conf.Load()
}
<commit_msg>unexport: couple of fmt -> log changes<commit_after>// The unexport command unexports exported identifiers which are not imported
// by any other Go code.
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/refactor/importgraph"
)

func main() {
	var (
		flagPackage    = flag.String("package", "", "package import path to be unexported")
		flagIdentifier = flag.String("identifier", "", "comma-separated list of identifiers names; if empty all identifiers are unexported")
		flagDryRun     = flag.Bool("dryrun", false, "show the change, but do not apply")
		flagVerbose    = flag.Bool("verbose", false, "show more information. Useful for debugging.")
	)

	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)

	flag.Parse()

	log.SetPrefix("unexport:")

	if err := runMain(&config{
		importPath:   *flagPackage,
		identifiers:  strings.Split(*flagIdentifier, ","),
		buildContext: &build.Default,
		dryRun:       *flagDryRun,
		verbose:      *flagVerbose,
	}); err != nil {
		log.Println(err)
		os.Exit(1)
	}
}

// config is used to define how unexport should be work
type config struct {
	// importPath defines the package defined with the importpath
	importPath string

	// identifiers is used to limit the changes of unexporting to certain identifiers
	identifiers []string

	// build context
	buildContext *build.Context

	// logging/development ...
	dryRun  bool
	verbose bool
}

// runMain runs the actual command. It's an helper function so we can easily
// calls defers or return errors.
func runMain(conf *config) error {
	if conf.importPath == "" {
		return errors.New("import path of the package must be given")
	}

	path := conf.importPath

	prog, err := loadProgram(conf.buildContext, map[string]bool{path: true})
	if err != nil {
		return err
	}

	_, rev, errors := importgraph.Build(conf.buildContext)
	if len(errors) > 0 {
		// With a large GOPATH tree, errors are inevitable.
		// Report them but proceed.
		log.Printf("while scanning Go workspace:\n")
		for path, err := range errors {
			log.Printf("Package %q: %s.\n", path, err)
		}
	}

	// Enumerate the set of potentially affected packages.
	possiblePackages := make(map[string]bool)
	for _, obj := range findExportedObjects(prog, path) {
		for path := range rev.Search(obj.Pkg().Path()) {
			possiblePackages[path] = true
		}
	}

	if conf.verbose {
		log.Println("Possible affected packages:")
		for pkg := range possiblePackages {
			log.Println("\t", pkg)
		}
	}

	// reload the program with all possible packages to fetch the packageinfo's
	globalProg, err := loadProgram(conf.buildContext, possiblePackages)
	if err != nil {
		return err
	}

	objsToUpdate := make(map[types.Object]bool, 0)
	objects := findExportedObjects(globalProg, path)

	if conf.verbose {
		log.Println("Exported identififers are:")
		for _, obj := range objects {
			log.Println("\t", obj)
		}
	}

	for _, info := range globalProg.Imported {
		safeObjects := filterObjects(info, objects)
		for _, obj := range safeObjects {
			objsToUpdate[obj] = true
		}
	}

	if conf.verbose {
		log.Println("Safe to unexport identifiers are:")
		for obj := range objsToUpdate {
			log.Println("\t", obj)
		}
	}

	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range globalProg.Imported {
		for id, obj := range info.Defs {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if objsToUpdate[obj] {
				nidents++
				id.Name = strings.ToLower(obj.Name())
				filesToUpdate[globalProg.Fset.File(id.Pos())] = true
			}
		}
	}

	var nerrs, npkgs int
	for _, info := range globalProg.Imported {
		first := true
		for _, f := range info.Files {
			tokenFile := globalProg.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
				}
				if err := rewriteFile(globalProg.Fset, f, tokenFile.Name()); err != nil {
					log.Println(err)
					nerrs++
				}
			}
		}
	}

	log.Printf("Unexported %d occurrence%s in %d file%s in %d package%s.\n", nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}

	return nil
}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

func rewriteFile(fset *token.FileSet, f *ast.File, filename string) error {
	var buf bytes.Buffer
	if err := format.Node(&buf, fset, f); err != nil {
		return fmt.Errorf("failed to pretty-print syntax tree: %v", err)
	}
	return ioutil.WriteFile(filename, buf.Bytes(), 0644)
}

// filterObjects filters the given objects and returns objects which are not in use by the given info package
func filterObjects(info *loader.PackageInfo, exported map[*ast.Ident]types.Object) map[*ast.Ident]types.Object {
	filtered := make(map[*ast.Ident]types.Object, 0)
	for id, ex := range exported {
		if !hasUse(info, ex) {
			filtered[id] = ex
		}
	}

	return filtered
}

// hasUse returns true if the given obj is part of the use in info
func hasUse(info *loader.PackageInfo, obj types.Object) bool {
	for _, o := range info.Uses {
		if o == obj {
			return true
		}
	}
	return false
}

// exportedObjects returns objects which are exported only
func exportedObjects(info *loader.PackageInfo) map[*ast.Ident]types.Object {
	objects := make(map[*ast.Ident]types.Object, 0)
	for id, obj := range info.Defs {
		if obj == nil {
			continue
		}

		if obj.Exported() {
			objects[id] = obj
		}
	}

	return objects
}

func findExportedObjects(prog *loader.Program, path string) map[*ast.Ident]types.Object {
	var pkgObj *types.Package
	for pkg := range prog.AllPackages {
		if pkg.Path() == path {
			pkgObj = pkg
			break
		}
	}

	info := prog.AllPackages[pkgObj]
	return exportedObjects(info)
}

func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:       ctxt,
		ParserMode:  parser.ParseComments,
		AllowErrors: false,
	}

	for pkg := range pkgs {
		conf.ImportWithTests(pkg)
	}
	return conf.Load()
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

func TestLoadconfig(t *testing.T) {
	var res bool
	res = LoadConfig(Default_conf)
	if res != true {
		t.Error("Expected true, got ", res)
	}

	var err error
	err = ValidateConfig(config)
	if err != nil {
		t.Error("ValidateConfig failed ", err.Error())
	}
}

// func TestRunCommand(t *testing.T) {
// 	var res bool
// 	command := []string{"touch", "file.txt"}
// 	res = RunCommand(command)
// 	if res != true {
// 		t.Error("Expected true, got ", res)
// 	}
// }
<commit_msg>write tests for helper<commit_after>package main

import (
	"testing"
)

func TestLoadconfig(t *testing.T) {
	var res bool
	res = LoadConfig(Default_conf)
	if res != true {
		t.Error("Expected true, got ", res)
	}

	var err error
	err = ValidateConfig(config)
	if err != nil {
		t.Error("ValidateConfig failed ", err.Error())
	}
}

func TestParseFields(t *testing.T) {
	cdr_fields := []ParseFields{
		{Orig_field: "uuid", Dest_field: "callid", Type_field: "string"},
		{Orig_field: "caller_id_name", Dest_field: "caller_id_name", Type_field: "string"},
	}
	strfields := get_fields_select(cdr_fields)
	if strfields != "rowid, uuid, caller_id_name" {
		t.Error("Expected 'rowid, uuid, caller_id_name', got ", strfields)
	}

	insertf, _ := build_fieldlist_insert(cdr_fields)
	if insertf != "switch, callid, caller_id_name" {
		t.Error("Expected 'switch, callid, caller_id_name', got ", insertf)
	}

	cdr_fields = []ParseFields{
		{Orig_field: "uuid", Dest_field: "callid", Type_field: "string"},
		{Orig_field: "customfield", Dest_field: "extradata", Type_field: "jsonb"},
	}

	insertf_extra, extradata := build_fieldlist_insert(cdr_fields)
	if insertf_extra != "switch, callid, extradata" {
		t.Error("Expected 'switch, callid, extradata', got ", insertf_extra)
	}
	expectedmap := map[int]string{1: "customfield"}
	if extradata[1] != expectedmap[1] {
		t.Error("Expected 'map[1:customfield]', got ", extradata)
	}

}
<|endoftext|>