<commit_before>// See LICENSE file for copyright and license details.

// Модуль direction реализует работу с направлениями
// в гексагональной сетке.
//
package dir

import (
	"errors"
	"log"
	"my/marauder/pos"
)

// Dir обозначает некоторое направления.
// Например, движение в определенную сторону
// или направление взгляда юнита.
//
type Dir int

// Константы направлений.
const (
	NorthEast = iota
	East
	SouthEast
	SouthWest
	West
	NorthWest
	None
)

// dirToPosDiff это вспомогательная таблица
// для преобразования из позиции в направление.
//
var dirToPosDiff = [2][6]pos.Pos{
	{
		{1, -1},
		{1, 0},
		{1, 1},
		{0, 1},
		{-1, 0},
		{0, -1},
	},
	{
		{0, -1},
		{1, 0},
		{0, 1},
		{-1, 1},
		{-1, 0},
		{-1, -1},
	},
}

// Diff возвращает разницу ("угол") между индексами направлений.
func (self Dir) Diff(other Dir) int {
	d := self - other
	if d < 0 {
		d = -d
	}
	if d > 6/2 {
		d = 6 - d
	}
	return int(d)
}

// Opposite возвращает противоположное направление.
func (self Dir) Opposite() Dir {
	directionIndex := self + 6/2
	if directionIndex >= 6 {
		directionIndex -= 6
	}
	return directionIndex
}

func getTableIndex(p pos.Pos) int {
	var isOddRow bool = (p.Y%2 == 1)
	var subtableIndex int
	if isOddRow {
		subtableIndex = 1
	} else {
		subtableIndex = 0
	}
	return subtableIndex
}

// GetNeighbourPos возвращает соседнюю позицию в определенном направлении.
func GetNeighbourPos(p pos.Pos, i Dir) pos.Pos {
	subtableIndex := getTableIndex(p)
	if i >= 6 {
		log.Fatal("bad direction")
	}
	difference := dirToPosDiff[subtableIndex][i]
	return p.Add(difference)
}

// GetDirFromPosToPos принимает две прилежащих
// позиции и возвращает индекс направления.
//
func GetDirFromPosToPos(
	a pos.Pos, b pos.Pos,
) (Dir, error) {
	if a.Distance(b) != 1 {
		return 0, errors.New("distance != 1")
	}
	diff := b.Subtract(a)
	for i := 0; i < 6; i++ {
		if diff == dirToPosDiff[a.Y%2][i] {
			return Dir(i), nil
		}
	}
	return 0, errors.New("bad positions")
}
<commit_msg>dir/dir.go: Updated comments<commit_after>// See LICENSE file for copyright and license details.

// Package dir provides hexagonal directions.
//
// Модуль direction реализует работу с направлениями
// в гексагональной сетке.
//
package dir

import (
	"errors"
	"log"
	"my/marauder/pos"
)

// Dir обозначает некоторое направления.
// Например, движение в определенную сторону
// или направление взгляда юнита.
//
type Dir int

// Константы направлений.
const (
	NorthEast = iota
	East
	SouthEast
	SouthWest
	West
	NorthWest
	None
)

// dirToPosDiff это вспомогательная таблица
// для преобразования из позиции в направление.
//
var dirToPosDiff = [2][6]pos.Pos{
	{
		{1, -1},
		{1, 0},
		{1, 1},
		{0, 1},
		{-1, 0},
		{0, -1},
	},
	{
		{0, -1},
		{1, 0},
		{0, 1},
		{-1, 1},
		{-1, 0},
		{-1, -1},
	},
}

// Diff returns difference between this and some other direction.
func (self Dir) Diff(other Dir) int {
	d := self - other
	if d < 0 {
		d = -d
	}
	if d > 6/2 {
		d = 6 - d
	}
	return int(d)
}

// Opposite return opposite direction.
func (self Dir) Opposite() Dir {
	directionIndex := self + 6/2
	if directionIndex >= 6 {
		directionIndex -= 6
	}
	return directionIndex
}

func getTableIndex(p pos.Pos) int {
	var isOddRow bool = (p.Y%2 == 1)
	var subtableIndex int
	if isOddRow {
		subtableIndex = 1
	} else {
		subtableIndex = 0
	}
	return subtableIndex
}

// GetNeighbourPos возвращает соседнюю позицию в определенном направлении.
func GetNeighbourPos(p pos.Pos, i Dir) pos.Pos {
	subtableIndex := getTableIndex(p)
	if i >= 6 {
		log.Fatal("bad direction")
	}
	difference := dirToPosDiff[subtableIndex][i]
	return p.Add(difference)
}

// GetDirFromPosToPos принимает две прилежащих
// позиции и возвращает индекс направления.
//
func GetDirFromPosToPos(
	a pos.Pos, b pos.Pos,
) (Dir, error) {
	if a.Distance(b) != 1 {
		return 0, errors.New("distance != 1")
	}
	diff := b.Subtract(a)
	for i := 0; i < 6; i++ {
		if diff == dirToPosDiff[a.Y%2][i] {
			return Dir(i), nil
		}
	}
	return 0, errors.New("bad positions")
}
<|endoftext|>


<commit_before>package main

import (
	"runtime"
	gl     "github.com/polyfloyd/go-gl"
	glfw   "github.com/go-gl/glfw3"
	input  "polyfloyd/irix/input"
	mathgl "github.com/go-gl/mathgl/mgl32"
	mesh   "polyfloyd/irix/mesh"
	shader "polyfloyd/irix/shader"
)

type Display struct {
	Buffer  []float32
	HideOff bool

	cubeHeight  int
	cubeLength  int
	cubeWidth   int

	camRot  mathgl.Quat
	camZoom float32

	frontBuffer       []float32
	ledModel          *mesh.Mesh
	shader            *shader.Program
	shouldSwapBuffers bool
	win  *glfw.Window
}

func NewDisplay(w, h, l int) *Display {
	disp := &Display{
		cubeHeight:  h,
		cubeLength:  l,
		cubeWidth:   w,
		Buffer:      make([]float32, w*h*l * 3),
		frontBuffer: make([]float32, w*h*l * 3),
	}
	disp.ResetView()
	return disp
}

func (disp *Display) Start() {
	runtime.LockOSThread()
	runtime.GOMAXPROCS(runtime.NumCPU())

	for i := 0; i < len(disp.frontBuffer); i += 3 {
		disp.frontBuffer[i + 0] = 0.0
		disp.frontBuffer[i + 1] = 0.4
		disp.frontBuffer[i + 2] = 1.0
	}

	input.OnKeyPress(glfw.KeyS, func(_ glfw.ModifierKey) {
		disp.HideOff = !disp.HideOff
	})
	input.OnKeyPress(glfw.KeyR, func(_ glfw.ModifierKey) {
		disp.ResetView()
	})
	input.OnMouseScroll(func(dx, dy float64) {
		disp.camZoom += float32(dy) * UI_ZOOMACCEL
	})
	input.OnMouseDrag(glfw.MouseButtonLeft, func(x, y float64) {
		disp.camRot = mathgl.QuatRotate(float32(x) / UI_DRAGDIV, mathgl.Vec3{0, 1, 0}).Mul(disp.camRot)
		disp.camRot = mathgl.QuatRotate(float32(y) / UI_DRAGDIV, mathgl.Vec3{1, 0, 0}).Mul(disp.camRot)
	})

	if !glfw.Init() {
		panic("Can't init GLFW!")
	}
	glfw.SwapInterval(1)

	var err error
	disp.win, err = glfw.CreateWindow(UI_WIN_W, UI_WIN_H, INFO, nil, nil)
	if err != nil {
		panic(err)
	}
	disp.win.MakeContextCurrent()

	resize := func(w, h int) {
		gl.Viewport(0, 0, w, h)
	}
	disp.win.SetSizeCallback(func(win *glfw.Window, w, h int) {
		resize(w, h)
	})
	input.SetInputWindow(disp.win)
	resize(disp.win.GetSize())

	if err := disp.initGL(); err != nil {
		panic(err)
	}

	for !disp.win.ShouldClose() {
		if (disp.shouldSwapBuffers) {
			disp.frontBuffer, disp.Buffer = disp.Buffer, disp.frontBuffer
			disp.shouldSwapBuffers = false
		}
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

		disp.render()

		disp.win.SwapBuffers()
		glfw.PollEvents()
	}
	disp.win.Destroy()
	runtime.UnlockOSThread()
}

func (disp *Display) render() {
	uniformColor := disp.shader.Uniform["color_led"]
	uniformMVP   := disp.shader.Uniform["mat_modviewproj"]

	projection := mathgl.Perspective(
		UI_FOVY,
		func(w, h int) float32 {
			return float32(w) / float32(h)
		}(disp.win.GetSize()),
		UI_ZNEAR,
		UI_ZFAR,
	)
	center := mathgl.Translate3D(
		-(UI_SPACING*float32(disp.cubeWidth)/2  - UI_SPACING/2),
		-(UI_SPACING*float32(disp.cubeHeight)/2 - UI_SPACING/2),
		-(UI_SPACING*float32(disp.cubeLength)/2 - UI_SPACING/2),
	)
	view := func() mathgl.Mat4 {
		m := mathgl.Ident4()
		m = m.Mul4(mathgl.Translate3D(0, 0, disp.camZoom))
		m = m.Mul4(disp.camRot.Mat4())
		return m
	}()

	for x := 0; x < disp.cubeWidth; x++ {
		for y := 0; y < disp.cubeHeight; y++ {
			for z := 0; z < disp.cubeLength; z++ {
				i := x*disp.cubeHeight*disp.cubeLength + y*disp.cubeLength + z

				r := disp.frontBuffer[i*3 + 0]
				g := disp.frontBuffer[i*3 + 1]
				b := disp.frontBuffer[i*3 + 2]
				if disp.HideOff && (r==0 && g==0 && b==0) {
					continue
				}

				model := mathgl.Translate3D(
					float32(x) * UI_SPACING,
					float32(y) * UI_SPACING,
					float32(z) * UI_SPACING,
				).Mul4(center);

				mvp := projection.Mul4(view).Mul4(model)
				uniformMVP.UniformMatrix4f(false, (*[16]float32)(&mvp))
				uniformColor.Uniform3f(r, g, b)
				disp.ledModel.Render()
			}
		}
	}
}

func (disp *Display) initGL() error {
	if err := gl.Init(); err != nil { return err }

	gl.Enable(gl.DEPTH_TEST)
	gl.ClearColor(0.12, 0.12, 0.12, 1.0)

	m, err := mesh.Build(mesh.GenIcosahedron(2))
	if (err != nil) { return err }
	disp.ledModel = m[0]
	disp.ledModel.Load()

	vert, err := shader.CreateVertexObject(SHADER_SRC_VX)
	if (err != nil) { return err }
	if err := vert.Load(); err != nil { return err }
	frag, err := shader.CreateFragmentObject(SHADER_SRC_FG)
	if (err != nil) { return err }
	if err := frag.Load(); err != nil { return err }
	disp.shader, err = shader.Link(true, vert, frag)
	if (err != nil) { return err }

	disp.shader.Enable()
	disp.ledModel.Enable()
	return nil
}

func (disp *Display) SwapBuffers() {
	disp.shouldSwapBuffers = true
}

func (disp *Display) ResetView() {
	disp.camRot  = mathgl.QuatIdent()
	disp.camZoom = -160
}

const SHADER_SRC_VX = `
	#version 330 core

	{{.vert_position  }}
	{{.vert_normal    }}
	{{.vert_tex2      }}
	{{.vert_color     }}
	{{.mat_modviewproj}}

	out vec3 frag_normal;
	out vec2 frag_tex2;
	out vec3 frag_color;

	void main() {
		frag_normal = vert_normal;
		frag_tex2   = vert_tex2;
		frag_color  = vert_color;
		gl_Position = mat_modviewproj * vec4(vert_position, 1.0);
	}
`

const SHADER_SRC_FG = `
	#version 330 core

	vec3 LIGHT_VEC   = normalize(vec3(1, 1, 1));
	vec3 LIGHT_COLOR = vec3(0.2, 0.2, 0.2);

	in vec3 frag_normal;
	in vec2 frag_tex2;
	in vec3 frag_color;

	uniform vec3 color_led;

	out vec3 color;

	void main() {
		float cosTheta = clamp(dot(frag_normal, LIGHT_VEC), 0, 1);
		color = color_led + LIGHT_COLOR * cosTheta;
	}
`
<commit_msg>Stop using Irix input<commit_after>package main

import (
	"runtime"
	gl     "github.com/polyfloyd/go-gl"
	glfw   "github.com/go-gl/glfw3"
	mathgl "github.com/go-gl/mathgl/mgl32"
	mesh   "polyfloyd/irix/mesh"
	shader "polyfloyd/irix/shader"
)

type Display struct {
	Buffer  []float32
	HideOff bool

	cubeHeight  int
	cubeLength  int
	cubeWidth   int

	camRot  mathgl.Quat
	camZoom float32

	frontBuffer       []float32
	ledModel          *mesh.Mesh
	shader            *shader.Program
	shouldSwapBuffers bool
	win  *glfw.Window
}

func NewDisplay(w, h, l int) *Display {
	disp := &Display{
		cubeHeight:  h,
		cubeLength:  l,
		cubeWidth:   w,
		Buffer:      make([]float32, w*h*l * 3),
		frontBuffer: make([]float32, w*h*l * 3),
	}
	disp.ResetView()
	return disp
}

func (disp *Display) Start() {
	runtime.LockOSThread()
	runtime.GOMAXPROCS(runtime.NumCPU())

	for i := 0; i < len(disp.frontBuffer); i += 3 {
		disp.frontBuffer[i + 0] = 0.0
		disp.frontBuffer[i + 1] = 0.4
		disp.frontBuffer[i + 2] = 1.0
	}

	if err := disp.init(); err != nil {
		panic(err)
	}

	for !disp.win.ShouldClose() {
		if (disp.shouldSwapBuffers) {
			disp.frontBuffer, disp.Buffer = disp.Buffer, disp.frontBuffer
			disp.shouldSwapBuffers = false
		}
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

		disp.render()

		disp.win.SwapBuffers()
		glfw.PollEvents()
	}
	disp.win.Destroy()
	runtime.UnlockOSThread()
}

func (disp *Display) render() {
	uniformColor := disp.shader.Uniform["color_led"]
	uniformMVP   := disp.shader.Uniform["mat_modviewproj"]

	projection := mathgl.Perspective(
		UI_FOVY,
		func(w, h int) float32 {
			return float32(w) / float32(h)
		}(disp.win.GetSize()),
		UI_ZNEAR,
		UI_ZFAR,
	)
	center := mathgl.Translate3D(
		-(UI_SPACING*float32(disp.cubeWidth)/2  - UI_SPACING/2),
		-(UI_SPACING*float32(disp.cubeHeight)/2 - UI_SPACING/2),
		-(UI_SPACING*float32(disp.cubeLength)/2 - UI_SPACING/2),
	)
	view := func() mathgl.Mat4 {
		m := mathgl.Ident4()
		m = m.Mul4(mathgl.Translate3D(0, 0, disp.camZoom))
		m = m.Mul4(disp.camRot.Mat4())
		return m
	}()

	for x := 0; x < disp.cubeWidth; x++ {
		for y := 0; y < disp.cubeHeight; y++ {
			for z := 0; z < disp.cubeLength; z++ {
				i := x*disp.cubeHeight*disp.cubeLength + y*disp.cubeLength + z

				r := disp.frontBuffer[i*3 + 0]
				g := disp.frontBuffer[i*3 + 1]
				b := disp.frontBuffer[i*3 + 2]
				if disp.HideOff && (r==0 && g==0 && b==0) {
					continue
				}

				model := mathgl.Translate3D(
					float32(x) * UI_SPACING,
					float32(y) * UI_SPACING,
					float32(z) * UI_SPACING,
				).Mul4(center);

				mvp := projection.Mul4(view).Mul4(model)
				uniformMVP.UniformMatrix4f(false, (*[16]float32)(&mvp))
				uniformColor.Uniform3f(r, g, b)
				disp.ledModel.Render()
			}
		}
	}
}

func (disp *Display) init() error {
	if !glfw.Init() {
		panic("Can't init GLFW!")
	}
	{
		var err error
		disp.win, err = glfw.CreateWindow(UI_WIN_W, UI_WIN_H, INFO, nil, nil)
		if err != nil {
			panic(err)
		}
	}
	disp.win.MakeContextCurrent()
	resize := func(w, h int) { gl.Viewport(0, 0, w, h) }
	disp.win.SetSizeCallback(func(win *glfw.Window, w, h int) {
		resize(w, h)
	})
	resize(disp.win.GetSize())
	glfw.SwapInterval(1)

	var dragButtonDown bool
	var mousePosLastX float64
	var mousePosLastY float64
	disp.win.SetCursorPositionCallback(func(_ *glfw.Window, x, y float64) {
		deltaX := x - mousePosLastX
		deltaY := y - mousePosLastY
		mousePosLastX = x
		mousePosLastY = y
		if (dragButtonDown) {
			disp.camRot = mathgl.QuatRotate(float32(deltaX) / UI_DRAGDIV, mathgl.Vec3{0, 1, 0}).Mul(disp.camRot)
			disp.camRot = mathgl.QuatRotate(float32(deltaY) / UI_DRAGDIV, mathgl.Vec3{1, 0, 0}).Mul(disp.camRot)
		}
	})
	disp.win.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton,
		action glfw.Action, mods glfw.ModifierKey) {
		dragButtonDown = action == glfw.Press && button == glfw.MouseButtonLeft
	})
	disp.win.SetScrollCallback(func(_ *glfw.Window, dx, dy float64) {
		disp.camZoom += float32(dy) * UI_ZOOMACCEL
	})
	disp.win.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, scancode int,
		action glfw.Action, mods glfw.ModifierKey) {
		if (action != glfw.Release) {
			switch(key) {
			case glfw.KeyS: disp.HideOff = !disp.HideOff
			case glfw.KeyR: disp.ResetView()
			}
		}
	})

	if err := gl.Init(); err != nil { return err }
	gl.Enable(gl.DEPTH_TEST)
	gl.ClearColor(0.12, 0.12, 0.12, 1.0)

	m, err := mesh.Build(mesh.GenIcosahedron(2))
	if (err != nil) { return err }
	disp.ledModel = m[0]
	disp.ledModel.Load()

	vert, err := shader.CreateVertexObject(SHADER_SRC_VX)
	if (err != nil) { return err }
	if err := vert.Load(); err != nil { return err }
	frag, err := shader.CreateFragmentObject(SHADER_SRC_FG)
	if (err != nil) { return err }
	if err := frag.Load(); err != nil { return err }
	disp.shader, err = shader.Link(true, vert, frag)
	if (err != nil) { return err }

	disp.shader.Enable()
	disp.ledModel.Enable()
	return nil
}

func (disp *Display) SwapBuffers() {
	disp.shouldSwapBuffers = true
}

func (disp *Display) ResetView() {
	disp.camRot  = mathgl.QuatIdent()
	disp.camZoom = -160
}

const SHADER_SRC_VX = `
	#version 330 core

	{{.vert_position  }}
	{{.vert_normal    }}
	{{.vert_tex2      }}
	{{.vert_color     }}
	{{.mat_modviewproj}}

	out vec3 frag_normal;
	out vec2 frag_tex2;
	out vec3 frag_color;

	void main() {
		frag_normal = vert_normal;
		frag_tex2   = vert_tex2;
		frag_color  = vert_color;
		gl_Position = mat_modviewproj * vec4(vert_position, 1.0);
	}
`

const SHADER_SRC_FG = `
	#version 330 core

	vec3 LIGHT_VEC   = normalize(vec3(1, 1, 1));
	vec3 LIGHT_COLOR = vec3(0.2, 0.2, 0.2);

	in vec3 frag_normal;
	in vec2 frag_tex2;
	in vec3 frag_color;

	uniform vec3 color_led;

	out vec3 color;

	void main() {
		float cosTheta = clamp(dot(frag_normal, LIGHT_VEC), 0, 1);
		color = color_led + LIGHT_COLOR * cosTheta;
	}
`
<|endoftext|>


<commit_before>package heroku

import (
	"net/http"

	"github.com/remind101/empire"
	streamhttp "github.com/remind101/empire/pkg/stream/http"
	"golang.org/x/net/context"
)

type PostLogs struct {
	*empire.Empire
}

func (h *PostLogs) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	a, err := findApp(ctx, h)
	if err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/json; boundary=NL")
	rw := streamhttp.StreamingResponseWriter(w)
	h.StreamLogs(a, rw)

	return nil
}
<commit_msg>Fix Content-Type.<commit_after>package heroku

import (
	"net/http"

	"github.com/remind101/empire"
	streamhttp "github.com/remind101/empire/pkg/stream/http"
	"golang.org/x/net/context"
)

type PostLogs struct {
	*empire.Empire
}

func (h *PostLogs) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	a, err := findApp(ctx, h)
	if err != nil {
		return err
	}

	w.Header().Set("Content-Type", "text/plain; boundary=NL")
	rw := streamhttp.StreamingResponseWriter(w)
	h.StreamLogs(a, rw)

	return nil
}
<|endoftext|>


<commit_before>package blog

import (
	"fmt"
	"github.com/hoisie/web"
	"github.com/jmoiron/monet/app"
	"github.com/jmoiron/monet/db"
	"github.com/jmoiron/monet/template"
	"github.com/jmoiron/syndicate"
	"labix.org/v2/mgo/bson"
	"time"
)

var base = template.Base{Path: "base.mandira"}

// Attach the blog app frontend
func Attach(url string) {
	web.Get(url+"blog/page/(\\d+)", blogPage)
	web.Get(url+"blog/([^/]+)/", blogDetail)
	web.Get(url+"blog/", blogIndex)
	web.Get(url+"stream/page/(\\d+)", streamPage)
	web.Get(url+"stream/", streamIndex)
	web.Get(url+"blog/rss", rss)
	web.Get(url+"blog/atom", atom)
}

// Render the post, using the cached ContentRendered if available, or generating
// and re-saving it to the database if not
func RenderPost(post *Post) string {
	if len(post.ContentRendered) == 0 {
		db.Upsert(post)
	}
	return template.Render("blog/post.mandira", post)
}

// A Flatpage view.  Attach it via web.Get wherever you want flatpages to be available
func Flatpage(ctx *web.Context, url string) string {
	p := GetPage(url)
	if p == nil {
		ctx.Abort(404, "Page not found")
		return ""
	}

	return template.Render("base.mandira", M{
		"body":        p.ContentRendered,
		"title":       "jmoiron.net",
		"description": "Blog and assorted media from Jason Moiron.",
	})
}

func Index(s string) string {
	var post *Post
	var entry *Entry
	var posts []Post
	var entries []*Entry

	err := db.Latest(post, M{"published": 1}).Limit(7).All(&posts)
	if err != nil {
		fmt.Println(err)
	}
	err = db.Latest(entry, nil).Limit(4).All(&entries)
	if err != nil {
		fmt.Println(err)
	}

	post = &posts[0]
	return base.Render("index.mandira", M{
		"Post":        RenderPost(post),
		"Posts":       posts[1:],
		"Entries":     entries,
		"title":       "jmoiron.net",
		"description": post.Summary})
}

func blogIndex(ctx *web.Context) string {
	return blogPage(ctx, "1")
}

func blogPage(ctx *web.Context, page string) string {
	pn := app.PageNumber(page)
	perPage := 15
	paginator := app.NewPaginator(pn, perPage)
	paginator.Link = "/blog/page/"

	var post *Post
	var posts []Post
	// do a search, if required, of title and content
	var err error
	var numObjects int

	if len(ctx.Params["Search"]) > 0 {
		term := M{"$regex": ctx.Params["Search"]}
		search := M{"published": 1, "$or": []M{M{"title": term}, M{"content": term}}}
		err = db.Latest(post, search).Skip(paginator.Skip).Limit(perPage).All(&posts)
		numObjects, _ = db.Latest(post, search).Count()
	} else {
		err = db.Latest(post, M{"published": 1}).Skip(paginator.Skip).
			Limit(perPage).Iter().All(&posts)
		numObjects, _ = db.Find(post, M{"published": 1}).Count()
	}

	if err != nil {
		fmt.Println(err)
	}

	return base.Render("blog/index.mandira", M{
		"Posts": posts, "Pagination": paginator.Render(numObjects)}, ctx.Params)
}

func _createFeed() *syndicate.Feed {
	var posts []Post
	var post *Post

	err := db.Latest(post, M{"published": 1}).Limit(10).Iter().All(&posts)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	feed := &syndicate.Feed{
		Title:       "jmoiron.net blog",
		Link:        &syndicate.Link{Href: "http://jmoiron.net"},
		Description: "the blog of Jason Moiron, all thoughts his own",
		Author:      &syndicate.Author{"Jason Moiron", "jmoiron@jmoiron.net"},
		Updated:     time.Now(),
	}

	for _, post := range posts {
		feed.Add(&syndicate.Item{
			Title:       post.Title,
			Link:        &syndicate.Link{Href: "http://jmoiron.net/blog/" + post.Slug + "/"},
			Description: post.Summary,
			Created:     time.Unix(int64(post.Timestamp), 0),
		})
	}
	return feed
}

func atom(ctx *web.Context) string {
	feed := _createFeed()
	ctx.Header().Set("Content-Type", "application/xml")
	if feed == nil {
		return "<!-- error -->"
	}
	text, err := feed.ToAtom()
	if err != nil {
		fmt.Println(err)
		return "<!-- error -->"
	}
	return text
}

func rss(ctx *web.Context) string {
	feed := _createFeed()
	ctx.Header().Set("Content-Type", "application/xml")
	if feed == nil {
		return "<!-- error -->"
	}
	text, err := feed.ToRss()
	if err != nil {
		fmt.Println(err)
		return "<!-- error -->"
	}
	return text
}

func blogDetail(ctx *web.Context, slug string) string {
	var post = new(Post)
	err := db.Find(post, M{"slug": slug}).One(&post)
	if err != nil {
		fmt.Println(err)
		ctx.Abort(404, "Page not found")
		return ""
	}

	return template.Render("base.mandira", M{
		"body":        RenderPost(post),
		"title":       post.Title,
		"description": post.Summary})
}

func streamIndex(ctx *web.Context) string {
	return streamPage(ctx, "1")
}

func streamPage(ctx *web.Context, page string) string {
	num := app.PageNumber(page)
	perPage := 25
	paginator := app.NewPaginator(num, perPage)
	paginator.Link = "/stream/page/"

	var entry *Entry
	var entries []*Entry

	// do a search, if required, of title and content
	var err error
	var numObjects int

	if len(ctx.Params["Search"]) > 0 {
		re := new(bson.RegEx)
		re.Pattern = ctx.Params["Search"]
		re.Options = "i"
		term := M{"$regex": re}
		search := M{"summaryrendered": term}
		//search := M{"$or": []M{M{"title": term}, M{"summaryrendered": term}}}
		err = db.Latest(entry, search).Skip(paginator.Skip).Limit(perPage).All(&entries)
		numObjects, _ = db.Latest(entry, search).Count()
	} else {
		err = db.Latest(entry, nil).Skip(paginator.Skip).Limit(perPage).Iter().All(&entries)
		numObjects, _ = db.Cursor(entry).Count()
	}

	if err != nil {
		fmt.Println(err)
	}

	return base.Render("blog/stream/index.mandira", M{
		"Entries":    entries,
		"Pagination": paginator.Render(numObjects),
		"title":      "Lifestream"}, ctx.Params)
}
<commit_msg>use rendered content in feeds<commit_after>package blog

import (
	"fmt"
	"github.com/hoisie/web"
	"github.com/jmoiron/monet/app"
	"github.com/jmoiron/monet/db"
	"github.com/jmoiron/monet/template"
	"github.com/jmoiron/syndicate"
	"labix.org/v2/mgo/bson"
	"time"
)

var base = template.Base{Path: "base.mandira"}

// Attach the blog app frontend
func Attach(url string) {
	web.Get(url+"blog/page/(\\d+)", blogPage)
	web.Get(url+"blog/([^/]+)/", blogDetail)
	web.Get(url+"blog/", blogIndex)
	web.Get(url+"stream/page/(\\d+)", streamPage)
	web.Get(url+"stream/", streamIndex)
	web.Get(url+"blog/rss", rss)
	web.Get(url+"blog/atom", atom)
}

// Render the post, using the cached ContentRendered if available, or generating
// and re-saving it to the database if not
func RenderPost(post *Post) string {
	if len(post.ContentRendered) == 0 {
		db.Upsert(post)
	}
	return template.Render("blog/post.mandira", post)
}

// A Flatpage view.  Attach it via web.Get wherever you want flatpages to be available
func Flatpage(ctx *web.Context, url string) string {
	p := GetPage(url)
	if p == nil {
		ctx.Abort(404, "Page not found")
		return ""
	}

	return template.Render("base.mandira", M{
		"body":        p.ContentRendered,
		"title":       "jmoiron.net",
		"description": "Blog and assorted media from Jason Moiron.",
	})
}

func Index(s string) string {
	var post *Post
	var entry *Entry
	var posts []Post
	var entries []*Entry

	err := db.Latest(post, M{"published": 1}).Limit(7).All(&posts)
	if err != nil {
		fmt.Println(err)
	}
	err = db.Latest(entry, nil).Limit(4).All(&entries)
	if err != nil {
		fmt.Println(err)
	}

	post = &posts[0]
	return base.Render("index.mandira", M{
		"Post":        RenderPost(post),
		"Posts":       posts[1:],
		"Entries":     entries,
		"title":       "jmoiron.net",
		"description": post.Summary})
}

func blogIndex(ctx *web.Context) string {
	return blogPage(ctx, "1")
}

func blogPage(ctx *web.Context, page string) string {
	pn := app.PageNumber(page)
	perPage := 15
	paginator := app.NewPaginator(pn, perPage)
	paginator.Link = "/blog/page/"

	var post *Post
	var posts []Post
	// do a search, if required, of title and content
	var err error
	var numObjects int

	if len(ctx.Params["Search"]) > 0 {
		term := M{"$regex": ctx.Params["Search"]}
		search := M{"published": 1, "$or": []M{M{"title": term}, M{"content": term}}}
		err = db.Latest(post, search).Skip(paginator.Skip).Limit(perPage).All(&posts)
		numObjects, _ = db.Latest(post, search).Count()
	} else {
		err = db.Latest(post, M{"published": 1}).Skip(paginator.Skip).
			Limit(perPage).Iter().All(&posts)
		numObjects, _ = db.Find(post, M{"published": 1}).Count()
	}

	if err != nil {
		fmt.Println(err)
	}

	return base.Render("blog/index.mandira", M{
		"Posts": posts, "Pagination": paginator.Render(numObjects)}, ctx.Params)
}

func _createFeed() *syndicate.Feed {
	var posts []Post
	var post *Post

	err := db.Latest(post, M{"published": 1}).Limit(10).Iter().All(&posts)
	if err != nil {
		fmt.Println(err)
		return nil
	}

	feed := &syndicate.Feed{
		Title:       "jmoiron.net blog",
		Link:        &syndicate.Link{Href: "http://jmoiron.net"},
		Description: "the blog of Jason Moiron, all thoughts his own",
		Author:      &syndicate.Author{"Jason Moiron", "jmoiron@jmoiron.net"},
		Updated:     time.Now(),
	}

	for _, post := range posts {
		feed.Add(&syndicate.Item{
			Title:       post.Title,
			Link:        &syndicate.Link{Href: "http://jmoiron.net/blog/" + post.Slug + "/"},
			Description: post.ContentRendered,
			Created:     time.Unix(int64(post.Timestamp), 0),
		})
	}
	return feed
}

func atom(ctx *web.Context) string {
	feed := _createFeed()
	ctx.Header().Set("Content-Type", "application/xml")
	if feed == nil {
		return "<!-- error -->"
	}
	text, err := feed.ToAtom()
	if err != nil {
		fmt.Println(err)
		return "<!-- error -->"
	}
	return text
}

func rss(ctx *web.Context) string {
	feed := _createFeed()
	ctx.Header().Set("Content-Type", "application/xml")
	if feed == nil {
		return "<!-- error -->"
	}
	text, err := feed.ToRss()
	if err != nil {
		fmt.Println(err)
		return "<!-- error -->"
	}
	return text
}

func blogDetail(ctx *web.Context, slug string) string {
	var post = new(Post)
	err := db.Find(post, M{"slug": slug}).One(&post)
	if err != nil {
		fmt.Println(err)
		ctx.Abort(404, "Page not found")
		return ""
	}

	return template.Render("base.mandira", M{
		"body":        RenderPost(post),
		"title":       post.Title,
		"description": post.Summary})
}

func streamIndex(ctx *web.Context) string {
	return streamPage(ctx, "1")
}

func streamPage(ctx *web.Context, page string) string {
	num := app.PageNumber(page)
	perPage := 25
	paginator := app.NewPaginator(num, perPage)
	paginator.Link = "/stream/page/"

	var entry *Entry
	var entries []*Entry

	// do a search, if required, of title and content
	var err error
	var numObjects int

	if len(ctx.Params["Search"]) > 0 {
		re := new(bson.RegEx)
		re.Pattern = ctx.Params["Search"]
		re.Options = "i"
		term := M{"$regex": re}
		search := M{"summaryrendered": term}
		//search := M{"$or": []M{M{"title": term}, M{"summaryrendered": term}}}
		err = db.Latest(entry, search).Skip(paginator.Skip).Limit(perPage).All(&entries)
		numObjects, _ = db.Latest(entry, search).Count()
	} else {
		err = db.Latest(entry, nil).Skip(paginator.Skip).Limit(perPage).Iter().All(&entries)
		numObjects, _ = db.Cursor(entry).Count()
	}

	if err != nil {
		fmt.Println(err)
	}

	return base.Render("blog/stream/index.mandira", M{
		"Entries":    entries,
		"Pagination": paginator.Render(numObjects),
		"title":      "Lifestream"}, ctx.Params)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/spf13/viper"
	"log"
	"net/http"
	"net/url"
	"time"
)

// Used https://mholt.github.io/json-to-go/
type MergeRequest struct {
	ID           int       `json:"id"`
	Iid          int       `json:"iid"`
	ProjectID    int       `json:"project_id"`
	Title        string    `json:"title"`
	Description  string    `json:"description"`
	State        string    `json:"state"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
	TargetBranch string    `json:"target_branch"`
	SourceBranch string    `json:"source_branch"`
	Upvotes      int       `json:"upvotes"`
	Downvotes    int       `json:"downvotes"`
	Author       struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
		WebURL    string `json:"web_url"`
	} `json:"author"`
	Assignee                 interface{}   `json:"assignee"`
	SourceProjectID          int           `json:"source_project_id"`
	TargetProjectID          int           `json:"target_project_id"`
	Labels                   []interface{} `json:"labels"`
	WorkInProgress           bool          `json:"work_in_progress"`
	Milestone                interface{}   `json:"milestone"`
	MergeWhenBuildSucceeds   bool          `json:"merge_when_build_succeeds"`
	MergeStatus              string        `json:"merge_status"`
	Sha                      string        `json:"sha"`
	MergeCommitSha           string        `json:"merge_commit_sha"`
	Subscribed               bool          `json:"subscribed"`
	UserNotesCount           int           `json:"user_notes_count"`
	ApprovalsBeforeMerge     interface{}   `json:"approvals_before_merge"`
	ShouldRemoveSourceBranch interface{}   `json:"should_remove_source_branch"`
	ForceRemoveSourceBranch  bool          `json:"force_remove_source_branch"`
	WebURL                   string        `json:"web_url"`
}

type Branch struct {
   Name string `json:"name"`
   Commit struct {
      ID string `json:"id"`
      Message string `json:"message"`
      ParentIds []string `json:"parent_ids"`
      AuthoredDate time.Time `json:"authored_date"`
      AuthorName string `json:"author_name"`
      AuthorEmail string `json:"author_email"`
      CommittedDate time.Time `json:"committed_date"`
      CommitterName string `json:"committer_name"`
      CommitterEmail string `json:"committer_email"`
   } `json:"commit"`
   Protected bool `json:"protected"`
   DevelopersCanPush bool `json:"developers_can_push"`
   DevelopersCanMerge bool `json:"developers_can_merge"`
}

type Commit struct {
   ID string `json:"id"`
   ShortID string `json:"short_id"`
   Title string `json:"title"`
   AuthorName string `json:"author_name"`
   AuthorEmail string `json:"author_email"`
   CreatedAt time.Time `json:"created_at"`
   Message string `json:"message"`
}

func getMergedRequests(gitlabToken string, projectName string) (error, []MergeRequest) {

   projectName = url.QueryEscape(projectName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/merge_requests?state=opened&private_token=%s", projectName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Fatal("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Fatal("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var record []MergeRequest

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, record
}

func getBranches(gitlabToken string, projectName string) (error, []Branch) {

   projectName = url.QueryEscape(projectName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/repository/branches?private_token=%s", projectName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Fatal("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Fatal("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var record []Branch

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, record
}

func getCommits(gitlabToken string, projectName string, commitName string) (error, []Commit) {

   projectName = url.QueryEscape(projectName)

   commitName = url.QueryEscape(commitName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/repository/commits?ref_name=%s&private_token=%s",
      projectName, commitName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Fatal("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Fatal("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var record []Commit

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, record
}

func main() {

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()

	if err != nil {
		log.Println("Error: no configuration file not found")
		return
	}

	gitlabToken := viper.GetString("connection.token")

   projectName := "gnutls/gnutls"

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the merged requests from the GitLab project
   err, mergedRequests := getMergedRequests(gitlabToken, projectName)
   if err != nil {
      log.Println("Error: can't get the merged requests [", err, "]")
      return
   }

   for _, r := range mergedRequests {
      fmt.Println("merged requests title = ", r.Title)
      fmt.Println("                status = ", r.State)
      fmt.Println("                created at = ", r.CreatedAt)
      fmt.Println("                source branch = ", r.SourceBranch)
      fmt.Println("                target branch = ", r.TargetBranch)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the branches from the GitLab project
   err, branches := getBranches(gitlabToken, projectName)
   if err != nil {
      log.Println("Error: can't get the branches [", err, "]")
      return
   }

   for _, r := range branches {
      fmt.Println("branch name = ", r.Name)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the commits from a specific branch of the GitLab project
   err, commits := getCommits(gitlabToken, projectName, "cert-fast-load")
   if err != nil {
      log.Println("Error: can't get the commits [", err, "]")
      return
   }

   for _, r := range commits {
      fmt.Printf("commit date = %s  title = %s  \n", r.CreatedAt, r.Title)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get which branch was merged in which branch
   for _, branch := range branches {
      for _, mergedRequest := range mergedRequests {
         fmt.Printf("compare %s vs %s\n", branch.Name, mergedRequest.Title)
         if branch.Name == mergedRequest.SourceBranch {
            fmt.Printf("branch '%s' was merged into branch '%s' on %s\n", branch.Name, mergedRequest.TargetBranch,
               mergedRequest.UpdatedAt.Format("2006-01-02 15:04"))
         }
      }
   }
}
<commit_msg>Some refactoring and add comments<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/spf13/viper"
	"log"
	"net/http"
	"net/url"
	"time"
)

// Used https://mholt.github.io/json-to-go/
// MergeRequest contains the Merge Request data
type MergeRequest struct {
	ID           int       `json:"id"`
	Iid          int       `json:"iid"`
	ProjectID    int       `json:"project_id"`
	Title        string    `json:"title"`
	Description  string    `json:"description"`
	State        string    `json:"state"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
	TargetBranch string    `json:"target_branch"`
	SourceBranch string    `json:"source_branch"`
	Upvotes      int       `json:"upvotes"`
	Downvotes    int       `json:"downvotes"`
	Author       struct {
		Name      string `json:"name"`
		Username  string `json:"username"`
		ID        int    `json:"id"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
		WebURL    string `json:"web_url"`
	} `json:"author"`
	Assignee                 interface{}   `json:"assignee"`
	SourceProjectID          int           `json:"source_project_id"`
	TargetProjectID          int           `json:"target_project_id"`
	Labels                   []interface{} `json:"labels"`
	WorkInProgress           bool          `json:"work_in_progress"`
	Milestone                interface{}   `json:"milestone"`
	MergeWhenBuildSucceeds   bool          `json:"merge_when_build_succeeds"`
	MergeStatus              string        `json:"merge_status"`
	Sha                      string        `json:"sha"`
	MergeCommitSha           string        `json:"merge_commit_sha"`
	Subscribed               bool          `json:"subscribed"`
	UserNotesCount           int           `json:"user_notes_count"`
	ApprovalsBeforeMerge     interface{}   `json:"approvals_before_merge"`
	ShouldRemoveSourceBranch interface{}   `json:"should_remove_source_branch"`
	ForceRemoveSourceBranch  bool          `json:"force_remove_source_branch"`
	WebURL                   string        `json:"web_url"`
}

// Branch contains the branch data
type Branch struct {
   Name string `json:"name"`
   Commit struct {
      ID string `json:"id"`
      Message string `json:"message"`
      ParentIds []string `json:"parent_ids"`
      AuthoredDate time.Time `json:"authored_date"`
      AuthorName string `json:"author_name"`
      AuthorEmail string `json:"author_email"`
      CommittedDate time.Time `json:"committed_date"`
      CommitterName string `json:"committer_name"`
      CommitterEmail string `json:"committer_email"`
   } `json:"commit"`
   Protected bool `json:"protected"`
   DevelopersCanPush bool `json:"developers_can_push"`
   DevelopersCanMerge bool `json:"developers_can_merge"`
}

// Commit contains the commit data
type Commit struct {
   ID string `json:"id"`
   ShortID string `json:"short_id"`
   Title string `json:"title"`
   AuthorName string `json:"author_name"`
   AuthorEmail string `json:"author_email"`
   CreatedAt time.Time `json:"created_at"`
   Message string `json:"message"`
}

/**
 * getMergedRequests retrieves the Merge Requests that have been already merged.
 *
 * Doc: https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests
 */
func getMergedRequests(gitlabToken string, projectName string) (error, []MergeRequest) {

   projectName = url.QueryEscape(projectName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/merge_requests?state=merged&private_token=%s", projectName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Println("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Println("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var mergedRequests []MergeRequest

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&mergedRequests); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, mergedRequests
}

/**
 * getBranches retrieves branches from a project.
 *
 * Doc: https://docs.gitlab.com/ee/api/branches.html#list-repository-branches
 */
func getBranches(gitlabToken string, projectName string) (error, []Branch) {

   projectName = url.QueryEscape(projectName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/repository/branches?private_token=%s", projectName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Println("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Println("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var branches []Branch

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&branches); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, branches
}

/**
 * getCommits retrieves all the commits of a repository branch.
 *
 * Doc: https://docs.gitlab.com/ee/api/commits.html#list-repository-commits
 */
func getCommits(gitlabToken string, projectName string, commitName string) (error, []Commit) {

   projectName = url.QueryEscape(projectName)

   commitName = url.QueryEscape(commitName)

   url := fmt.Sprintf("http://www.gitlab.com/api/v3/projects/%s/repository/commits?ref_name=%s&private_token=%s",
      projectName, commitName, gitlabToken)

   // Build the request
   req, err := http.NewRequest("GET", url, nil)
   if err != nil {
      log.Println("NewRequest: ", err)
      return err, nil
   }

   // Create a HTTP Client for control over HTTP client headers, redirect policy, and other settings.
   client := &http.Client{}

   // Send an HTTP request and returns an HTTP response
   resp, err := client.Do(req)
   if err != nil {
      log.Println("Do: ", err)
      return err, nil
   }

   // Defer the closing of the body
   defer resp.Body.Close()

   // Fill the record with the data from the JSON
   var commits []Commit

   // Use json.Decode for reading streams of JSON data
   if err := json.NewDecoder(resp.Body).Decode(&commits); err != nil {
      log.Println(err)
      return err, nil
   }

   return nil, commits
}

func main() {

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()

	if err != nil {
		log.Println("Error: no configuration file not found")
		return
	}

	gitlabToken := viper.GetString("connection.token")

   projectName := "gnutls/gnutls"

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the merged requests from a GitLab project
   err, mergedRequests := getMergedRequests(gitlabToken, projectName)
   if err != nil {
      log.Println("Error: can't get the merged requests [", err, "]")
      return
   }

   for _, r := range mergedRequests {
      fmt.Println("merged requests title = ", r.Title)
      fmt.Println("                status = ", r.State)
      fmt.Println("                created at = ", r.CreatedAt)
      fmt.Println("                source branch = ", r.SourceBranch)
      fmt.Println("                target branch = ", r.TargetBranch)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the branches from a GitLab project
   err, branches := getBranches(gitlabToken, projectName)
   if err != nil {
      log.Println("Error: can't get the branches [", err, "]")
      return
   }

   for _, r := range branches {
      fmt.Println("branch name = ", r.Name)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get all the commits from a specific branch of the GitLab project
   err, commits := getCommits(gitlabToken, projectName, "cert-fast-load")
   if err != nil {
      log.Println("Error: can't get the commits [", err, "]")
      return
   }

   for _, r := range commits {
      fmt.Printf("commit date = %s  title = %s  \n", r.CreatedAt, r.Title)
   }

   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Get which branch was merged in which branch
   for _, branch := range branches {
      for _, mergedRequest := range mergedRequests {
         fmt.Printf("compare %s vs %s\n", branch.Name, mergedRequest.Title)
         if branch.Name == mergedRequest.SourceBranch {
            fmt.Printf("branch '%s' was merged into branch '%s' on %s\n", branch.Name, mergedRequest.TargetBranch,
               mergedRequest.UpdatedAt.Format("2006-01-02 15:04"))
         }
      }
   }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 metadata provides access to Google Compute Engine (GCE)
// metadata and API service accounts.
//
// This package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package metadata

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"google.golang.org/cloud/internal"
)

type cachedValue struct {
	k    string
	trim bool
	mu   sync.Mutex
	v    string
}

var (
	projID  = &cachedValue{k: "project/project-id", trim: true}
	projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
	instID  = &cachedValue{k: "instance/id", trim: true}
)

var metaClient = &http.Client{
	Transport: &internal.Transport{
		Base: &http.Transport{
			Dial: dialer().Dial,
			ResponseHeaderTimeout: 750 * time.Millisecond,
		},
	},
}

// go13Dialer is nil until we're using Go 1.3+.
// This is a workaround for https://github.com/golang/oauth2/issues/70, where
// net.Dialer.KeepAlive is unavailable on Go 1.2 (which App Engine as of
// Jan 2015 still runs).
//
// TODO(bradfitz,jbd,adg,dsymonds): remove this once App Engine supports Go
// 1.3+ and go-app-builder also supports 1.3+, or when Go 1.2 is no longer an
// option on App Engine.
var go13Dialer func() *net.Dialer

func dialer() *net.Dialer {
	if fn := go13Dialer; fn != nil {
		return fn()
	}
	return &net.Dialer{
		Timeout: 750 * time.Millisecond,
	}
}

// NotDefinedError is returned when requested metadata is not defined.
//
// The underlying string is the suffix after "/computeMetadata/v1/".
//
// This error is not returned if the value is defined to be the empty
// string.
type NotDefinedError string

func (suffix NotDefinedError) Error() string {
	return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
}

// Get returns a value from the metadata service.
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
//
// If the GCE_METADATA_HOST environment variable is not defined, a default of
// 169.254.169.254 will be used instead.
//
// If the requested metadata is not defined, the returned error will
// be of type NotDefinedError.
func Get(suffix string) (string, error) {
	// Using a fixed IP makes it very difficult to spoof the metadata service in
	// a container, which is an important use-case for local testing of cloud
	// deployments. To enable spoofing of the metadata service, the environment
	// variable GCE_METADATA_HOST is first inspected to decide where metadata
	// requests shall go.
	host := os.Getenv("GCE_METADATA_HOST")
	if host == "" {
		// Using 169.254.169.254 instead of "metadata" here because Go
		// binaries built with the "netgo" tag and without cgo won't
		// know the search suffix for "metadata" is
		// ".google.internal", and this IP address is documented as
		// being stable anyway.
		host = "169.254.169.254"
	}
	url := "http://" + host + "/computeMetadata/v1/" + suffix
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Metadata-Flavor", "Google")
	res, err := metaClient.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if res.StatusCode == http.StatusNotFound {
		return "", NotDefinedError(suffix)
	}
	if res.StatusCode != 200 {
		return "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
	}
	all, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(all), nil
}

func getTrimmed(suffix string) (s string, err error) {
	s, err = Get(suffix)
	s = strings.TrimSpace(s)
	return
}

func (c *cachedValue) get() (v string, err error) {
	defer c.mu.Unlock()
	c.mu.Lock()
	if c.v != "" {
		return c.v, nil
	}
	if c.trim {
		v, err = getTrimmed(c.k)
	} else {
		v, err = Get(c.k)
	}
	if err == nil {
		c.v = v
	}
	return
}

var onGCE struct {
	sync.Mutex
	set bool
	v   bool
}

// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
	defer onGCE.Unlock()
	onGCE.Lock()
	if onGCE.set {
		return onGCE.v
	}
	onGCE.set = true

	// We use the DNS name of the metadata service here instead of the IP address
	// because we expect that to fail faster in the not-on-GCE case.
	res, err := metaClient.Get("http://metadata.google.internal")
	if err != nil {
		return false
	}
	onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
	return onGCE.v
}

// ProjectID returns the current instance's project ID string.
func ProjectID() (string, error) { return projID.get() }

// NumericProjectID returns the current instance's numeric project ID.
func NumericProjectID() (string, error) { return projNum.get() }

// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
	return getTrimmed("instance/network-interfaces/0/ip")
}

// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) {
	return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
}

// Hostname returns the instance's hostname. This will probably be of
// the form "INSTANCENAME.c.PROJECT.internal" but that isn't
// guaranteed.
//
// TODO: what is this defined to be? Docs say "The host name of the
// instance."
func Hostname() (string, error) {
	return getTrimmed("network-interfaces/0/ip")
}

// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() ([]string, error) {
	var s []string
	j, err := Get("instance/tags")
	if err != nil {
		return nil, err
	}
	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
		return nil, err
	}
	return s, nil
}

// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
	return instID.get()
}

// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }

// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM.  The value of
// an attribute can be obtained with ProjectAttributeValue.
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }

func lines(suffix string) ([]string, error) {
	j, err := Get(suffix)
	if err != nil {
		return nil, err
	}
	s := strings.Split(strings.TrimSpace(j), "\n")
	for i := range s {
		s[i] = strings.TrimSpace(s[i])
	}
	return s, nil
}

// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// InstanceAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func InstanceAttributeValue(attr string) (string, error) {
	return Get("instance/attributes/" + attr)
}

// ProjectAttributeValue returns the value of the provided
// project attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// ProjectAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func ProjectAttributeValue(attr string) (string, error) {
	return Get("project/attributes/" + attr)
}

// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func Scopes(serviceAccount string) ([]string, error) {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}
<commit_msg>compute/metadata: fix Hostname, add InstanceName and Zone<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 metadata provides access to Google Compute Engine (GCE)
// metadata and API service accounts.
//
// This package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package metadata

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"google.golang.org/cloud/internal"
)

type cachedValue struct {
	k    string
	trim bool
	mu   sync.Mutex
	v    string
}

var (
	projID  = &cachedValue{k: "project/project-id", trim: true}
	projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
	instID  = &cachedValue{k: "instance/id", trim: true}
)

var metaClient = &http.Client{
	Transport: &internal.Transport{
		Base: &http.Transport{
			Dial: dialer().Dial,
			ResponseHeaderTimeout: 750 * time.Millisecond,
		},
	},
}

// go13Dialer is nil until we're using Go 1.3+.
// This is a workaround for https://github.com/golang/oauth2/issues/70, where
// net.Dialer.KeepAlive is unavailable on Go 1.2 (which App Engine as of
// Jan 2015 still runs).
//
// TODO(bradfitz,jbd,adg,dsymonds): remove this once App Engine supports Go
// 1.3+ and go-app-builder also supports 1.3+, or when Go 1.2 is no longer an
// option on App Engine.
var go13Dialer func() *net.Dialer

func dialer() *net.Dialer {
	if fn := go13Dialer; fn != nil {
		return fn()
	}
	return &net.Dialer{
		Timeout: 750 * time.Millisecond,
	}
}

// NotDefinedError is returned when requested metadata is not defined.
//
// The underlying string is the suffix after "/computeMetadata/v1/".
//
// This error is not returned if the value is defined to be the empty
// string.
type NotDefinedError string

func (suffix NotDefinedError) Error() string {
	return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
}

// Get returns a value from the metadata service.
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
//
// If the GCE_METADATA_HOST environment variable is not defined, a default of
// 169.254.169.254 will be used instead.
//
// If the requested metadata is not defined, the returned error will
// be of type NotDefinedError.
func Get(suffix string) (string, error) {
	// Using a fixed IP makes it very difficult to spoof the metadata service in
	// a container, which is an important use-case for local testing of cloud
	// deployments. To enable spoofing of the metadata service, the environment
	// variable GCE_METADATA_HOST is first inspected to decide where metadata
	// requests shall go.
	host := os.Getenv("GCE_METADATA_HOST")
	if host == "" {
		// Using 169.254.169.254 instead of "metadata" here because Go
		// binaries built with the "netgo" tag and without cgo won't
		// know the search suffix for "metadata" is
		// ".google.internal", and this IP address is documented as
		// being stable anyway.
		host = "169.254.169.254"
	}
	url := "http://" + host + "/computeMetadata/v1/" + suffix
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Metadata-Flavor", "Google")
	res, err := metaClient.Do(req)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if res.StatusCode == http.StatusNotFound {
		return "", NotDefinedError(suffix)
	}
	if res.StatusCode != 200 {
		return "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
	}
	all, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	return string(all), nil
}

func getTrimmed(suffix string) (s string, err error) {
	s, err = Get(suffix)
	s = strings.TrimSpace(s)
	return
}

func (c *cachedValue) get() (v string, err error) {
	defer c.mu.Unlock()
	c.mu.Lock()
	if c.v != "" {
		return c.v, nil
	}
	if c.trim {
		v, err = getTrimmed(c.k)
	} else {
		v, err = Get(c.k)
	}
	if err == nil {
		c.v = v
	}
	return
}

var onGCE struct {
	sync.Mutex
	set bool
	v   bool
}

// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
	defer onGCE.Unlock()
	onGCE.Lock()
	if onGCE.set {
		return onGCE.v
	}
	onGCE.set = true

	// We use the DNS name of the metadata service here instead of the IP address
	// because we expect that to fail faster in the not-on-GCE case.
	res, err := metaClient.Get("http://metadata.google.internal")
	if err != nil {
		return false
	}
	onGCE.v = res.Header.Get("Metadata-Flavor") == "Google"
	return onGCE.v
}

// ProjectID returns the current instance's project ID string.
func ProjectID() (string, error) { return projID.get() }

// NumericProjectID returns the current instance's numeric project ID.
func NumericProjectID() (string, error) { return projNum.get() }

// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
	return getTrimmed("instance/network-interfaces/0/ip")
}

// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) {
	return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
}

// Hostname returns the instance's hostname. This will be of the form
// "<instanceID>.c.<projID>.internal".
func Hostname() (string, error) {
	return getTrimmed("instance/hostname")
}

// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() ([]string, error) {
	var s []string
	j, err := Get("instance/tags")
	if err != nil {
		return nil, err
	}
	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
		return nil, err
	}
	return s, nil
}

// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
	return instID.get()
}

// InstanceName returns the current VM's instance ID string.
func InstanceName() (string, error) {
	host, err := Hostname()
	if err != nil {
		return "", err
	}
	return strings.Split(host, ".")[0], nil
}

// Zone returns the current VM's zone, such as "us-central1-b".
func Zone() (string, error) {
	zone, err := getTrimmed("instance/zone")
	// zone is of the form "projects/<projNum>/zones/<zoneName>".
	if err != nil {
		return "", err
	}
	return zone[strings.LastIndex(zone, "/")+1:], nil
}

// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }

// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM.  The value of
// an attribute can be obtained with ProjectAttributeValue.
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }

func lines(suffix string) ([]string, error) {
	j, err := Get(suffix)
	if err != nil {
		return nil, err
	}
	s := strings.Split(strings.TrimSpace(j), "\n")
	for i := range s {
		s[i] = strings.TrimSpace(s[i])
	}
	return s, nil
}

// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// InstanceAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func InstanceAttributeValue(attr string) (string, error) {
	return Get("instance/attributes/" + attr)
}

// ProjectAttributeValue returns the value of the provided
// project attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// ProjectAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func ProjectAttributeValue(attr string) (string, error) {
	return Get("project/attributes/" + attr)
}

// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func Scopes(serviceAccount string) ([]string, error) {
	if serviceAccount == "" {
		serviceAccount = "default"
	}
	return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}
<|endoftext|>


<commit_before>package libcmdline

import (
	"regexp"
	"strings"
	"text/tabwriter"
	"text/template"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libkb"
)

type Command interface {
	libkb.Command
	ParseArgv(*cli.Context) error // A command-specific parse-args
	Run() error                   // Run in client mode
}

type ForkCmd int

const (
	NormalFork ForkCmd = iota
	NoFork
	ForceFork
)

type CommandLine struct {
	app          *cli.App
	ctx          *cli.Context
	cmd          Command
	name         string  // the name of the chosen command
	service      bool    // The server is a special command
	fork         ForkCmd // If the command is to stop (then don't start the server)
	noStandalone bool    // On if this command can't run in standalone mode
	defaultCmd   string
}

func (p CommandLine) IsService() bool       { return p.service }
func (p *CommandLine) SetService()          { p.service = true }
func (p CommandLine) GetForkCmd() ForkCmd   { return p.fork }
func (p *CommandLine) SetForkCmd(v ForkCmd) { p.fork = v }
func (p *CommandLine) SetNoStandalone()     { p.noStandalone = true }
func (p CommandLine) IsNoStandalone() bool  { return p.noStandalone }

func (p CommandLine) GetSplitLogOutput() (bool, bool) {
	return p.GetBool("split-log-output", true)
}
func (p CommandLine) GetLogFile() string {
	return p.GetGString("log-file")
}
func (p CommandLine) GetNoAutoFork() (bool, bool) {
	return p.GetBool("no-auto-fork", true)
}
func (p CommandLine) GetAutoFork() (bool, bool) {
	return p.GetBool("auto-fork", true)
}
func (p CommandLine) GetHome() string {
	return p.GetGString("home")
}
func (p CommandLine) GetServerURI() string {
	return p.GetGString("server")
}
func (p CommandLine) GetConfigFilename() string {
	return p.GetGString("config-file")
}
func (p CommandLine) GetSessionFilename() string {
	return p.GetGString("session-file")
}
func (p CommandLine) GetDbFilename() string {
	return p.GetGString("db")
}
func (p CommandLine) GetDebug() (bool, bool) {
	return p.GetBool("debug", true)
}
func (p CommandLine) GetPGPFingerprint() *libkb.PGPFingerprint {
	return libkb.PGPFingerprintFromHexNoError(p.GetGString("fingerprint"))
}
func (p CommandLine) GetProxy() string {
	return p.GetGString("proxy")
}
func (p CommandLine) GetUsername() libkb.NormalizedUsername {
	return libkb.NewNormalizedUsername(p.GetGString("username"))
}
func (p CommandLine) GetLogFormat() string {
	return p.GetGString("log-format")
}
func (p CommandLine) GetGpgHome() string {
	return p.GetGString("gpg-home")
}
func (p CommandLine) GetAPIDump() (bool, bool) {
	return p.GetBool("api-dump-unsafe", true)
}
func (p CommandLine) GetRunMode() (libkb.RunMode, error) {
	return libkb.StringToRunMode(p.GetGString("run-mode"))
}
func (p CommandLine) GetPinentry() string {
	return p.GetGString("pinentry")
}
func (p CommandLine) GetGString(s string) string {
	return p.ctx.GlobalString(s)
}
func (p CommandLine) GetGInt(s string) int {
	return p.ctx.GlobalInt(s)
}
func (p CommandLine) GetGpg() string {
	return p.GetGString("gpg")
}
func (p CommandLine) GetSecretKeyringTemplate() string {
	return p.GetGString("secret-keyring")
}
func (p CommandLine) GetSocketFile() string {
	return p.GetGString("socket-file")
}
func (p CommandLine) GetPidFile() string {
	return p.GetGString("pid-file")
}
func (p CommandLine) GetGpgOptions() []string {
	var ret []string
	s := p.GetGString("gpg-options")
	if len(s) > 0 {
		ret = regexp.MustCompile(`\s+`).Split(s, -1)
	}
	return ret
}

func (p CommandLine) GetMerkleKIDs() []string {
	s := p.GetGString("merkle-kids")
	if len(s) != 0 {
		return strings.Split(s, ":")
	}
	return nil
}
func (p CommandLine) GetUserCacheSize() (int, bool) {
	ret := p.GetGInt("user-cache-size")
	if ret != 0 {
		return ret, true
	}
	return 0, false
}
func (p CommandLine) GetProofCacheSize() (int, bool) {
	ret := p.GetGInt("proof-cache-size")
	if ret != 0 {
		return ret, true
	}
	return 0, false
}
func (p CommandLine) GetDaemonPort() (ret int, set bool) {
	if ret = p.GetGInt("daemon-port"); ret != 0 {
		set = true
	}
	return
}

func (p CommandLine) GetStandalone() (bool, bool) {
	return p.GetBool("standalone", true)
}

func (p CommandLine) GetLocalRPCDebug() string {
	return p.GetGString("local-rpc-debug-unsafe")
}

func (p CommandLine) GetTimers() string {
	return p.GetGString("timers")
}

func (p CommandLine) GetBool(s string, glbl bool) (bool, bool) {
	var v bool
	if glbl {
		v = p.ctx.GlobalBool(s)
	} else {
		v = p.ctx.Bool(s)
	}
	return v, v
}

type CmdBaseHelp struct {
	ctx *cli.Context
}

func (c *CmdBaseHelp) GetUsage() libkb.Usage {
	return libkb.Usage{}
}
func (c *CmdBaseHelp) ParseArgv(*cli.Context) error { return nil }

type CmdGeneralHelp struct {
	CmdBaseHelp
}

func (c *CmdBaseHelp) RunClient() error { return c.Run() }

// This is a hack to work around keybase/cli destroying the HelpPrinter
// object.
func (c *CmdBaseHelp) MakeHelpPrinter() {
	if cli.HelpPrinter != nil {
		return
	}
	funcMap := template.FuncMap{
		"join": strings.Join,
	}

	cli.HelpPrinter = func(templ string, data interface{}) {
		w := tabwriter.NewWriter(c.ctx.App.Writer, 0, 8, 1, '\t', 0)
		t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
		err := t.Execute(w, data)
		if err != nil {
			panic(err)
		}
		w.Flush()
	}
}

func (c *CmdBaseHelp) Run() error {
	c.MakeHelpPrinter()
	cli.ShowAppHelp(c.ctx)
	return nil
}

type CmdSpecificHelp struct {
	CmdBaseHelp
	name string
}

func (c CmdSpecificHelp) Run() error {
	cli.ShowCommandHelp(c.ctx, c.name)
	return nil
}

func NewCommandLine(addHelp bool, extraFlags []cli.Flag) *CommandLine {
	app := cli.NewApp()
	ret := &CommandLine{app: app, fork: NormalFork}
	ret.PopulateApp(addHelp, extraFlags)
	return ret
}

func (p *CommandLine) PopulateApp(addHelp bool, extraFlags []cli.Flag) {
	app := p.app
	app.Name = "keybase"
	app.Version = libkb.Version
	app.Usage = "Keybase command line client"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "home, H",
			Usage: "specify an (alternate) home directory",
		},
		cli.StringFlag{
			Name:  "server, s",
			Usage: "specify server API",
		},
		cli.StringFlag{
			Name:  "config-file, c",
			Usage: "specify an (alternate) master config file",
		},
		cli.StringFlag{
			Name:  "session-file",
			Usage: "specify an alternate session data file",
		},
		cli.StringFlag{
			Name:  "db",
			Usage: "specify an alternate local DB location",
		},
		cli.StringFlag{
			Name:  "api-uri-path-prefix",
			Usage: "specify an alternate API URI path prefix",
		},
		cli.StringFlag{
			Name:  "username, u",
			Usage: "specify Keybase username of the current user",
		},
		cli.StringFlag{
			Name:  "pinentry",
			Usage: "specify a path to find a pinentry program",
		},
		cli.StringFlag{
			Name:  "secret-keyring",
			Usage: "location of the Keybase secret-keyring (P3SKB-encoded)",
		},
		cli.StringFlag{
			Name:  "socket-file",
			Usage: "location of the keybased socket-file",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Usage: "location of the keybased pid-file (to ensure only one running daemon)",
		},
		cli.StringFlag{
			Name: "proxy",
			Usage: "specify an HTTP(s) proxy to ship all Web " +
				"requests over",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debugging mode",
		},
		cli.StringFlag{
			Name:  "run-mode",
			Usage: "run mode (devel, staging, prod)", // These are defined in libkb/constants.go
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "log format (default, plain, file, fancy)",
		},
		cli.StringFlag{
			Name:  "pgpdir, gpgdir",
			Usage: "specify a PGP directory (default is ~/.gnupg)",
		},
		cli.BoolFlag{
			Name:  "api-dump-unsafe",
			Usage: "dump API call internals (may leak secrets)",
		},
		cli.StringFlag{
			Name:  "merkle-key-fingerprints",
			Usage: "set of admissable Merkle Tree fingerprints (colon-separated)",
		},
		cli.IntFlag{
			Name:  "user-cache-size",
			Usage: "number of User entries to cache",
		},
		cli.IntFlag{
			Name:  "proof-cache-size",
			Usage: "number of proof entries to cache",
		},
		cli.StringFlag{
			Name:  "gpg",
			Usage: "path to GPG client (optional for exporting keys)",
		},
		cli.StringFlag{
			Name:  "gpg-options",
			Usage: "options to use when calling GPG",
		},
		cli.IntFlag{
			Name:  "daemon-port",
			Usage: "specify a daemon port on 127.0.0.1",
		},
		cli.BoolFlag{
			Name:  "standalone",
			Usage: "use the client without any daemon support",
		},
		cli.StringFlag{
			Name:  "local-rpc-debug-unsafe",
			Usage: "use to debug local RPC (may leak secrets)",
		},
		cli.StringFlag{
			Name:  "log-file",
			Usage: "specify a log file for the keybase service",
		},
		cli.BoolFlag{
			Name:  "split-log-output",
			Usage: "output service log messages to current terminal",
		},
	}
	if extraFlags != nil {
		app.Flags = append(app.Flags, extraFlags...)
	}

	// Finally, add help if we asked for it
	if addHelp {
		app.Action = func(c *cli.Context) {
			p.cmd = &CmdGeneralHelp{CmdBaseHelp{c}}
			p.ctx = c
			p.name = "help"
		}
	}
	app.Commands = []cli.Command{}
}

func filter(cmds []cli.Command, fn func(cli.Command) bool) []cli.Command {
	var filter []cli.Command
	for _, cmd := range cmds {
		if fn(cmd) {
			filter = append(filter, cmd)
		}
	}
	return filter
}

func (p *CommandLine) AddCommands(cmds []cli.Command) {
	cmds = filter(cmds, func(c cli.Command) bool {
		return c.Name != ""
	})
	p.app.Commands = append(p.app.Commands, cmds...)
}

func (p *CommandLine) SetDefaultCommand(name string, cmd Command) {
	p.defaultCmd = name
	p.app.Action = func(c *cli.Context) {
		p.cmd = cmd
		p.ctx = c
		p.name = name
	}
}

// Called back from inside our subcommands, when they're picked...
func (p *CommandLine) ChooseCommand(cmd Command, name string, ctx *cli.Context) {
	p.cmd = cmd
	p.name = name
	p.ctx = ctx
}

func (p *CommandLine) Parse(args []string) (cmd Command, err error) {
	// This is suboptimal, but the default help action when there are
	// no args crashes.
	// (cli sets HelpPrinter to nil when p.app.Run(...) returns.)
	if len(args) == 1 && p.defaultCmd == "help" {
		args = append(args, p.defaultCmd)
	}

	// Actually pick a command
	err = p.app.Run(args)

	// Should not be populated
	cmd = p.cmd

	if err != nil || cmd == nil {
		return
	}

	// cli.HelpPrinter is nil here...anything that needs it will panic.

	// If we failed to parse arguments properly, switch to the help command
	if err = p.cmd.ParseArgv(p.ctx); err != nil {
		libkb.G.Log.Errorf("In '%s': %s", p.name, err)
		cmd = &CmdSpecificHelp{CmdBaseHelp{p.ctx}, p.name}
	} else if _, err = p.GetRunMode(); err != nil {
		cmd = &CmdSpecificHelp{CmdBaseHelp{p.ctx}, p.name}
	}

	return
}
<commit_msg>address gabriel's comment<commit_after>package libcmdline

import (
	"regexp"
	"strings"
	"text/tabwriter"
	"text/template"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libkb"
)

type Command interface {
	libkb.Command
	ParseArgv(*cli.Context) error // A command-specific parse-args
	Run() error                   // Run in client mode
}

type ForkCmd int

const (
	NormalFork ForkCmd = iota
	NoFork
	ForceFork
)

type CommandLine struct {
	app          *cli.App
	ctx          *cli.Context
	cmd          Command
	name         string  // the name of the chosen command
	service      bool    // The server is a special command
	fork         ForkCmd // If the command is to stop (then don't start the server)
	noStandalone bool    // On if this command can't run in standalone mode
	defaultCmd   string
}

func (p CommandLine) IsService() bool       { return p.service }
func (p *CommandLine) SetService()          { p.service = true }
func (p CommandLine) GetForkCmd() ForkCmd   { return p.fork }
func (p *CommandLine) SetForkCmd(v ForkCmd) { p.fork = v }
func (p *CommandLine) SetNoStandalone()     { p.noStandalone = true }
func (p CommandLine) IsNoStandalone() bool  { return p.noStandalone }

func (p CommandLine) GetSplitLogOutput() (bool, bool) {
	return p.GetBool("split-log-output", true)
}
func (p CommandLine) GetLogFile() string {
	return p.GetGString("log-file")
}
func (p CommandLine) GetNoAutoFork() (bool, bool) {
	return p.GetBool("no-auto-fork", true)
}
func (p CommandLine) GetAutoFork() (bool, bool) {
	return p.GetBool("auto-fork", true)
}
func (p CommandLine) GetHome() string {
	return p.GetGString("home")
}
func (p CommandLine) GetServerURI() string {
	return p.GetGString("server")
}
func (p CommandLine) GetConfigFilename() string {
	return p.GetGString("config-file")
}
func (p CommandLine) GetSessionFilename() string {
	return p.GetGString("session-file")
}
func (p CommandLine) GetDbFilename() string {
	return p.GetGString("db")
}
func (p CommandLine) GetDebug() (bool, bool) {
	return p.GetBool("debug", true)
}
func (p CommandLine) GetPGPFingerprint() *libkb.PGPFingerprint {
	return libkb.PGPFingerprintFromHexNoError(p.GetGString("fingerprint"))
}
func (p CommandLine) GetProxy() string {
	return p.GetGString("proxy")
}
func (p CommandLine) GetUsername() libkb.NormalizedUsername {
	return libkb.NewNormalizedUsername(p.GetGString("username"))
}
func (p CommandLine) GetLogFormat() string {
	return p.GetGString("log-format")
}
func (p CommandLine) GetGpgHome() string {
	return p.GetGString("gpg-home")
}
func (p CommandLine) GetAPIDump() (bool, bool) {
	return p.GetBool("api-dump-unsafe", true)
}
func (p CommandLine) GetRunMode() (libkb.RunMode, error) {
	return libkb.StringToRunMode(p.GetGString("run-mode"))
}
func (p CommandLine) GetPinentry() string {
	return p.GetGString("pinentry")
}
func (p CommandLine) GetGString(s string) string {
	return p.ctx.GlobalString(s)
}
func (p CommandLine) GetGInt(s string) int {
	return p.ctx.GlobalInt(s)
}
func (p CommandLine) GetGpg() string {
	return p.GetGString("gpg")
}
func (p CommandLine) GetSecretKeyringTemplate() string {
	return p.GetGString("secret-keyring")
}
func (p CommandLine) GetSocketFile() string {
	return p.GetGString("socket-file")
}
func (p CommandLine) GetPidFile() string {
	return p.GetGString("pid-file")
}
func (p CommandLine) GetGpgOptions() []string {
	var ret []string
	s := p.GetGString("gpg-options")
	if len(s) > 0 {
		ret = regexp.MustCompile(`\s+`).Split(s, -1)
	}
	return ret
}

func (p CommandLine) GetMerkleKIDs() []string {
	s := p.GetGString("merkle-kids")
	if len(s) != 0 {
		return strings.Split(s, ":")
	}
	return nil
}
func (p CommandLine) GetUserCacheSize() (int, bool) {
	ret := p.GetGInt("user-cache-size")
	if ret != 0 {
		return ret, true
	}
	return 0, false
}
func (p CommandLine) GetProofCacheSize() (int, bool) {
	ret := p.GetGInt("proof-cache-size")
	if ret != 0 {
		return ret, true
	}
	return 0, false
}
func (p CommandLine) GetDaemonPort() (ret int, set bool) {
	if ret = p.GetGInt("daemon-port"); ret != 0 {
		set = true
	}
	return
}

func (p CommandLine) GetStandalone() (bool, bool) {
	return p.GetBool("standalone", true)
}

func (p CommandLine) GetLocalRPCDebug() string {
	return p.GetGString("local-rpc-debug-unsafe")
}

func (p CommandLine) GetTimers() string {
	return p.GetGString("timers")
}

func (p CommandLine) GetBool(s string, glbl bool) (bool, bool) {
	var v bool
	if glbl {
		v = p.ctx.GlobalBool(s)
	} else {
		v = p.ctx.Bool(s)
	}
	return v, v
}

type CmdBaseHelp struct {
	ctx *cli.Context
}

func (c *CmdBaseHelp) GetUsage() libkb.Usage {
	return libkb.Usage{}
}
func (c *CmdBaseHelp) ParseArgv(*cli.Context) error { return nil }

type CmdGeneralHelp struct {
	CmdBaseHelp
}

func (c *CmdBaseHelp) RunClient() error { return c.Run() }

// This is a hack to work around keybase/cli destroying the HelpPrinter
// object.
func (c *CmdBaseHelp) MakeHelpPrinter() {
	if cli.HelpPrinter != nil {
		return
	}
	funcMap := template.FuncMap{
		"join": strings.Join,
	}

	cli.HelpPrinter = func(templ string, data interface{}) {
		w := tabwriter.NewWriter(c.ctx.App.Writer, 0, 8, 1, '\t', 0)
		t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
		err := t.Execute(w, data)
		if err != nil {
			panic(err)
		}
		w.Flush()
	}
}

func (c *CmdBaseHelp) Run() error {
	c.MakeHelpPrinter()
	cli.ShowAppHelp(c.ctx)
	return nil
}

type CmdSpecificHelp struct {
	CmdBaseHelp
	name string
}

func (c CmdSpecificHelp) Run() error {
	cli.ShowCommandHelp(c.ctx, c.name)
	return nil
}

func NewCommandLine(addHelp bool, extraFlags []cli.Flag) *CommandLine {
	app := cli.NewApp()
	ret := &CommandLine{app: app, fork: NormalFork}
	ret.PopulateApp(addHelp, extraFlags)
	return ret
}

func (p *CommandLine) PopulateApp(addHelp bool, extraFlags []cli.Flag) {
	app := p.app
	app.Name = "keybase"
	app.Version = libkb.Version
	app.Usage = "Keybase command line client"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "home, H",
			Usage: "specify an (alternate) home directory",
		},
		cli.StringFlag{
			Name:  "server, s",
			Usage: "specify server API",
		},
		cli.StringFlag{
			Name:  "config-file, c",
			Usage: "specify an (alternate) master config file",
		},
		cli.StringFlag{
			Name:  "session-file",
			Usage: "specify an alternate session data file",
		},
		cli.StringFlag{
			Name:  "db",
			Usage: "specify an alternate local DB location",
		},
		cli.StringFlag{
			Name:  "api-uri-path-prefix",
			Usage: "specify an alternate API URI path prefix",
		},
		cli.StringFlag{
			Name:  "username, u",
			Usage: "specify Keybase username of the current user",
		},
		cli.StringFlag{
			Name:  "pinentry",
			Usage: "specify a path to find a pinentry program",
		},
		cli.StringFlag{
			Name:  "secret-keyring",
			Usage: "location of the Keybase secret-keyring (P3SKB-encoded)",
		},
		cli.StringFlag{
			Name:  "socket-file",
			Usage: "location of the keybased socket-file",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Usage: "location of the keybased pid-file (to ensure only one running daemon)",
		},
		cli.StringFlag{
			Name: "proxy",
			Usage: "specify an HTTP(s) proxy to ship all Web " +
				"requests over",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debugging mode",
		},
		cli.StringFlag{
			Name:  "run-mode",
			Usage: "run mode (devel, staging, prod)", // These are defined in libkb/constants.go
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "log format (default, plain, file, fancy)",
		},
		cli.StringFlag{
			Name:  "pgpdir, gpgdir",
			Usage: "specify a PGP directory (default is ~/.gnupg)",
		},
		cli.BoolFlag{
			Name:  "api-dump-unsafe",
			Usage: "dump API call internals (may leak secrets)",
		},
		cli.StringFlag{
			Name:  "merkle-key-fingerprints",
			Usage: "set of admissable Merkle Tree fingerprints (colon-separated)",
		},
		cli.IntFlag{
			Name:  "user-cache-size",
			Usage: "number of User entries to cache",
		},
		cli.IntFlag{
			Name:  "proof-cache-size",
			Usage: "number of proof entries to cache",
		},
		cli.StringFlag{
			Name:  "gpg",
			Usage: "path to GPG client (optional for exporting keys)",
		},
		cli.StringFlag{
			Name:  "gpg-options",
			Usage: "options to use when calling GPG",
		},
		cli.IntFlag{
			Name:  "daemon-port",
			Usage: "specify a daemon port on 127.0.0.1",
		},
		cli.BoolFlag{
			Name:  "standalone",
			Usage: "use the client without any daemon support",
		},
		cli.StringFlag{
			Name:  "local-rpc-debug-unsafe",
			Usage: "use to debug local RPC (may leak secrets)",
		},
		cli.StringFlag{
			Name:  "log-file",
			Usage: "specify a log file for the keybase service",
		},
		cli.BoolFlag{
			Name:  "split-log-output",
			Usage: "output service log messages to current terminal",
		},
	}
	if extraFlags != nil {
		app.Flags = append(app.Flags, extraFlags...)
	}

	// Finally, add help if we asked for it
	if addHelp {
		app.Action = func(c *cli.Context) {
			p.cmd = &CmdGeneralHelp{CmdBaseHelp{c}}
			p.ctx = c
			p.name = "help"
		}
	}
	app.Commands = []cli.Command{}
}

func filter(cmds []cli.Command, fn func(cli.Command) bool) []cli.Command {
	var filter []cli.Command
	for _, cmd := range cmds {
		if fn(cmd) {
			filter = append(filter, cmd)
		}
	}
	return filter
}

func (p *CommandLine) AddCommands(cmds []cli.Command) {
	cmds = filter(cmds, func(c cli.Command) bool {
		return c.Name != ""
	})
	p.app.Commands = append(p.app.Commands, cmds...)
}

func (p *CommandLine) SetDefaultCommand(name string, cmd Command) {
	p.defaultCmd = name
	p.app.Action = func(c *cli.Context) {
		p.cmd = cmd
		p.ctx = c
		p.name = name
	}
}

// Called back from inside our subcommands, when they're picked...
func (p *CommandLine) ChooseCommand(cmd Command, name string, ctx *cli.Context) {
	p.cmd = cmd
	p.name = name
	p.ctx = ctx
}

func (p *CommandLine) Parse(args []string) (cmd Command, err error) {
	// This is suboptimal, but the default help action when there are
	// no args crashes.
	// (cli sets HelpPrinter to nil when p.app.Run(...) returns.)
	if len(args) == 1 && p.defaultCmd == "help" {
		args = append(args, p.defaultCmd)
	}

	// Actually pick a command
	err = p.app.Run(args)

	// Should not be populated
	cmd = p.cmd

	if err != nil || cmd == nil {
		return
	}

	// cli.HelpPrinter is nil here...anything that needs it will panic.

	// If we failed to parse arguments properly, switch to the help command
	if err = p.cmd.ParseArgv(p.ctx); err == nil {
		_, err = p.GetRunMode()
	}
	if err != nil {
		cmd = &CmdSpecificHelp{CmdBaseHelp{p.ctx}, p.name}
	}

	return
}
<|endoftext|>