<commit_before>package render

import (
	"image"
	"image/color"
	"math"
	"sort"

	"bitbucket.org/oakmoundstudio/oak/physics"
	"github.com/200sc/go-compgeo/dcel"
)

type Polyhedron struct {
	Sprite
	dcel.DCEL
	Center physics.Vector
}

func NewCuboid(x, y, z, w, h, d float64) *Polyhedron {
	px := x
	py := y
	dc := dcel.DCEL{}
	// Is there a smart way to loop through this?
	// verts
	x = w
	y = h
	z = -d
	dc.Vertices = make([]*dcel.Point, 8)
	dc.HalfEdges = make([]*dcel.Edge, 24)
	dc.OutEdges = make([]*dcel.Edge, 8)
	for i := 0; i < 8; i++ {
		// Set coordinates of this vertex
		if x == 0 {
			x = w
		} else {
			x = 0
		}
		if i%2 == 0 {
			if y == 0 {
				y = h
			} else {
				y = 0
			}
		}
		if i%4 == 0 {
			z += d
		}

		dc.Vertices[i] = dcel.NewPoint(x, y, z)
	}
	corners := []int{0, 3, 5, 6}
	// These edges, except for the ones
	// at a corner's index, are those a
	// corner's edges' twins start from
	addEdges := []int{7, 4, 2, 1}
	edge := 0
	for k, i := range corners {
		addEdgesK := []int{}
		for k2, v := range addEdges {
			if k2 != k {
				addEdgesK = append(addEdgesK, v)
			}
		}
		m := 0
		for j := edge; j < edge+6; j += 2 {
			dc.HalfEdges[j] = &dcel.Edge{
				Origin: dc.Vertices[i],
			}
			dc.OutEdges[i] = dc.HalfEdges[j]
			dc.HalfEdges[j+1] = &dcel.Edge{
				Origin: dc.Vertices[addEdgesK[m]],
			}
			dc.OutEdges[addEdgesK[m]] = dc.HalfEdges[j+1]
			m++
		}
		// 6 edges per corner
		edge += 6
	}
	// Set Twins
	for i := range dc.HalfEdges {
		dc.HalfEdges[i].Twin = dc.HalfEdges[dcel.EdgeTwin(i)]
	}
	// We're ignoring prev, next, face for now
	// because this is way harder than it should be
	return NewPolyhedronFromDCEL(&dc, px, py)
}

func NewPolyhedronFromDCEL(dc *dcel.DCEL, x, y float64) *Polyhedron {
	p := new(Polyhedron)
	p.SetPos(x, y)
	p.DCEL = *dc
	p.Update()
	p.Center = physics.NewVector(p.X+(1+p.MaxX())/2, p.Y+(1+p.MaxY())/2)
	return p
}

func (p *Polyhedron) Update() {

	p.clearNegativePoints()

	// Reset p's rgba
	maxX := p.MaxX() + 1
	maxY := p.MaxY() + 1
	rect := image.Rect(0, 0, int(maxX), int(maxY))
	rgba := image.NewRGBA(rect)
	// We ignore Z -- Z is used for rotations
	// There isn't an alternative to this, aside from
	// recoloring things to account for different z values,
	// without having a camera system, which is a lot of work

	// Try to maintain center
	if p.Center.X != 0 || p.Center.Y != 0 {
		cx := p.X + maxX/2
		cy := p.Y + maxY/2
		p.X -= (cx - p.Center.X)
		p.Y -= (cy - p.Center.Y)
	}

	red := color.RGBA{255, 0, 0, 255}
	gray := color.RGBA{160, 160, 160, 255}
	blue := color.RGBA{0, 0, 255, 255}

	// Eventually:
	// For all Faces, Edges, and Vertices, sort by z value
	// and draw them high-to-low
	zOrder := make([]interface{}, len(p.HalfEdges)/2+len(p.Faces)-1+len(p.Vertices))

	// Step 1: draw all edges
	// Given the edge twin mandate, we can just use
	// every other halfEdge.
	//fmt.Println(p.DCEL)
	for i := 0; i < len(p.HalfEdges); i += 2 {
		points, err := p.FullEdge(i)
		if err != nil {
			continue
		}
		// draw a line from points[0] to points[1]
		//fmt.Println("Drawing from ", points[0][0], points[0][1], "to",
		//points[1][0], points[1][1])
		zOrder = append(zOrder, points)
		// drawLineOnto(rgba, int(points[0][0]), int(points[0][1]),
		// 	int(points[1][0]), int(points[1][1]), gray)
	}

	// Step 2: draw all vertices
	for _, v := range p.Vertices {
		zOrder = append(zOrder, v)
		//rgba.Set(int(v[0]), int(v[1]), red)
	}

	for i := 1; i < len(p.Faces); i++ {
		f := p.Faces[i]
		verts := f.Vertices()
		max_z := math.MaxFloat64 * -1
		phys_verts := make([]physics.Vector, len(verts))
		for i, v := range verts {
			phys_verts[i] = physics.NewVector(v[0], v[1])
			if v[2] > max_z {
				max_z = v[2]
			}
		}
		poly, err := NewPolygon(phys_verts)
		if err != nil {
			continue
		}
		fpoly := facePolygon{
			poly,
			max_z,
		}
		zOrder = append(zOrder, fpoly)
	}

	// This is very hacky
	sort.Slice(zOrder, func(i, j int) bool {
		z1 := 0.0
		z2 := 0.0
		switch v := zOrder[i].(type) {
		case facePolygon:
			z1 = v.z
		case dcel.Point:
			z1 = v[2] + .002
		case [2]*dcel.Point:
			z1 = math.Max(v[0][2], v[1][2]) + .001
		}
		switch v := zOrder[j].(type) {
		case facePolygon:
			z2 = v.z
		case dcel.Point:
			z2 = v[2] + .002
		case [2]*dcel.Point:
			z2 = math.Max(v[0][2], v[1][2]) + .001
		}
		return z1 < z2
	})

	for _, item := range zOrder {
		switch v := item.(type) {
		case facePolygon:
			for x := v.Rect.minX; x < v.Rect.maxX; x++ {
				for y := v.Rect.minY; y < v.Rect.maxY; y++ {
					if v.Contains(x, y) {
						rgba.Set(int(x), int(y), blue)
					}
				}
			}
		case dcel.Point:
			rgba.Set(int(v[0]), int(v[1]), red)
		case [2]*dcel.Point:
			drawLineOnto(rgba, int(v[0][0]), int(v[0][1]),
				int(v[1][0]), int(v[1][1]), gray)
		}
	}

	p.SetRGBA(rgba)
}

type facePolygon struct {
	*Polygon
	z float64
}

func (p *Polyhedron) RotZ(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v0 := v[0]*ct - v[1]*st
		v[1] = v[1]*ct + v[0]*st
		v[0] = v0
	}
	p.Update()
}

func (p *Polyhedron) RotX(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v1 := v[1]*ct - v[2]*st
		v[2] = v[2]*ct + v[1]*st
		v[1] = v1
	}
	p.Update()
}

func (p *Polyhedron) RotY(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v0 := v[0]*ct - v[2]*st
		v[2] = v[2]*ct + v[0]*st
		v[0] = v0
	}
	p.Update()
}

func (p *Polyhedron) Scale(factor float64) {
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] * factor
		p.Vertices[i][1] = v[1] * factor
		p.Vertices[i][2] = v[2] * factor
	}
	p.Update()
}

func (p *Polyhedron) clearNegativePoints() {
	// Anything with an x,y less than 0 needs to be increased,
	// this is a limitation so we stay in the bounds of a given rgba
	// rectangle on screen, so we increase everything by minX,minY
	x := p.MinX()
	y := p.MinY()
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] - x
	}
	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1] - y
	}
}

// Utilities
func (p *Polyhedron) String() string {
	return "Polyhedron"
}

func (p *Polyhedron) ShiftX(x float64) {
	p.Center.X += x
	p.Sprite.ShiftX(x)
}

func (p *Polyhedron) ShiftY(y float64) {
	p.Center.Y += y
	p.Sprite.ShiftY(y)
}
<commit_msg>Custom colors for polyhedrons<commit_after>package render

import (
	"image"
	"image/color"
	"math"
	"sort"

	"bitbucket.org/oakmoundstudio/oak/physics"
	"github.com/200sc/go-compgeo/dcel"
)

type Polyhedron struct {
	Sprite
	dcel.DCEL
	Center physics.Vector
}

func NewCuboid(x, y, z, w, h, d float64) *Polyhedron {
	px := x
	py := y
	dc := dcel.DCEL{}
	// Is there a smart way to loop through this?
	// verts
	x = w
	y = h
	z = -d
	dc.Vertices = make([]*dcel.Point, 8)
	dc.HalfEdges = make([]*dcel.Edge, 24)
	dc.OutEdges = make([]*dcel.Edge, 8)
	for i := 0; i < 8; i++ {
		// Set coordinates of this vertex
		if x == 0 {
			x = w
		} else {
			x = 0
		}
		if i%2 == 0 {
			if y == 0 {
				y = h
			} else {
				y = 0
			}
		}
		if i%4 == 0 {
			z += d
		}

		dc.Vertices[i] = dcel.NewPoint(x, y, z)
	}
	corners := []int{0, 3, 5, 6}
	// These edges, except for the ones
	// at a corner's index, are those a
	// corner's edges' twins start from
	addEdges := []int{7, 4, 2, 1}
	edge := 0
	for k, i := range corners {
		addEdgesK := []int{}
		for k2, v := range addEdges {
			if k2 != k {
				addEdgesK = append(addEdgesK, v)
			}
		}
		m := 0
		for j := edge; j < edge+6; j += 2 {
			dc.HalfEdges[j] = &dcel.Edge{
				Origin: dc.Vertices[i],
			}
			dc.OutEdges[i] = dc.HalfEdges[j]
			dc.HalfEdges[j+1] = &dcel.Edge{
				Origin: dc.Vertices[addEdgesK[m]],
			}
			dc.OutEdges[addEdgesK[m]] = dc.HalfEdges[j+1]
			m++
		}
		// 6 edges per corner
		edge += 6
	}
	// Set Twins
	for i := range dc.HalfEdges {
		dc.HalfEdges[i].Twin = dc.HalfEdges[dcel.EdgeTwin(i)]
	}
	// We're ignoring prev, next, face for now
	// because this is way harder than it should be
	return NewPolyhedronFromDCEL(&dc, px, py)
}

func NewPolyhedronFromDCEL(dc *dcel.DCEL, x, y float64) *Polyhedron {
	p := new(Polyhedron)
	p.SetPos(x, y)
	p.DCEL = *dc
	p.Update()
	p.Center = physics.NewVector(p.X+(1+p.MaxX())/2, p.Y+(1+p.MaxY())/2)
	return p
}

func (p *Polyhedron) Update() {

	p.clearNegativePoints()

	// Reset p's rgba
	maxX := p.MaxX() + 1
	maxY := p.MaxY() + 1
	rect := image.Rect(0, 0, int(maxX), int(maxY))
	rgba := image.NewRGBA(rect)
	// We ignore Z -- Z is used for rotations
	// There isn't an alternative to this, aside from
	// recoloring things to account for different z values,
	// without having a camera system, which is a lot of work

	// Try to maintain center
	if p.Center.X != 0 || p.Center.Y != 0 {
		cx := p.X + maxX/2
		cy := p.Y + maxY/2
		p.X -= (cx - p.Center.X)
		p.Y -= (cy - p.Center.Y)
	}

	red := color.RGBA{255, 0, 0, 255}

	// Eventually:
	// For all Faces, Edges, and Vertices, sort by z value
	// and draw them high-to-low
	zOrder := make([]interface{}, len(p.HalfEdges)/2+len(p.Faces)-1+len(p.Vertices))

	// Step 1: draw all edges
	// Given the edge twin mandate, we can just use
	// every other halfEdge.
	//fmt.Println(p.DCEL)
	for i := 0; i < len(p.HalfEdges); i += 2 {
		points, err := p.FullEdge(i)
		if err != nil {
			continue
		}
		// draw a line from points[0] to points[1]
		//fmt.Println("Drawing from ", points[0][0], points[0][1], "to",
		//points[1][0], points[1][1])
		if p.HalfEdges[i].Color == nil {
			p.HalfEdges[i].Color = color.RGBA{255, 0, 255, 255}
		}
		zOrder = append(zOrder, coloredEdge{points, p.HalfEdges[i].Color})
		// drawLineOnto(rgba, int(points[0][0]), int(points[0][1]),
		// 	int(points[1][0]), int(points[1][1]), gray)
	}

	// Step 2: draw all vertices
	for _, v := range p.Vertices {
		zOrder = append(zOrder, v)
		//rgba.Set(int(v[0]), int(v[1]), red)
	}

	for i := 1; i < len(p.Faces); i++ {
		f := p.Faces[i]
		if f.Color == nil {
			f.Color = color.RGBA{0, 255, 255, 255}
		}
		verts := f.Vertices()
		max_z := math.MaxFloat64 * -1
		phys_verts := make([]physics.Vector, len(verts))
		for i, v := range verts {
			phys_verts[i] = physics.NewVector(v[0], v[1])
			if v[2] > max_z {
				max_z = v[2]
			}
		}
		poly, err := NewPolygon(phys_verts)
		if err != nil {
			continue
		}
		fpoly := facePolygon{
			poly,
			max_z,
			f.Color,
		}
		zOrder = append(zOrder, fpoly)
	}

	// This is very hacky
	sort.Slice(zOrder, func(i, j int) bool {
		z1 := 0.0
		z2 := 0.0
		switch v := zOrder[i].(type) {
		case facePolygon:
			z1 = v.z
		case dcel.Point:
			z1 = v[2] + .002
		case coloredEdge:
			z1 = math.Max(v.ps[0][2], v.ps[1][2]) + .001
		}
		switch v := zOrder[j].(type) {
		case facePolygon:
			z2 = v.z
		case dcel.Point:
			z2 = v[2] + .002
		case coloredEdge:
			z2 = math.Max(v.ps[0][2], v.ps[1][2]) + .001
		}
		return z1 < z2
	})

	for _, item := range zOrder {
		switch v := item.(type) {
		case facePolygon:
			for x := v.Rect.minX; x < v.Rect.maxX; x++ {
				for y := v.Rect.minY; y < v.Rect.maxY; y++ {
					if v.Contains(x, y) {
						rgba.Set(int(x), int(y), v.c)
					}
				}
			}
		case dcel.Point:
			rgba.Set(int(v[0]), int(v[1]), red)
		case coloredEdge:
			drawLineOnto(rgba, int(v.ps[0][0]), int(v.ps[0][1]),
				int(v.ps[1][0]), int(v.ps[1][1]), v.c)
		}
	}

	p.SetRGBA(rgba)
}

type coloredEdge struct {
	ps [2]*dcel.Point
	c  color.Color
}

type facePolygon struct {
	*Polygon
	z float64
	c color.Color
}

func (p *Polyhedron) RotZ(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v0 := v[0]*ct - v[1]*st
		v[1] = v[1]*ct + v[0]*st
		v[0] = v0
	}
	p.Update()
}

func (p *Polyhedron) RotX(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v1 := v[1]*ct - v[2]*st
		v[2] = v[2]*ct + v[1]*st
		v[1] = v1
	}
	p.Update()
}

func (p *Polyhedron) RotY(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for _, v := range p.Vertices {
		v0 := v[0]*ct - v[2]*st
		v[2] = v[2]*ct + v[0]*st
		v[0] = v0
	}
	p.Update()
}

func (p *Polyhedron) Scale(factor float64) {
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] * factor
		p.Vertices[i][1] = v[1] * factor
		p.Vertices[i][2] = v[2] * factor
	}
	p.Update()
}

func (p *Polyhedron) clearNegativePoints() {
	// Anything with an x,y less than 0 needs to be increased,
	// this is a limitation so we stay in the bounds of a given rgba
	// rectangle on screen, so we increase everything by minX,minY
	x := p.MinX()
	y := p.MinY()
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] - x
	}
	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1] - y
	}
}

// Utilities
func (p *Polyhedron) String() string {
	return "Polyhedron"
}

func (p *Polyhedron) ShiftX(x float64) {
	p.Center.X += x
	p.Sprite.ShiftX(x)
}

func (p *Polyhedron) ShiftY(y float64) {
	p.Center.Y += y
	p.Sprite.ShiftY(y)
}
<|endoftext|>


<commit_before>package renderer

import (
	"bufio"
	"fmt"
	"github.com/andreaskoch/docs/indexer"
	"github.com/andreaskoch/docs/mappers"
	"github.com/andreaskoch/docs/parser"
	"github.com/andreaskoch/docs/templates"
	"os"
	"text/template"
)

func Render(repositoryPaths []string) {
	for _, repositoryPath := range repositoryPaths {
		index := indexer.GetIndex(repositoryPath)
		RenderIndex(index)
	}
}

func RenderIndex(index indexer.Index) {

	index.Walk(func(item indexer.Item) {
		renderItem(item)
	})

}

func renderItem(item indexer.Item) {

	_, err := parser.Parse(&item)
	if err != nil {
		fmt.Printf("Could not parse item \"%v\": %v\n", item.Path, err)
		return
	}

	switch item.Type {
	case indexer.DocumentItemType:
		{
			file, err := os.Create(item.RenderedPath)
			if err != nil {
				panic(err)
			}
			writer := bufio.NewWriter(file)

			defer func() {
				writer.Flush()
				file.Close()
			}()

			document := mappers.GetDocument(item)
			template := template.New(indexer.DocumentItemType)
			template.Parse(templates.DocumentTemplate)
			template.Execute(writer, document)
		}
	}
}
<commit_msg>Extracted a render method from the renderItem switch statement<commit_after>package renderer

import (
	"bufio"
	"fmt"
	"github.com/andreaskoch/docs/indexer"
	"github.com/andreaskoch/docs/mappers"
	"github.com/andreaskoch/docs/parser"
	"github.com/andreaskoch/docs/templates"
	"os"
	"text/template"
)

func Render(repositoryPaths []string) {
	for _, repositoryPath := range repositoryPaths {
		index := indexer.GetIndex(repositoryPath)
		RenderIndex(index)
	}
}

func RenderIndex(index indexer.Index) {

	index.Walk(func(item indexer.Item) {
		renderItem(item)
	})

}

func renderItem(item indexer.Item) {

	_, err := parser.Parse(&item)
	if err != nil {
		fmt.Printf("Could not parse item \"%v\": %v\n", item.Path, err)
		return
	}

	switch item.Type {
	case indexer.DocumentItemType:
		{
			document := mappers.GetDocument(item)
			render(item, templates.DocumentTemplate, document)
		}
	}
}

func render(item indexer.Item, templateText string, viewModel interface{}) {
	file, err := os.Create(item.RenderedPath)
	if err != nil {
		panic(err)
	}
	writer := bufio.NewWriter(file)

	defer func() {
		writer.Flush()
		file.Close()
	}()

	template := template.New(item.Type)
	template.Parse(templateText)
	template.Execute(writer, viewModel)
}
<|endoftext|>


<commit_before>package blob

import (
	"context"
	"log"
	"sync"
	"time"

	"github.com/pkg/errors"
)

// CancelFunc requests cancellation of a storage operation.
type CancelFunc func()

// Storage encapsulates API for connecting to blob storage.
//
// The underlying storage system must provide:
//
// * high durability, availability and bit-rot protection
// * read-after-write - blob written using PubBlob() must be immediately readable using GetBlob() and ListBlobs()
// * atomicity - it mustn't be possible to observe partial results of PubBlob() via either GetBlob() or ListBlobs()
// * timestamps that don't go back in time (small clock skew up to minutes is allowed)
// * reasonably low latency for retrievals
//
// The required semantics are provided by existing commercial cloud storage products (Google Cloud, AWS, Azure).
type Storage interface {
	// PutBlob uploads the blob with given data to the repository or replaces existing blob with the provided
	// id with given contents.
	PutBlob(ctx context.Context, blobID ID, data []byte) error

	// DeleteBlob removes the blob from storage. Future Get() operations will fail with ErrNotFound.
	DeleteBlob(ctx context.Context, blobID ID) error

	// GetBlob returns full or partial contents of a blob with given ID.
	// If length>0, the the function retrieves a range of bytes [offset,offset+length)
	// If length<0, the entire blob must be fetched.
	GetBlob(ctx context.Context, blobID ID, offset, length int64) ([]byte, error)

	// ListBlobs invokes the provided callback for each blob in the storage.
	// Iteration continues until the callback returns an error or until all matching blobs have been reported.
	ListBlobs(ctx context.Context, blobIDPrefix ID, cb func(bm Metadata) error) error

	// ConnectionInfo returns JSON-serializable data structure containing information required to
	// connect to storage.
	ConnectionInfo() ConnectionInfo

	// Close releases all resources associated with storage.
	Close(ctx context.Context) error
}

// ID is a string that represents blob identifier.
type ID string

// Metadata represents metadata about a single BLOB in a storage.
type Metadata struct {
	BlobID    ID
	Length    int64
	Timestamp time.Time
}

// ErrBlobNotFound is returned when a BLOB cannot be found in storage.
var ErrBlobNotFound = errors.New("BLOB not found")

// ListAllBlobs returns Metadata for all blobs in a given storage that have the provided name prefix.
func ListAllBlobs(ctx context.Context, st Storage, prefix ID) ([]Metadata, error) {
	var result []Metadata

	err := st.ListBlobs(ctx, prefix, func(bm Metadata) error {
		result = append(result, bm)
		return nil
	})

	return result, err
}

// IterateAllPrefixesInParallel invokes the provided callback and returns the first error returned by the callback or nil.
func IterateAllPrefixesInParallel(ctx context.Context, parallelism int, st Storage, prefixes []ID, callback func(Metadata) error) error {
	if len(prefixes) == 1 {
		return st.ListBlobs(ctx, prefixes[0], callback)
	}

	if parallelism <= 0 {
		parallelism = 1
	}

	var wg sync.WaitGroup

	semaphore := make(chan struct{}, parallelism)
	errch := make(chan error, len(prefixes))

	for _, prefix := range prefixes {
		wg.Add(1)

		prefix := prefix

		// acquire semaphore
		semaphore <- struct{}{}

		go func() {
			defer wg.Done()
			defer func() {
				<-semaphore // release semaphore
			}()

			if err := st.ListBlobs(ctx, prefix, callback); err != nil {
				errch <- err
			}
		}()
	}

	wg.Wait()
	close(errch)

	// return first error or nil
	return <-errch
}

// ListAllBlobsConsistent lists all blobs with given name prefix in the provided storage until the results are
// consistent. The results are consistent if the list result fetched twice is identical. This guarantees that while
// the first scan was in progress, no new blob was added or removed.
// maxAttempts specifies maximum number of list attempts (must be >= 2)
func ListAllBlobsConsistent(ctx context.Context, st Storage, prefix ID, maxAttempts int) ([]Metadata, error) {
	var previous []Metadata

	for i := 0; i < maxAttempts; i++ {
		result, err := ListAllBlobs(ctx, st, prefix)
		if err != nil {
			return nil, err
		}

		if i > 0 && sameBlobs(result, previous) {
			return result, nil
		}

		previous = result
	}

	return nil, errors.Errorf("unable to achieve consistent snapshot despite %v attempts", maxAttempts)
}

// sameBlobs returns true if b1 & b2 contain the same blobs (ignoring order).
func sameBlobs(b1, b2 []Metadata) bool {
	if len(b1) != len(b2) {
		log.Printf("a")

		return false
	}

	m := map[ID]Metadata{}

	for _, b := range b1 {
		m[b.BlobID] = normalizeMetadata(b)
	}

	for _, b := range b2 {
		if r := m[b.BlobID]; r != normalizeMetadata(b) {
			return false
		}
	}

	return true
}

func normalizeMetadata(m Metadata) Metadata {
	return Metadata{m.BlobID, m.Length, normalizeTimestamp(m.Timestamp)}
}

func normalizeTimestamp(t time.Time) time.Time {
	return time.Unix(0, t.UnixNano())
}
<commit_msg>Trivial/cleanup: remove unused type<commit_after>package blob

import (
	"context"
	"log"
	"sync"
	"time"

	"github.com/pkg/errors"
)

// Storage encapsulates API for connecting to blob storage.
//
// The underlying storage system must provide:
//
// * high durability, availability and bit-rot protection
// * read-after-write - blob written using PubBlob() must be immediately readable using GetBlob() and ListBlobs()
// * atomicity - it mustn't be possible to observe partial results of PubBlob() via either GetBlob() or ListBlobs()
// * timestamps that don't go back in time (small clock skew up to minutes is allowed)
// * reasonably low latency for retrievals
//
// The required semantics are provided by existing commercial cloud storage products (Google Cloud, AWS, Azure).
type Storage interface {
	// PutBlob uploads the blob with given data to the repository or replaces existing blob with the provided
	// id with given contents.
	PutBlob(ctx context.Context, blobID ID, data []byte) error

	// DeleteBlob removes the blob from storage. Future Get() operations will fail with ErrNotFound.
	DeleteBlob(ctx context.Context, blobID ID) error

	// GetBlob returns full or partial contents of a blob with given ID.
	// If length>0, the the function retrieves a range of bytes [offset,offset+length)
	// If length<0, the entire blob must be fetched.
	GetBlob(ctx context.Context, blobID ID, offset, length int64) ([]byte, error)

	// ListBlobs invokes the provided callback for each blob in the storage.
	// Iteration continues until the callback returns an error or until all matching blobs have been reported.
	ListBlobs(ctx context.Context, blobIDPrefix ID, cb func(bm Metadata) error) error

	// ConnectionInfo returns JSON-serializable data structure containing information required to
	// connect to storage.
	ConnectionInfo() ConnectionInfo

	// Close releases all resources associated with storage.
	Close(ctx context.Context) error
}

// ID is a string that represents blob identifier.
type ID string

// Metadata represents metadata about a single BLOB in a storage.
type Metadata struct {
	BlobID    ID
	Length    int64
	Timestamp time.Time
}

// ErrBlobNotFound is returned when a BLOB cannot be found in storage.
var ErrBlobNotFound = errors.New("BLOB not found")

// ListAllBlobs returns Metadata for all blobs in a given storage that have the provided name prefix.
func ListAllBlobs(ctx context.Context, st Storage, prefix ID) ([]Metadata, error) {
	var result []Metadata

	err := st.ListBlobs(ctx, prefix, func(bm Metadata) error {
		result = append(result, bm)
		return nil
	})

	return result, err
}

// IterateAllPrefixesInParallel invokes the provided callback and returns the first error returned by the callback or nil.
func IterateAllPrefixesInParallel(ctx context.Context, parallelism int, st Storage, prefixes []ID, callback func(Metadata) error) error {
	if len(prefixes) == 1 {
		return st.ListBlobs(ctx, prefixes[0], callback)
	}

	if parallelism <= 0 {
		parallelism = 1
	}

	var wg sync.WaitGroup

	semaphore := make(chan struct{}, parallelism)
	errch := make(chan error, len(prefixes))

	for _, prefix := range prefixes {
		wg.Add(1)

		prefix := prefix

		// acquire semaphore
		semaphore <- struct{}{}

		go func() {
			defer wg.Done()
			defer func() {
				<-semaphore // release semaphore
			}()

			if err := st.ListBlobs(ctx, prefix, callback); err != nil {
				errch <- err
			}
		}()
	}

	wg.Wait()
	close(errch)

	// return first error or nil
	return <-errch
}

// ListAllBlobsConsistent lists all blobs with given name prefix in the provided storage until the results are
// consistent. The results are consistent if the list result fetched twice is identical. This guarantees that while
// the first scan was in progress, no new blob was added or removed.
// maxAttempts specifies maximum number of list attempts (must be >= 2)
func ListAllBlobsConsistent(ctx context.Context, st Storage, prefix ID, maxAttempts int) ([]Metadata, error) {
	var previous []Metadata

	for i := 0; i < maxAttempts; i++ {
		result, err := ListAllBlobs(ctx, st, prefix)
		if err != nil {
			return nil, err
		}

		if i > 0 && sameBlobs(result, previous) {
			return result, nil
		}

		previous = result
	}

	return nil, errors.Errorf("unable to achieve consistent snapshot despite %v attempts", maxAttempts)
}

// sameBlobs returns true if b1 & b2 contain the same blobs (ignoring order).
func sameBlobs(b1, b2 []Metadata) bool {
	if len(b1) != len(b2) {
		log.Printf("a")

		return false
	}

	m := map[ID]Metadata{}

	for _, b := range b1 {
		m[b.BlobID] = normalizeMetadata(b)
	}

	for _, b := range b2 {
		if r := m[b.BlobID]; r != normalizeMetadata(b) {
			return false
		}
	}

	return true
}

func normalizeMetadata(m Metadata) Metadata {
	return Metadata{m.BlobID, m.Length, normalizeTimestamp(m.Timestamp)}
}

func normalizeTimestamp(t time.Time) time.Time {
	return time.Unix(0, t.UnixNano())
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 render

import (
	"net/http"
	"time"

	"github.com/webx-top/echo"
)

var (
	DefaultOptions = &Options{
		Skipper:              echo.DefaultSkipper,
		ErrorPages:           make(map[int]string),
		DefaultHTTPErrorCode: http.StatusInternalServerError,
		SetFuncMap: []echo.HandlerFunc{
			func(c echo.Context) error {
				c.SetFunc(`Lang`, c.Lang)
				c.SetFunc(`Now`, time.Now)
				c.SetFunc(`T`, c.T)
				return nil
			},
		},
	}
)

type ErrorProcessor func(ctx echo.Context, err error) (processed bool, newErr error)

type Options struct {
	Skipper              echo.Skipper
	ErrorPages           map[int]string
	ErrorProcessors      []ErrorProcessor
	DefaultHTTPErrorCode int
	SetFuncMap           []echo.HandlerFunc
}

func (opt *Options) AddFuncSetter(set ...echo.HandlerFunc) *Options {
	if opt.SetFuncMap == nil {
		opt.SetFuncMap = make([]echo.HandlerFunc, len(DefaultOptions.SetFuncMap))
		for index, setter := range DefaultOptions.SetFuncMap {
			opt.SetFuncMap[index] = setter
		}
	}
	opt.SetFuncMap = append(opt.SetFuncMap, set...)
	return opt
}

func (opt *Options) SetFuncSetter(set ...echo.HandlerFunc) *Options {
	opt.SetFuncMap = set
	return opt
}

func (opt *Options) AddErrorProcessor(h ...ErrorProcessor) *Options {
	opt.ErrorProcessors = append(opt.ErrorProcessors, h...)
	return opt
}

func (opt *Options) SetErrorProcessor(h ...ErrorProcessor) *Options {
	opt.ErrorProcessors = h
	return opt
}

// Middleware set renderer
func Middleware(d echo.Renderer) echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			c.SetRenderer(d)
			return h.Handle(c)
		})
	}
}

func Auto() echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			c.SetAuto(true)
			return h.Handle(c)
		})
	}
}

func setAndGetErrorMessage(c echo.Context, debugMessage string, prodMessage string) string {
	if c.Echo().Debug() {
		c.Data().SetInfo(debugMessage, 0)
		return debugMessage
	}
	c.Data().SetInfo(prodMessage, 0)
	return prodMessage
}

func HTTPErrorHandler(opt *Options) echo.HTTPErrorHandler {
	if opt == nil {
		opt = DefaultOptions
	}
	if opt.ErrorPages == nil {
		opt.ErrorPages = DefaultOptions.ErrorPages
	}
	if opt.DefaultHTTPErrorCode < 1 {
		opt.DefaultHTTPErrorCode = DefaultOptions.DefaultHTTPErrorCode
	}
	if opt.SetFuncMap == nil {
		opt.SetFuncMap = DefaultOptions.SetFuncMap
	}
	tmplNum := len(opt.ErrorPages)
	return func(err error, c echo.Context) {
		if err != nil {
			defer c.Logger().Debug(err, `: `, c.Request().URL().String())
		}
		if c.Response().Committed() {
			return
		}
		code := opt.DefaultHTTPErrorCode
		data := c.Data().Reset()
		title := http.StatusText(code)
		var (
			panicErr  *echo.PanicError
			msg       string
			processed bool
		)
		for _, processor := range opt.ErrorProcessors {
			if processor == nil {
				continue
			}
			processed, err = processor(c, err)
			if processed {
				break
			}
		}
		switch e := err.(type) {
		case *echo.HTTPError:
			if e.Code > 0 {
				code = e.Code
				title = http.StatusText(code)
			}
			msg = e.Message
			data.SetError(e)
		case *echo.PanicError:
			panicErr = e
			msg = setAndGetErrorMessage(c, e.Error(), title)
		case *echo.Error:
			code = e.Code.HTTPCode()
			msg = e.Message
			data.SetError(e)
		default:
			msg = e.Error()
			data.SetError(e)
		}
		if c.Request().Method() == echo.HEAD {
			c.NoContent(code)
			return
		}
		if tmplNum < 1 {
			c.String(msg, code)
			return
		}
		tmpl, ok := opt.ErrorPages[code]
		if !ok {
			if code != 0 {
				tmpl, ok = opt.ErrorPages[0]
			} else {
				code = DefaultOptions.DefaultHTTPErrorCode
			}
			if !ok {
				c.String(msg, code)
				return
			}
		}
		if c.Format() != echo.ContentTypeHTML {
			c.SetCode(opt.DefaultHTTPErrorCode)
			goto END
		}
		c.SetCode(code)
		c.SetFunc(`Lang`, c.Lang)
		if len(opt.SetFuncMap) > 0 {
			for _, setFunc := range opt.SetFuncMap {
				err = setFunc(c)
				if err != nil {
					c.String(err.Error())
					return
				}
			}
		}
		data.SetData(echo.H{
			"title":   title,
			"content": msg,
			"debug":   c.Echo().Debug(),
			"code":    code,
			"panic":   panicErr,
		}, data.GetCode().Int())

	END:
		if renderErr := c.SetAuto(true).Render(tmpl, nil); renderErr != nil {
			msg += "\n" + renderErr.Error()
			c.String(msg, code)
		}
	}
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 render

import (
	"net/http"
	"time"

	"github.com/webx-top/echo"
)

var (
	DefaultOptions = &Options{
		Skipper:              echo.DefaultSkipper,
		ErrorPages:           make(map[int]string),
		DefaultHTTPErrorCode: http.StatusInternalServerError,
		SetFuncMap: []echo.HandlerFunc{
			func(c echo.Context) error {
				c.SetFunc(`Lang`, c.Lang)
				c.SetFunc(`Now`, time.Now)
				c.SetFunc(`T`, c.T)
				return nil
			},
		},
	}
)

type ErrorProcessor func(ctx echo.Context, err error) (processed bool, newErr error)

type Options struct {
	Skipper              echo.Skipper
	ErrorPages           map[int]string
	ErrorProcessors      []ErrorProcessor
	DefaultHTTPErrorCode int
	SetFuncMap           []echo.HandlerFunc
}

func (opt *Options) AddFuncSetter(set ...echo.HandlerFunc) *Options {
	if opt.SetFuncMap == nil {
		opt.SetFuncMap = make([]echo.HandlerFunc, len(DefaultOptions.SetFuncMap))
		for index, setter := range DefaultOptions.SetFuncMap {
			opt.SetFuncMap[index] = setter
		}
	}
	opt.SetFuncMap = append(opt.SetFuncMap, set...)
	return opt
}

func (opt *Options) SetFuncSetter(set ...echo.HandlerFunc) *Options {
	opt.SetFuncMap = set
	return opt
}

func (opt *Options) AddErrorProcessor(h ...ErrorProcessor) *Options {
	opt.ErrorProcessors = append(opt.ErrorProcessors, h...)
	return opt
}

func (opt *Options) SetErrorProcessor(h ...ErrorProcessor) *Options {
	opt.ErrorProcessors = h
	return opt
}

// Middleware set renderer
func Middleware(d echo.Renderer) echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			c.SetRenderer(d)
			return h.Handle(c)
		})
	}
}

func Auto() echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			c.SetAuto(true)
			return h.Handle(c)
		})
	}
}

func setAndGetErrorMessage(c echo.Context, debugMessage string, prodMessage string) string {
	if c.Echo().Debug() {
		c.Data().SetInfo(debugMessage, 0)
		return debugMessage
	}
	c.Data().SetInfo(prodMessage, 0)
	return prodMessage
}

func HTTPErrorHandler(opt *Options) echo.HTTPErrorHandler {
	if opt == nil {
		opt = DefaultOptions
	}
	if opt.ErrorPages == nil {
		opt.ErrorPages = DefaultOptions.ErrorPages
	}
	if opt.DefaultHTTPErrorCode < 1 {
		opt.DefaultHTTPErrorCode = DefaultOptions.DefaultHTTPErrorCode
	}
	if opt.SetFuncMap == nil {
		opt.SetFuncMap = DefaultOptions.SetFuncMap
	}
	tmplNum := len(opt.ErrorPages)
	return func(err error, c echo.Context) {
		if err != nil {
			defer c.Logger().Debug(err, `: `, c.Request().URL().String())
		}
		if c.Response().Committed() {
			return
		}
		code := http.StatusInternalServerError
		data := c.Data().Reset()
		title := http.StatusText(code)
		var (
			panicErr  *echo.PanicError
			msg       string
			processed bool
		)
		for _, processor := range opt.ErrorProcessors {
			if processor == nil {
				continue
			}
			processed, err = processor(c, err)
			if processed {
				break
			}
		}
		switch e := err.(type) {
		case *echo.HTTPError:
			if e.Code > 0 {
				code = e.Code
				title = http.StatusText(code)
			}
			msg = e.Message
			data.SetError(e)
		case *echo.PanicError:
			panicErr = e
			msg = setAndGetErrorMessage(c, e.Error(), title)
		case *echo.Error:
			code = e.Code.HTTPCode()
			msg = e.Message
			data.SetError(e)
		default:
			msg = e.Error()
			data.SetError(e)
		}
		if c.Request().Method() == echo.HEAD {
			c.NoContent(code)
			return
		}
		if tmplNum < 1 {
			c.String(msg, code)
			return
		}
		tmpl, ok := opt.ErrorPages[code]
		if !ok {
			if code != 0 {
				tmpl, ok = opt.ErrorPages[0]
			} else {
				code = DefaultOptions.DefaultHTTPErrorCode
			}
			if !ok {
				c.String(msg, code)
				return
			}
		}
		if c.Format() != echo.ContentTypeHTML {
			c.SetCode(opt.DefaultHTTPErrorCode)
			goto END
		}
		c.SetCode(code)
		c.SetFunc(`Lang`, c.Lang)
		if len(opt.SetFuncMap) > 0 {
			for _, setFunc := range opt.SetFuncMap {
				err = setFunc(c)
				if err != nil {
					c.String(err.Error())
					return
				}
			}
		}
		data.SetData(echo.H{
			"title":   title,
			"content": msg,
			"debug":   c.Echo().Debug(),
			"code":    code,
			"panic":   panicErr,
		}, data.GetCode().Int())

	END:
		if renderErr := c.SetAuto(true).Render(tmpl, nil); renderErr != nil {
			msg += "\n" + renderErr.Error()
			c.String(msg, code)
		}
	}
}
<|endoftext|>


<commit_before>package core

import (
	"crypto/aes"
	"crypto/cipher"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func DecryptFile(target, out, keyfile string) bool {
	keyContents, error := ioutil.ReadFile(keyfile)
	if error != nil {
		log.Printf("Could not load keyfile %v\r\n", keyfile)
		return false
	}

	inFile, err := os.Open(target)
	if err != nil {
		log.Printf("Could not load archive %v\r\n", target)
		return false
	}
	defer inFile.Close()

	block, err := aes.NewCipher(keyContents)
	if err != nil {
		log.Printf("Could not load AES Cipher %v\r\n", err)
		return false
	}

	var iv [aes.BlockSize]byte
	stream := cipher.NewOFB(block, iv[:])

	outPntr, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0770)
	if err != nil {
		log.Printf("Could open %v for writing\r\n", out)
		return false
	}
	defer outPntr.Close()

	reader := &cipher.StreamReader{S: stream, R: inFile}
	// Copy the input file to the output file, decrypting as we go.
	if _, err := io.Copy(outPntr, reader); err != nil {
		panic(err)
	}

	return true
}

func EncryptFile(target, out, keyfile string) bool {
	keyContents, error := ioutil.ReadFile(keyfile)
	if error != nil {
		log.Printf("Could not load keyfile %v\r\n", keyfile)
		return false
	}

	inFile, err := os.Open(target)
	if err != nil {
		log.Printf("Could not load archive %v\r\n", target)
		return false
	}
	defer inFile.Close()

	block, err := aes.NewCipher(keyContents)
	if err != nil {
		log.Printf("Could not load AES Cipher %v\r\n", err)
		return false
	}

	var iv [aes.BlockSize]byte
	stream := cipher.NewOFB(block, iv[:])

	outPntr, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0770)
	if err != nil {
		log.Printf("Could open %v for writing\r\n", out)
		return false
	}
	defer outPntr.Close()

	writer := &cipher.StreamWriter{S: stream, W: outPntr}

	if _, err := io.Copy(writer, inFile); err != nil {
		log.Printf("Could not encrypt\r\n", out)
		return false
	}
	writer.Close()
	return true
}
<commit_msg>Support newlines in keyfile<commit_after>package core

import (
	"crypto/aes"
	"crypto/cipher"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

func DecryptFile(target, out, keyfile string) bool {
	keyContents, error := ioutil.ReadFile(keyfile)
	if error != nil {
		log.Printf("Could not load keyfile %v\r\n", keyfile)
		return false
	}

	inFile, err := os.Open(target)
	if err != nil {
		log.Printf("Could not load archive %v\r\n", target)
		return false
	}
	defer inFile.Close()

	keyContentsStr := strings.Replace(string(keyContents), "\n", "", -1)

	block, err := aes.NewCipher([]byte(keyContentsStr))
	if err != nil {
		log.Printf("Could not load AES Cipher %v\r\n", err)
		return false
	}

	var iv [aes.BlockSize]byte
	stream := cipher.NewOFB(block, iv[:])

	outPntr, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0770)
	if err != nil {
		log.Printf("Could open %v for writing\r\n", out)
		return false
	}
	defer outPntr.Close()

	reader := &cipher.StreamReader{S: stream, R: inFile}
	// Copy the input file to the output file, decrypting as we go.
	if _, err := io.Copy(outPntr, reader); err != nil {
		panic(err)
	}

	return true
}

func EncryptFile(target, out, keyfile string) bool {
	keyContents, error := ioutil.ReadFile(keyfile)
	if error != nil {
		log.Printf("Could not load keyfile %v\r\n", keyfile)
		return false
	}

	inFile, err := os.Open(target)
	if err != nil {
		log.Printf("Could not load archive %v\r\n", target)
		return false
	}
	defer inFile.Close()

	block, err := aes.NewCipher(keyContents)
	if err != nil {
		log.Printf("Could not load AES Cipher %v\r\n", err)
		return false
	}

	var iv [aes.BlockSize]byte
	stream := cipher.NewOFB(block, iv[:])

	outPntr, err := os.OpenFile(out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0770)
	if err != nil {
		log.Printf("Could open %v for writing\r\n", out)
		return false
	}
	defer outPntr.Close()

	writer := &cipher.StreamWriter{S: stream, W: outPntr}

	if _, err := io.Copy(writer, inFile); err != nil {
		log.Printf("Could not encrypt\r\n", out)
		return false
	}
	writer.Close()
	return true
}
<|endoftext|>


<commit_before>package repository

import (
	"bufio"
	"os"
	"path/filepath"
	"regexp"
)

func GetRenderer(repositoryItem *Item) func() {

	return func() {

	}

}

func GetParser(repositoryItem *Item) func() {

	return func() {

	}

}

// Get the hash code of the rendered item
func GetRenderedItemHash(item Item) string {
	renderedItemPath := GetRenderedItemPath(item)

	file, err := os.Open(renderedItemPath)
	if err != nil {
		// file does not exist or cannot be accessed
		return ""
	}
	defer file.Close()

	fileReader := bufio.NewReader(file)
	firstLineBytes, _ := fileReader.ReadBytes('\n')
	if firstLineBytes == nil {
		// first line cannot be read
		return ""
	}

	// extract hash from line
	hashCodeRegexp := regexp.MustCompile("<!-- (\\w+) -->")
	matches := hashCodeRegexp.FindStringSubmatch(string(firstLineBytes))
	if len(matches) != 2 {
		return ""
	}

	extractedHashcode := matches[1]

	return string(extractedHashcode)
}

// Get the filepath of the rendered repository item
func GetRenderedItemPath(item Item) string {
	itemDirectory := filepath.Dir(item.Path)
	itemName := filepath.Base(item.Path)

	renderedFilePath := filepath.Join(itemDirectory, itemName+".html")
	return renderedFilePath
}
<commit_msg>Removed the GetRenderedItemHash function, because for now I really don't need the functionality. I might add it back later.<commit_after>package repository

import (
	"path/filepath"
)

func GetRenderer(repositoryItem *Item) func() {

	return func() {

	}

}

func GetParser(repositoryItem *Item) func() {

	return func() {

	}

}

// Get the filepath of the rendered repository item
func GetRenderedItemPath(item Item) string {
	itemDirectory := filepath.Dir(item.Path)
	itemName := filepath.Base(item.Path)

	renderedFilePath := filepath.Join(itemDirectory, itemName+".html")
	return renderedFilePath
}
<|endoftext|>


<commit_before>package requests

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"sensoserver/workers"

	"google.golang.org/api/oauth2/v2"

	"github.com/dchest/uniuri"
	uuid "github.com/satori/go.uuid"
)

var (
	httpClient = &http.Client{}
)

/*
Handle main page requests
*/
func Index(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "GET" {
		log.Println("Method not GET")
		w.Header().Set("Allow", "GET")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	path := "index.html"
	if r.URL.Path != "/" {
		path = r.URL.Path[1:len(r.URL.Path)]
	}
	w.Header().Add("Content-Type", getContentType(path))
	log.Println(path)
	if bs, err := Asset(path); err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusNotFound)
	} else {
		var reader = bytes.NewBuffer(bs)
		io.Copy(w, reader)
	}
}

/*
Google Callback code
*/

func HandleGoogleCallback(w http.ResponseWriter, r *http.Request) {
	/*requestDump, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println(err)
	}
	log.Println(string(requestDump))*/
	token := r.FormValue("idtoken")
	oauth2Service, err := oauth2.New(httpClient)
	tokenInfoCall := oauth2Service.Tokeninfo()
	tokenInfoCall.IdToken(token)
	tokenInfo, err := tokenInfoCall.Do()
	if err != nil {
		log.Println(err)
	}
	user, err := workers.GetUser(tokenInfo.UserId, tokenInfo.Email)
	log.Println("Error:", err)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
	log.Println(user.Email)
}

/*
register a new user with Google Cloud messaging
*/
func Register(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	//log.Println(registration.TopicString)
	if err == nil {
		registration.Topic.TopicString = uniuri.New()
		registration.Register()
		data, err := json.Marshal(&registration)
		if err == nil {
			log.Println("Registration Fulfilled: ", registration.Topic.TopicString)
			log.Println(string(data))
			io.WriteString(w, string(data))
		} else {
			log.Println(err)
		}
	}
}

//JoinTopic ... with a given topic join the token to the topic, this token will receive messages from FCM
func JoinTopic(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	if err == nil {
		err = registration.JoinTopic()
		data, err := json.Marshal(&registration)
		if err == nil {
			log.Println("Topic Joined")
			io.WriteString(w, string(data))
		} else {
			log.Println(err)
		}
	}
}

//LeaveTopic ... Remove a given token from a topic
func LeaveTopic(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	if err == nil {
		err = registration.LeaveTopic()
	}
}

//RecoverTopic ... Will eventually return a way to recover tokens from a topic
func RecoverTopic(w http.ResponseWriter, r *http.Request) {

}

//Load a registration request into a struct
func decodeRegistration(w http.ResponseWriter, r *http.Request) (*workers.Registration, error) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return nil, errors.New("Method not allowed")
	}
	var registration workers.Registration
	err := json.NewDecoder(r.Body).Decode(&registration)
	return &registration, err
}

//RefreshToken ... Replace an expired token with a new one
func RefreshToken(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	var refresh workers.RefreshToken
	err := json.NewDecoder(r.Body).Decode(&refresh)
	if err == nil {
		err = refresh.Refresh()
	}
}

//Reading ... process sensor data input
func Reading(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	message, err := decoder(r)
	if err != nil {
		//errorMessage := "Device not found: " + message.Sensor.Device
		w.WriteHeader(http.StatusInternalServerError)
		//w.Write([]byte(errorMessage))
		log.Println(err)
		return
	}
	log.Println("adding message to queue")
	workers.AddJob(*message)
}

//Helper to decode messages
func decoder(r *http.Request) (*workers.WorkRequest, error) {
	defer r.Body.Close()
	var message workers.WorkRequest
	err := json.NewDecoder(r.Body).Decode(&message)
	return &message, err
	/*if message.Sensor.Exists() {
		log.Println("Found the sensor")
		return &message, err
	} else {
		return &message, errors.New("Device Not Found")
	}*/
}

//RegisterDevice ... Register a new sensor with a given topic
func RegisterDevice(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	var device workers.Sensor
	//var topic workers.Topic
	err := json.NewDecoder(r.Body).Decode(&device)
	//Assign a unique id and a friendly name to connected device
	id := uuid.NewV4()
	device.Device = id.String()
	if err != nil || device.Topic.TopicString == "" {
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("☄ HTTP status code returned!"))
		return
	}
	device.Register()
	data, err := json.Marshal(&device)
	if err == nil {
		log.Println("Device Registered: ")
		log.Println("Device ", device.Device)
		log.Println("Name ", device.Name)
		io.WriteString(w, string(data))
	} else {
		log.Println("An error occurred")
		log.Println(err)
	}

}
<commit_msg>moar debuggin1<commit_after>package requests

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"sensoserver/workers"

	"google.golang.org/api/oauth2/v2"

	"github.com/dchest/uniuri"
	uuid "github.com/satori/go.uuid"
)

var (
	httpClient = &http.Client{}
)

/*
Handle main page requests
*/
func Index(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "GET" {
		log.Println("Method not GET")
		w.Header().Set("Allow", "GET")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	path := "index.html"
	if r.URL.Path != "/" {
		path = r.URL.Path[1:len(r.URL.Path)]
	}
	w.Header().Add("Content-Type", getContentType(path))
	log.Println(path)
	if bs, err := Asset(path); err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusNotFound)
	} else {
		var reader = bytes.NewBuffer(bs)
		io.Copy(w, reader)
	}
}

/*
Google Callback code
*/

func HandleGoogleCallback(w http.ResponseWriter, r *http.Request) {
	/*requestDump, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println(err)
	}
	log.Println(string(requestDump))*/
	token := r.FormValue("idtoken")
	oauth2Service, err := oauth2.New(httpClient)
	tokenInfoCall := oauth2Service.Tokeninfo()
	tokenInfoCall.IdToken(token)
	tokenInfo, err := tokenInfoCall.Do()
	if err != nil {
		log.Println(err)
	}
	user, err := workers.GetUser(tokenInfo.UserId, tokenInfo.Email)
	log.Println("Error:", err)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
	log.Println(user.Email)
}

/*
register a new user with Google Cloud messaging
*/
func Register(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	//log.Println(registration.TopicString)
	if err == nil {
		registration.Topic.TopicString = uniuri.New()
		registration.Register()
		data, err := json.Marshal(&registration)
		if err == nil {
			log.Println("Registration Fulfilled: ", registration.Topic.TopicString)
			log.Println(string(data))
			io.WriteString(w, string(data))
		} else {
			log.Println(err)
		}
	}
}

//JoinTopic ... with a given topic join the token to the topic, this token will receive messages from FCM
func JoinTopic(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	if err == nil {
		err = registration.JoinTopic()
		data, err := json.Marshal(&registration)
		if err == nil {
			log.Println("Topic Joined")
			io.WriteString(w, string(data))
		} else {
			log.Println(err)
		}
	}
}

//LeaveTopic ... Remove a given token from a topic
func LeaveTopic(w http.ResponseWriter, r *http.Request) {
	registration, err := decodeRegistration(w, r)
	if err == nil {
		err = registration.LeaveTopic()
	}
}

//RecoverTopic ... Will eventually return a way to recover tokens from a topic
func RecoverTopic(w http.ResponseWriter, r *http.Request) {

}

//Load a registration request into a struct
func decodeRegistration(w http.ResponseWriter, r *http.Request) (*workers.Registration, error) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return nil, errors.New("Method not allowed")
	}
	var registration workers.Registration
	err := json.NewDecoder(r.Body).Decode(&registration)
	return &registration, err
}

//RefreshToken ... Replace an expired token with a new one
func RefreshToken(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	var refresh workers.RefreshToken
	err := json.NewDecoder(r.Body).Decode(&refresh)
	if err == nil {
		err = refresh.Refresh()
	}
}

//Reading ... process sensor data input
func Reading(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	message, err := decoder(r)
	if err != nil {
		//errorMessage := "Device not found: " + message.Sensor.Device
		w.WriteHeader(http.StatusInternalServerError)
		//w.Write([]byte(errorMessage))
		log.Println(err)
		return
	}
	log.Println("adding message to queue")
	workers.AddJob(*message)
}

//Helper to decode messages
func decoder(r *http.Request) (*workers.WorkRequest, error) {
	defer r.Body.Close()
	var message workers.WorkRequest
	err := json.NewDecoder(r.Body).Decode(&message)
	data, err := json.Marshal(message)
	log.Println("Decoded message:",string(data))
	return &message, err
	/*if message.Sensor.Exists() {
		log.Println("Found the sensor")
		return &message, err
	} else {
		return &message, errors.New("Device Not Found")
	}*/
}

//RegisterDevice ... Register a new sensor with a given topic
func RegisterDevice(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	var device workers.Sensor
	//var topic workers.Topic
	err := json.NewDecoder(r.Body).Decode(&device)
	//Assign a unique id and a friendly name to connected device
	id := uuid.NewV4()
	device.Device = id.String()
	if err != nil || device.Topic.TopicString == "" {
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("☄ HTTP status code returned!"))
		return
	}
	device.Register()
	data, err := json.Marshal(&device)
	if err == nil {
		log.Println("Device Registered: ")
		log.Println("Device ", device.Device)
		log.Println("Name ", device.Name)
		io.WriteString(w, string(data))
	} else {
		log.Println("An error occurred")
		log.Println(err)
	}

}
<|endoftext|>


<commit_before>package tenus

import (
	"fmt"
	"net"
	"os"
	"syscall"

	"github.com/docker/libcontainer/netlink"
	"github.com/docker/libcontainer/system"
)

// VethOptions allows you to specify options for veth link.
type VethOptions struct {
	// Veth pair's peer interface name
	PeerName string
}

// Vether embeds Linker interface and adds few more functions mostly to handle peer link interface
type Vether interface {
	// Linker interface
	Linker
	// PeerNetInterface returns peer network interface
	PeerNetInterface() *net.Interface
	// SetPeerLinkUp sets peer link up - which also brings up the other peer in VethPair
	SetPeerLinkUp() error
	// DeletePeerLink deletes peer link - this also deletes the other peer in VethPair
	DeletePeerLink() error
	// SetPeerLinkIp configures peer link's IP address
	SetPeerLinkIp(net.IP, *net.IPNet) error
	// SetPeerLinkNsToDocker sends peer link into Docker
	SetPeerLinkNsToDocker(string, string) error
	// SetPeerLinkNsPid sends peer link into container specified by PID
	SetPeerLinkNsPid(int) error
	// SetPeerLinkNsFd sends peer link into container specified by path
	SetPeerLinkNsFd(string) error
	// SetPeerLinkNetInNs configures peer link's IP network in network namespace specified by PID
	SetPeerLinkNetInNs(int, net.IP, *net.IPNet, *net.IP) error
}

// VethPair is a Link. Veth links are created in pairs called peers.
type VethPair struct {
	Link
	// Peer network interface
	peerIfc *net.Interface
}

// NewVethPair creates a pair of veth network links.
//
// It is equivalent of running:
// 		ip link add name veth${RANDOM STRING} type veth peer name veth${RANDOM STRING}.
// NewVethPair returns Vether which is initialized to a pointer of type VethPair if the
// veth link was successfully created on Linux host. Newly created pair of veth links
// are assigned random names starting with "veth".
// NewVethPair returns error if the veth pair could not be created.
func NewVethPair() (Vether, error) {
	ifcName := makeNetInterfaceName("veth")
	peerName := makeNetInterfaceName("veth")

	if err := netlink.NetworkCreateVethPair(ifcName, peerName, 0); err != nil {
		return nil, err
	}

	newIfc, err := net.InterfaceByName(ifcName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	peerIfc, err := net.InterfaceByName(peerName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	return &VethPair{
		Link: Link{
			ifc: newIfc,
		},
		peerIfc: peerIfc,
	}, nil
}

// NewVethPairWithOptions creates a pair of veth network links.
//
// It is equivalent of running:
// 		ip link add name ${first device name} type veth peer name ${second device name}
// NewVethPairWithOptions returns Vether which is initialized to a pointer of type VethPair if the
// veth link was successfully created on the Linux host. It accepts VethOptions which allow you to set
// peer interface name. It returns error if the veth pair could not be created.
func NewVethPairWithOptions(ifcName string, opts VethOptions) (Vether, error) {
	peerName := opts.PeerName

	if ok, err := NetInterfaceNameValid(ifcName); !ok {
		return nil, err
	}

	if _, err := net.InterfaceByName(ifcName); err == nil {
		return nil, fmt.Errorf("Interface name %s already assigned on the host", ifcName)
	}

	if peerName != "" {
		if ok, err := NetInterfaceNameValid(peerName); !ok {
			return nil, err
		}

		if _, err := net.InterfaceByName(peerName); err == nil {
			return nil, fmt.Errorf("Interface name %s already assigned on the host", peerName)
		}
	} else {
		peerName = makeNetInterfaceName("veth")
	}

	if err := netlink.NetworkCreateVethPair(ifcName, peerName, 0); err != nil {
		return nil, err
	}

	newIfc, err := net.InterfaceByName(ifcName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	peerIfc, err := net.InterfaceByName(peerName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	return &VethPair{
		Link: Link{
			ifc: newIfc,
		},
		peerIfc: peerIfc,
	}, nil
}

// NetInterface returns veth link's primary network interface
func (veth *VethPair) NetInterface() *net.Interface {
	return veth.ifc
}

// NetInterface returns veth link's peer network interface
func (veth *VethPair) PeerNetInterface() *net.Interface {
	return veth.peerIfc
}

// SetPeerLinkUp sets peer link up
func (veth *VethPair) SetPeerLinkUp() error {
	return netlink.NetworkLinkUp(veth.peerIfc)
}

// DeletePeerLink deletes peer link. It also deletes the other peer interface in VethPair
func (veth *VethPair) DeletePeerLink() error {
	return netlink.NetworkLinkDel(veth.peerIfc.Name)
}

// SetPeerLinkIp configures peer link's IP address
func (veth *VethPair) SetPeerLinkIp(ip net.IP, nw *net.IPNet) error {
	return netlink.NetworkLinkAddIp(veth.peerIfc, ip, nw)
}

// SetPeerLinkNsToDocker sends peer link into Docker
func (veth *VethPair) SetPeerLinkNsToDocker(name string, dockerHost string) error {
	pid, err := DockerPidByName(name, dockerHost)
	if err != nil {
		return fmt.Errorf("Failed to find docker %s :  %s", name, err)
	}

	return netlink.NetworkSetNsPid(veth.peerIfc, pid)
}

// SetPeerLinkNsPid sends peer link into container specified by PID
func (veth *VethPair) SetPeerLinkNsPid(nspid int) error {
	return netlink.NetworkSetNsPid(veth.peerIfc, nspid)
}

// SetPeerLinkNsFd sends peer link into container specified by path
func (veth *VethPair) SetPeerLinkNsFd(nspath string) error {
	fd, err := syscall.Open(nspath, syscall.O_RDONLY, 0)
	if err != nil {
		return fmt.Errorf("Could not attach to Network namespace: %s", err)
	}

	return netlink.NetworkSetNsFd(veth.peerIfc, fd)
}

// SetPeerLinkNetInNs configures peer link's IP network in network namespace specified by PID
func (veth *VethPair) SetPeerLinkNetInNs(nspid int, ip net.IP, network *net.IPNet, gw *net.IP) error {
	origNs, _ := NetNsHandle(os.Getpid())
	defer syscall.Close(int(origNs))
	defer system.Setns(origNs, syscall.CLONE_NEWNET)

	if err := SetNetNsToPid(nspid); err != nil {
		return fmt.Errorf("Setting network namespace failed: %s", err)
	}

	if err := netlink.NetworkLinkAddIp(veth.peerIfc, ip, network); err != nil {
		return fmt.Errorf("Unable to set IP: %s in pid: %d network namespace", ip.String(), nspid)
	}

	if err := netlink.NetworkLinkUp(veth.peerIfc); err != nil {
		return fmt.Errorf("Unable to bring %s interface UP: %s", veth.peerIfc.Name, nspid)
	}

	if gw != nil {
		if err := netlink.AddDefaultGw(gw.String(), veth.peerIfc.Name); err != nil {
			return fmt.Errorf("Unable to set Default gateway: %s in pid: %d network namespace", gw.String(), nspid)
		}
	}

	return nil
}
<commit_msg>Added TX queue length as an option to VethPair creation<commit_after>package tenus

import (
	"fmt"
	"net"
	"os"
	"syscall"

	"github.com/docker/libcontainer/netlink"
	"github.com/docker/libcontainer/system"
)

// VethOptions allows you to specify options for veth link.
type VethOptions struct {
	// Veth pair's peer interface name
	PeerName string
	// TX queue length
	TxQueueLen int
}

// Vether embeds Linker interface and adds few more functions mostly to handle peer link interface
type Vether interface {
	// Linker interface
	Linker
	// PeerNetInterface returns peer network interface
	PeerNetInterface() *net.Interface
	// SetPeerLinkUp sets peer link up - which also brings up the other peer in VethPair
	SetPeerLinkUp() error
	// DeletePeerLink deletes peer link - this also deletes the other peer in VethPair
	DeletePeerLink() error
	// SetPeerLinkIp configures peer link's IP address
	SetPeerLinkIp(net.IP, *net.IPNet) error
	// SetPeerLinkNsToDocker sends peer link into Docker
	SetPeerLinkNsToDocker(string, string) error
	// SetPeerLinkNsPid sends peer link into container specified by PID
	SetPeerLinkNsPid(int) error
	// SetPeerLinkNsFd sends peer link into container specified by path
	SetPeerLinkNsFd(string) error
	// SetPeerLinkNetInNs configures peer link's IP network in network namespace specified by PID
	SetPeerLinkNetInNs(int, net.IP, *net.IPNet, *net.IP) error
}

// VethPair is a Link. Veth links are created in pairs called peers.
type VethPair struct {
	Link
	// Peer network interface
	peerIfc *net.Interface
}

// NewVethPair creates a pair of veth network links.
//
// It is equivalent of running:
// 		ip link add name veth${RANDOM STRING} type veth peer name veth${RANDOM STRING}.
// NewVethPair returns Vether which is initialized to a pointer of type VethPair if the
// veth link was successfully created on Linux host. Newly created pair of veth links
// are assigned random names starting with "veth".
// NewVethPair returns error if the veth pair could not be created.
func NewVethPair() (Vether, error) {
	ifcName := makeNetInterfaceName("veth")
	peerName := makeNetInterfaceName("veth")

	if err := netlink.NetworkCreateVethPair(ifcName, peerName, 0); err != nil {
		return nil, err
	}

	newIfc, err := net.InterfaceByName(ifcName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	peerIfc, err := net.InterfaceByName(peerName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	return &VethPair{
		Link: Link{
			ifc: newIfc,
		},
		peerIfc: peerIfc,
	}, nil
}

// NewVethPairWithOptions creates a pair of veth network links.
//
// It is equivalent of running:
// 		ip link add name ${first device name} type veth peer name ${second device name}
// NewVethPairWithOptions returns Vether which is initialized to a pointer of type VethPair if the
// veth link was successfully created on the Linux host. It accepts VethOptions which allow you to set
// peer interface name. It returns error if the veth pair could not be created.
func NewVethPairWithOptions(ifcName string, opts VethOptions) (Vether, error) {
	peerName := opts.PeerName
	txQLen := opts.TxQueueLen

	if ok, err := NetInterfaceNameValid(ifcName); !ok {
		return nil, err
	}

	if _, err := net.InterfaceByName(ifcName); err == nil {
		return nil, fmt.Errorf("Interface name %s already assigned on the host", ifcName)
	}

	if peerName != "" {
		if ok, err := NetInterfaceNameValid(peerName); !ok {
			return nil, err
		}

		if _, err := net.InterfaceByName(peerName); err == nil {
			return nil, fmt.Errorf("Interface name %s already assigned on the host", peerName)
		}
	} else {
		peerName = makeNetInterfaceName("veth")
	}

	if err := netlink.NetworkCreateVethPair(ifcName, peerName, txQLen); err != nil {
		return nil, err
	}

	newIfc, err := net.InterfaceByName(ifcName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	peerIfc, err := net.InterfaceByName(peerName)
	if err != nil {
		return nil, fmt.Errorf("Could not find the new interface: %s", err)
	}

	return &VethPair{
		Link: Link{
			ifc: newIfc,
		},
		peerIfc: peerIfc,
	}, nil
}

// NetInterface returns veth link's primary network interface
func (veth *VethPair) NetInterface() *net.Interface {
	return veth.ifc
}

// NetInterface returns veth link's peer network interface
func (veth *VethPair) PeerNetInterface() *net.Interface {
	return veth.peerIfc
}

// SetPeerLinkUp sets peer link up
func (veth *VethPair) SetPeerLinkUp() error {
	return netlink.NetworkLinkUp(veth.peerIfc)
}

// DeletePeerLink deletes peer link. It also deletes the other peer interface in VethPair
func (veth *VethPair) DeletePeerLink() error {
	return netlink.NetworkLinkDel(veth.peerIfc.Name)
}

// SetPeerLinkIp configures peer link's IP address
func (veth *VethPair) SetPeerLinkIp(ip net.IP, nw *net.IPNet) error {
	return netlink.NetworkLinkAddIp(veth.peerIfc, ip, nw)
}

// SetPeerLinkNsToDocker sends peer link into Docker
func (veth *VethPair) SetPeerLinkNsToDocker(name string, dockerHost string) error {
	pid, err := DockerPidByName(name, dockerHost)
	if err != nil {
		return fmt.Errorf("Failed to find docker %s :  %s", name, err)
	}

	return netlink.NetworkSetNsPid(veth.peerIfc, pid)
}

// SetPeerLinkNsPid sends peer link into container specified by PID
func (veth *VethPair) SetPeerLinkNsPid(nspid int) error {
	return netlink.NetworkSetNsPid(veth.peerIfc, nspid)
}

// SetPeerLinkNsFd sends peer link into container specified by path
func (veth *VethPair) SetPeerLinkNsFd(nspath string) error {
	fd, err := syscall.Open(nspath, syscall.O_RDONLY, 0)
	if err != nil {
		return fmt.Errorf("Could not attach to Network namespace: %s", err)
	}

	return netlink.NetworkSetNsFd(veth.peerIfc, fd)
}

// SetPeerLinkNetInNs configures peer link's IP network in network namespace specified by PID
func (veth *VethPair) SetPeerLinkNetInNs(nspid int, ip net.IP, network *net.IPNet, gw *net.IP) error {
	origNs, _ := NetNsHandle(os.Getpid())
	defer syscall.Close(int(origNs))
	defer system.Setns(origNs, syscall.CLONE_NEWNET)

	if err := SetNetNsToPid(nspid); err != nil {
		return fmt.Errorf("Setting network namespace failed: %s", err)
	}

	if err := netlink.NetworkLinkAddIp(veth.peerIfc, ip, network); err != nil {
		return fmt.Errorf("Unable to set IP: %s in pid: %d network namespace", ip.String(), nspid)
	}

	if err := netlink.NetworkLinkUp(veth.peerIfc); err != nil {
		return fmt.Errorf("Unable to bring %s interface UP: %s", veth.peerIfc.Name, nspid)
	}

	if gw != nil {
		if err := netlink.AddDefaultGw(gw.String(), veth.peerIfc.Name); err != nil {
			return fmt.Errorf("Unable to set Default gateway: %s in pid: %d network namespace", gw.String(), nspid)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package ytdl

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
)

const youtubeBaseURL = "https://www.youtube.com/watch"
const youtubeEmbededBaseURL = "https://www.youtube.com/embed/"
const youtubeDateFormat = "2006-01-02"

// VideoInfo contains the info a youtube video
type VideoInfo struct {
	// The video ID
	ID string `json:"id"`
	// The video title
	Title string `json:"title"`
	// The video description
	Description string `json:"description"`
	// The date the video was published
	DatePublished time.Time `json:"datePublished"`
	// Formats the video is available in
	Formats []Format `json:"formats"`
	// List of keywords associated with the video
	Keywords []string `json:"keywords"`
	// Author of the video
	Author string `json:"author"`
	// Duration of the video
	Duration time.Duration

	//TODO: Add author
	htmlPlayerFile string
}

// GetVideoInfo fetches info from a url string, url object, or a url string
func GetVideoInfo(value interface{}) (*VideoInfo, error) {
	switch value.(type) {
	case *url.URL:
		return GetVideoInfoFromURL(value.(*url.URL))
	case string:
		u, err := url.ParseRequestURI(value.(string))
		if err != nil {
			return GetVideoInfoFromID(value.(string))
		}
		return GetVideoInfoFromURL(u)
	default:
		return nil, fmt.Errorf("Identifier type must be a string, *url.URL, or []byte")
	}
}

// GetVideoInfoFromURL fetches video info from a youtube url
func GetVideoInfoFromURL(u *url.URL) (*VideoInfo, error) {
	videoID := u.Query().Get("v")
	if len(videoID) == 0 {
		return nil, fmt.Errorf("Invalid youtube url, no video id")
	}
	return GetVideoInfoFromID(videoID)
}

// GetVideoInfoFromID fetches video info from a youtube video id
func GetVideoInfoFromID(id string) (*VideoInfo, error) {
	u, _ := url.ParseRequestURI(youtubeBaseURL)
	values := u.Query()
	values.Set("v", id)
	u.RawQuery = values.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Invalid status code: %d", resp.StatusCode)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return getVideoInfoFromHTML(id, body)
}

// GetDownloadURL gets the download url for a format
func (info *VideoInfo) GetDownloadURL(format Format) (*url.URL, error) {
	return getDownloadURL(format, info.htmlPlayerFile)
}

// GetThumbnailURL returns a url for the thumbnail image
// with the given quality
func (info *VideoInfo) GetThumbnailURL(quality ThumbnailQuality) *url.URL {
	u, _ := url.Parse(fmt.Sprintf("http://img.youtube.com/vi/%s/%s.jpg",
		info.ID, quality))
	return u
}

// Download is a convenience method to download a format to an io.Writer
func (info *VideoInfo) Download(format Format, dest io.Writer) error {
	u, err := info.GetDownloadURL(format)
	if err != nil {
		return err
	}
	resp, err := http.Get(u.String())
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		return fmt.Errorf("Invalid status code: %d", resp.StatusCode)
	}
	_, err = io.Copy(dest, resp.Body)
	return err
}

func getVideoInfoFromHTML(id string, html []byte) (*VideoInfo, error) {
	doc, err := goquery.NewDocumentFromReader(bytes.NewReader(html))
	if err != nil {
		return nil, err
	}

	info := &VideoInfo{}

	// extract description and title
	info.Description = strings.TrimSpace(doc.Find("#eow-description").Text())
	info.Title = strings.TrimSpace(doc.Find("#eow-title").Text())
	info.ID = id
	dateStr, ok := doc.Find("meta[itemprop=\"datePublished\"]").Attr("content")
	if !ok {
		log.Debug("Unable to extract date published")
	} else {
		date, err := time.Parse(youtubeDateFormat, dateStr)
		if err == nil {
			info.DatePublished = date
		} else {
			log.Debug("Unable to parse date published", err.Error())
		}
	}

	// match json in javascript
	re := regexp.MustCompile("ytplayer.config = (.*?);ytplayer.load")
	matches := re.FindSubmatch(html)

	var jsonConfig map[string]interface{}
	if len(matches) > 0 {
		err = json.Unmarshal(matches[1], &jsonConfig)
		if err != nil {
			return nil, err
		}
	} else {
		var resp *http.Response
		resp, err = http.Get(youtubeEmbededBaseURL + id)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			return nil, fmt.Errorf("Embeded url request returned status code %d	", resp.StatusCode)
		}
		html, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
		re = regexp.MustCompile("yt.setConfig('PLAYER_CONFIG', (.*?)</script>")
		matches := re.FindSubmatch(html)
		if len(matches) == 0 {
			return nil, fmt.Errorf("Error extracting json")
		}
	}

	inf := jsonConfig["args"].(map[string]interface{})
	if status, ok := inf["status"].(string); ok && status == "fail" {
		return nil, fmt.Errorf("Error %d:%s", inf["errorcode"], inf["reason"])
	}
	if a, ok := inf["author"].(string); ok {
		info.Author = a
	} else {
		log.Warn("Unable to extract author")
	}

	if length, ok := inf["length_seconds"].(string); ok {
		if duration, err := strconv.ParseInt(length, 10, 64); err == nil {
			info.Duration = time.Second * time.Duration(duration)
		} else {
			log.Warn("Unable to parse duration string: ", length)
		}
	} else {
		log.Warn("Unable to extract duration")
	}
	/*
		// For the future maybe
		parseKey := func(key string) []string {
			val, ok := inf[key].(string)
			if !ok {
				return nil
			}
			vals := []string{}
			split := strings.Split(val, ",")
			for _, v := range split {
				if v != "" {
					vals = append(vals, v)
				}
			}
			return vals
		}
	*/
	/*
		fmtList := parseKey("fmt_list")
		fexp := parseKey("fexp")
		watermark := parseKey("watermark")
		keywords := parseKey("keywords")

		if len(fmtList) != 0 {
			vals := []string{}
			for _, v := range fmtList {
				vals = append(vals, strings.Split(v, "/")...)
		} else {
			info["fmt_list"] = []string{}
		}

		videoVerticals := []string{}
		if videoVertsStr, ok := inf["video_verticals"].(string); ok {
			videoVertsStr = string([]byte(videoVertsStr)[1 : len(videoVertsStr)-2])
			videoVertsSplit := strings.Split(videoVertsStr, ", ")
			for _, v := range videoVertsSplit {
				if v != "" {
					videoVerticals = append(videoVerticals, v)
				}
			}
		}
	*/

	var formatStrings []string
	if fmtStreamMap, ok := inf["url_encoded_fmt_stream_map"].(string); ok {
		formatStrings = append(formatStrings, strings.Split(fmtStreamMap, ",")...)
	}

	if adaptiveFormats, ok := inf["adaptive_fmts"].(string); ok {
		formatStrings = append(formatStrings, strings.Split(adaptiveFormats, ",")...)
	}
	var formats []Format
	for _, v := range formatStrings {
		query, err := url.ParseQuery(v)
		if err == nil {
			data := make(Format)
			if strings.HasPrefix(query.Get("conn"), "rtmp") {
				data["rtmp"] = true
			}
			for k, v := range query {
				if len(v) == 1 {
					data[FormatKey(k)] = v[0]
				} else {
					data[FormatKey(k)] = v
				}
			}
			itag, _ := strconv.Atoi(query.Get("itag"))
			if meta, ok := FORMATS[itag]; ok {
				for k, v := range meta {
					data[FormatKey(k)] = v
				}
				formats = append(formats, data)
			} else {
				log.Debug("No metadata found for itag: ", itag, ", skipping...")
			}
		}
	}
	info.Formats = formats
	info.htmlPlayerFile = jsonConfig["assets"].(map[string]interface{})["js"].(string)
	return info, nil
}
<commit_msg>fixed regular expression for getting json from embeded url<commit_after>package ytdl

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
)

const youtubeBaseURL = "https://www.youtube.com/watch"
const youtubeEmbededBaseURL = "https://www.youtube.com/embed/"
const youtubeDateFormat = "2006-01-02"

// VideoInfo contains the info a youtube video
type VideoInfo struct {
	// The video ID
	ID string `json:"id"`
	// The video title
	Title string `json:"title"`
	// The video description
	Description string `json:"description"`
	// The date the video was published
	DatePublished time.Time `json:"datePublished"`
	// Formats the video is available in
	Formats []Format `json:"formats"`
	// List of keywords associated with the video
	Keywords []string `json:"keywords"`
	// Author of the video
	Author string `json:"author"`
	// Duration of the video
	Duration time.Duration

	//TODO: Add author
	htmlPlayerFile string
}

// GetVideoInfo fetches info from a url string, url object, or a url string
func GetVideoInfo(value interface{}) (*VideoInfo, error) {
	switch value.(type) {
	case *url.URL:
		return GetVideoInfoFromURL(value.(*url.URL))
	case string:
		u, err := url.ParseRequestURI(value.(string))
		if err != nil {
			return GetVideoInfoFromID(value.(string))
		}
		return GetVideoInfoFromURL(u)
	default:
		return nil, fmt.Errorf("Identifier type must be a string, *url.URL, or []byte")
	}
}

// GetVideoInfoFromURL fetches video info from a youtube url
func GetVideoInfoFromURL(u *url.URL) (*VideoInfo, error) {
	videoID := u.Query().Get("v")
	if len(videoID) == 0 {
		return nil, fmt.Errorf("Invalid youtube url, no video id")
	}
	return GetVideoInfoFromID(videoID)
}

// GetVideoInfoFromID fetches video info from a youtube video id
func GetVideoInfoFromID(id string) (*VideoInfo, error) {
	u, _ := url.ParseRequestURI(youtubeBaseURL)
	values := u.Query()
	values.Set("v", id)
	u.RawQuery = values.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Invalid status code: %d", resp.StatusCode)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return getVideoInfoFromHTML(id, body)
}

// GetDownloadURL gets the download url for a format
func (info *VideoInfo) GetDownloadURL(format Format) (*url.URL, error) {
	return getDownloadURL(format, info.htmlPlayerFile)
}

// GetThumbnailURL returns a url for the thumbnail image
// with the given quality
func (info *VideoInfo) GetThumbnailURL(quality ThumbnailQuality) *url.URL {
	u, _ := url.Parse(fmt.Sprintf("http://img.youtube.com/vi/%s/%s.jpg",
		info.ID, quality))
	return u
}

// Download is a convenience method to download a format to an io.Writer
func (info *VideoInfo) Download(format Format, dest io.Writer) error {
	u, err := info.GetDownloadURL(format)
	if err != nil {
		return err
	}
	resp, err := http.Get(u.String())
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		return fmt.Errorf("Invalid status code: %d", resp.StatusCode)
	}
	_, err = io.Copy(dest, resp.Body)
	return err
}

func getVideoInfoFromHTML(id string, html []byte) (*VideoInfo, error) {
	doc, err := goquery.NewDocumentFromReader(bytes.NewReader(html))
	if err != nil {
		return nil, err
	}

	info := &VideoInfo{}

	// extract description and title
	info.Description = strings.TrimSpace(doc.Find("#eow-description").Text())
	info.Title = strings.TrimSpace(doc.Find("#eow-title").Text())
	info.ID = id
	dateStr, ok := doc.Find("meta[itemprop=\"datePublished\"]").Attr("content")
	if !ok {
		log.Debug("Unable to extract date published")
	} else {
		date, err := time.Parse(youtubeDateFormat, dateStr)
		if err == nil {
			info.DatePublished = date
		} else {
			log.Debug("Unable to parse date published", err.Error())
		}
	}

	// match json in javascript
	re := regexp.MustCompile("ytplayer.config = (.*?);ytplayer.load")
	matches := re.FindSubmatch(html)

	var jsonConfig map[string]interface{}
	if len(matches) > 0 {
		err = json.Unmarshal(matches[1], &jsonConfig)
		if err != nil {
			return nil, err
		}
	} else {
		var resp *http.Response
		resp, err = http.Get(youtubeEmbededBaseURL + id)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			return nil, fmt.Errorf("Embeded url request returned status code %d	", resp.StatusCode)
		}
		html, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
		re = regexp.MustCompile("yt.setConfig\\('PLAYER_CONFIG', (.*?)\\)</script>")
		matches := re.FindSubmatch(html)
		if len(matches) == 0 {
			return nil, fmt.Errorf("Error extracting json")
		}
	}

	inf := jsonConfig["args"].(map[string]interface{})
	if status, ok := inf["status"].(string); ok && status == "fail" {
		return nil, fmt.Errorf("Error %d:%s", inf["errorcode"], inf["reason"])
	}
	if a, ok := inf["author"].(string); ok {
		info.Author = a
	} else {
		log.Warn("Unable to extract author")
	}

	if length, ok := inf["length_seconds"].(string); ok {
		if duration, err := strconv.ParseInt(length, 10, 64); err == nil {
			info.Duration = time.Second * time.Duration(duration)
		} else {
			log.Warn("Unable to parse duration string: ", length)
		}
	} else {
		log.Warn("Unable to extract duration")
	}
	/*
		// For the future maybe
		parseKey := func(key string) []string {
			val, ok := inf[key].(string)
			if !ok {
				return nil
			}
			vals := []string{}
			split := strings.Split(val, ",")
			for _, v := range split {
				if v != "" {
					vals = append(vals, v)
				}
			}
			return vals
		}
	*/
	/*
		fmtList := parseKey("fmt_list")
		fexp := parseKey("fexp")
		watermark := parseKey("watermark")
		keywords := parseKey("keywords")

		if len(fmtList) != 0 {
			vals := []string{}
			for _, v := range fmtList {
				vals = append(vals, strings.Split(v, "/")...)
		} else {
			info["fmt_list"] = []string{}
		}

		videoVerticals := []string{}
		if videoVertsStr, ok := inf["video_verticals"].(string); ok {
			videoVertsStr = string([]byte(videoVertsStr)[1 : len(videoVertsStr)-2])
			videoVertsSplit := strings.Split(videoVertsStr, ", ")
			for _, v := range videoVertsSplit {
				if v != "" {
					videoVerticals = append(videoVerticals, v)
				}
			}
		}
	*/

	var formatStrings []string
	if fmtStreamMap, ok := inf["url_encoded_fmt_stream_map"].(string); ok {
		formatStrings = append(formatStrings, strings.Split(fmtStreamMap, ",")...)
	}

	if adaptiveFormats, ok := inf["adaptive_fmts"].(string); ok {
		formatStrings = append(formatStrings, strings.Split(adaptiveFormats, ",")...)
	}
	var formats []Format
	for _, v := range formatStrings {
		query, err := url.ParseQuery(v)
		if err == nil {
			data := make(Format)
			if strings.HasPrefix(query.Get("conn"), "rtmp") {
				data["rtmp"] = true
			}
			for k, v := range query {
				if len(v) == 1 {
					data[FormatKey(k)] = v[0]
				} else {
					data[FormatKey(k)] = v
				}
			}
			itag, _ := strconv.Atoi(query.Get("itag"))
			if meta, ok := FORMATS[itag]; ok {
				for k, v := range meta {
					data[FormatKey(k)] = v
				}
				formats = append(formats, data)
			} else {
				log.Debug("No metadata found for itag: ", itag, ", skipping...")
			}
		}
	}
	info.Formats = formats
	info.htmlPlayerFile = jsonConfig["assets"].(map[string]interface{})["js"].(string)
	return info, nil
}
<|endoftext|>


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

// This program can be used as go_android_GOARCH_exec by the Go tool.
// It executes binaries on an android device using adb.
package main

import (
	"bytes"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

func run(args ...string) string {
	buf := new(bytes.Buffer)
	cmd := exec.Command("adb", args...)
	cmd.Stdout = io.MultiWriter(os.Stdout, buf)
	cmd.Stderr = os.Stderr
	log.Printf("adb %s", strings.Join(args, " "))
	err := cmd.Run()
	if err != nil {
		log.Fatalf("adb %s: %v", strings.Join(args, " "), err)
	}
	return buf.String()
}

const (
	// Directory structure on the target device androidtest.bash assumes.
	deviceGoroot = "/data/local/tmp/goroot"
	deviceGopath = "/data/local/tmp/gopath"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("go_android_exec: ")

	// Prepare a temporary directory that will be cleaned up at the end.
	deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d",
		filepath.Base(os.Args[1]), os.Getpid())
	run("shell", "mkdir", "-p", deviceGotmp)

	// Determine the package by examining the current working
	// directory, which will look something like
	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
	// We extract everything after the $GOROOT or $GOPATH to run on the
	// same relative directory on the target device.
	subdir, inGoRoot := subdir()
	deviceCwd := filepath.Join(deviceGoroot, subdir)
	if !inGoRoot {
		deviceCwd = filepath.Join(deviceGopath, subdir)
	}

	// Binary names can conflict.
	// E.g. template.test from the {html,text}/template packages.
	binName := filepath.Base(os.Args[1])
	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGotmp, binName, os.Getpid())

	// The push of the binary happens in parallel with other tests.
	// Unfortunately, a simultaneous call to adb shell hold open
	// file descriptors, so it is necessary to push then move to
	// avoid a "text file busy" error on execution.
	// https://code.google.com/p/android/issues/detail?id=65857
	run("push", os.Args[1], deviceBin+"-tmp")
	run("shell", "cp '"+deviceBin+"-tmp' '"+deviceBin+"'")
	run("shell", "rm '"+deviceBin+"-tmp'")

	// The adb shell command will return an exit code of 0 regardless
	// of the command run. E.g.
	//      $ adb shell false
	//      $ echo $?
	//      0
	// https://code.google.com/p/android/issues/detail?id=3254
	// So we append the exitcode to the output and parse it from there.
	const exitstr = "exitcode="
	cmd := `export TMPDIR="` + deviceGotmp + `"` +
		`; export GOROOT="` + deviceGoroot + `"` +
		`; export GOPATH="` + deviceGopath + `"` +
		`; cd "` + deviceCwd + `"` +
		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
		"; echo -n " + exitstr + "$?"
	output := run("shell", cmd)

	run("shell", "rm", "-rf", deviceGotmp) // Clean up.

	output = output[strings.LastIndex(output, "\n")+1:]
	if !strings.HasPrefix(output, exitstr) {
		log.Fatalf("no exit code: %q", output)
	}
	code, err := strconv.Atoi(output[len(exitstr):])
	if err != nil {
		log.Fatalf("bad exit code: %v", err)
	}
	os.Exit(code)
}

// subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool) {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) {
		subdir, err := filepath.Rel(root, cwd)
		if err != nil {
			log.Fatal(err)
		}
		return subdir, true
	}

	for _, p := range filepath.SplitList(build.Default.GOPATH) {
		if !strings.HasPrefix(cwd, p) {
			continue
		}
		subdir, err := filepath.Rel(p, cwd)
		if err == nil {
			return subdir, false
		}
	}
	log.Fatalf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
		cwd, runtime.GOROOT(), build.Default.GOPATH)
	return "", false
}
<commit_msg>misc/android: make the exec wrapper exit code parsing more robust<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This program can be used as go_android_GOARCH_exec by the Go tool.
// It executes binaries on an android device using adb.
package main

import (
	"bytes"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

func run(args ...string) string {
	buf := new(bytes.Buffer)
	cmd := exec.Command("adb", args...)
	cmd.Stdout = io.MultiWriter(os.Stdout, buf)
	cmd.Stderr = os.Stderr
	log.Printf("adb %s", strings.Join(args, " "))
	err := cmd.Run()
	if err != nil {
		log.Fatalf("adb %s: %v", strings.Join(args, " "), err)
	}
	return buf.String()
}

const (
	// Directory structure on the target device androidtest.bash assumes.
	deviceGoroot = "/data/local/tmp/goroot"
	deviceGopath = "/data/local/tmp/gopath"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("go_android_exec: ")

	// Prepare a temporary directory that will be cleaned up at the end.
	deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d",
		filepath.Base(os.Args[1]), os.Getpid())
	run("shell", "mkdir", "-p", deviceGotmp)

	// Determine the package by examining the current working
	// directory, which will look something like
	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
	// We extract everything after the $GOROOT or $GOPATH to run on the
	// same relative directory on the target device.
	subdir, inGoRoot := subdir()
	deviceCwd := filepath.Join(deviceGoroot, subdir)
	if !inGoRoot {
		deviceCwd = filepath.Join(deviceGopath, subdir)
	}

	// Binary names can conflict.
	// E.g. template.test from the {html,text}/template packages.
	binName := filepath.Base(os.Args[1])
	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGotmp, binName, os.Getpid())

	// The push of the binary happens in parallel with other tests.
	// Unfortunately, a simultaneous call to adb shell hold open
	// file descriptors, so it is necessary to push then move to
	// avoid a "text file busy" error on execution.
	// https://code.google.com/p/android/issues/detail?id=65857
	run("push", os.Args[1], deviceBin+"-tmp")
	run("shell", "cp '"+deviceBin+"-tmp' '"+deviceBin+"'")
	run("shell", "rm '"+deviceBin+"-tmp'")

	// The adb shell command will return an exit code of 0 regardless
	// of the command run. E.g.
	//      $ adb shell false
	//      $ echo $?
	//      0
	// https://code.google.com/p/android/issues/detail?id=3254
	// So we append the exitcode to the output and parse it from there.
	const exitstr = "exitcode="
	cmd := `export TMPDIR="` + deviceGotmp + `"` +
		`; export GOROOT="` + deviceGoroot + `"` +
		`; export GOPATH="` + deviceGopath + `"` +
		`; cd "` + deviceCwd + `"` +
		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
		"; echo -n " + exitstr + "$?"
	output := run("shell", cmd)

	run("shell", "rm", "-rf", deviceGotmp) // Clean up.

	exitIdx := strings.LastIndex(output, exitstr)
	if exitIdx == -1 {
		log.Fatalf("no exit code: %q", output)
	}
	code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
	if err != nil {
		log.Fatalf("bad exit code: %v", err)
	}
	os.Exit(code)
}

// subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool) {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) {
		subdir, err := filepath.Rel(root, cwd)
		if err != nil {
			log.Fatal(err)
		}
		return subdir, true
	}

	for _, p := range filepath.SplitList(build.Default.GOPATH) {
		if !strings.HasPrefix(cwd, p) {
			continue
		}
		subdir, err := filepath.Rel(p, cwd)
		if err == nil {
			return subdir, false
		}
	}
	log.Fatalf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
		cwd, runtime.GOROOT(), build.Default.GOPATH)
	return "", false
}
<|endoftext|>