<commit_before>package game

import (
	"fmt"
	"image/color"
	"time"

	"golang.org/x/image/font/basicfont"

	"github.com/Bredgren/game1/game/camera"
	"github.com/Bredgren/game1/game/keymap"
	"github.com/Bredgren/game1/game/keymap/button"
	"github.com/Bredgren/game1/game/ui"
	"github.com/Bredgren/geo"
	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

const (
	buttonWidth  = 350
	buttonHeight = 20
)

type mainMenuState struct {
	p            *player
	screenHeight int
	cam          *camera.Camera
	bg           *background
	keymap       keymap.Layers
	remapAction  keymap.Action
	remap        bool
	remapText    *ui.Text

	menu           ui.Drawer
	btns           map[keymap.Action]*ui.Button
	actionText     map[keymap.Action]*ui.Text
	keyText        map[keymap.Action]*ui.Text
	gamepadText    map[keymap.Action]*ui.Text
	canClickButton bool
}

func newMainMenu(p *player, screenHeight int, cam *camera.Camera, bg *background,
	km keymap.Layers) *mainMenuState {
	m := &mainMenuState{
		p:            p,
		screenHeight: screenHeight,
		cam:          cam,
		bg:           bg,
		keymap:       km,

		btns:           map[keymap.Action]*ui.Button{},
		actionText:     map[keymap.Action]*ui.Text{},
		keyText:        map[keymap.Action]*ui.Text{},
		gamepadText:    map[keymap.Action]*ui.Text{},
		canClickButton: true,
	}

	m.setupMenu()
	m.setupKeymap()

	return m
}

func (m *mainMenuState) setupMenu() {
	idleImg, _ := ebiten.NewImage(buttonWidth, buttonHeight, ebiten.FilterNearest)
	idleImg.Fill(color.NRGBA{200, 200, 200, 50})
	hoverImg, _ := ebiten.NewImage(buttonWidth, buttonHeight, ebiten.FilterNearest)
	hoverImg.Fill(color.NRGBA{100, 100, 100, 50})

	var elements []ui.WeightedDrawer

	m.remapText = &ui.Text{
		Anchor: ui.AnchorCenter,
		Color:  color.Black,
		Face:   basicfont.Face7x13,
		Wt:     0.5,
	}

	elements = append(elements, m.remapText)

	actions := []keymap.Action{
		left, right, move, jump, punch, punchH, punchV, uppercut, slam, launch,
	}
	for _, action := range actions {
		action := action // For use in callbacks

		_, isAxis := m.keymap[playerLayer].GamepadAxis.GetAxis(action)
		m.keyText[action] = &ui.Text{
			Anchor: ui.AnchorLeft,
			Color:  color.Black,
			Face:   basicfont.Face7x13,
			Wt:     1,
		}
		m.gamepadText[action] = &ui.Text{
			Anchor: ui.AnchorLeft,
			Color:  color.Black,
			Face:   basicfont.Face7x13,
			Wt:     1,
		}
		m.actionText[action] = &ui.Text{
			Text: string(action),
			Anchor: ui.Anchor{
				Src:    geo.VecXY(0, 0.5),
				Dst:    geo.VecXY(0, 0.5),
				Offset: geo.VecXY(5, 0),
			},
			Color: color.Black,
			Face:  basicfont.Face7x13,
			Wt:    1.6,
		}

		var onClick func()
		if isAxis {
			onClick = func() {
				// m.remap = true
				// m.remapAction = action
				m.remapText.Text = fmt.Sprintf("Select new axis for '%s'", action)
			}
		} else {
			onClick = func() {
				m.remap = true
				m.remapAction = action
				m.remapText.Text = fmt.Sprintf("Select new key for '%s'", action)
			}
		}
		m.btns[action] = &ui.Button{
			IdleImg:     idleImg,
			HoverImg:    hoverImg,
			IdleAnchor:  ui.AnchorCenter,
			HoverAnchor: ui.AnchorCenter,
			Element: &ui.HorizontalContainer{
				Wt: 1,
				Elements: []ui.WeightedDrawer{
					m.actionText[action],
					m.keyText[action],
					m.gamepadText[action],
				},
			},
			Wt:      1,
			OnClick: onClick,
		}
		elements = append(elements, m.btns[action])
	}

	m.menu = &ui.VerticalContainer{
		Wt:       1,
		Elements: elements,
	}

	m.updateText()
}

func (m *mainMenuState) updateText() {
	actions := []keymap.Action{
		left, right, move, jump, punch, punchH, punchV, uppercut, slam, launch,
	}
	for _, action := range actions {
		if btn, ok := m.keymap[playerLayer].KeyMouse.GetButton(action); ok {
			m.keyText[action].Text = btn.String()
			m.keyText[action].Color = color.Black
		} else {
			m.keyText[action].Text = "N/A"
			if _, valid := defaultKeyMap.KeyMouse.GetButton(action); valid {
				m.keyText[action].Color = color.NRGBA{200, 0, 0, 200}
			} else {
				m.keyText[action].Color = color.NRGBA{0, 0, 0, 100}
			}
		}

		if btn, ok := m.keymap[playerLayer].GamepadBtn.GetButton(action); ok {
			m.gamepadText[action].Text = fmt.Sprintf("Gamepad %d", btn)
			m.gamepadText[action].Color = color.Black
		} else if axis, ok := m.keymap[playerLayer].GamepadAxis.GetAxis(action); ok {
			m.gamepadText[action].Text = fmt.Sprintf("Axis %d", axis)
			m.gamepadText[action].Color = color.Black
		} else {
			m.gamepadText[action].Text = "N/A"
			if _, valid := defaultKeyMap.GamepadBtn.GetButton(action); valid {
				m.gamepadText[action].Color = color.NRGBA{200, 0, 0, 200}
			} else {
				m.gamepadText[action].Color = color.NRGBA{0, 0, 0, 100}
			}
		}
	}
}

func (m *mainMenuState) setupKeymap() {
	//// Setup remap layer
	// Button handlers
	remapHandlers := keymap.ButtonHandlerMap{}
	for key := ebiten.Key0; key <= ebiten.KeyMax; key++ {
		action := keymap.Action(fmt.Sprintf("key%d", key))
		remapHandlers[action] = m.keyRemapHandler(button.FromKey(key))
	}
	remapHandlers[keymap.Action("mouse0")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonLeft))
	remapHandlers[keymap.Action("mouse1")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonMiddle))
	remapHandlers[keymap.Action("mouse2")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonRight))

	// Gamepad handlers
	for btn := ebiten.GamepadButton0; btn < ebiten.GamepadButtonMax; btn++ {
		action := keymap.Action(fmt.Sprintf("btn%d", btn))
		remapHandlers[action] = m.btnRemapHandler(btn)
	}

	// Axis handlers
	axisHandlers := keymap.AxisHandlerMap{}
	// // We don't know how many axes there will be at this point so just do alot :P
	// for axis := 0; axis < 100; axis++ {
	// 	action := keymap.Action(fmt.Sprintf("axis%d", axis))
	// 	axisHandlers[action] = m.axisRemapHandler(axis)
	// }

	m.keymap[remapLayer] = keymap.New(remapHandlers, axisHandlers)

	// Button actions
	for key := ebiten.Key0; key <= ebiten.KeyMax; key++ {
		action := keymap.Action(fmt.Sprintf("key%d", key))
		m.keymap[remapLayer].KeyMouse.Set(button.FromKey(key), action)
	}
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonLeft), "mouse0")
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonMiddle), "mouse1")
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonRight), "mouse2")

	// Gamepad actions
	for btn := ebiten.GamepadButton0; btn < ebiten.GamepadButtonMax; btn++ {
		action := keymap.Action(fmt.Sprintf("btn%d", btn))
		m.keymap[remapLayer].GamepadBtn.Set(btn, action)
	}

	// Axis actions
	// for axis := 0; axis < 100; axis++ {
	// 	action := keymap.Action(fmt.Sprintf("axis%d", axis))
	// 	m.keymap[remapLayer].GamepadAxis.Set(axis, action)
	// }

	//// Setup UI handlers
	leftClickHandlers := keymap.ButtonHandlerMap{
		leftClick: m.leftMouseHandler,
	}
	m.keymap[leftClickLayer] = keymap.New(leftClickHandlers, nil)
	m.keymap[leftClickLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonLeft), leftClick)

	colorFn := func(action keymap.Action) keymap.ButtonHandler {
		return func(down bool) bool {
			if down {
				m.actionText[action].Color = color.White
			} else {
				m.actionText[action].Color = color.Black
			}
			return false
		}
	}

	axisFn := func(action keymap.Action) keymap.AxisHandler {
		return func(val float64) bool {
			var axis int
			fmt.Sscanf(m.gamepadText[action].Text, "Axis %d", &axis)
			m.gamepadText[action].Text = fmt.Sprintf("Axis %d (%.2f)", axis, val)
			return false
		}
	}

	// UI handlers
	uiHandlers := keymap.ButtonHandlerMap{
		left:     colorFn(left),
		right:    colorFn(right),
		jump:     colorFn(jump),
		uppercut: colorFn(uppercut),
		slam:     colorFn(slam),
		punch:    colorFn(punch),
		launch:   colorFn(launch),
	}
	uiAxisHandlers := keymap.AxisHandlerMap{
		move:   axisFn(move),
		punchH: axisFn(punchH),
		punchV: axisFn(punchV),
	}
	m.keymap[uiLayer] = keymap.New(uiHandlers, uiAxisHandlers)
	setDefaultKeyMap(m.keymap[uiLayer])
}

func (m *mainMenuState) keyRemapHandler(btn button.KeyMouse) keymap.ButtonHandler {
	return func(down bool) bool {
		if !m.canClickButton && btn.IsMouse() {
			// This prevents us from always immediately remapping to left mouse
			return false
		}

		_, valid := defaultKeyMap.KeyMouse.GetButton(m.remapAction)
		if down && m.remap && valid {
			m.keymap[playerLayer].KeyMouse.Set(btn, m.remapAction)
			m.keymap[uiLayer].KeyMouse.Set(btn, m.remapAction)
			m.remap = false
			m.remapText.Text = ""
			m.updateText()

			if btn.IsMouse() {
				// This prevents us from clicking a button if remapping to left mouse while hover
				// over a button
				m.canClickButton = false
			}

			return true
		}

		// No reason to stop propagation here because either the button is up or is not
		// remappable
		return false
	}
}

func (m *mainMenuState) btnRemapHandler(btn ebiten.GamepadButton) keymap.ButtonHandler {
	return func(down bool) bool {
		_, valid := defaultKeyMap.GamepadBtn.GetButton(m.remapAction)
		if down && m.remap && valid {
			m.keymap[playerLayer].GamepadBtn.Set(btn, m.remapAction)
			m.keymap[uiLayer].GamepadBtn.Set(btn, m.remapAction)
			m.remap = false
			m.updateText()
		}

		// No reason to stop propagation here because either the button is up or is not
		// remappable
		return false
	}
}

// func (m *mainMenuState) axisRemapHandler(axis int) keymap.AxisHandler {
// 	return func(val float64) bool {
// 		remap := m.remap
// 		if val != 0 && remap {
// 			log.Println("remap axis to", axis)
// 			m.keymap[playerLayer].GamepadAxis.Set(axis, m.remapAction)
// 			m.remap = false
// 		}
// 		return remap
// 	}
// }

func (m *mainMenuState) begin(previousState gameStateName) {
	m.cam.Target = fixedCameraTarget{geo.VecXY(m.p.pos.X, -float64(m.screenHeight)*0.4)}
}

func (m *mainMenuState) end() {

}

func (m *mainMenuState) nextState() gameStateName {
	return mainMenu
}

func (m *mainMenuState) update(dt time.Duration) {
	m.p.update(dt)

	for _, b := range m.btns {
		b.Update()
	}
}

func (m *mainMenuState) draw(dst *ebiten.Image, cam *camera.Camera) {
	m.bg.Draw(dst, cam)
	m.p.draw(dst, cam)

	x, y := 120.0, 20.0
	height := 220.0
	ebitenutil.DrawRect(dst, x, y, buttonWidth, height, color.NRGBA{100, 100, 100, 50})
	m.menu.Draw(dst, geo.RectXYWH(x, y, buttonWidth, height))
}

func (m *mainMenuState) leftMouseHandler(down bool) bool {
	if m.canClickButton && down {
		for _, b := range m.btns {
			if b.Hover {
				b.OnClick()
				m.canClickButton = false
				return true
			}
		}
	}
	m.canClickButton = !down
	return false
}
<commit_msg>Reword remap indication string<commit_after>package game

import (
	"fmt"
	"image/color"
	"time"

	"golang.org/x/image/font/basicfont"

	"github.com/Bredgren/game1/game/camera"
	"github.com/Bredgren/game1/game/keymap"
	"github.com/Bredgren/game1/game/keymap/button"
	"github.com/Bredgren/game1/game/ui"
	"github.com/Bredgren/geo"
	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

const (
	buttonWidth  = 350
	buttonHeight = 20
)

type mainMenuState struct {
	p            *player
	screenHeight int
	cam          *camera.Camera
	bg           *background
	keymap       keymap.Layers
	remapAction  keymap.Action
	remap        bool
	remapText    *ui.Text

	menu           ui.Drawer
	btns           map[keymap.Action]*ui.Button
	actionText     map[keymap.Action]*ui.Text
	keyText        map[keymap.Action]*ui.Text
	gamepadText    map[keymap.Action]*ui.Text
	canClickButton bool
}

func newMainMenu(p *player, screenHeight int, cam *camera.Camera, bg *background,
	km keymap.Layers) *mainMenuState {
	m := &mainMenuState{
		p:            p,
		screenHeight: screenHeight,
		cam:          cam,
		bg:           bg,
		keymap:       km,

		btns:           map[keymap.Action]*ui.Button{},
		actionText:     map[keymap.Action]*ui.Text{},
		keyText:        map[keymap.Action]*ui.Text{},
		gamepadText:    map[keymap.Action]*ui.Text{},
		canClickButton: true,
	}

	m.setupMenu()
	m.setupKeymap()

	return m
}

func (m *mainMenuState) setupMenu() {
	idleImg, _ := ebiten.NewImage(buttonWidth, buttonHeight, ebiten.FilterNearest)
	idleImg.Fill(color.NRGBA{200, 200, 200, 50})
	hoverImg, _ := ebiten.NewImage(buttonWidth, buttonHeight, ebiten.FilterNearest)
	hoverImg.Fill(color.NRGBA{100, 100, 100, 50})

	var elements []ui.WeightedDrawer

	m.remapText = &ui.Text{
		Anchor: ui.AnchorCenter,
		Color:  color.Black,
		Face:   basicfont.Face7x13,
		Wt:     0.5,
	}

	elements = append(elements, m.remapText)

	actions := []keymap.Action{
		left, right, move, jump, punch, punchH, punchV, uppercut, slam, launch,
	}
	for _, action := range actions {
		action := action // For use in callbacks

		_, isAxis := m.keymap[playerLayer].GamepadAxis.GetAxis(action)
		m.keyText[action] = &ui.Text{
			Anchor: ui.AnchorLeft,
			Color:  color.Black,
			Face:   basicfont.Face7x13,
			Wt:     1,
		}
		m.gamepadText[action] = &ui.Text{
			Anchor: ui.AnchorLeft,
			Color:  color.Black,
			Face:   basicfont.Face7x13,
			Wt:     1,
		}
		m.actionText[action] = &ui.Text{
			Text: string(action),
			Anchor: ui.Anchor{
				Src:    geo.VecXY(0, 0.5),
				Dst:    geo.VecXY(0, 0.5),
				Offset: geo.VecXY(5, 0),
			},
			Color: color.Black,
			Face:  basicfont.Face7x13,
			Wt:    1.6,
		}

		var onClick func()
		if isAxis {
			onClick = func() {
				// m.remap = true
				// m.remapAction = action
				m.remapText.Text = fmt.Sprintf("Select new axis for '%s'", action)
			}
		} else {
			onClick = func() {
				m.remap = true
				m.remapAction = action
				m.remapText.Text = fmt.Sprintf("Press new key/mouse button for '%s'", action)
			}
		}
		m.btns[action] = &ui.Button{
			IdleImg:     idleImg,
			HoverImg:    hoverImg,
			IdleAnchor:  ui.AnchorCenter,
			HoverAnchor: ui.AnchorCenter,
			Element: &ui.HorizontalContainer{
				Wt: 1,
				Elements: []ui.WeightedDrawer{
					m.actionText[action],
					m.keyText[action],
					m.gamepadText[action],
				},
			},
			Wt:      1,
			OnClick: onClick,
		}
		elements = append(elements, m.btns[action])
	}

	m.menu = &ui.VerticalContainer{
		Wt:       1,
		Elements: elements,
	}

	m.updateText()
}

func (m *mainMenuState) updateText() {
	actions := []keymap.Action{
		left, right, move, jump, punch, punchH, punchV, uppercut, slam, launch,
	}
	for _, action := range actions {
		if btn, ok := m.keymap[playerLayer].KeyMouse.GetButton(action); ok {
			m.keyText[action].Text = btn.String()
			m.keyText[action].Color = color.Black
		} else {
			m.keyText[action].Text = "N/A"
			if _, valid := defaultKeyMap.KeyMouse.GetButton(action); valid {
				m.keyText[action].Color = color.NRGBA{200, 0, 0, 200}
			} else {
				m.keyText[action].Color = color.NRGBA{0, 0, 0, 100}
			}
		}

		if btn, ok := m.keymap[playerLayer].GamepadBtn.GetButton(action); ok {
			m.gamepadText[action].Text = fmt.Sprintf("Gamepad %d", btn)
			m.gamepadText[action].Color = color.Black
		} else if axis, ok := m.keymap[playerLayer].GamepadAxis.GetAxis(action); ok {
			m.gamepadText[action].Text = fmt.Sprintf("Axis %d", axis)
			m.gamepadText[action].Color = color.Black
		} else {
			m.gamepadText[action].Text = "N/A"
			if _, valid := defaultKeyMap.GamepadBtn.GetButton(action); valid {
				m.gamepadText[action].Color = color.NRGBA{200, 0, 0, 200}
			} else {
				m.gamepadText[action].Color = color.NRGBA{0, 0, 0, 100}
			}
		}
	}
}

func (m *mainMenuState) setupKeymap() {
	//// Setup remap layer
	// Button handlers
	remapHandlers := keymap.ButtonHandlerMap{}
	for key := ebiten.Key0; key <= ebiten.KeyMax; key++ {
		action := keymap.Action(fmt.Sprintf("key%d", key))
		remapHandlers[action] = m.keyRemapHandler(button.FromKey(key))
	}
	remapHandlers[keymap.Action("mouse0")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonLeft))
	remapHandlers[keymap.Action("mouse1")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonMiddle))
	remapHandlers[keymap.Action("mouse2")] = m.keyRemapHandler(button.FromMouse(ebiten.MouseButtonRight))

	// Gamepad handlers
	for btn := ebiten.GamepadButton0; btn < ebiten.GamepadButtonMax; btn++ {
		action := keymap.Action(fmt.Sprintf("btn%d", btn))
		remapHandlers[action] = m.btnRemapHandler(btn)
	}

	// Axis handlers
	axisHandlers := keymap.AxisHandlerMap{}
	// // We don't know how many axes there will be at this point so just do alot :P
	// for axis := 0; axis < 100; axis++ {
	// 	action := keymap.Action(fmt.Sprintf("axis%d", axis))
	// 	axisHandlers[action] = m.axisRemapHandler(axis)
	// }

	m.keymap[remapLayer] = keymap.New(remapHandlers, axisHandlers)

	// Button actions
	for key := ebiten.Key0; key <= ebiten.KeyMax; key++ {
		action := keymap.Action(fmt.Sprintf("key%d", key))
		m.keymap[remapLayer].KeyMouse.Set(button.FromKey(key), action)
	}
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonLeft), "mouse0")
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonMiddle), "mouse1")
	m.keymap[remapLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonRight), "mouse2")

	// Gamepad actions
	for btn := ebiten.GamepadButton0; btn < ebiten.GamepadButtonMax; btn++ {
		action := keymap.Action(fmt.Sprintf("btn%d", btn))
		m.keymap[remapLayer].GamepadBtn.Set(btn, action)
	}

	// Axis actions
	// for axis := 0; axis < 100; axis++ {
	// 	action := keymap.Action(fmt.Sprintf("axis%d", axis))
	// 	m.keymap[remapLayer].GamepadAxis.Set(axis, action)
	// }

	//// Setup UI handlers
	leftClickHandlers := keymap.ButtonHandlerMap{
		leftClick: m.leftMouseHandler,
	}
	m.keymap[leftClickLayer] = keymap.New(leftClickHandlers, nil)
	m.keymap[leftClickLayer].KeyMouse.Set(button.FromMouse(ebiten.MouseButtonLeft), leftClick)

	colorFn := func(action keymap.Action) keymap.ButtonHandler {
		return func(down bool) bool {
			if down {
				m.actionText[action].Color = color.White
			} else {
				m.actionText[action].Color = color.Black
			}
			return false
		}
	}

	axisFn := func(action keymap.Action) keymap.AxisHandler {
		return func(val float64) bool {
			var axis int
			fmt.Sscanf(m.gamepadText[action].Text, "Axis %d", &axis)
			m.gamepadText[action].Text = fmt.Sprintf("Axis %d (%.2f)", axis, val)
			return false
		}
	}

	// UI handlers
	uiHandlers := keymap.ButtonHandlerMap{
		left:     colorFn(left),
		right:    colorFn(right),
		jump:     colorFn(jump),
		uppercut: colorFn(uppercut),
		slam:     colorFn(slam),
		punch:    colorFn(punch),
		launch:   colorFn(launch),
	}
	uiAxisHandlers := keymap.AxisHandlerMap{
		move:   axisFn(move),
		punchH: axisFn(punchH),
		punchV: axisFn(punchV),
	}
	m.keymap[uiLayer] = keymap.New(uiHandlers, uiAxisHandlers)
	setDefaultKeyMap(m.keymap[uiLayer])
}

func (m *mainMenuState) keyRemapHandler(btn button.KeyMouse) keymap.ButtonHandler {
	return func(down bool) bool {
		if !m.canClickButton && btn.IsMouse() {
			// This prevents us from always immediately remapping to left mouse
			return false
		}

		_, valid := defaultKeyMap.KeyMouse.GetButton(m.remapAction)
		if down && m.remap && valid {
			m.keymap[playerLayer].KeyMouse.Set(btn, m.remapAction)
			m.keymap[uiLayer].KeyMouse.Set(btn, m.remapAction)
			m.remap = false
			m.remapText.Text = ""
			m.updateText()

			if btn.IsMouse() {
				// This prevents us from clicking a button if remapping to left mouse while hover
				// over a button
				m.canClickButton = false
			}

			return true
		}

		// No reason to stop propagation here because either the button is up or is not
		// remappable
		return false
	}
}

func (m *mainMenuState) btnRemapHandler(btn ebiten.GamepadButton) keymap.ButtonHandler {
	return func(down bool) bool {
		_, valid := defaultKeyMap.GamepadBtn.GetButton(m.remapAction)
		if down && m.remap && valid {
			m.keymap[playerLayer].GamepadBtn.Set(btn, m.remapAction)
			m.keymap[uiLayer].GamepadBtn.Set(btn, m.remapAction)
			m.remap = false
			m.updateText()
		}

		// No reason to stop propagation here because either the button is up or is not
		// remappable
		return false
	}
}

// func (m *mainMenuState) axisRemapHandler(axis int) keymap.AxisHandler {
// 	return func(val float64) bool {
// 		remap := m.remap
// 		if val != 0 && remap {
// 			log.Println("remap axis to", axis)
// 			m.keymap[playerLayer].GamepadAxis.Set(axis, m.remapAction)
// 			m.remap = false
// 		}
// 		return remap
// 	}
// }

func (m *mainMenuState) begin(previousState gameStateName) {
	m.cam.Target = fixedCameraTarget{geo.VecXY(m.p.pos.X, -float64(m.screenHeight)*0.4)}
}

func (m *mainMenuState) end() {

}

func (m *mainMenuState) nextState() gameStateName {
	return mainMenu
}

func (m *mainMenuState) update(dt time.Duration) {
	m.p.update(dt)

	for _, b := range m.btns {
		b.Update()
	}
}

func (m *mainMenuState) draw(dst *ebiten.Image, cam *camera.Camera) {
	m.bg.Draw(dst, cam)
	m.p.draw(dst, cam)

	x, y := 120.0, 20.0
	height := 220.0
	ebitenutil.DrawRect(dst, x, y, buttonWidth, height, color.NRGBA{100, 100, 100, 50})
	m.menu.Draw(dst, geo.RectXYWH(x, y, buttonWidth, height))
}

func (m *mainMenuState) leftMouseHandler(down bool) bool {
	if m.canClickButton && down {
		for _, b := range m.btns {
			if b.Hover {
				b.OnClick()
				m.canClickButton = false
				return true
			}
		}
	}
	m.canClickButton = !down
	return false
}
<|endoftext|>


<commit_before>package getter

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"testing"
)

func TestHttpGetter_impl(t *testing.T) {
	var _ Getter = new(HttpGetter)
}

func TestHttpGetter_header(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_meta(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdir(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdirGlob(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir-glob"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_none(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/none"

	// Get it!
	if err := g.Get(dst, &u); err == nil {
		t.Fatal("should error")
	}
}

func TestHttpGetter_file(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempFile(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/file"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_auth(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-auth"
	u.User = url.UserPassword("foo", "bar")

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_authNetrc(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Write the netrc file
	path, closer := tempFileContents(t, fmt.Sprintf(testHttpNetrc, ln.Addr().String()))
	defer closer()
	defer tempEnv(t, "NETRC", path)()

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

// test round tripper that only returns an error
type errRoundTripper struct{}

func (errRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return nil, errors.New("test round tripper")
}

// verify that the default httpClient no longer comes from http.DefaultClient
func TestHttpGetter_cleanhttp(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	// break the default http client
	http.DefaultClient.Transport = errRoundTripper{}
	defer func() {
		http.DefaultClient.Transport = http.DefaultTransport
	}()

	g := new(HttpGetter)
	dst := tempDir(t)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func testHttpServer(t *testing.T) net.Listener {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/file", testHttpHandlerFile)
	mux.HandleFunc("/header", testHttpHandlerHeader)
	mux.HandleFunc("/meta", testHttpHandlerMeta)
	mux.HandleFunc("/meta-auth", testHttpHandlerMetaAuth)
	mux.HandleFunc("/meta-subdir", testHttpHandlerMetaSubdir)
	mux.HandleFunc("/meta-subdir-glob", testHttpHandlerMetaSubdirGlob)

	var server http.Server
	server.Handler = mux
	go server.Serve(ln)

	return ln
}

func testHttpHandlerFile(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello\n"))
}

func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Terraform-Get", testModuleURL("basic").String())
	w.WriteHeader(200)
}

func testHttpHandlerMeta(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaAuth(w http.ResponseWriter, r *http.Request) {
	user, pass, ok := r.BasicAuth()
	if !ok {
		w.WriteHeader(401)
		return
	}

	if user != "foo" || pass != "bar" {
		w.WriteHeader(401)
		return
	}

	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaSubdir(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//subdir").String())))
}

func testHttpHandlerMetaSubdirGlob(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//sub*").String())))
}

func testHttpHandlerNone(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(testHttpNoneStr))
}

const testHttpMetaStr = `
<html>
<head>
<meta name="terraform-get" content="%s">
</head>
</html>
`

const testHttpNoneStr = `
<html>
<head>
</head>
</html>
`

const testHttpNetrc = `
machine %s
login foo
password bar
`
<commit_msg>clean up temporary file generated by get_http_test<commit_after>package getter

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"testing"
)

func TestHttpGetter_impl(t *testing.T) {
	var _ Getter = new(HttpGetter)
}

func TestHttpGetter_header(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_meta(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdir(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdirGlob(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir-glob"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_none(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/none"

	// Get it!
	if err := g.Get(dst, &u); err == nil {
		t.Fatal("should error")
	}
}

func TestHttpGetter_file(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempFile(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/file"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_auth(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-auth"
	u.User = url.UserPassword("foo", "bar")

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_authNetrc(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Write the netrc file
	path, closer := tempFileContents(t, fmt.Sprintf(testHttpNetrc, ln.Addr().String()))
	defer closer()
	defer tempEnv(t, "NETRC", path)()

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

// test round tripper that only returns an error
type errRoundTripper struct{}

func (errRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return nil, errors.New("test round tripper")
}

// verify that the default httpClient no longer comes from http.DefaultClient
func TestHttpGetter_cleanhttp(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	// break the default http client
	http.DefaultClient.Transport = errRoundTripper{}
	defer func() {
		http.DefaultClient.Transport = http.DefaultTransport
	}()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func testHttpServer(t *testing.T) net.Listener {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/file", testHttpHandlerFile)
	mux.HandleFunc("/header", testHttpHandlerHeader)
	mux.HandleFunc("/meta", testHttpHandlerMeta)
	mux.HandleFunc("/meta-auth", testHttpHandlerMetaAuth)
	mux.HandleFunc("/meta-subdir", testHttpHandlerMetaSubdir)
	mux.HandleFunc("/meta-subdir-glob", testHttpHandlerMetaSubdirGlob)

	var server http.Server
	server.Handler = mux
	go server.Serve(ln)

	return ln
}

func testHttpHandlerFile(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello\n"))
}

func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Terraform-Get", testModuleURL("basic").String())
	w.WriteHeader(200)
}

func testHttpHandlerMeta(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaAuth(w http.ResponseWriter, r *http.Request) {
	user, pass, ok := r.BasicAuth()
	if !ok {
		w.WriteHeader(401)
		return
	}

	if user != "foo" || pass != "bar" {
		w.WriteHeader(401)
		return
	}

	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaSubdir(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//subdir").String())))
}

func testHttpHandlerMetaSubdirGlob(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//sub*").String())))
}

func testHttpHandlerNone(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(testHttpNoneStr))
}

const testHttpMetaStr = `
<html>
<head>
<meta name="terraform-get" content="%s">
</head>
</html>
`

const testHttpNoneStr = `
<html>
<head>
</head>
</html>
`

const testHttpNetrc = `
machine %s
login foo
password bar
`
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/couchbaselabs/go-couchbase"

	"github.com/couchbaselabs/cbfs/config"
)

var workers = flag.Int("workers", 4, "Number of upload workers")
var couchbaseServer = flag.String("couchbase", "", "Couchbase URL")
var couchbaseBucket = flag.String("bucket", "default", "Couchbase bucket")

var cb *couchbase.Bucket

var commands = map[string]struct {
	nargs  int
	f      func(args []string)
	argstr string
}{
	"upload":  {2, uploadCommand, "/src/dir http://cbfs:8484/path/"},
	"getconf": {0, getConfCommand, ""},
	"setconf": {2, setConfCommand, "prop value"},
}

func init() {
	log.SetFlags(log.Lmicroseconds)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Usage of %s [-flags] cmd cmdargs\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\nCommands:\n")

		for k, v := range commands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", k, v.argstr)
		}

		fmt.Fprintf(os.Stderr, "\nFlags:\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

}

var wg = sync.WaitGroup{}

type uploadReq struct {
	src  string
	dest string
}

func recognizeTypeByName(n, def string) string {
	byname := mime.TypeByExtension(n)
	switch {
	case byname != "":
		return byname
	case strings.HasSuffix(n, ".js"):
		return "application/javascript"
	}
	return def
}

func uploadFile(src, dest string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	someBytes := make([]byte, 512)
	n, err := f.Read(someBytes)
	if err != nil && err != io.EOF {
		return err
	}
	someBytes = someBytes[:n]
	_, err = f.Seek(0, 0)
	if err != nil {
		return err
	}

	preq, err := http.NewRequest("PUT", dest, f)
	if err != nil {
		return err
	}

	ctype := http.DetectContentType(someBytes)
	if strings.HasPrefix(ctype, "text/plain") ||
		strings.HasPrefix(ctype, "application/octet-stream") {
		ctype = recognizeTypeByName(src, ctype)
	}

	preq.Header.Set("Content-Type", ctype)

	resp, err := http.DefaultClient.Do(preq)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 201 {
		return fmt.Errorf("HTTP Error:  %v", resp.Status)
	}
	return nil
}

func uploader(ch chan uploadReq) {
	defer wg.Done()
	for req := range ch {
		log.Printf("%v -> %v", req.src, req.dest)
		retries := 0
		done := false
		for !done {
			err := uploadFile(req.src, req.dest)
			if err != nil {
				if retries < 3 {
					retries++
					log.Printf("Error uploading file: %v... retrying",
						err)
					time.Sleep(time.Duration(retries) * time.Second)
				} else {
					log.Fatalf("Error uploading file: %v", err)
				}
			} else {
				done = true
			}
		}
	}
}

func syncUp(src, u string, ch chan<- uploadReq) {
	err := filepath.Walk(src,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			switch info.Mode() & os.ModeType {
			case os.ModeDir:
				// ignoring quietly
			case os.ModeCharDevice, os.ModeDevice,
				os.ModeNamedPipe, os.ModeSocket, os.ModeSymlink:

				log.Printf("Ignoring special file: %v", path)
			default:
				shortPath := path[len(src):]
				ch <- uploadReq{path, u + shortPath}
			}
			return err
		})
	if err != nil {
		log.Fatalf("Traversal error: %v", err)
	}
}

func uploadCommand(args []string) {
	ch := make(chan uploadReq)

	for i := 0; i < *workers; i++ {
		wg.Add(1)
		go uploader(ch)
	}

	syncUp(args[0], args[1], ch)

	close(ch)
	wg.Wait()
}

func getConfCommand(args []string) {
	if cb == nil {
		log.Fatalf("No couchbase bucket specified")
	}
	conf := cbfsconfig.CBFSConfig{}
	err := conf.RetrieveConfig(cb)
	if err != nil {
		log.Fatalf("Error getting config: %v", err)
	}

	conf.Dump(os.Stdout)
}

func parseDuration(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Fatalf("Unable to parse duration: %v", err)
	}
	return d
}

func parseInt(s string) int {
	i, err := strconv.Atoi(s)
	if err != nil {
		log.Fatalf("Error parsing int: %v", err)
	}
	return i
}

func setConfCommand(args []string) {
	if cb == nil {
		log.Fatalf("No couchbase bucket specified")
	}
	conf := cbfsconfig.DefaultConfig()
	err := conf.RetrieveConfig(cb)
	if err != nil {
		log.Printf("Error getting config: %v, using default", err)
	}

	switch args[0] {
	default:
		log.Fatalf("Unhandled property: %v (try running getconf)",
			args[0])
	case "gcfreq":
		conf.GCFreq = parseDuration(args[1])
	case "hash":
		conf.Hash = args[1]
	case "hbfreq":
		conf.HeartbeatFreq = parseDuration(args[1])
	case "minrepl":
		conf.MinReplicas = parseInt(args[1])
	case "cleanCount":
		conf.NodeCleanCount = parseInt(args[1])
	case "reconcileFreq":
		conf.ReconcileFreq = parseDuration(args[1])
	case "nodeCheckFreq":
		conf.StaleNodeCheckFreq = parseDuration(args[1])
	case "staleLimit":
		conf.StaleNodeLimit = parseDuration(args[1])
	}

	err = conf.StoreConfig(cb)
	if err != nil {
		log.Fatalf("Error updating config: %v", err)
	}
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
	}

	if *couchbaseServer != "" {
		var err error
		cb, err = couchbase.GetBucket(*couchbaseServer,
			"default", *couchbaseBucket)
		if err != nil {
			log.Fatalf("Error connecting to couchbase: %v", err)
		}
	}

	cmdName := flag.Arg(0)
	cmd, ok := commands[cmdName]
	if !ok {
		fmt.Fprintf(os.Stderr, "Unknown command: %v\n", cmdName)
		flag.Usage()
	}
	if flag.NArg()-1 != cmd.nargs {
		fmt.Fprintf(os.Stderr, "Incorrect arguments for %v\n", cmdName)
		flag.Usage()
	}

	cmd.f(flag.Args()[1:])
}
<commit_msg>Show default config when there are no overrides.<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/couchbaselabs/go-couchbase"

	"github.com/couchbaselabs/cbfs/config"
)

var workers = flag.Int("workers", 4, "Number of upload workers")
var couchbaseServer = flag.String("couchbase", "", "Couchbase URL")
var couchbaseBucket = flag.String("bucket", "default", "Couchbase bucket")

var cb *couchbase.Bucket

var commands = map[string]struct {
	nargs  int
	f      func(args []string)
	argstr string
}{
	"upload":  {2, uploadCommand, "/src/dir http://cbfs:8484/path/"},
	"getconf": {0, getConfCommand, ""},
	"setconf": {2, setConfCommand, "prop value"},
}

func init() {
	log.SetFlags(log.Lmicroseconds)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Usage of %s [-flags] cmd cmdargs\n",
			os.Args[0])

		fmt.Fprintf(os.Stderr, "\nCommands:\n")

		for k, v := range commands {
			fmt.Fprintf(os.Stderr, "  %s %s\n", k, v.argstr)
		}

		fmt.Fprintf(os.Stderr, "\nFlags:\n")
		flag.PrintDefaults()
		os.Exit(1)
	}

}

var wg = sync.WaitGroup{}

type uploadReq struct {
	src  string
	dest string
}

func recognizeTypeByName(n, def string) string {
	byname := mime.TypeByExtension(n)
	switch {
	case byname != "":
		return byname
	case strings.HasSuffix(n, ".js"):
		return "application/javascript"
	}
	return def
}

func uploadFile(src, dest string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()

	someBytes := make([]byte, 512)
	n, err := f.Read(someBytes)
	if err != nil && err != io.EOF {
		return err
	}
	someBytes = someBytes[:n]
	_, err = f.Seek(0, 0)
	if err != nil {
		return err
	}

	preq, err := http.NewRequest("PUT", dest, f)
	if err != nil {
		return err
	}

	ctype := http.DetectContentType(someBytes)
	if strings.HasPrefix(ctype, "text/plain") ||
		strings.HasPrefix(ctype, "application/octet-stream") {
		ctype = recognizeTypeByName(src, ctype)
	}

	preq.Header.Set("Content-Type", ctype)

	resp, err := http.DefaultClient.Do(preq)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 201 {
		return fmt.Errorf("HTTP Error:  %v", resp.Status)
	}
	return nil
}

func uploader(ch chan uploadReq) {
	defer wg.Done()
	for req := range ch {
		log.Printf("%v -> %v", req.src, req.dest)
		retries := 0
		done := false
		for !done {
			err := uploadFile(req.src, req.dest)
			if err != nil {
				if retries < 3 {
					retries++
					log.Printf("Error uploading file: %v... retrying",
						err)
					time.Sleep(time.Duration(retries) * time.Second)
				} else {
					log.Fatalf("Error uploading file: %v", err)
				}
			} else {
				done = true
			}
		}
	}
}

func syncUp(src, u string, ch chan<- uploadReq) {
	err := filepath.Walk(src,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			switch info.Mode() & os.ModeType {
			case os.ModeDir:
				// ignoring quietly
			case os.ModeCharDevice, os.ModeDevice,
				os.ModeNamedPipe, os.ModeSocket, os.ModeSymlink:

				log.Printf("Ignoring special file: %v", path)
			default:
				shortPath := path[len(src):]
				ch <- uploadReq{path, u + shortPath}
			}
			return err
		})
	if err != nil {
		log.Fatalf("Traversal error: %v", err)
	}
}

func uploadCommand(args []string) {
	ch := make(chan uploadReq)

	for i := 0; i < *workers; i++ {
		wg.Add(1)
		go uploader(ch)
	}

	syncUp(args[0], args[1], ch)

	close(ch)
	wg.Wait()
}

func getConfCommand(args []string) {
	if cb == nil {
		log.Fatalf("No couchbase bucket specified")
	}
	conf := cbfsconfig.DefaultConfig()
	err := conf.RetrieveConfig(cb)
	if err != nil {
		log.Printf("Error getting config: %v", err)
		log.Printf("Using default, as shown below:")
	}

	conf.Dump(os.Stdout)
}

func parseDuration(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Fatalf("Unable to parse duration: %v", err)
	}
	return d
}

func parseInt(s string) int {
	i, err := strconv.Atoi(s)
	if err != nil {
		log.Fatalf("Error parsing int: %v", err)
	}
	return i
}

func setConfCommand(args []string) {
	if cb == nil {
		log.Fatalf("No couchbase bucket specified")
	}
	conf := cbfsconfig.DefaultConfig()
	err := conf.RetrieveConfig(cb)
	if err != nil {
		log.Printf("Error getting config: %v, using default", err)
	}

	switch args[0] {
	default:
		log.Fatalf("Unhandled property: %v (try running getconf)",
			args[0])
	case "gcfreq":
		conf.GCFreq = parseDuration(args[1])
	case "hash":
		conf.Hash = args[1]
	case "hbfreq":
		conf.HeartbeatFreq = parseDuration(args[1])
	case "minrepl":
		conf.MinReplicas = parseInt(args[1])
	case "cleanCount":
		conf.NodeCleanCount = parseInt(args[1])
	case "reconcileFreq":
		conf.ReconcileFreq = parseDuration(args[1])
	case "nodeCheckFreq":
		conf.StaleNodeCheckFreq = parseDuration(args[1])
	case "staleLimit":
		conf.StaleNodeLimit = parseDuration(args[1])
	}

	err = conf.StoreConfig(cb)
	if err != nil {
		log.Fatalf("Error updating config: %v", err)
	}
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
	}

	if *couchbaseServer != "" {
		var err error
		cb, err = couchbase.GetBucket(*couchbaseServer,
			"default", *couchbaseBucket)
		if err != nil {
			log.Fatalf("Error connecting to couchbase: %v", err)
		}
	}

	cmdName := flag.Arg(0)
	cmd, ok := commands[cmdName]
	if !ok {
		fmt.Fprintf(os.Stderr, "Unknown command: %v\n", cmdName)
		flag.Usage()
	}
	if flag.NArg()-1 != cmd.nargs {
		fmt.Fprintf(os.Stderr, "Incorrect arguments for %v\n", cmdName)
		flag.Usage()
	}

	cmd.f(flag.Args()[1:])
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
)

type GitController struct {
	Folder string
}

func (this *GitController) ExistsLocal() bool {

	exitcode, _, _, err := CmdRun(this.Folder, "git", "status")

	if err != nil {
		EXIT_ERROR("Error executing command 'git status'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	return exitcode == 0
}

func (this *GitController) ExecGitCommand(args ...string) string {
	exitcode, stdout, stderr, err := CmdRun(this.Folder, "git", args...)

	if err != nil {
		EXIT_ERROR("Error executing command 'git "+args[0]+"'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	if exitcode != 0 {
		EXIT_ERROR("Error in command 'git "+args[0]+"'\n\n"+stderr, EXIT_GIT_ERROR)
	}

	return stdout
}

func (this *GitController) ExecCredGitCommand(cred GGCredentials, args ...string) string {

	if IsEmpty(cred.Host) || IsEmpty(cred.Username) || IsEmpty(cred.Password) {
		return this.ExecGitCommand(args...)
	}

	credRC := "machine " + cred.Host + " login " + cred.Username + " password " + cred.Password

	EnterNetRCBlock(credRC)

	stdout := this.ExecGitCommand(args...)

	ExitNetRCBlock()

	return stdout
}

func (this *GitController) QueryGitCommand(args ...string) string {
	exitcode, stdout, stderr, err := CmdRun(this.Folder, "git", args...)

	if err != nil {
		EXIT_ERROR("Error executing command 'git "+args[0]+"'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	if exitcode != 0 {
		EXIT_ERROR("Error in command 'git "+args[0]+"'\n\n"+stderr, EXIT_GIT_ERROR)
	}

	return stdout
}

func (this *GitController) RemoveAllRemotes() {
	branches := this.QueryGitCommand("remote")

	for _, remote := range strings.Split(branches, "\n") {
		if !IsEmpty(remote) {
			this.ExecGitCommand("remote", "rm", remote)
		}
	}
}

func (this *GitController) CloneOrPull(branch string, remote string, cred GGCredentials) {

	if this.ExistsLocal() {
		this.RemoveAllRemotes()
		this.ExecGitCommand("remote", "add", "origin", remote)

		this.ExecCredGitCommand(cred, "fetch", "--all")
		this.ExecGitCommand("reset", "--hard", "origin/"+branch)

	} else {
		this.ExecCredGitCommand(cred, "clone", remote, ".", "--origin", "origin")
	}

	this.ExecGitCommand("checkout", "-f", "origin/"+branch)
}

func (this *GitController) PushBack(branch string, remote string, cred GGCredentials, useForce bool) {

	this.RemoveAllRemotes()

	this.ExecGitCommand("remote", "add", "origin", remote)
	status := this.ExecGitCommand("status")
	LOG_OUT(status)

	this.RemoveAllRemotes()

	var commandoutput string

	if useForce {
		commandoutput = this.ExecCredGitCommand(cred, "push", remote, "HEAD:"+branch, "--force")
	} else {
		commandoutput = this.ExecCredGitCommand(cred, "push", remote, "HEAD:"+branch)
	}

	LOG_OUT(commandoutput)
}

func (this *GitController) ListLocalBranches() []string {
	stdout := this.QueryGitCommand("branch", "-a", "--list")
	lines := strings.Split(stdout, "\n")

	result := make([]string, 0)

	for _, line := range lines {
		line = strings.TrimSpace(line)
		line = strings.TrimLeft(line, "*")
		line = strings.TrimSpace(line)

		branch := ""

		if strings.Contains(line, " -> ") {
			line = line[:strings.Index(line, " -> ")]
		}

		if strings.HasPrefix(strings.ToLower(line), "remotes/origin/") {
			branch = line[15:]
		} else {
			branch = line
		}

		branch = strings.TrimSpace(branch)

		if !IsEmpty(branch) && !strings.EqualFold(branch, "HEAD") && branch[0:1] != "(" {
			result = AppendIfUniqueCaseInsensitive(result, branch)
		}
	}

	return result
}
<commit_msg>better status display in stdout<commit_after>package main

import (
	"strings"
)

type GitController struct {
	Folder string
}

func (this *GitController) ExistsLocal() bool {

	exitcode, _, _, err := CmdRun(this.Folder, "git", "status")

	if err != nil {
		EXIT_ERROR("Error executing command 'git status'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	return exitcode == 0
}

func (this *GitController) ExecGitCommand(args ...string) string {
	exitcode, stdout, stderr, err := CmdRun(this.Folder, "git", args...)

	if err != nil {
		EXIT_ERROR("Error executing command 'git "+args[0]+"'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	if exitcode != 0 {
		EXIT_ERROR("Error in command 'git "+args[0]+"'\n\n"+stderr, EXIT_GIT_ERROR)
	}

	return stdout
}

func (this *GitController) ExecCredGitCommand(cred GGCredentials, args ...string) string {

	if IsEmpty(cred.Host) || IsEmpty(cred.Username) || IsEmpty(cred.Password) {
		return this.ExecGitCommand(args...)
	}

	credRC := "machine " + cred.Host + " login " + cred.Username + " password " + cred.Password

	EnterNetRCBlock(credRC)

	stdout := this.ExecGitCommand(args...)

	ExitNetRCBlock()

	return stdout
}

func (this *GitController) QueryGitCommand(args ...string) string {
	exitcode, stdout, stderr, err := CmdRun(this.Folder, "git", args...)

	if err != nil {
		EXIT_ERROR("Error executing command 'git "+args[0]+"'\n\n"+err.Error(), EXIT_GIT_ERROR)
	}

	if exitcode != 0 {
		EXIT_ERROR("Error in command 'git "+args[0]+"'\n\n"+stderr, EXIT_GIT_ERROR)
	}

	return stdout
}

func (this *GitController) RemoveAllRemotes() {
	branches := this.QueryGitCommand("remote")

	for _, remote := range strings.Split(branches, "\n") {
		if !IsEmpty(remote) {
			this.ExecGitCommand("remote", "rm", remote)
		}
	}
}

func (this *GitController) CloneOrPull(branch string, remote string, cred GGCredentials) {

	if this.ExistsLocal() {
		this.RemoveAllRemotes()
		this.ExecGitCommand("remote", "add", "origin", remote)

		this.ExecCredGitCommand(cred, "fetch", "--all")
		this.ExecGitCommand("checkout", "-f", "origin/"+branch)
		this.ExecGitCommand("reset", "--hard", "origin/"+branch)

	} else {
		this.ExecCredGitCommand(cred, "clone", remote, ".", "--origin", "origin")
		this.ExecGitCommand("checkout", "-f", "origin/"+branch)
	}

	this.ExecCredGitCommand(cred, "branch", "-u", "origin/"+branch, branch)
	this.ExecCredGitCommand(cred, "clean", "-f", "-d")
}

func (this *GitController) PushBack(branch string, remote string, cred GGCredentials, useForce bool) {

	this.RemoveAllRemotes()
	this.ExecGitCommand("remote", "add", "origin", remote)

	this.ExecCredGitCommand(cred, "fetch", "--all")
	this.ExecCredGitCommand(cred, "checkout", "-f", branch)
	this.ExecCredGitCommand(cred, "branch", "-u", "origin/"+branch, branch)
	status := this.ExecGitCommand("status")
	LOG_OUT(status)

	var commandoutput string

	if useForce {
		commandoutput = this.ExecCredGitCommand(cred, "push", "origin", "HEAD:"+branch, "--force")
	} else {
		commandoutput = this.ExecCredGitCommand(cred, "push", "origin", "HEAD:"+branch)
	}

	LOG_OUT(commandoutput)
}

func (this *GitController) ListLocalBranches() []string {
	stdout := this.QueryGitCommand("branch", "-a", "--list")
	lines := strings.Split(stdout, "\n")

	result := make([]string, 0)

	for _, line := range lines {
		line = strings.TrimSpace(line)
		line = strings.TrimLeft(line, "*")
		line = strings.TrimSpace(line)

		branch := ""

		if strings.Contains(line, " -> ") {
			line = line[:strings.Index(line, " -> ")]
		}

		if strings.HasPrefix(strings.ToLower(line), "remotes/origin/") {
			branch = line[15:]
		} else {
			branch = line
		}

		branch = strings.TrimSpace(branch)

		if !IsEmpty(branch) && !strings.EqualFold(branch, "HEAD") && branch[0:1] != "(" {
			result = AppendIfUniqueCaseInsensitive(result, branch)
		}
	}

	return result
}
<|endoftext|>


<commit_before>// Copyright 2013 Google. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

/*
Package github provides a client for using the GitHub API.

Access different parts of the GitHub API using the various services on a GitHub
Client:

	client := github.NewClient(nil)

	// list all organizations for user "willnorris"
	orgs, err := client.Organizations.List("willnorris", nil)

Set optional parameters for an API method by passing an Options object.

	// list recently updated repositories for org "github"
	opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
	repos, err := client.Repositories.ListByOrg("github", opt)

Make authenticated API calls by constructing a GitHub client using an OAuth
capable http.Client:

	import "code.google.com/p/goauth2/oauth"

	// simple OAuth transport if you already have an access token;
	// see goauth2 library for full usage
	t := &oauth.Transport{
		Config: &oauth.Config{},
		Token: &oauth.Token{AccessToken: "..."},
	}

	client := github.NewClient(t.Client())

	// list all repositories for the authenticated user
	repos, err := client.Repositories.List(nil)

Note that when using an authenticated Client, all calls made by the client will
include the specified OAuth token. Therefore, authenticated clients should
almost never be shared between different users.

The full GitHub API is documented at http://developer.github.com/v3/.
*/
package github

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.github.com/"
	userAgent      = "go-github/" + libraryVersion
)

// A Client manages communication with the GitHub API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public GitHub API, but can be
	// set to a domain endpoint to use with GitHub Enterprise.  BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the GitHub API.
	UserAgent string

	// Services used for talking to different parts of the API

	Organizations *OrganizationsService
	Repositories  *RepositoriesService
	Users         *UsersService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int
}

// NewClient returns a new GitHub API client.  If a nil httpClient is
// provided, http.DefaultClient will be used.  To use API methods which require
// authentication, provide an http.Client that can handle that.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
	c.Organizations = &OrganizationsService{client: c}
	c.Repositories = &RepositoriesService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// NewRequest creates an API request. A relative URL can be provided in urls,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urls string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urls)
	if err != nil {
		return nil, err
	}

	url_ := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url_.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response.  The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		err = json.NewDecoder(resp.Body).Decode(v)
	}
	return resp, err
}

/*
An ErrorResponse reports one or more errors caused by an API request.

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:message` // error message
	Errors   []Error        `json:errors`  // more detail on individual errors
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

/*
An Error reports more details on an individual error in an ErrorResponse.
These are the possible validation error codes:

    missing:
        resource does not exist
    missing_field:
        a required field on a resource has not been set
    invalid:
        the formatting of a field is invalid
    already_exists:
        another resource has the same valid as this field

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type Error struct {
	Resource string `json:resource` // resource on which the error occurred
	Field    string `json:field`    // field on which the error occurred
	Code     string `json:code`     // validation error code
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v error caused by %v field on %v resource",
		e.Code, e.Field, e.Resource)
}

// CheckResponse checks the API response for errors, and returns them if
// present.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil {
		errorResponse := &ErrorResponse{Response: r}
		if data != nil {
			err = json.Unmarshal(data, errorResponse)
		}
		return errorResponse
	}
	return fmt.Errorf("github: got HTTP response code %d and error reading body: %v",
		r.StatusCode, err)
}

// API response wrapper to a rate limit request.
type rateResponse struct {
	Rate *Rate `json:rate`
}

// Rate represents the rate limit for the current client.  Unauthenticated
// requests are limited to 60 per hour.  Authenticated requests are limited to
// 5,000 per hour.
type Rate struct {
	// The number of requests per hour the client is currently limited to.
	Limit int `json:limit`

	// The number of remaining requests the client can make this hour.
	Remaining int `json:remaining`
}

// RateLimit returns the rate limit for the current client.
func (c *Client) RateLimit() (*Rate, error) {
	req, err := c.NewRequest("GET", "rate_limit", nil)
	if err != nil {
		return nil, err
	}

	response := new(rateResponse)
	_, err = c.Do(req, response)
	return response.Rate, err
}
<commit_msg>drop errors caused from reading error response body<commit_after>// Copyright 2013 Google. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

/*
Package github provides a client for using the GitHub API.

Access different parts of the GitHub API using the various services on a GitHub
Client:

	client := github.NewClient(nil)

	// list all organizations for user "willnorris"
	orgs, err := client.Organizations.List("willnorris", nil)

Set optional parameters for an API method by passing an Options object.

	// list recently updated repositories for org "github"
	opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
	repos, err := client.Repositories.ListByOrg("github", opt)

Make authenticated API calls by constructing a GitHub client using an OAuth
capable http.Client:

	import "code.google.com/p/goauth2/oauth"

	// simple OAuth transport if you already have an access token;
	// see goauth2 library for full usage
	t := &oauth.Transport{
		Config: &oauth.Config{},
		Token: &oauth.Token{AccessToken: "..."},
	}

	client := github.NewClient(t.Client())

	// list all repositories for the authenticated user
	repos, err := client.Repositories.List(nil)

Note that when using an authenticated Client, all calls made by the client will
include the specified OAuth token. Therefore, authenticated clients should
almost never be shared between different users.

The full GitHub API is documented at http://developer.github.com/v3/.
*/
package github

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.github.com/"
	userAgent      = "go-github/" + libraryVersion
)

// A Client manages communication with the GitHub API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public GitHub API, but can be
	// set to a domain endpoint to use with GitHub Enterprise.  BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the GitHub API.
	UserAgent string

	// Services used for talking to different parts of the API

	Organizations *OrganizationsService
	Repositories  *RepositoriesService
	Users         *UsersService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int
}

// NewClient returns a new GitHub API client.  If a nil httpClient is
// provided, http.DefaultClient will be used.  To use API methods which require
// authentication, provide an http.Client that can handle that.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
	c.Organizations = &OrganizationsService{client: c}
	c.Repositories = &RepositoriesService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// NewRequest creates an API request. A relative URL can be provided in urls,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urls string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urls)
	if err != nil {
		return nil, err
	}

	url_ := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, url_.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response.  The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		err = json.NewDecoder(resp.Body).Decode(v)
	}
	return resp, err
}

/*
An ErrorResponse reports one or more errors caused by an API request.

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:message` // error message
	Errors   []Error        `json:errors`  // more detail on individual errors
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

/*
An Error reports more details on an individual error in an ErrorResponse.
These are the possible validation error codes:

    missing:
        resource does not exist
    missing_field:
        a required field on a resource has not been set
    invalid:
        the formatting of a field is invalid
    already_exists:
        another resource has the same valid as this field

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type Error struct {
	Resource string `json:resource` // resource on which the error occurred
	Field    string `json:field`    // field on which the error occurred
	Code     string `json:code`     // validation error code
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v error caused by %v field on %v resource",
		e.Code, e.Field, e.Resource)
}

// CheckResponse checks the API response for errors, and returns them if
// present.  API error responses are expected to have either no response body,
// or a JSON response body that maps to ErrorResponse.  Any other response body
// will be silently ignored.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}
	return errorResponse
}

// API response wrapper to a rate limit request.
type rateResponse struct {
	Rate *Rate `json:rate`
}

// Rate represents the rate limit for the current client.  Unauthenticated
// requests are limited to 60 per hour.  Authenticated requests are limited to
// 5,000 per hour.
type Rate struct {
	// The number of requests per hour the client is currently limited to.
	Limit int `json:limit`

	// The number of remaining requests the client can make this hour.
	Remaining int `json:remaining`
}

// RateLimit returns the rate limit for the current client.
func (c *Client) RateLimit() (*Rate, error) {
	req, err := c.NewRequest("GET", "rate_limit", nil)
	if err != nil {
		return nil, err
	}

	response := new(rateResponse)
	_, err = c.Do(req, response)
	return response.Rate, err
}
<|endoftext|>


<commit_before>package teams

import (
	"fmt"
	"sort"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
)

type statusList struct {
	Teams  []keybase1.MemberInfo `json:"teams"`
	Status libkb.AppStatus       `json:"status"`
}

func (r *statusList) GetAppStatus() *libkb.AppStatus {
	return &r.Status
}

func getTeamsListFromServer(ctx context.Context, g *libkb.GlobalContext, uid keybase1.UID, all bool) ([]keybase1.MemberInfo, error) {
	var endpoint string
	if all {
		endpoint = "team/teammates_for_user"
	} else {
		endpoint = "team/for_user"
	}
	a := libkb.NewAPIArg(endpoint)
	if uid.Exists() {
		a.Args = libkb.HTTPArgs{
			"uid": libkb.S{Val: uid.String()},
		}
	}
	a.NetContext = ctx
	a.SessionType = libkb.APISessionTypeREQUIRED
	var list statusList
	if err := g.API.GetDecode(a, &list); err != nil {
		return nil, err
	}
	return list.Teams, nil
}

func List(ctx context.Context, g *libkb.GlobalContext, arg keybase1.TeamListArg) (*keybase1.AnnotatedTeamList, error) {
	var uid keybase1.UID
	if arg.UserAssertion != "" {
		res := g.Resolver.ResolveFullExpression(ctx, arg.UserAssertion)
		if res.GetError() != nil {
			return nil, res.GetError()
		}
		uid = res.GetUID()
	}

	meUID := g.ActiveDevice.UID()

	teams, err := getTeamsListFromServer(ctx, g, uid, arg.All)
	if err != nil {
		return nil, err
	}

	teamNames := make(map[string]bool)
	upakLoader := g.GetUPAKLoader()
	annotatedTeams := make([]keybase1.AnnotatedMemberInfo, len(teams))
	administeredTeams := make(map[string]bool)
	for idx, memberInfo := range teams {
		teamNames[memberInfo.FqName] = true
		if memberInfo.UserID == meUID && (memberInfo.Role.IsAdminOrAbove() || (memberInfo.Implicit != nil && memberInfo.Implicit.Role.IsAdminOrAbove())) {
			administeredTeams[memberInfo.FqName] = true
		}

		memberuid := memberInfo.UserID
		username, err := upakLoader.LookupUsername(context.Background(), memberuid)
		if err != nil {
			return nil, err
		}
		fullName, err := engine.GetFullName(context.Background(), g, memberuid)
		if err != nil {
			return nil, err
		}
		annotatedTeams[idx] = keybase1.AnnotatedMemberInfo{
			TeamID:   memberInfo.TeamID,
			FqName:   memberInfo.FqName,
			UserID:   memberInfo.UserID,
			Role:     memberInfo.Role,
			Implicit: memberInfo.Implicit,
			Username: username.String(),
			FullName: fullName,
		}
	}

	annotatedInvites := make(map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite)
	for teamName := range teamNames {
		_, ok := administeredTeams[teamName]
		if ok {
			t, err := GetForTeamManagementByStringName(ctx, g, teamName, true)
			if err != nil {
				return nil, err
			}
			teamAnnotatedInvites, err := AnnotateInvites(ctx, g, t.chain().inner.ActiveInvites, teamName)
			if err != nil {
				return nil, err
			}
			for teamInviteID, annotatedTeamInvite := range teamAnnotatedInvites {
				annotatedInvites[teamInviteID] = annotatedTeamInvite
			}
		}
	}

	tl := keybase1.AnnotatedTeamList{
		Teams: annotatedTeams,
		AnnotatedActiveInvites: annotatedInvites,
	}

	return &tl, nil
}

func AnnotateInvites(ctx context.Context, g *libkb.GlobalContext,
	invites map[keybase1.TeamInviteID]keybase1.TeamInvite, teamName string) (map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite, error) {

	annotatedInvites := make(map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite, len(invites))
	upakLoader := g.GetUPAKLoader()
	for id, invite := range invites {
		username, err := upakLoader.LookupUsername(context.Background(), invite.Inviter.Uid)
		if err != nil {
			return annotatedInvites, err
		}
		annotatedInvites[id] = keybase1.AnnotatedTeamInvite{
			Role:            invite.Role,
			Id:              invite.Id,
			Type:            invite.Type,
			Name:            invite.Name,
			InviterUsername: username.String(),
			TeamName:        teamName,
		}
	}
	return annotatedInvites, nil
}

func TeamTree(ctx context.Context, g *libkb.GlobalContext, arg keybase1.TeamTreeArg) (res keybase1.TeamTreeResult, err error) {
	if !arg.Name.IsRootTeam() {
		return res, fmt.Errorf("cannot get tree of non-root team")
	}

	serverList, err := getTeamsListFromServer(ctx, g, "", false)
	if err != nil {
		return res, err
	}

	// Map from team name (string) to entry
	entryMap := make(map[string]keybase1.TeamTreeEntry)

	// The server might have omitted some teams, oh well.
	// Trusts the server for role.
	// Load the teams by ID to make sure they are valid and get the validated names.
	for _, info := range serverList {
		serverName, err := info.TeamName()
		if err != nil {
			return res, err
		}
		if !serverName.RootAncestorName().Eq(arg.Name) {
			// Skip those not in this tree.
			continue
		}
		team, err := Load(ctx, g, keybase1.LoadTeamArg{
			ID:          info.TeamID,
			ForceRepoll: true,
		})
		if err != nil {
			return res, err
		}
		var admin bool // true if an admin or implicit admin
		if info.Role.IsAdminOrAbove() {
			admin = true
		}
		if info.Implicit != nil && info.Implicit.Role.IsAdminOrAbove() {
			admin = true
		}
		entryMap[team.Name().String()] = keybase1.TeamTreeEntry{
			Name:  team.Name(),
			Admin: admin,
		}
	}

	// Add all parent names (recursively)
	// So that if only A.B.C is in the list, we add A.B and A as well.
	// Adding map entries while iterating is safe.
	// "If map entries are created during iteration, that entry may be produced during the iteration or may be skipped."
	for _, entry := range entryMap {
		name := entry.Name.DeepCopy()
		for name.Depth() > 0 {
			_, ok := entryMap[name.String()]
			if !ok {
				entryMap[name.String()] = keybase1.TeamTreeEntry{
					Name:  name,
					Admin: false,
				}
			}
			name, err = name.Parent()
			if err != nil {
				break
			}
		}
	}

	for _, entry := range entryMap {
		res.Entries = append(res.Entries, entry)
	}

	if len(res.Entries) == 0 {
		return res, fmt.Errorf("team not found: %v", arg.Name)
	}

	// Order into a tree order. Which happens to be alphabetical ordering.
	// Example: [a, a.b, a.b.c, a.b.d, a.e.f, a.e.g]
	sort.Slice(res.Entries, func(i, j int) bool {
		return res.Entries[i].Name.String() < res.Entries[j].Name.String()
	})

	return res, nil
}
<commit_msg>Don't bail out when GetForTeamManagementByStringName fails<commit_after>package teams

import (
	"fmt"
	"sort"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
)

type statusList struct {
	Teams  []keybase1.MemberInfo `json:"teams"`
	Status libkb.AppStatus       `json:"status"`
}

func (r *statusList) GetAppStatus() *libkb.AppStatus {
	return &r.Status
}

func getTeamsListFromServer(ctx context.Context, g *libkb.GlobalContext, uid keybase1.UID, all bool) ([]keybase1.MemberInfo, error) {
	var endpoint string
	if all {
		endpoint = "team/teammates_for_user"
	} else {
		endpoint = "team/for_user"
	}
	a := libkb.NewAPIArg(endpoint)
	if uid.Exists() {
		a.Args = libkb.HTTPArgs{
			"uid": libkb.S{Val: uid.String()},
		}
	}
	a.NetContext = ctx
	a.SessionType = libkb.APISessionTypeREQUIRED
	var list statusList
	if err := g.API.GetDecode(a, &list); err != nil {
		return nil, err
	}
	return list.Teams, nil
}

func List(ctx context.Context, g *libkb.GlobalContext, arg keybase1.TeamListArg) (*keybase1.AnnotatedTeamList, error) {
	var uid keybase1.UID
	if arg.UserAssertion != "" {
		res := g.Resolver.ResolveFullExpression(ctx, arg.UserAssertion)
		if res.GetError() != nil {
			return nil, res.GetError()
		}
		uid = res.GetUID()
	}

	meUID := g.ActiveDevice.UID()

	teams, err := getTeamsListFromServer(ctx, g, uid, arg.All)
	if err != nil {
		return nil, err
	}

	teamNames := make(map[string]bool)
	upakLoader := g.GetUPAKLoader()
	annotatedTeams := make([]keybase1.AnnotatedMemberInfo, len(teams))
	administeredTeams := make(map[string]bool)
	for idx, memberInfo := range teams {
		teamNames[memberInfo.FqName] = true
		if memberInfo.UserID == meUID && (memberInfo.Role.IsAdminOrAbove() || (memberInfo.Implicit != nil && memberInfo.Implicit.Role.IsAdminOrAbove())) {
			administeredTeams[memberInfo.FqName] = true
		}

		memberuid := memberInfo.UserID
		username, err := upakLoader.LookupUsername(context.Background(), memberuid)
		if err != nil {
			return nil, err
		}
		fullName, err := engine.GetFullName(context.Background(), g, memberuid)
		if err != nil {
			return nil, err
		}
		annotatedTeams[idx] = keybase1.AnnotatedMemberInfo{
			TeamID:   memberInfo.TeamID,
			FqName:   memberInfo.FqName,
			UserID:   memberInfo.UserID,
			Role:     memberInfo.Role,
			Implicit: memberInfo.Implicit,
			Username: username.String(),
			FullName: fullName,
		}
	}

	annotatedInvites := make(map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite)
	for teamName := range teamNames {
		_, ok := administeredTeams[teamName]
		if ok {
			t, err := GetForTeamManagementByStringName(ctx, g, teamName, true)
			if err != nil {
				g.Log.Warning("Error while getting team (%s): %v", teamName, err)
				continue
			}
			teamAnnotatedInvites, err := AnnotateInvites(ctx, g, t.chain().inner.ActiveInvites, teamName)
			if err != nil {
				return nil, err
			}
			for teamInviteID, annotatedTeamInvite := range teamAnnotatedInvites {
				annotatedInvites[teamInviteID] = annotatedTeamInvite
			}
		}
	}

	tl := keybase1.AnnotatedTeamList{
		Teams: annotatedTeams,
		AnnotatedActiveInvites: annotatedInvites,
	}

	return &tl, nil
}

func AnnotateInvites(ctx context.Context, g *libkb.GlobalContext,
	invites map[keybase1.TeamInviteID]keybase1.TeamInvite, teamName string) (map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite, error) {

	annotatedInvites := make(map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite, len(invites))
	upakLoader := g.GetUPAKLoader()
	for id, invite := range invites {
		username, err := upakLoader.LookupUsername(context.Background(), invite.Inviter.Uid)
		if err != nil {
			return annotatedInvites, err
		}
		annotatedInvites[id] = keybase1.AnnotatedTeamInvite{
			Role:            invite.Role,
			Id:              invite.Id,
			Type:            invite.Type,
			Name:            invite.Name,
			InviterUsername: username.String(),
			TeamName:        teamName,
		}
	}
	return annotatedInvites, nil
}

func TeamTree(ctx context.Context, g *libkb.GlobalContext, arg keybase1.TeamTreeArg) (res keybase1.TeamTreeResult, err error) {
	if !arg.Name.IsRootTeam() {
		return res, fmt.Errorf("cannot get tree of non-root team")
	}

	serverList, err := getTeamsListFromServer(ctx, g, "", false)
	if err != nil {
		return res, err
	}

	// Map from team name (string) to entry
	entryMap := make(map[string]keybase1.TeamTreeEntry)

	// The server might have omitted some teams, oh well.
	// Trusts the server for role.
	// Load the teams by ID to make sure they are valid and get the validated names.
	for _, info := range serverList {
		serverName, err := info.TeamName()
		if err != nil {
			return res, err
		}
		if !serverName.RootAncestorName().Eq(arg.Name) {
			// Skip those not in this tree.
			continue
		}
		team, err := Load(ctx, g, keybase1.LoadTeamArg{
			ID:          info.TeamID,
			ForceRepoll: true,
		})
		if err != nil {
			return res, err
		}
		var admin bool // true if an admin or implicit admin
		if info.Role.IsAdminOrAbove() {
			admin = true
		}
		if info.Implicit != nil && info.Implicit.Role.IsAdminOrAbove() {
			admin = true
		}
		entryMap[team.Name().String()] = keybase1.TeamTreeEntry{
			Name:  team.Name(),
			Admin: admin,
		}
	}

	// Add all parent names (recursively)
	// So that if only A.B.C is in the list, we add A.B and A as well.
	// Adding map entries while iterating is safe.
	// "If map entries are created during iteration, that entry may be produced during the iteration or may be skipped."
	for _, entry := range entryMap {
		name := entry.Name.DeepCopy()
		for name.Depth() > 0 {
			_, ok := entryMap[name.String()]
			if !ok {
				entryMap[name.String()] = keybase1.TeamTreeEntry{
					Name:  name,
					Admin: false,
				}
			}
			name, err = name.Parent()
			if err != nil {
				break
			}
		}
	}

	for _, entry := range entryMap {
		res.Entries = append(res.Entries, entry)
	}

	if len(res.Entries) == 0 {
		return res, fmt.Errorf("team not found: %v", arg.Name)
	}

	// Order into a tree order. Which happens to be alphabetical ordering.
	// Example: [a, a.b, a.b.c, a.b.d, a.e.f, a.e.g]
	sort.Slice(res.Entries, func(i, j int) bool {
		return res.Entries[i].Name.String() < res.Entries[j].Name.String()
	})

	return res, nil
}
<|endoftext|>


<commit_before>package goahocorasick

// AhoCorasick is executor.
type AhoCorasick struct {
	root *node
}

type node struct {
	children map[rune]*node
	depth    int
	fail     *node
	hit      bool
}

// New executor with keywords.
func New(keywords []string) *AhoCorasick {
	a := AhoCorasick{root: newNode(0)}
	a.createTrie(keywords)
	a.createFail()
	return &a
}

func newNode(depth int) *node {
	return &node{
		children: map[rune]*node{},
		depth:    depth}
}

func (a *AhoCorasick) createTrie(keywords []string) {
	for _, keyword := range keywords {
		n := a.root
		for _, r := range keyword {
			v, ok := n.children[r]
			if !ok {
				v = newNode(n.depth + 1)
				n.children[r] = v
			}
			n = v
		}
		n.hit = true
	}
}

func (a *AhoCorasick) createFail() {
	for k, v := range a.root.children {
		a.walkCreateFail(v, []rune{k})
	}
}

func (a *AhoCorasick) walkCreateFail(n *node, text []rune) {
	n.fail = a.backwardMatchNode(text)
	for k, v := range n.children {
		a.walkCreateFail(v, append(text, k))
	}
}

func (a *AhoCorasick) backwardMatchNode(text []rune) *node {
	for t := text[1:]; len(t) > 0; t = t[1:] {
		n, ok := a.matchNode(t)
		if ok {
			return n
		}
	}
	return a.root
}

func (a *AhoCorasick) matchNode(text []rune) (*node, bool) {
	n := a.root
	for _, r := range text {
		v, ok := n.children[r]
		if ok {
			n = v
		} else {
			return nil, false
		}
	}
	return n, true
}

// Match keywords and returns index and length in units of rune(utf8).
func (a *AhoCorasick) Match(text string) [][]int {
	result := make([][]int, 0)
	n := a.root
	i := 0

	for _, r := range text {
	L:
		if n.hit {
			result = append(result, []int{i - n.depth, n.depth})
		}
		child, ok := n.children[r]
		if ok {
			for n != a.root {
				n = n.fail
				if n.hit {
					result = append(result, []int{i - n.depth, n.depth})
				}
			}
			n = child
			i++
		} else if n == a.root {
			i++
		} else {
			n = n.fail
			goto L
		}
	}

	return result
}
<commit_msg>Fix gometalinter warning<commit_after>package goahocorasick

// AhoCorasick is executor.
type AhoCorasick struct {
	root *node
}

type node struct {
	children map[rune]*node
	depth    int
	fail     *node
	hit      bool
}

// New executor with keywords.
func New(keywords []string) *AhoCorasick {
	a := AhoCorasick{root: newNode(0)}
	a.createTrie(keywords)
	a.createFail()
	return &a
}

func newNode(depth int) *node {
	return &node{
		children: map[rune]*node{},
		depth:    depth}
}

func (a *AhoCorasick) createTrie(keywords []string) {
	for _, keyword := range keywords {
		n := a.root
		for _, r := range keyword {
			v, ok := n.children[r]
			if !ok {
				v = newNode(n.depth + 1)
				n.children[r] = v
			}
			n = v
		}
		n.hit = true
	}
}

func (a *AhoCorasick) createFail() {
	for k, v := range a.root.children {
		a.walkCreateFail(v, []rune{k})
	}
}

func (a *AhoCorasick) walkCreateFail(n *node, text []rune) {
	n.fail = a.backwardMatchNode(text)
	for k, v := range n.children {
		a.walkCreateFail(v, append(text, k))
	}
}

func (a *AhoCorasick) backwardMatchNode(text []rune) *node {
	for t := text[1:]; len(t) > 0; t = t[1:] {
		n, ok := a.matchNode(t)
		if ok {
			return n
		}
	}
	return a.root
}

func (a *AhoCorasick) matchNode(text []rune) (*node, bool) {
	n := a.root
	for _, r := range text {
		v, ok := n.children[r]
		if ok {
			n = v
		} else {
			return nil, false
		}
	}
	return n, true
}

// Match keywords and returns index and length in units of rune(utf8).
func (a *AhoCorasick) Match(text string) [][]int {
	var result [][]int
	n := a.root
	i := 0

	for _, r := range text {
	L:
		if n.hit {
			result = append(result, []int{i - n.depth, n.depth})
		}
		child, ok := n.children[r]
		if ok {
			for n != a.root {
				n = n.fail
				if n.hit {
					result = append(result, []int{i - n.depth, n.depth})
				}
			}
			n = child
			i++
		} else if n == a.root {
			i++
		} else {
			n = n.fail
			goto L
		}
	}

	return result
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Pulcy.
//
// 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 golang

import (
	"fmt"
	"os"
	"path/filepath"

	log "github.com/op/go-logging"

	"github.com/pulcy/pulsar/git"
	vcsurl "github.com/sourcegraph/go-vcsurl"
)

type GoPathFlags struct {
	Package string // If set, use this package instead of the origin URL from the local repo
}

// CreateLocalGoPath creates a local .gobuild folder with a GOPATH folder structure in it.
func CreateLocalGoPath(log *log.Logger, flags *GoPathFlags) error {
	// Parse repo info
	if flags.Package == "" {
		remote, err := git.GetRemoteOriginUrl(log)
		if err != nil {
			return maskAny(err)
		}
		flags.Package = remote
	}
	gitURL, err := vcsurl.Parse(flags.Package)
	if err != nil {
		return maskAny(err)
	}
	// Prepare dirs
	curDir, err := os.Getwd()
	if err != nil {
		return maskAny(err)
	}
	gobuildDir := filepath.Join(curDir, ".gobuild")
	orgDir := filepath.Join(gobuildDir, "src", string(gitURL.RepoHost), gitURL.Username)
	repoDir := filepath.Join(orgDir, gitURL.Name)
	if _, err := os.Stat(repoDir); err != nil {
		if err := os.MkdirAll(orgDir, 0755); err != nil {
			return maskAny(err)
		}
		if err := os.Symlink(curDir, repoDir); err != nil {
			return maskAny(err)
		}
	}

	fmt.Println(gobuildDir)

	return nil
}
<commit_msg>Using relative link when possible<commit_after>// Copyright (c) 2016 Pulcy.
//
// 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 golang

import (
	"fmt"
	"os"
	"path/filepath"

	log "github.com/op/go-logging"

	"github.com/pulcy/pulsar/git"
	vcsurl "github.com/sourcegraph/go-vcsurl"
)

type GoPathFlags struct {
	Package string // If set, use this package instead of the origin URL from the local repo
}

// CreateLocalGoPath creates a local .gobuild folder with a GOPATH folder structure in it.
func CreateLocalGoPath(log *log.Logger, flags *GoPathFlags) error {
	// Parse repo info
	if flags.Package == "" {
		remote, err := git.GetRemoteOriginUrl(log)
		if err != nil {
			return maskAny(err)
		}
		flags.Package = remote
	}
	gitURL, err := vcsurl.Parse(flags.Package)
	if err != nil {
		return maskAny(err)
	}
	// Prepare dirs
	curDir, err := os.Getwd()
	if err != nil {
		return maskAny(err)
	}
	gobuildDir := filepath.Join(curDir, ".gobuild")
	orgDir := filepath.Join(gobuildDir, "src", string(gitURL.RepoHost), gitURL.Username)
	repoDir := filepath.Join(orgDir, gitURL.Name)
	relRepoDir, err := filepath.Rel(orgDir, curDir)
	targetDir := curDir
	if err == nil {
		targetDir = relRepoDir
	}
	if _, err := os.Stat(repoDir); err != nil {
		if err := os.MkdirAll(orgDir, 0755); err != nil {
			return maskAny(err)
		}
		if err := os.Symlink(targetDir, repoDir); err != nil {
			return maskAny(err)
		}
	}

	fmt.Println(gobuildDir)

	return nil
}
<|endoftext|>


<commit_before>/*Package golden provides tools for comparing large mutli-line strings.

Golden files are files in the ./testdata/ subdirectory of the package under test.
Golden files can be automatically updated to match new values by running
`go test pkgname -test.update-golden`. To ensure the update is correct
compare the diff of the old expected value to the new expected value.
*/
package golden // import "gotest.tools/v3/golden"

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"gotest.tools/v3/assert"
	"gotest.tools/v3/assert/cmp"
	"gotest.tools/v3/internal/format"
)

var flagUpdate = flag.Bool("test.update-golden", false, "update golden file")

type helperT interface {
	Helper()
}

// Open opens the file in ./testdata
func Open(t assert.TestingT, filename string) *os.File {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	f, err := os.Open(Path(filename))
	assert.NilError(t, err)
	return f
}

// Get returns the contents of the file in ./testdata
func Get(t assert.TestingT, filename string) []byte {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	expected, err := ioutil.ReadFile(Path(filename))
	assert.NilError(t, err)
	return expected
}

// Path returns the full path to a file in ./testdata
func Path(filename string) string {
	if filepath.IsAbs(filename) {
		return filename
	}
	return filepath.Join("testdata", filename)
}

func update(filename string, actual []byte) error {
	if *flagUpdate {
		return ioutil.WriteFile(Path(filename), actual, 0644)
	}
	return nil
}

func removeCarriageReturn(in []byte) []byte {
	return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1)
}

// Assert compares actual to the expected value in the golden file.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// This is equivalent to assert.Assert(t, String(actual, filename))
func Assert(t assert.TestingT, actual string, filename string, msgAndArgs ...interface{}) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.Assert(t, String(actual, filename), msgAndArgs...)
}

// String compares actual to the contents of filename and returns success
// if the strings are equal.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// Any \r\n substrings in actual are converted to a single \n character
// before comparing it to the expected string. When updating the golden file the
// normalized version will be written to the file. This allows Windows to use
// the same golden files as other operating systems.
func String(actual string, filename string) cmp.Comparison {
	return func() cmp.Result {
		actualBytes := removeCarriageReturn([]byte(actual))
		result, expected := compare(actualBytes, filename)
		if result != nil {
			return result
		}
		diff := format.UnifiedDiff(format.DiffConfig{
			A:    string(expected),
			B:    string(actualBytes),
			From: "expected",
			To:   "actual",
		})
		return cmp.ResultFailure("\n" + diff + failurePostamble(filename))
	}
}

func failurePostamble(filename string) string {
	return fmt.Sprintf(`

You can run 'go test . -test.update-golden' to automatically update %s to the new expected value.'
`, Path(filename))
}

// AssertBytes compares actual to the expected value in the golden.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// This is equivalent to assert.Assert(t, Bytes(actual, filename))
func AssertBytes(
	t assert.TestingT,
	actual []byte,
	filename string,
	msgAndArgs ...interface{},
) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.Assert(t, Bytes(actual, filename), msgAndArgs...)
}

// Bytes compares actual to the contents of filename and returns success
// if the bytes are equal.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
func Bytes(actual []byte, filename string) cmp.Comparison {
	return func() cmp.Result {
		result, expected := compare(actual, filename)
		if result != nil {
			return result
		}
		msg := fmt.Sprintf("%v (actual) != %v (expected)", actual, expected)
		return cmp.ResultFailure(msg + failurePostamble(filename))
	}
}

func compare(actual []byte, filename string) (cmp.Result, []byte) {
	if err := update(filename, actual); err != nil {
		return cmp.ResultFromError(err), nil
	}
	expected, err := ioutil.ReadFile(Path(filename))
	if err != nil {
		return cmp.ResultFromError(err), nil
	}
	if bytes.Equal(expected, actual) {
		return cmp.ResultSuccess, nil
	}
	return nil, expected
}
<commit_msg>golden: Add a var to disable normalization of crlf<commit_after>/*Package golden provides tools for comparing large mutli-line strings.

Golden files are files in the ./testdata/ subdirectory of the package under test.
Golden files can be automatically updated to match new values by running
`go test pkgname -test.update-golden`. To ensure the update is correct
compare the diff of the old expected value to the new expected value.
*/
package golden // import "gotest.tools/v3/golden"

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"gotest.tools/v3/assert"
	"gotest.tools/v3/assert/cmp"
	"gotest.tools/v3/internal/format"
)

var flagUpdate = flag.Bool("test.update-golden", false, "update golden file")

type helperT interface {
	Helper()
}

// NormalizeCRLFToLF enables end-of-line normalization for actual values passed
// to Assert and String, as well as the values saved to golden files with
// -test.update-golden.
//
// Defaults to true. If you use the core.autocrlf=true git setting on windows
// you will need to set this to false.
//
// The value may be set to false by setting GOTESTTOOLS_GOLDEN_NormalizeCRLFToLF=false
// in the environment before running tests.
//
// The default value may change in a future major release.
var NormalizeCRLFToLF = os.Getenv("GOTESTTOOLS_GOLDEN_NormalizeCRLFToLF") != "false"

// Open opens the file in ./testdata
func Open(t assert.TestingT, filename string) *os.File {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	f, err := os.Open(Path(filename))
	assert.NilError(t, err)
	return f
}

// Get returns the contents of the file in ./testdata
func Get(t assert.TestingT, filename string) []byte {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	expected, err := ioutil.ReadFile(Path(filename))
	assert.NilError(t, err)
	return expected
}

// Path returns the full path to a file in ./testdata
func Path(filename string) string {
	if filepath.IsAbs(filename) {
		return filename
	}
	return filepath.Join("testdata", filename)
}

func update(filename string, actual []byte) error {
	if *flagUpdate {
		return ioutil.WriteFile(Path(filename), actual, 0644)
	}
	return nil
}

func removeCarriageReturn(in []byte) []byte {
	if !NormalizeCRLFToLF {
		return in
	}
	return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1)
}

// Assert compares actual to the expected value in the golden file.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// This is equivalent to assert.Assert(t, String(actual, filename))
func Assert(t assert.TestingT, actual string, filename string, msgAndArgs ...interface{}) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.Assert(t, String(actual, filename), msgAndArgs...)
}

// String compares actual to the contents of filename and returns success
// if the strings are equal.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// Any \r\n substrings in actual are converted to a single \n character
// before comparing it to the expected string. When updating the golden file the
// normalized version will be written to the file. This allows Windows to use
// the same golden files as other operating systems.
func String(actual string, filename string) cmp.Comparison {
	return func() cmp.Result {
		actualBytes := removeCarriageReturn([]byte(actual))
		result, expected := compare(actualBytes, filename)
		if result != nil {
			return result
		}
		diff := format.UnifiedDiff(format.DiffConfig{
			A:    string(expected),
			B:    string(actualBytes),
			From: "expected",
			To:   "actual",
		})
		return cmp.ResultFailure("\n" + diff + failurePostamble(filename))
	}
}

func failurePostamble(filename string) string {
	return fmt.Sprintf(`

You can run 'go test . -test.update-golden' to automatically update %s to the new expected value.'
`, Path(filename))
}

// AssertBytes compares actual to the expected value in the golden.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
//
// This is equivalent to assert.Assert(t, Bytes(actual, filename))
func AssertBytes(
	t assert.TestingT,
	actual []byte,
	filename string,
	msgAndArgs ...interface{},
) {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}
	assert.Assert(t, Bytes(actual, filename), msgAndArgs...)
}

// Bytes compares actual to the contents of filename and returns success
// if the bytes are equal.
//
// Running `go test pkgname -test.update-golden` will write the value of actual
// to the golden file.
func Bytes(actual []byte, filename string) cmp.Comparison {
	return func() cmp.Result {
		result, expected := compare(actual, filename)
		if result != nil {
			return result
		}
		msg := fmt.Sprintf("%v (actual) != %v (expected)", actual, expected)
		return cmp.ResultFailure(msg + failurePostamble(filename))
	}
}

func compare(actual []byte, filename string) (cmp.Result, []byte) {
	if err := update(filename, actual); err != nil {
		return cmp.ResultFromError(err), nil
	}
	expected, err := ioutil.ReadFile(Path(filename))
	if err != nil {
		return cmp.ResultFromError(err), nil
	}
	if bytes.Equal(expected, actual) {
		return cmp.ResultSuccess, nil
	}
	return nil, expected
}
<|endoftext|>