<commit_before>package md3

import (
	"bytes"
	"fmt"
	"io"
	"log"
)

const (
	maxQPath       = 64
	maxFrameLength = 16

	md3HeaderIdent  = "IDP3"
	md3SurfaceIdent = md3HeaderIdent
	md3MaxVersion   = 15
	md3VertexSize   = 8
)

type surfaceHeader struct {
	name string

	flags int32 // Unused.

	num_frames    int32
	num_shaders   int32
	num_verts     int32
	num_triangles int32

	ofs_triangles int32
	ofs_shaders   int32
	ofs_st        int32
	ofs_xyznormal int32
	ofs_end       int32
}

type fileHeader struct {
	name string

	version int32
	flags   int32 // Unused.

	num_frames   int32
	num_tags     int32
	num_surfaces int32
	num_skins    int32 // Unused.

	ofs_frames   int32
	ofs_tags     int32
	ofs_surfaces int32
	ofs_eof      int32
}

func Read(data []byte) (*Model, error) {
	var (
		header *fileHeader
		err    error
	)

	r := bytes.NewReader(data)
	header, err = readMD3Header(r)
	if err != nil {
		log.Println("Error reading header:", err)
		return nil, err
	}

	model := new(Model)
	surfaces := make([]*Surface, 0, 1)

	model.name = header.name

	surfaceOutput := readSurfaceList(data[header.ofs_surfaces:], int(header.num_surfaces))
	tagOutput := readTagList(data[header.ofs_tags:], int(header.num_tags), int(header.num_frames))
	frameOutput := readFrameList(data[header.ofs_frames:], int(header.num_frames))

	for completions := header.num_surfaces + 1; completions > 0; completions-- {
		select {
		case surface := <-surfaceOutput:
			if surface != nil {
				surfaces = append(surfaces, surface)
			}
		case tags := <-tagOutput:
			model.tags = tags
		case frames := <-frameOutput:
			model.frames = frames
		}
	}

	model.surfaces = surfaces

	return model, nil
}

func readTagList(data []byte, count int, numFrames int) <-chan []*Tag {
	output := make(chan []*Tag)

	go func(output chan<- []*Tag) {
		// defer close(output)

		r := bytes.NewReader(data)
		tagMap := make(map[string]*Tag)
		tags := make([]*Tag, 0, count)
		var ok bool
		var tag *Tag
		var frame TagFrame
		var name string
		var err error
		var numTagsToRead = count * numFrames

		for i := 0; i < numTagsToRead; i++ {
			name, frame, err = readTag(r)

			if err != nil {
				log.Println("Error reading tag list:", err)
				break
			}

			if tag, ok = tagMap[name]; !ok {
				tag = new(Tag)
				tag.name = name
				tags = append(tags, tag)
				tagMap[name] = tag
			}

			tag.frames = append(tag.frames, frame)
		}

		output <- tags
	}(output)

	return output
}

func readTag(r io.Reader) (string, TagFrame, error) {
	var err error
	var name string
	var frame TagFrame

	name, err = readNulString(r, maxQPath)
	if err != nil {
		return name, frame, err
	}

	vecPointers := []*Vec3{
		&frame.Origin,
		&frame.XOrientation,
		&frame.YOrientation,
		&frame.ZOrientation,
	}

	for _, ptr := range vecPointers {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return name, frame, err
		}
	}

	return name, frame, nil
}

func readMD3Header(r io.Reader) (*fileHeader, error) {
	header := new(fileHeader)
	var ident string
	var err error

	ident, err = readFixedString(r, 4)
	switch {
	case err != nil:
		log.Println("Error reading header identifier", err)
		return nil, err
	case ident != md3HeaderIdent:
		return nil, fmt.Errorf("MD3 header identifier is %q, should be %q", ident, md3HeaderIdent)
	}

	header.version, err = readS32(r)
	switch {
	case err != nil:
		log.Println("Error reading header version", err)
		return nil, err
	case header.version > md3MaxVersion:
		return nil, fmt.Errorf("MD3 header version (%d) exceeds max version (%d)", header.version, md3MaxVersion)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		log.Println("Error reading header model name", err)
		return nil, err
	}

	var s32Fields = [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_tags,
		&header.num_surfaces,
		&header.num_skins,
		&header.ofs_frames,
		&header.ofs_tags,
		&header.ofs_surfaces,
		&header.ofs_eof,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readSurfaceHeader(r io.Reader) (*surfaceHeader, error) {
	var err error
	var ident string

	header := new(surfaceHeader)

	ident, err = readFixedString(r, 4)
	if err != nil {
		return nil, err
	} else if ident != md3SurfaceIdent {
		return nil, fmt.Errorf("Surface header identifier is %q, should be %q", ident, md3SurfaceIdent)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		return nil, err
	}

	var s32Fields = [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_shaders,
		&header.num_verts,
		&header.num_triangles,
		&header.ofs_triangles,
		&header.ofs_shaders,
		&header.ofs_st,
		&header.ofs_xyznormal,
		&header.ofs_end,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readVertex(r io.Reader) (Vertex, error) {
	var result Vertex
	var err error

	result.Origin, err = readF16Vec3(r)
	if err != nil {
		return result, err
	}

	result.Normal, err = readSphereNormal(r)

	return result, err
}

func readXYZNormals(r io.Reader, count int) ([]Vertex, error) {
	vertices := make([]Vertex, count)
	for index := range vertices {
		var err error
		vertices[index], err = readVertex(r)
		if err != nil {
			return nil, err
		}
	}
	return vertices, nil
}

func readTriangleList(data []byte, count int) <-chan []Triangle {
	output := make(chan []Triangle)
	go func() {
		var err error
		tris := make([]Triangle, count)
		r := bytes.NewReader(data)
		for index := range tris {
			tri := Triangle{}

			tri.A, err = readS32(r)
			if err != nil {
				break
			}

			tri.B, err = readS32(r)
			if err != nil {
				break
			}

			tri.C, err = readS32(r)
			if err != nil {
				break
			}

			tris[index] = tri
		}

		if err != nil {
			log.Println("Error reading triangles:", err)
		}

		output <- tris
	}()
	return output
}

func readTexCoordList(data []byte, count int) <-chan []TexCoord {
	output := make(chan []TexCoord)
	go func() {
		var err error
		tcs := make([]TexCoord, count)
		r := bytes.NewReader(data)
		for index := range tcs {
			tc := TexCoord{}

			tc.S, err = readF32(r)
			if err != nil {
				break
			}

			tc.T, err = readF32(r)
			if err != nil {
				break
			}

			tcs[index] = tc
		}

		if err != nil {
			log.Println("Error reading texcoords:", err)
		}

		output <- tcs
	}()
	return output
}

func readShaderList(data []byte, count int) <-chan []Shader {
	output := make(chan []Shader)
	go func() {
		var err error
		shaders := make([]Shader, count)
		r := bytes.NewReader(data)
		for index := range shaders {
			shader := Shader{}

			shader.Name, err = readNulString(r, maxQPath)
			if err != nil {
				break
			}

			shader.Index, err = readS32(r)
			if err != nil {
				break
			}

			shaders[index] = shader
		}

		if err != nil {
			log.Println("Error reading shaders:", err)
		}

		output <- shaders
	}()
	return output
}

func readSurfaceList(data []byte, count int) <-chan *Surface {
	output := make(chan *Surface)
	go func(data []byte, output chan<- *Surface) {
		for index := 0; index < count; index++ {
			reader := bytes.NewReader(data[:])
			header, err := readSurfaceHeader(reader)
			if err != nil {
				log.Println("Error reading surface header:", err)
				break
			}

			go func(data []byte) {
				surf, err := readSurface(header, data)
				if err != nil {
					log.Printf("Error reading surface %q: %s\n", header.name, err)
				}

				surf.name = header.name
				surf.numFrames = int(header.num_frames)

				output <- surf
			}(data)

			data = data[header.ofs_end:]
		}
	}(data, output)
	return output
}

func readSurface(h *surfaceHeader, data []byte) (*Surface, error) {
	surface := new(Surface)

	triangleOutput := readTriangleList(data[h.ofs_triangles:], int(h.num_triangles))
	shaderOutput := readShaderList(data[h.ofs_shaders:], int(h.num_shaders))
	texcoordOutput := readTexCoordList(data[h.ofs_st:], int(h.num_verts))
	verticesOutput := readVertexFrames(data[h.ofs_xyznormal:], int(h.num_frames), int(h.num_verts))

	surface.vertices = <-verticesOutput
	surface.triangles = <-triangleOutput
	surface.texcoords = <-texcoordOutput
	surface.shaders = <-shaderOutput

	return surface, nil
}

type frameAndVertices struct {
	index    int
	vertices []Vertex
}

func readVertexFrames(data []byte, numVertices, numFrames int) <-chan [][]Vertex {
	output := make(chan [][]Vertex)

	go func(data []byte) {
		var (
			frameVertices = make([][]Vertex, numFrames)
			frameReceiver = make(chan frameAndVertices)
			frameSize     = numVertices * md3VertexSize
		)

		for frame := range frameVertices {
			go func(frame int, data []byte) {
				reader := bytes.NewReader(data)
				vertices, err := readXYZNormals(reader, numVertices)
				if err != nil {
					log.Println("Error reading vertices:", err)
				}
				frameReceiver <- frameAndVertices{frame, vertices}
			}(frame, data[:frameSize])
			data = data[frameSize:]
		}

		for _ = range frameVertices {
			pack := <-frameReceiver
			frameVertices[pack.index] = pack.vertices
		}

		output <- frameVertices
	}(data)

	return output
}

func readFrame(r io.Reader) (*Frame, error) {
	var err error
	frame := new(Frame)

	frame.name, err = readNulString(r, maxFrameLength)
	if err != nil {
		return nil, err
	}

	for _, ptr := range []*Vec3{&frame.min, &frame.max, &frame.origin} {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return nil, err
		}
	}

	frame.radius, err = readF32(r)
	if err != nil {
		return nil, err
	}

	return frame, nil
}

func readFrameList(data []byte, count int) <-chan []*Frame {
	output := make(chan []*Frame)

	go func(output chan<- []*Frame) {
		// defer close(output)

		var err error
		reader := bytes.NewReader(data)
		frames := make([]*Frame, count)

		for index := range frames {
			frames[index], err = readFrame(reader)

			if err != nil {
				log.Println("Error reading frame list:", err)
				frames = nil
				break
			}
		}

		output <- frames
	}(output)

	return output
}
<commit_msg>Pass output channel as a write-only channel.<commit_after>package md3

import (
	"bytes"
	"fmt"
	"io"
	"log"
)

const (
	maxQPath       = 64
	maxFrameLength = 16

	md3HeaderIdent  = "IDP3"
	md3SurfaceIdent = md3HeaderIdent
	md3MaxVersion   = 15
	md3VertexSize   = 8
)

type surfaceHeader struct {
	name string

	flags int32 // Unused.

	num_frames    int32
	num_shaders   int32
	num_verts     int32
	num_triangles int32

	ofs_triangles int32
	ofs_shaders   int32
	ofs_st        int32
	ofs_xyznormal int32
	ofs_end       int32
}

type fileHeader struct {
	name string

	version int32
	flags   int32 // Unused.

	num_frames   int32
	num_tags     int32
	num_surfaces int32
	num_skins    int32 // Unused.

	ofs_frames   int32
	ofs_tags     int32
	ofs_surfaces int32
	ofs_eof      int32
}

func Read(data []byte) (*Model, error) {
	var (
		header *fileHeader
		err    error
	)

	r := bytes.NewReader(data)
	header, err = readMD3Header(r)
	if err != nil {
		log.Println("Error reading header:", err)
		return nil, err
	}

	model := new(Model)
	surfaces := make([]*Surface, 0, 1)

	model.name = header.name

	surfaceOutput := readSurfaceList(data[header.ofs_surfaces:], int(header.num_surfaces))
	tagOutput := readTagList(data[header.ofs_tags:], int(header.num_tags), int(header.num_frames))
	frameOutput := readFrameList(data[header.ofs_frames:], int(header.num_frames))

	for completions := header.num_surfaces + 1; completions > 0; completions-- {
		select {
		case surface := <-surfaceOutput:
			if surface != nil {
				surfaces = append(surfaces, surface)
			}
		case tags := <-tagOutput:
			model.tags = tags
		case frames := <-frameOutput:
			model.frames = frames
		}
	}

	model.surfaces = surfaces

	return model, nil
}

func readTagList(data []byte, count int, numFrames int) <-chan []*Tag {
	output := make(chan []*Tag)

	go func(output chan<- []*Tag) {
		// defer close(output)

		r := bytes.NewReader(data)
		tagMap := make(map[string]*Tag)
		tags := make([]*Tag, 0, count)
		var ok bool
		var tag *Tag
		var frame TagFrame
		var name string
		var err error
		var numTagsToRead = count * numFrames

		for i := 0; i < numTagsToRead; i++ {
			name, frame, err = readTag(r)

			if err != nil {
				log.Println("Error reading tag list:", err)
				break
			}

			if tag, ok = tagMap[name]; !ok {
				tag = new(Tag)
				tag.name = name
				tags = append(tags, tag)
				tagMap[name] = tag
			}

			tag.frames = append(tag.frames, frame)
		}

		output <- tags
	}(output)

	return output
}

func readTag(r io.Reader) (string, TagFrame, error) {
	var err error
	var name string
	var frame TagFrame

	name, err = readNulString(r, maxQPath)
	if err != nil {
		return name, frame, err
	}

	vecPointers := []*Vec3{
		&frame.Origin,
		&frame.XOrientation,
		&frame.YOrientation,
		&frame.ZOrientation,
	}

	for _, ptr := range vecPointers {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return name, frame, err
		}
	}

	return name, frame, nil
}

func readMD3Header(r io.Reader) (*fileHeader, error) {
	header := new(fileHeader)
	var ident string
	var err error

	ident, err = readFixedString(r, 4)
	switch {
	case err != nil:
		log.Println("Error reading header identifier", err)
		return nil, err
	case ident != md3HeaderIdent:
		return nil, fmt.Errorf("MD3 header identifier is %q, should be %q", ident, md3HeaderIdent)
	}

	header.version, err = readS32(r)
	switch {
	case err != nil:
		log.Println("Error reading header version", err)
		return nil, err
	case header.version > md3MaxVersion:
		return nil, fmt.Errorf("MD3 header version (%d) exceeds max version (%d)", header.version, md3MaxVersion)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		log.Println("Error reading header model name", err)
		return nil, err
	}

	var s32Fields = [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_tags,
		&header.num_surfaces,
		&header.num_skins,
		&header.ofs_frames,
		&header.ofs_tags,
		&header.ofs_surfaces,
		&header.ofs_eof,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readSurfaceHeader(r io.Reader) (*surfaceHeader, error) {
	var err error
	var ident string

	header := new(surfaceHeader)

	ident, err = readFixedString(r, 4)
	if err != nil {
		return nil, err
	} else if ident != md3SurfaceIdent {
		return nil, fmt.Errorf("Surface header identifier is %q, should be %q", ident, md3SurfaceIdent)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		return nil, err
	}

	var s32Fields = [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_shaders,
		&header.num_verts,
		&header.num_triangles,
		&header.ofs_triangles,
		&header.ofs_shaders,
		&header.ofs_st,
		&header.ofs_xyznormal,
		&header.ofs_end,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readVertex(r io.Reader) (Vertex, error) {
	var result Vertex
	var err error

	result.Origin, err = readF16Vec3(r)
	if err != nil {
		return result, err
	}

	result.Normal, err = readSphereNormal(r)

	return result, err
}

func readXYZNormals(r io.Reader, count int) ([]Vertex, error) {
	vertices := make([]Vertex, count)
	for index := range vertices {
		var err error
		vertices[index], err = readVertex(r)
		if err != nil {
			return nil, err
		}
	}
	return vertices, nil
}

func readTriangleList(data []byte, count int) <-chan []Triangle {
	output := make(chan []Triangle)
	go func() {
		var err error
		tris := make([]Triangle, count)
		r := bytes.NewReader(data)
		for index := range tris {
			tri := Triangle{}

			tri.A, err = readS32(r)
			if err != nil {
				break
			}

			tri.B, err = readS32(r)
			if err != nil {
				break
			}

			tri.C, err = readS32(r)
			if err != nil {
				break
			}

			tris[index] = tri
		}

		if err != nil {
			log.Println("Error reading triangles:", err)
		}

		output <- tris
	}()
	return output
}

func readTexCoordList(data []byte, count int) <-chan []TexCoord {
	output := make(chan []TexCoord)
	go func() {
		var err error
		tcs := make([]TexCoord, count)
		r := bytes.NewReader(data)
		for index := range tcs {
			tc := TexCoord{}

			tc.S, err = readF32(r)
			if err != nil {
				break
			}

			tc.T, err = readF32(r)
			if err != nil {
				break
			}

			tcs[index] = tc
		}

		if err != nil {
			log.Println("Error reading texcoords:", err)
		}

		output <- tcs
	}()
	return output
}

func readShaderList(data []byte, count int) <-chan []Shader {
	output := make(chan []Shader)
	go func() {
		var err error
		shaders := make([]Shader, count)
		r := bytes.NewReader(data)
		for index := range shaders {
			shader := Shader{}

			shader.Name, err = readNulString(r, maxQPath)
			if err != nil {
				break
			}

			shader.Index, err = readS32(r)
			if err != nil {
				break
			}

			shaders[index] = shader
		}

		if err != nil {
			log.Println("Error reading shaders:", err)
		}

		output <- shaders
	}()
	return output
}

func readSurfaceList(data []byte, count int) <-chan *Surface {
	output := make(chan *Surface)
	go func(data []byte, output chan<- *Surface) {
		for index := 0; index < count; index++ {
			reader := bytes.NewReader(data[:])
			header, err := readSurfaceHeader(reader)
			if err != nil {
				log.Println("Error reading surface header:", err)
				break
			}

			go func(data []byte) {
				surf, err := readSurface(header, data)
				if err != nil {
					log.Printf("Error reading surface %q: %s\n", header.name, err)
				}

				surf.name = header.name
				surf.numFrames = int(header.num_frames)

				output <- surf
			}(data)

			data = data[header.ofs_end:]
		}
	}(data, output)
	return output
}

func readSurface(h *surfaceHeader, data []byte) (*Surface, error) {
	surface := new(Surface)

	triangleOutput := readTriangleList(data[h.ofs_triangles:], int(h.num_triangles))
	shaderOutput := readShaderList(data[h.ofs_shaders:], int(h.num_shaders))
	texcoordOutput := readTexCoordList(data[h.ofs_st:], int(h.num_verts))
	verticesOutput := readVertexFrames(data[h.ofs_xyznormal:], int(h.num_frames), int(h.num_verts))

	surface.vertices = <-verticesOutput
	surface.triangles = <-triangleOutput
	surface.texcoords = <-texcoordOutput
	surface.shaders = <-shaderOutput

	return surface, nil
}

type frameAndVertices struct {
	index    int
	vertices []Vertex
}

func readVertexFrames(data []byte, numVertices, numFrames int) <-chan [][]Vertex {
	output := make(chan [][]Vertex)

	go func(data []byte, output chan<- [][]Vertex) {
		var (
			frameVertices = make([][]Vertex, numFrames)
			frameReceiver = make(chan frameAndVertices)
			frameSize     = numVertices * md3VertexSize
		)

		for frame := range frameVertices {
			go func(frame int, data []byte) {
				reader := bytes.NewReader(data)
				vertices, err := readXYZNormals(reader, numVertices)
				if err != nil {
					log.Println("Error reading vertices:", err)
				}
				frameReceiver <- frameAndVertices{frame, vertices}
			}(frame, data[:frameSize])
			data = data[frameSize:]
		}

		for _ = range frameVertices {
			pack := <-frameReceiver
			frameVertices[pack.index] = pack.vertices
		}

		output <- frameVertices
	}(data, output)

	return output
}

func readFrame(r io.Reader) (*Frame, error) {
	var err error
	frame := new(Frame)

	frame.name, err = readNulString(r, maxFrameLength)
	if err != nil {
		return nil, err
	}

	for _, ptr := range []*Vec3{&frame.min, &frame.max, &frame.origin} {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return nil, err
		}
	}

	frame.radius, err = readF32(r)
	if err != nil {
		return nil, err
	}

	return frame, nil
}

func readFrameList(data []byte, count int) <-chan []*Frame {
	output := make(chan []*Frame)

	go func(output chan<- []*Frame) {
		// defer close(output)

		var err error
		reader := bytes.NewReader(data)
		frames := make([]*Frame, count)

		for index := range frames {
			frames[index], err = readFrame(reader)

			if err != nil {
				log.Println("Error reading frame list:", err)
				frames = nil
				break
			}
		}

		output <- frames
	}(output)

	return output
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/veandco/go-sdl2/sdl"
	"os"
	"reflect"
    "runtime"
	"unsafe"
)

type Pixel uint32

// Creates a slice of Pixel from a raw pointer
func sliceFromPixelPtr(data unsafe.Pointer, length int) []Pixel {
	var pixels []Pixel
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pixels))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return pixels
}

func lockTexture(tex *sdl.Texture, width int, height int) (pixels []Pixel, pitch int) {
	var data unsafe.Pointer
	err := tex.Lock(nil, &data, &pitch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "tex.Lock: %v", err)
		panic(err)
	}
	// Convert pitch units from byte to pixels
	pitch /= 4
	pixels = sliceFromPixelPtr(data, width*height)
	return
}

// Clip x to half-open interval [a,b)
func clip(x int, a int, b int) int {
	if x < a {
		return a
	}
	if x >= b {
		return b
	}
	return x
}

var escape *string
var counter int

// Generate some heap-allocated stuff
func generateGarbage() {
	escape = new(string)
	*escape = fmt.Sprintf("%v", counter)
}

// Draw cross-hairs through (x0,y0) onto the given pixel buffer.
func drawCross(pixels []Pixel, pitch int, width int, height int, x0 int, y0 int) {
	x0 = clip(x0, 0, width)
	y0 = clip(y0, 0, height)
	for y := 0; y < height; y++ {
		generateGarbage()
		for x := 0; x < width; x++ {
			var color Pixel
			if y == y0 || x == x0 {
				color = 0xFFFFFFFF
			} else {
				color = 0xFF000000
			}
			pixels[y*pitch+x] = color
		}
	}
}

var winTitle string = "Crosshair"
var winWidth, winHeight int = 800, 600

func run() int {
    // See discussion at https://github.com/golang/go/wiki/LockOSThread
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()

	// Create window
	window, err := sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %v\n", err)
		panic(err)
	}
	defer window.Destroy()

	// Create renderer
	width, height := window.GetSize()
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %v\n", err)
		panic(err)
	}
	defer renderer.Destroy()

	// Create texture
	tex, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, width, height)
	if err != nil {
		fmt.Fprintf(os.Stderr, "renderer.CreateTexture: %v\n", err)
		panic(err)
	}
	defer tex.Destroy()

	// Show crosshair animation.  Quit when a key comes up.
	var mouseX, mouseY int
	for {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				return 0
			case *sdl.MouseMotionEvent:
				mouseX = int(t.X)
				mouseY = int(t.Y)
			case *sdl.KeyUpEvent:
				return 0
			}
		}

		pixels, pitch := lockTexture(tex, width, height)
		drawCross(pixels, pitch, width, height, mouseX, mouseY)
		tex.Unlock()

		err := renderer.Clear()
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Clear: %v", err)
			panic(err)
		}
		renderer.Copy(tex, nil, nil)
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Copy: %v", err)
			panic(err)
		}
		renderer.Present()
	}

	return 0
}

func main() {
	run()
}
<commit_msg>Push QuitEvent if escape key is pressed.<commit_after>package main

import (
	"fmt"
	"github.com/veandco/go-sdl2/sdl"
	"os"
	"reflect"
	"runtime"
	"unsafe"
)

type Pixel uint32

// Creates a slice of Pixel from a raw pointer
func sliceFromPixelPtr(data unsafe.Pointer, length int) []Pixel {
	var pixels []Pixel
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pixels))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return pixels
}

func lockTexture(tex *sdl.Texture, width int, height int) (pixels []Pixel, pitch int) {
	var data unsafe.Pointer
	err := tex.Lock(nil, &data, &pitch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "tex.Lock: %v", err)
		panic(err)
	}
	// Convert pitch units from byte to pixels
	pitch /= 4
	pixels = sliceFromPixelPtr(data, width*height)
	return
}

// Clip x to half-open interval [a,b)
func clip(x int, a int, b int) int {
	if x < a {
		return a
	}
	if x >= b {
		return b
	}
	return x
}

var escape *string
var counter int

// Generate some heap-allocated stuff
func generateGarbage() {
	escape = new(string)
	*escape = fmt.Sprintf("%v", counter)
}

// Draw cross-hairs through (x0,y0) onto the given pixel buffer.
func drawCross(pixels []Pixel, pitch int, width int, height int, x0 int, y0 int) {
	x0 = clip(x0, 0, width)
	y0 = clip(y0, 0, height)
	for y := 0; y < height; y++ {
		generateGarbage()
		for x := 0; x < width; x++ {
			var color Pixel
			if y == y0 || x == x0 {
				color = 0xFFFFFFFF
			} else {
				color = 0xFF000000
			}
			pixels[y*pitch+x] = color
		}
	}
}

var winTitle string = "Crosshair"
var winWidth, winHeight int = 800, 600

func run() int {
	// See discussion at https://github.com/golang/go/wiki/LockOSThread
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// Create window
	window, err := sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %v\n", err)
		panic(err)
	}
	defer window.Destroy()

	// Create renderer
	width, height := window.GetSize()
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %v\n", err)
		panic(err)
	}
	defer renderer.Destroy()

	// Create texture
	tex, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, width, height)
	if err != nil {
		fmt.Fprintf(os.Stderr, "renderer.CreateTexture: %v\n", err)
		panic(err)
	}
	defer tex.Destroy()

	// Show crosshair animation.  Quit when a key comes up.
	var mouseX, mouseY int
	for {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				return 0
			case *sdl.MouseMotionEvent:
				mouseX = int(t.X)
				mouseY = int(t.Y)
			case *sdl.KeyUpEvent:
				sdl.PushEvent(&sdl.QuitEvent{Type: sdl.QUIT})
			}
		}

		pixels, pitch := lockTexture(tex, width, height)
		drawCross(pixels, pitch, width, height, mouseX, mouseY)
		tex.Unlock()

		err := renderer.Clear()
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Clear: %v", err)
			panic(err)
		}
		renderer.Copy(tex, nil, nil)
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Copy: %v", err)
			panic(err)
		}
		renderer.Present()
	}

	return 0
}

func main() {
	run()
}
<|endoftext|>


<commit_before>package mapify_test

import (
	. "github.com/clouch/mapify"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Mapify", func() {
	Describe("Convert a struct to a map", func() {
		Context("Without pointer values", func() {
			test := TestA{
				ID:    "1",
				Revs:  []string{"1234"},
				Hello: "World",
			}
			It("Should return a map of of the necessaty values", func() {
				testA, err := Do(&test)
				Ω(err).Should(BeNil())

				var world interface{} = "World"
				var revs interface{} = []string{"1234"}
				var id interface{} = "1"

				Ω(testA).Should(HaveKeyWithValue("ID", id))
				Ω(testA).Should(HaveKeyWithValue("Hello", world))
				Ω(testA).Should(HaveKeyWithValue("Revs", revs))
			})
			Context("Test with a struct with pointer values", func() {
				bar := "Bar"
				num := 1
				test := TestB{
					ID:    "1",
					Revs:  []string{"1234"},
					Hello: "World",
					Foo:   &bar,
					Num:   &num,
				}
				It("Should return a map of of the necessaty values", func() {
					testA, err := Do(&test)
					Ω(err).Should(BeNil())

					var world interface{} = "World"
					var revs interface{} = []string{"1234"}
					var id interface{} = "1"
					var foo interface{} = bar
					var num interface{} = 1

					Ω(testA).Should(HaveKeyWithValue("ID", id))
					Ω(testA).Should(HaveKeyWithValue("Hello", world))
					Ω(testA).Should(HaveKeyWithValue("Revs", revs))
					Ω(testA).Should(HaveKeyWithValue("Foo", foo))
					Ω(testA).Should(HaveKeyWithValue("Num", num))
				})
			})

			Context("Test with a struct with nil pointer values", func() {
				bar := "Bar"
				test := TestB{
					ID:    "1",
					Revs:  []string{"1234"},
					Hello: "World",
					Foo:   &bar,
				}
				It("Should return a map of of the necessaty values", func() {
					testA, err := Do(&test)
					Ω(err).Should(BeNil())

					var world interface{} = "World"
					var revs interface{} = []string{"1234"}
					var id interface{} = "1"
					var foo interface{} = bar

					Ω(testA).Should(HaveKeyWithValue("ID", id))
					Ω(testA).Should(HaveKeyWithValue("Hello", world))
					Ω(testA).Should(HaveKeyWithValue("Revs", revs))
					Ω(testA).Should(HaveKeyWithValue("Foo", foo))
					Ω(testA).Should(HaveKey("Num"))
					Ω(testA["Num"]).Should(BeNil())
				})
			})

			Context("Test with a struct with nil and not-nil pointer values", func() {
				It("Should return a map of of the necessaty values", func() {
				})
			})

		})
	})
})

type TestA struct {
	ID    string
	Revs  []string
	Hello string
}

type TestB struct {
	ID    string
	Revs  []string
	Hello string
	Foo   *string
	Num   *int
}
<commit_msg>Remove unused test<commit_after>package mapify_test

import (
	. "github.com/clouch/mapify"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Mapify", func() {
	Describe("Convert a struct to a map", func() {
		Context("Without pointer values", func() {
			test := TestA{
				ID:    "1",
				Revs:  []string{"1234"},
				Hello: "World",
			}
			It("Should return a map of of the necessaty values", func() {
				testA, err := Do(&test)
				Ω(err).Should(BeNil())

				var world interface{} = "World"
				var revs interface{} = []string{"1234"}
				var id interface{} = "1"

				Ω(testA).Should(HaveKeyWithValue("ID", id))
				Ω(testA).Should(HaveKeyWithValue("Hello", world))
				Ω(testA).Should(HaveKeyWithValue("Revs", revs))
			})
			Context("Test with a struct with pointer values", func() {
				bar := "Bar"
				num := 1
				test := TestB{
					ID:    "1",
					Revs:  []string{"1234"},
					Hello: "World",
					Foo:   &bar,
					Num:   &num,
				}
				It("Should return a map of of the necessaty values", func() {
					testA, err := Do(&test)
					Ω(err).Should(BeNil())

					var world interface{} = "World"
					var revs interface{} = []string{"1234"}
					var id interface{} = "1"
					var foo interface{} = bar
					var num interface{} = 1

					Ω(testA).Should(HaveKeyWithValue("ID", id))
					Ω(testA).Should(HaveKeyWithValue("Hello", world))
					Ω(testA).Should(HaveKeyWithValue("Revs", revs))
					Ω(testA).Should(HaveKeyWithValue("Foo", foo))
					Ω(testA).Should(HaveKeyWithValue("Num", num))
				})
			})

			Context("Test with a struct with nil pointer values", func() {
				bar := "Bar"
				test := TestB{
					ID:    "1",
					Revs:  []string{"1234"},
					Hello: "World",
					Foo:   &bar,
				}
				It("Should return a map of of the necessaty values", func() {
					testA, err := Do(&test)
					Ω(err).Should(BeNil())

					var world interface{} = "World"
					var revs interface{} = []string{"1234"}
					var id interface{} = "1"
					var foo interface{} = bar

					Ω(testA).Should(HaveKeyWithValue("ID", id))
					Ω(testA).Should(HaveKeyWithValue("Hello", world))
					Ω(testA).Should(HaveKeyWithValue("Revs", revs))
					Ω(testA).Should(HaveKeyWithValue("Foo", foo))
					Ω(testA).Should(HaveKey("Num"))
					Ω(testA["Num"]).Should(BeNil())
				})
			})

		})
	})
})

type TestA struct {
	ID    string
	Revs  []string
	Hello string
}

type TestB struct {
	ID    string
	Revs  []string
	Hello string
	Foo   *string
	Num   *int
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"math"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclparse"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	"github.com/hashicorp/packer-plugin-sdk/template"
	"github.com/hashicorp/packer/hcl2template"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/version"
	"golang.org/x/sync/semaphore"

	"github.com/hako/durafmt"
	"github.com/posener/complete"
)

type BuildCommand struct {
	Meta
}

func (c *BuildCommand) Run(args []string) int {
	ctx, cleanup := handleTermInterrupt(c.Ui)
	defer cleanup()

	cfg, ret := c.ParseArgs(args)
	if ret != 0 {
		return ret
	}

	return c.RunContext(ctx, cfg)
}

func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) {
	var cfg BuildArgs
	flags := c.Meta.FlagSet("build", FlagSetBuildFilter|FlagSetVars)
	flags.Usage = func() { c.Ui.Say(c.Help()) }
	cfg.AddFlagSets(flags)
	if err := flags.Parse(args); err != nil {
		return &cfg, 1
	}

	if cfg.ParallelBuilds < 1 {
		cfg.ParallelBuilds = math.MaxInt64
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		return &cfg, 1
	}
	cfg.Path = args[0]
	return &cfg, 0
}

func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (*hcl2template.PackerConfig, int) {
	parser := &hcl2template.Parser{
		CorePackerVersion:       version.SemVer,
		CorePackerVersionString: version.FormattedVersion(),
		Parser:                  hclparse.NewParser(),
		PluginConfig:            m.CoreConfig.Components.PluginConfig,
	}
	cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars)
	return cfg, writeDiags(m.Ui, parser.Files(), diags)
}

func writeDiags(ui packersdk.Ui, files map[string]*hcl.File, diags hcl.Diagnostics) int {
	// write HCL errors/diagnostics if any.
	b := bytes.NewBuffer(nil)
	err := hcl.NewDiagnosticTextWriter(b, files, 80, false).WriteDiagnostics(diags)
	if err != nil {
		ui.Error("could not write diagnostic: " + err.Error())
		return 1
	}
	if b.Len() != 0 {
		if diags.HasErrors() {
			ui.Error(b.String())
			return 1
		}
		ui.Say(b.String())
	}
	return 0
}

func (m *Meta) GetConfig(cla *MetaArgs) (packer.Handler, int) {
	cfgType, err := cla.GetConfigType()
	if err != nil {
		m.Ui.Error(fmt.Sprintf("%q: %s", cla.Path, err))
		return nil, 1
	}

	switch cfgType {
	case ConfigTypeHCL2:
		// TODO(azr): allow to pass a slice of files here.
		return m.GetConfigFromHCL(cla)
	default:
		// TODO: uncomment once we've polished HCL a bit more.
		// c.Ui.Say(`Legacy JSON Configuration Will Be Used.
		// The template will be parsed in the legacy configuration style. This style
		// will continue to work but users are encouraged to move to the new style.
		// See: https://packer.io/guides/hcl
		// `)
		return m.GetConfigFromJSON(cla)
	}
}

func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.Handler, int) {
	// Parse the template
	var tpl *template.Template
	var err error
	if cla.Path == "" {
		// here cla validation passed so this means we want a default builder
		// and we probably are in the console command
		tpl, err = template.Parse(TiniestBuilder)
	} else {
		tpl, err = template.ParseFile(cla.Path)
	}

	if err != nil {
		m.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
		return nil, 1
	}

	// Get the core
	core, err := m.Core(tpl, cla)
	ret := 0
	if err != nil {
		m.Ui.Error(err.Error())
		ret = 1
	}
	return &CoreWrapper{core}, ret
}

func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int {
	packerStarter, ret := c.GetConfig(&cla.MetaArgs)
	if ret != 0 {
		return ret
	}
	diags := packerStarter.Initialize(packer.InitializeOptions{})
	ret = writeDiags(c.Ui, nil, diags)
	if ret != 0 {
		return ret
	}

	builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{
		Only:    cla.Only,
		Except:  cla.Except,
		Debug:   cla.Debug,
		Force:   cla.Force,
		OnError: cla.OnError,
	})

	// here, something could have gone wrong but we still want to run valid
	// builds.
	ret = writeDiags(c.Ui, nil, diags)

	if cla.Debug {
		c.Ui.Say("Debug mode enabled. Builds will not be parallelized.")
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorCyan,
		packer.UiColorMagenta,
		packer.UiColorYellow,
		packer.UiColorBlue,
	}
	buildUis := make(map[packersdk.Build]packersdk.Ui)
	for i := range builds {
		ui := c.Ui
		if cla.Color {
			// Only set up UI colors if -machine-readable isn't set.
			if _, ok := c.Ui.(*packer.MachineReadableUi); !ok {
				ui = &packer.ColoredUi{
					Color: colors[i%len(colors)],
					Ui:    ui,
				}
				ui.Say(fmt.Sprintf("%s: output will be in this color.", builds[i].Name()))
				if i+1 == len(builds) {
					// Add a newline between the color output and the actual output
					c.Ui.Say("")
				}
			}
		}
		// Now add timestamps if requested
		if cla.TimestampUi {
			ui = &packer.TimestampedUi{
				Ui: ui,
			}
		}

		buildUis[builds[i]] = ui
	}

	log.Printf("Build debug mode: %v", cla.Debug)
	log.Printf("Force build: %v", cla.Force)
	log.Printf("On error: %v", cla.OnError)

	// Get the start of the build command
	buildCommandStart := time.Now()

	// Run all the builds in parallel and wait for them to complete
	var wg sync.WaitGroup
	var artifacts = struct {
		sync.RWMutex
		m map[string][]packersdk.Artifact
	}{m: make(map[string][]packersdk.Artifact)}
	// Get the builds we care about
	var errors = struct {
		sync.RWMutex
		m map[string]error
	}{m: make(map[string]error)}
	limitParallel := semaphore.NewWeighted(cla.ParallelBuilds)
	for i := range builds {
		if err := buildCtx.Err(); err != nil {
			log.Println("Interrupted, not going to start any more builds.")
			break
		}

		b := builds[i]
		name := b.Name()
		ui := buildUis[b]
		if err := limitParallel.Acquire(buildCtx, 1); err != nil {
			ui.Error(fmt.Sprintf("Build '%s' failed to acquire semaphore: %s", name, err))
			errors.Lock()
			errors.m[name] = err
			errors.Unlock()
			break
		}
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Run the build in a goroutine
		go func() {
			// Get the start of the build
			buildStart := time.Now()

			defer wg.Done()

			defer limitParallel.Release(1)

			log.Printf("Starting build run: %s", name)
			runArtifacts, err := b.Run(buildCtx, ui)

			// Get the duration of the build and parse it
			buildEnd := time.Now()
			buildDuration := buildEnd.Sub(buildStart)
			fmtBuildDuration := durafmt.Parse(buildDuration).LimitFirstN(2)

			if err != nil {
				ui.Error(fmt.Sprintf("Build '%s' errored after %s: %s", name, fmtBuildDuration, err))
				errors.Lock()
				errors.m[name] = err
				errors.Unlock()
			} else {
				ui.Say(fmt.Sprintf("Build '%s' finished after %s.", name, fmtBuildDuration))
				if nil != runArtifacts {
					artifacts.Lock()
					artifacts.m[name] = runArtifacts
					artifacts.Unlock()
				}
			}
		}()

		if cla.Debug {
			log.Printf("Debug enabled, so waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

		if cla.ParallelBuilds == 1 {
			log.Printf("Parallelization disabled, waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

	}

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	// Get the duration of the buildCommand command and parse it
	buildCommandEnd := time.Now()
	buildCommandDuration := buildCommandEnd.Sub(buildCommandStart)
	fmtBuildCommandDuration := durafmt.Parse(buildCommandDuration).LimitFirstN(2)
	c.Ui.Say(fmt.Sprintf("\n==> Wait completed after %s", fmtBuildCommandDuration))

	if err := buildCtx.Err(); err != nil {
		c.Ui.Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	if len(errors.m) > 0 {
		c.Ui.Machine("error-count", strconv.FormatInt(int64(len(errors.m)), 10))

		c.Ui.Error("\n==> Some builds didn't complete successfully and had errors:")
		for name, err := range errors.m {
			// Create a UI for the machine readable stuff to be targeted
			ui := &packer.TargetedUI{
				Target: name,
				Ui:     c.Ui,
			}

			ui.Machine("error", err.Error())

			c.Ui.Error(fmt.Sprintf("--> %s: %s", name, err))
		}
	}

	if len(artifacts.m) > 0 {
		c.Ui.Say("\n==> Builds finished. The artifacts of successful builds are:")
		for name, buildArtifacts := range artifacts.m {
			// Create a UI for the machine readable stuff to be targeted
			ui := &packer.TargetedUI{
				Target: name,
				Ui:     c.Ui,
			}

			// Machine-readable helpful
			ui.Machine("artifact-count", strconv.FormatInt(int64(len(buildArtifacts)), 10))

			for i, artifact := range buildArtifacts {
				var message bytes.Buffer
				fmt.Fprintf(&message, "--> %s: ", name)

				if artifact != nil {
					fmt.Fprint(&message, artifact.String())
				} else {
					fmt.Fprint(&message, "<nothing>")
				}

				iStr := strconv.FormatInt(int64(i), 10)
				if artifact != nil {
					ui.Machine("artifact", iStr, "builder-id", artifact.BuilderId())
					ui.Machine("artifact", iStr, "id", artifact.Id())
					ui.Machine("artifact", iStr, "string", artifact.String())

					files := artifact.Files()
					ui.Machine("artifact",
						iStr,
						"files-count", strconv.FormatInt(int64(len(files)), 10))
					for fi, file := range files {
						fiStr := strconv.FormatInt(int64(fi), 10)
						ui.Machine("artifact", iStr, "file", fiStr, file)
					}
				} else {
					ui.Machine("artifact", iStr, "nil")
				}

				ui.Machine("artifact", iStr, "end")
				c.Ui.Say(message.String())
			}
		}
	} else {
		c.Ui.Say("\n==> Builds finished but no artifacts were created.")
	}

	if len(errors.m) > 0 {
		// If any errors occurred, exit with a non-zero exit status
		ret = 1
	}

	return ret
}

func (*BuildCommand) Help() string {
	helpText := `
Usage: packer build [options] TEMPLATE

  Will execute multiple builds in parallel as defined in the template.
  The various artifacts created by the template will be outputted.

Options:

  -color=false                  Disable color output. (Default: color)
  -debug                        Debug mode enabled for builds.
  -except=foo,bar,baz           Run all builds and post-processors other than these.
  -only=foo,bar,baz             Build only the specified builds.
  -force                        Force a build to continue if artifacts exist, deletes existing artifacts.
  -machine-readable             Produce machine-readable output.
  -on-error=[cleanup|abort|ask|run-cleanup-provisioner] If the build fails do: clean up (default), abort, ask, or run-cleanup-provisioner.
  -parallel-builds=1            Number of builds to run in parallel. 1 disables parallelization. 0 means no limit (Default: 0)
  -timestamp-ui                 Enable prefixing of each ui output with an RFC3339 timestamp.
  -var 'key=value'              Variable for templates, can be used multiple times.
  -var-file=path                JSON or HCL2 file containing user variables.
`

	return strings.TrimSpace(helpText)
}

func (*BuildCommand) Synopsis() string {
	return "build image(s) from template"
}

func (*BuildCommand) AutocompleteArgs() complete.Predictor {
	return complete.PredictNothing
}

func (*BuildCommand) AutocompleteFlags() complete.Flags {
	return complete.Flags{
		"-color":            complete.PredictNothing,
		"-debug":            complete.PredictNothing,
		"-except":           complete.PredictNothing,
		"-only":             complete.PredictNothing,
		"-force":            complete.PredictNothing,
		"-machine-readable": complete.PredictNothing,
		"-on-error":         complete.PredictNothing,
		"-parallel":         complete.PredictNothing,
		"-timestamp-ui":     complete.PredictNothing,
		"-var":              complete.PredictNothing,
		"-var-file":         complete.PredictNothing,
	}
}
<commit_msg>change template parsing error to include warning about file extensions (#10652)<commit_after>package command

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"math"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclparse"
	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
	"github.com/hashicorp/packer-plugin-sdk/template"
	"github.com/hashicorp/packer/hcl2template"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/version"
	"golang.org/x/sync/semaphore"

	"github.com/hako/durafmt"
	"github.com/posener/complete"
)

type BuildCommand struct {
	Meta
}

func (c *BuildCommand) Run(args []string) int {
	ctx, cleanup := handleTermInterrupt(c.Ui)
	defer cleanup()

	cfg, ret := c.ParseArgs(args)
	if ret != 0 {
		return ret
	}

	return c.RunContext(ctx, cfg)
}

func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) {
	var cfg BuildArgs
	flags := c.Meta.FlagSet("build", FlagSetBuildFilter|FlagSetVars)
	flags.Usage = func() { c.Ui.Say(c.Help()) }
	cfg.AddFlagSets(flags)
	if err := flags.Parse(args); err != nil {
		return &cfg, 1
	}

	if cfg.ParallelBuilds < 1 {
		cfg.ParallelBuilds = math.MaxInt64
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		return &cfg, 1
	}
	cfg.Path = args[0]
	return &cfg, 0
}

func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (*hcl2template.PackerConfig, int) {
	parser := &hcl2template.Parser{
		CorePackerVersion:       version.SemVer,
		CorePackerVersionString: version.FormattedVersion(),
		Parser:                  hclparse.NewParser(),
		PluginConfig:            m.CoreConfig.Components.PluginConfig,
	}
	cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars)
	return cfg, writeDiags(m.Ui, parser.Files(), diags)
}

func writeDiags(ui packersdk.Ui, files map[string]*hcl.File, diags hcl.Diagnostics) int {
	// write HCL errors/diagnostics if any.
	b := bytes.NewBuffer(nil)
	err := hcl.NewDiagnosticTextWriter(b, files, 80, false).WriteDiagnostics(diags)
	if err != nil {
		ui.Error("could not write diagnostic: " + err.Error())
		return 1
	}
	if b.Len() != 0 {
		if diags.HasErrors() {
			ui.Error(b.String())
			return 1
		}
		ui.Say(b.String())
	}
	return 0
}

func (m *Meta) GetConfig(cla *MetaArgs) (packer.Handler, int) {
	cfgType, err := cla.GetConfigType()
	if err != nil {
		m.Ui.Error(fmt.Sprintf("%q: %s", cla.Path, err))
		return nil, 1
	}

	switch cfgType {
	case ConfigTypeHCL2:
		// TODO(azr): allow to pass a slice of files here.
		return m.GetConfigFromHCL(cla)
	default:
		// TODO: uncomment once we've polished HCL a bit more.
		// c.Ui.Say(`Legacy JSON Configuration Will Be Used.
		// The template will be parsed in the legacy configuration style. This style
		// will continue to work but users are encouraged to move to the new style.
		// See: https://packer.io/guides/hcl
		// `)
		return m.GetConfigFromJSON(cla)
	}
}

func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.Handler, int) {
	// Parse the template
	var tpl *template.Template
	var err error
	if cla.Path == "" {
		// here cla validation passed so this means we want a default builder
		// and we probably are in the console command
		tpl, err = template.Parse(TiniestBuilder)
	} else {
		tpl, err = template.ParseFile(cla.Path)
	}

	if err != nil {
		m.Ui.Error(fmt.Sprintf("Failed to parse file as legacy JSON template: "+
			"if you are using an HCL template, check your file extensions; they "+
			"should be either *.pkr.hcl or *.pkr.json; see the docs for more "+
			"details: https://www.packer.io/docs/templates/hcl_templates. \n"+
			"Original error: %s", err))
		return nil, 1
	}

	// Get the core
	core, err := m.Core(tpl, cla)
	ret := 0
	if err != nil {
		m.Ui.Error(err.Error())
		ret = 1
	}
	return &CoreWrapper{core}, ret
}

func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int {
	packerStarter, ret := c.GetConfig(&cla.MetaArgs)
	if ret != 0 {
		return ret
	}
	diags := packerStarter.Initialize(packer.InitializeOptions{})
	ret = writeDiags(c.Ui, nil, diags)
	if ret != 0 {
		return ret
	}

	builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{
		Only:    cla.Only,
		Except:  cla.Except,
		Debug:   cla.Debug,
		Force:   cla.Force,
		OnError: cla.OnError,
	})

	// here, something could have gone wrong but we still want to run valid
	// builds.
	ret = writeDiags(c.Ui, nil, diags)

	if cla.Debug {
		c.Ui.Say("Debug mode enabled. Builds will not be parallelized.")
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorCyan,
		packer.UiColorMagenta,
		packer.UiColorYellow,
		packer.UiColorBlue,
	}
	buildUis := make(map[packersdk.Build]packersdk.Ui)
	for i := range builds {
		ui := c.Ui
		if cla.Color {
			// Only set up UI colors if -machine-readable isn't set.
			if _, ok := c.Ui.(*packer.MachineReadableUi); !ok {
				ui = &packer.ColoredUi{
					Color: colors[i%len(colors)],
					Ui:    ui,
				}
				ui.Say(fmt.Sprintf("%s: output will be in this color.", builds[i].Name()))
				if i+1 == len(builds) {
					// Add a newline between the color output and the actual output
					c.Ui.Say("")
				}
			}
		}
		// Now add timestamps if requested
		if cla.TimestampUi {
			ui = &packer.TimestampedUi{
				Ui: ui,
			}
		}

		buildUis[builds[i]] = ui
	}

	log.Printf("Build debug mode: %v", cla.Debug)
	log.Printf("Force build: %v", cla.Force)
	log.Printf("On error: %v", cla.OnError)

	// Get the start of the build command
	buildCommandStart := time.Now()

	// Run all the builds in parallel and wait for them to complete
	var wg sync.WaitGroup
	var artifacts = struct {
		sync.RWMutex
		m map[string][]packersdk.Artifact
	}{m: make(map[string][]packersdk.Artifact)}
	// Get the builds we care about
	var errors = struct {
		sync.RWMutex
		m map[string]error
	}{m: make(map[string]error)}
	limitParallel := semaphore.NewWeighted(cla.ParallelBuilds)
	for i := range builds {
		if err := buildCtx.Err(); err != nil {
			log.Println("Interrupted, not going to start any more builds.")
			break
		}

		b := builds[i]
		name := b.Name()
		ui := buildUis[b]
		if err := limitParallel.Acquire(buildCtx, 1); err != nil {
			ui.Error(fmt.Sprintf("Build '%s' failed to acquire semaphore: %s", name, err))
			errors.Lock()
			errors.m[name] = err
			errors.Unlock()
			break
		}
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Run the build in a goroutine
		go func() {
			// Get the start of the build
			buildStart := time.Now()

			defer wg.Done()

			defer limitParallel.Release(1)

			log.Printf("Starting build run: %s", name)
			runArtifacts, err := b.Run(buildCtx, ui)

			// Get the duration of the build and parse it
			buildEnd := time.Now()
			buildDuration := buildEnd.Sub(buildStart)
			fmtBuildDuration := durafmt.Parse(buildDuration).LimitFirstN(2)

			if err != nil {
				ui.Error(fmt.Sprintf("Build '%s' errored after %s: %s", name, fmtBuildDuration, err))
				errors.Lock()
				errors.m[name] = err
				errors.Unlock()
			} else {
				ui.Say(fmt.Sprintf("Build '%s' finished after %s.", name, fmtBuildDuration))
				if nil != runArtifacts {
					artifacts.Lock()
					artifacts.m[name] = runArtifacts
					artifacts.Unlock()
				}
			}
		}()

		if cla.Debug {
			log.Printf("Debug enabled, so waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

		if cla.ParallelBuilds == 1 {
			log.Printf("Parallelization disabled, waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

	}

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	// Get the duration of the buildCommand command and parse it
	buildCommandEnd := time.Now()
	buildCommandDuration := buildCommandEnd.Sub(buildCommandStart)
	fmtBuildCommandDuration := durafmt.Parse(buildCommandDuration).LimitFirstN(2)
	c.Ui.Say(fmt.Sprintf("\n==> Wait completed after %s", fmtBuildCommandDuration))

	if err := buildCtx.Err(); err != nil {
		c.Ui.Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	if len(errors.m) > 0 {
		c.Ui.Machine("error-count", strconv.FormatInt(int64(len(errors.m)), 10))

		c.Ui.Error("\n==> Some builds didn't complete successfully and had errors:")
		for name, err := range errors.m {
			// Create a UI for the machine readable stuff to be targeted
			ui := &packer.TargetedUI{
				Target: name,
				Ui:     c.Ui,
			}

			ui.Machine("error", err.Error())

			c.Ui.Error(fmt.Sprintf("--> %s: %s", name, err))
		}
	}

	if len(artifacts.m) > 0 {
		c.Ui.Say("\n==> Builds finished. The artifacts of successful builds are:")
		for name, buildArtifacts := range artifacts.m {
			// Create a UI for the machine readable stuff to be targeted
			ui := &packer.TargetedUI{
				Target: name,
				Ui:     c.Ui,
			}

			// Machine-readable helpful
			ui.Machine("artifact-count", strconv.FormatInt(int64(len(buildArtifacts)), 10))

			for i, artifact := range buildArtifacts {
				var message bytes.Buffer
				fmt.Fprintf(&message, "--> %s: ", name)

				if artifact != nil {
					fmt.Fprint(&message, artifact.String())
				} else {
					fmt.Fprint(&message, "<nothing>")
				}

				iStr := strconv.FormatInt(int64(i), 10)
				if artifact != nil {
					ui.Machine("artifact", iStr, "builder-id", artifact.BuilderId())
					ui.Machine("artifact", iStr, "id", artifact.Id())
					ui.Machine("artifact", iStr, "string", artifact.String())

					files := artifact.Files()
					ui.Machine("artifact",
						iStr,
						"files-count", strconv.FormatInt(int64(len(files)), 10))
					for fi, file := range files {
						fiStr := strconv.FormatInt(int64(fi), 10)
						ui.Machine("artifact", iStr, "file", fiStr, file)
					}
				} else {
					ui.Machine("artifact", iStr, "nil")
				}

				ui.Machine("artifact", iStr, "end")
				c.Ui.Say(message.String())
			}
		}
	} else {
		c.Ui.Say("\n==> Builds finished but no artifacts were created.")
	}

	if len(errors.m) > 0 {
		// If any errors occurred, exit with a non-zero exit status
		ret = 1
	}

	return ret
}

func (*BuildCommand) Help() string {
	helpText := `
Usage: packer build [options] TEMPLATE

  Will execute multiple builds in parallel as defined in the template.
  The various artifacts created by the template will be outputted.

Options:

  -color=false                  Disable color output. (Default: color)
  -debug                        Debug mode enabled for builds.
  -except=foo,bar,baz           Run all builds and post-processors other than these.
  -only=foo,bar,baz             Build only the specified builds.
  -force                        Force a build to continue if artifacts exist, deletes existing artifacts.
  -machine-readable             Produce machine-readable output.
  -on-error=[cleanup|abort|ask|run-cleanup-provisioner] If the build fails do: clean up (default), abort, ask, or run-cleanup-provisioner.
  -parallel-builds=1            Number of builds to run in parallel. 1 disables parallelization. 0 means no limit (Default: 0)
  -timestamp-ui                 Enable prefixing of each ui output with an RFC3339 timestamp.
  -var 'key=value'              Variable for templates, can be used multiple times.
  -var-file=path                JSON or HCL2 file containing user variables.
`

	return strings.TrimSpace(helpText)
}

func (*BuildCommand) Synopsis() string {
	return "build image(s) from template"
}

func (*BuildCommand) AutocompleteArgs() complete.Predictor {
	return complete.PredictNothing
}

func (*BuildCommand) AutocompleteFlags() complete.Flags {
	return complete.Flags{
		"-color":            complete.PredictNothing,
		"-debug":            complete.PredictNothing,
		"-except":           complete.PredictNothing,
		"-only":             complete.PredictNothing,
		"-force":            complete.PredictNothing,
		"-machine-readable": complete.PredictNothing,
		"-on-error":         complete.PredictNothing,
		"-parallel":         complete.PredictNothing,
		"-timestamp-ui":     complete.PredictNothing,
		"-var":              complete.PredictNothing,
		"-var-file":         complete.PredictNothing,
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/plans"
	"github.com/hashicorp/terraform/tfdiags"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/terraform"
)

// GraphCommand is a Command implementation that takes a Terraform
// configuration and outputs the dependency tree in graphical form.
type GraphCommand struct {
	Meta
}

func (c *GraphCommand) Run(args []string) int {
	var drawCycles bool
	var graphTypeStr string
	var moduleDepth int
	var verbose bool

	args, err := c.Meta.process(args, false)
	if err != nil {
		return 1
	}

	cmdFlags := c.Meta.defaultFlagSet("graph")
	cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles")
	cmdFlags.StringVar(&graphTypeStr, "type", "", "type")
	cmdFlags.IntVar(&moduleDepth, "module-depth", -1, "module-depth")
	cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	configPath, err := ModulePath(cmdFlags.Args())
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Check if the path is a plan
	var plan *plans.Plan
	planFile, err := c.PlanFile(configPath)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if planFile != nil {
		// Reset for backend loading
		configPath = ""
	}

	var diags tfdiags.Diagnostics

	backendConfig, backendDiags := c.loadBackendConfig(configPath)
	diags = diags.Append(backendDiags)
	if diags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Load the backend
	b, backendDiags := c.Backend(&BackendOpts{
		Config: backendConfig,
	})
	diags = diags.Append(backendDiags)
	if backendDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// We require a local backend
	local, ok := b.(backend.Local)
	if !ok {
		c.showDiagnostics(diags) // in case of any warnings in here
		c.Ui.Error(ErrUnsupportedLocalOp)
		return 1
	}

	// Build the operation
	opReq := c.Operation(b)
	opReq.ConfigDir = configPath
	opReq.ConfigLoader, err = c.initConfigLoader()
	opReq.PlanFile = planFile
	if err != nil {
		diags = diags.Append(err)
		c.showDiagnostics(diags)
		return 1
	}

	// Get the context
	ctx, _, ctxDiags := local.Context(opReq)
	diags = diags.Append(ctxDiags)
	if ctxDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	defer func() {
		err := opReq.StateLocker.Unlock(nil)
		if err != nil {
			c.Ui.Error(err.Error())
		}
	}()

	// Determine the graph type
	graphType := terraform.GraphTypePlan
	if plan != nil {
		graphType = terraform.GraphTypeApply
	}

	if graphTypeStr != "" {
		v, ok := terraform.GraphTypeMap[graphTypeStr]
		if !ok {
			c.Ui.Error(fmt.Sprintf("Invalid graph type requested: %s", graphTypeStr))
			return 1
		}

		graphType = v
	}

	// Skip validation during graph generation - we want to see the graph even if
	// it is invalid for some reason.
	g, graphDiags := ctx.Graph(graphType, &terraform.ContextGraphOpts{
		Verbose:  verbose,
		Validate: false,
	})
	diags = diags.Append(graphDiags)
	if graphDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	graphStr, err := terraform.GraphDot(g, &dag.DotOpts{
		DrawCycles: drawCycles,
		MaxDepth:   moduleDepth,
		Verbose:    verbose,
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error converting graph: %s", err))
		return 1
	}

	if diags.HasErrors() {
		// For this command we only show diagnostics if there are errors,
		// because printing out naked warnings could upset a naive program
		// consuming our dot output.
		c.showDiagnostics(diags)
		return 1
	}

	c.Ui.Output(graphStr)

	return 0
}

func (c *GraphCommand) Help() string {
	helpText := `
Usage: terraform graph [options] [DIR]

  Outputs the visual execution graph of Terraform resources according to
  configuration files in DIR (or the current directory if omitted).

  The graph is outputted in DOT format. The typical program that can
  read this format is GraphViz, but many web services are also available
  to read this format.

  The -type flag can be used to control the type of graph shown. Terraform
  creates different graphs for different operations. See the options below
  for the list of types supported. The default type is "plan" if a
  configuration is given, and "apply" if a plan file is passed as an
  argument.

Options:

  -draw-cycles     Highlight any cycles in the graph with colored edges.
                   This helps when diagnosing cycle errors.

  -module-depth=n  Specifies the depth of modules to show in the output.
                   By default this is -1, which will expand all.

  -type=plan       Type of graph to output. Can be: plan, plan-destroy, apply,
                   validate, input, refresh.

`
	return strings.TrimSpace(helpText)
}

func (c *GraphCommand) Synopsis() string {
	return "Create a visual graph of Terraform resources"
}
<commit_msg>command/graph: use user-supplied plugin path when running graph command (#18083)<commit_after>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/terraform/plans"
	"github.com/hashicorp/terraform/tfdiags"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/terraform"
)

// GraphCommand is a Command implementation that takes a Terraform
// configuration and outputs the dependency tree in graphical form.
type GraphCommand struct {
	Meta
}

func (c *GraphCommand) Run(args []string) int {
	var drawCycles bool
	var graphTypeStr string
	var moduleDepth int
	var verbose bool

	args, err := c.Meta.process(args, false)
	if err != nil {
		return 1
	}

	cmdFlags := c.Meta.defaultFlagSet("graph")
	cmdFlags.BoolVar(&drawCycles, "draw-cycles", false, "draw-cycles")
	cmdFlags.StringVar(&graphTypeStr, "type", "", "type")
	cmdFlags.IntVar(&moduleDepth, "module-depth", -1, "module-depth")
	cmdFlags.BoolVar(&verbose, "verbose", false, "verbose")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	configPath, err := ModulePath(cmdFlags.Args())
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Check for user-supplied plugin path
	if c.pluginPath, err = c.loadPluginPath(); err != nil {
		c.Ui.Error(fmt.Sprintf("Error loading plugin path: %s", err))
		return 1
	}

	// Check if the path is a plan
	var plan *plans.Plan
	planFile, err := c.PlanFile(configPath)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if planFile != nil {
		// Reset for backend loading
		configPath = ""
	}

	var diags tfdiags.Diagnostics

	backendConfig, backendDiags := c.loadBackendConfig(configPath)
	diags = diags.Append(backendDiags)
	if diags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// Load the backend
	b, backendDiags := c.Backend(&BackendOpts{
		Config: backendConfig,
	})
	diags = diags.Append(backendDiags)
	if backendDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	// We require a local backend
	local, ok := b.(backend.Local)
	if !ok {
		c.showDiagnostics(diags) // in case of any warnings in here
		c.Ui.Error(ErrUnsupportedLocalOp)
		return 1
	}

	// Build the operation
	opReq := c.Operation(b)
	opReq.ConfigDir = configPath
	opReq.ConfigLoader, err = c.initConfigLoader()
	opReq.PlanFile = planFile
	if err != nil {
		diags = diags.Append(err)
		c.showDiagnostics(diags)
		return 1
	}

	// Get the context
	ctx, _, ctxDiags := local.Context(opReq)
	diags = diags.Append(ctxDiags)
	if ctxDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	defer func() {
		err := opReq.StateLocker.Unlock(nil)
		if err != nil {
			c.Ui.Error(err.Error())
		}
	}()

	// Determine the graph type
	graphType := terraform.GraphTypePlan
	if plan != nil {
		graphType = terraform.GraphTypeApply
	}

	if graphTypeStr != "" {
		v, ok := terraform.GraphTypeMap[graphTypeStr]
		if !ok {
			c.Ui.Error(fmt.Sprintf("Invalid graph type requested: %s", graphTypeStr))
			return 1
		}

		graphType = v
	}

	// Skip validation during graph generation - we want to see the graph even if
	// it is invalid for some reason.
	g, graphDiags := ctx.Graph(graphType, &terraform.ContextGraphOpts{
		Verbose:  verbose,
		Validate: false,
	})
	diags = diags.Append(graphDiags)
	if graphDiags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	graphStr, err := terraform.GraphDot(g, &dag.DotOpts{
		DrawCycles: drawCycles,
		MaxDepth:   moduleDepth,
		Verbose:    verbose,
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error converting graph: %s", err))
		return 1
	}

	if diags.HasErrors() {
		// For this command we only show diagnostics if there are errors,
		// because printing out naked warnings could upset a naive program
		// consuming our dot output.
		c.showDiagnostics(diags)
		return 1
	}

	c.Ui.Output(graphStr)

	return 0
}

func (c *GraphCommand) Help() string {
	helpText := `
Usage: terraform graph [options] [DIR]

  Outputs the visual execution graph of Terraform resources according to
  configuration files in DIR (or the current directory if omitted).

  The graph is outputted in DOT format. The typical program that can
  read this format is GraphViz, but many web services are also available
  to read this format.

  The -type flag can be used to control the type of graph shown. Terraform
  creates different graphs for different operations. See the options below
  for the list of types supported. The default type is "plan" if a
  configuration is given, and "apply" if a plan file is passed as an
  argument.

Options:

  -draw-cycles     Highlight any cycles in the graph with colored edges.
                   This helps when diagnosing cycle errors.

  -module-depth=n  Specifies the depth of modules to show in the output.
                   By default this is -1, which will expand all.

  -type=plan       Type of graph to output. Can be: plan, plan-destroy, apply,
                   validate, input, refresh.

`
	return strings.TrimSpace(helpText)
}

func (c *GraphCommand) Synopsis() string {
	return "Create a visual graph of Terraform resources"
}
<|endoftext|>


<commit_before>package command

import (
	"encoding/json"
	"log"
	"math/rand"
	"regexp"
)

const (
	ImageSearchUrl = "http://ajax.googleapis.com/ajax/services/search/images"
)

type ImageCommand struct {
	pattern *regexp.Regexp
}

func Image() ImageCommand {
	return ImageCommand{regexp.MustCompile(`(?i)(image|img)\s+([^\s].*)`)}
}

func (c ImageCommand) Pattern() *regexp.Regexp {
	return c.pattern
}

func (c ImageCommand) Run(query string) []string {
	return findImages(query, Params{})
}

type GIFCommand struct {
	pattern *regexp.Regexp
}

func GIF() GIFCommand {
	return GIFCommand{regexp.MustCompile(`(?i)(gif|animate)\s+([^\s].*)`)}
}

func (c GIFCommand) Pattern() *regexp.Regexp {
	return c.pattern
}

func (c GIFCommand) Run(query string) []string {
	return findImages(query, Params{"imgtype": "animated"})
}

type Params map[string]string

var defaultParams = Params{
	"v":    "1.0",
	"safe": "active",
	"rsz":  "8",
}

type ImageResult struct {
	UnescapedUrl string `json:"unescapedUrl"`
}

type ResponseData struct {
	Images []ImageResult `json:"results"`
}

type ImageResults struct {
	Data ResponseData `json:"responseData"`
}

func findImages(query string, params Params) []string {
	for k, v := range defaultParams {
		params[k] = v
	}
	params["q"] = query

	var imgUrl string

	if body, err := NewHTTPClient(ImageSearchUrl).With(params).Get(); err == nil {
		var result ImageResults
		json.Unmarshal(body, &result)

		if images := result.Data.Images; len(images) > 0 {
			selected := images[rand.Intn(len(images))]

			imgUrl = selected.UnescapedUrl
		}
	} else {
		log.Println("ERROR:", err)
	}

	var urls []string
	if imgUrl != "" {
		urls = append(urls, imgUrl)
	}
	return urls
}
<commit_msg>Inline struct for image search results.<commit_after>package command

import (
	"encoding/json"
	"log"
	"math/rand"
	"regexp"
)

const (
	ImageSearchUrl = "http://ajax.googleapis.com/ajax/services/search/images"
)

type ImageCommand struct {
	pattern *regexp.Regexp
}

func Image() ImageCommand {
	return ImageCommand{regexp.MustCompile(`(?i)(image|img)\s+([^\s].*)`)}
}

func (c ImageCommand) Pattern() *regexp.Regexp {
	return c.pattern
}

func (c ImageCommand) Run(query string) []string {
	return findImages(query, Params{})
}

type GIFCommand struct {
	pattern *regexp.Regexp
}

func GIF() GIFCommand {
	return GIFCommand{regexp.MustCompile(`(?i)(gif|animate)\s+([^\s].*)`)}
}

func (c GIFCommand) Pattern() *regexp.Regexp {
	return c.pattern
}

func (c GIFCommand) Run(query string) []string {
	return findImages(query, Params{"imgtype": "animated"})
}

type Params map[string]string

var defaultParams = Params{
	"v":    "1.0",
	"safe": "active",
	"rsz":  "8",
}

type imageResults struct {
	Data struct {
		Images []struct {
			UnescapedUrl string `json:"unescapedUrl"`
		} `json:"results"`
	} `json:"responseData"`
}

func findImages(query string, params Params) []string {
	for k, v := range defaultParams {
		params[k] = v
	}
	params["q"] = query

	var imgUrl string

	if body, err := NewHTTPClient(ImageSearchUrl).With(params).Get(); err == nil {
		var result imageResults
		json.Unmarshal(body, &result)

		if images := result.Data.Images; len(images) > 0 {
			selected := images[rand.Intn(len(images))]

			imgUrl = selected.UnescapedUrl
		}
	} else {
		log.Println("ERROR:", err)
	}

	var urls []string
	if imgUrl != "" {
		urls = append(urls, imgUrl)
	}
	return urls
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/takipone/soracom-sdk-go"
)

const cfnStackName string = "Cassiopeia"
const soracomName string = "Cassiopeia"

type SetupCommand struct {
	Meta
}

func (c *SetupCommand) Run(args []string) int {
	// Create CloudTransit(Kinesis Stream and IAM Role by CloudFormation)
	svc := cloudformation.New(session.New(), &aws.Config{Region: aws.String("ap-northeast-1")})
	params := &cloudformation.DescribeStacksInput{
		StackName: aws.String(cfnStackName),
	}
	resp, err := svc.DescribeStacks(params)
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}
	if len(resp.Stacks) == 0 {
		params := &cloudformation.CreateStackInput{
			StackName:    aws.String(cfnStackName),
			Capabilities: []*string{aws.String("CAPABILITY_IAM")},
			Parameters: []*cloudformation.Parameter{{
				ParameterKey:     aws.String("ShardCount"),
				ParameterValue:   aws.String("1"),
				UsePreviousValue: aws.Bool(true),
			}},
			TemplateBody: aws.String(`
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Cassiopeia datastore and credentials stack",
  "Parameters": {
    "ShardCount": {
      "Description": "Number of Shards.",
      "Type": "Number",
      "Default": "1"
    }
  },
  "Resources": {
    "CloudTransit": {
      "Type": "AWS::Kinesis::Stream",
      "Properties": {
        "ShardCount": {
          "Ref": "ShardCount"
        }
      }
    },
    "EdgeTransitUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "Policies" : [ {
           "PolicyName" : "AllowKinesisPutRecord",
           "PolicyDocument" : {
              "Version": "2012-10-17",
              "Statement" : [ {
                 "Effect" : "Allow",
                 "Action" : "kinesis:Put*",
                 "Resource" : [ {
                    "Fn::GetAtt" : [ "CloudTransit", "Arn" ]
                 } ]
              } ]
           }
        } ]
      }
    },
    "ProcessorUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "Policies" : [ {
          "PolicyName" : "AllowKinesisGetRecord",
          "PolicyDocument" : {
            "Version": "2012-10-17",
            "Statement" : [
              {
                "Effect" : "Allow",
                "Action" : "kinesis:Get*",
                "Resource" : { "Fn::GetAtt" : [ "CloudTransit", "Arn" ] }
              },
              {
                "Effect": "Allow",
                "Action": [
                  "logs:CreateLogGroup",
                  "logs:CreateLogStream",
                  "logs:PutLogEvents"
                ],
                "Resource": "*"
              }
            ]
          }
        } ]
      }
    },
    "EdgeTransitAccessKey": {
       "Type" : "AWS::IAM::AccessKey",
       "Properties" : {
          "UserName" : { "Ref" : "EdgeTransitUser" }
       }
    },
    "ProcessorAccessKey": {
       "Type" : "AWS::IAM::AccessKey",
       "Properties" : {
          "UserName" : { "Ref" : "ProcessorUser" }
       }
    }
  },
  "Outputs": {
    "CloudTransit": { "Value": { "Ref": "CloudTransit" } },
    "EdgeTransitAccessKey": { "Value": { "Ref": "EdgeTransitAccessKey" } },
    "EdgeTransitSecretKey": { "Value": { "Fn::GetAtt" : [ "EdgeTransitAccessKey", "SecretAccessKey" ] } },
    "ProcessorAccessKey": { "Value": { "Ref": "ProcessorAccessKey" } },
    "ProcessorSecretKey": { "Value": { "Fn::GetAtt" : [ "ProcessorAccessKey", "SecretAccessKey" ] } }
  }
}
`),
		}
		_, err = svc.CreateStack(params)
		if err != nil {
			fmt.Println(err.Error())
			return 1
		}
		fmt.Print("CloudTransit creating.")
	}

	ct := map[string]string{}
	// Wait for the cloud transit has created.
	for {
		params := &cloudformation.DescribeStacksInput{
			StackName: aws.String(cfnStackName),
		}
		resp, err := svc.DescribeStacks(params)
		if err != nil {
			fmt.Println(err.Error())
			return 1
		}
		if *resp.Stacks[0].StackStatus == "CREATE_COMPLETE" {
			for _, v := range resp.Stacks[0].Outputs {
				ct[*v.OutputKey] = *v.OutputValue
			}
			break
		}
		fmt.Print(".")
		time.Sleep(30 * time.Second)
	}

	// Setup EdgeTransit
	ac := soracom.NewAPIClient(nil)
	email := os.Getenv("SORACOM_EMAIL")
	password := os.Getenv("SORACOM_PASSWORD")
	if email == "" {
		fmt.Println("SORACOM_EMAIL env var is required")
		return 1
	}
	if password == "" {
		fmt.Println("SORACOM_PASSWORD env var is required")
		return 1
	}

	err = ac.Auth(email, password)
	if err != nil {
		fmt.Printf("auth err: %v\n", err.Error())
		return 1
	}

	// Set AWS Credential into SORACOM Credential.
	o := &soracom.CredentialOptions{
		Type:        "aws-credentials",
		Description: "Cassiopeia credential",
		Credentials: soracom.Credentials{
			AccessKeyId:     ct["EdgeTransitAccessKey"],
			SecretAccessKey: ct["EdgeTransitSecretKey"],
		},
	}
	cr, err := ac.CreateCredentialWithName(soracomName, o)
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}
	fmt.Println("SORACOM Credential: " + cr.CredentialId + " created.")

	g, err := ac.CreateGroupWithName(soracomName)
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}
	fmt.Println("SORACOM Group: " + soracomName + " created.")
	gc := []soracom.GroupConfig{
		{
			Key:   "enabled",
			Value: "true",
		}, {
			Key:   "credentialsId",
			Value: cr.CredentialId,
		}, {
			Key: "destination",
			Value: soracom.FunnelDestinationConfig{
				Provider:    "aws",
				Service:     "kinesis",
				ResourceUrl: "https://kinesis.ap-northeast-1.amazonaws.com/" + ct["CloudTransit"],
			},
		}, {
			Key:   "contentType",
			Value: "",
		},
	}
	_, err = ac.UpdateGroupConfigurations(g.GroupID, "SoracomFunnel", gc)
	if err != nil {
		fmt.Println(err.Error())
		return 1
	}
	fmt.Println("update Group Configuration.")

	return 0
}

func (c *SetupCommand) Synopsis() string {
	return "Initialize(Create) components"
}
func (c *SetupCommand) Help() string {
	helpText := `
Usage: cas setup [options]

	Initialize(Create) components.

Options:

`
	return strings.TrimSpace(helpText)
}
<commit_msg>implement Docker PullImage<commit_after>package command

import (
	"bytes"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/fsouza/go-dockerclient"
	"github.com/takipone/soracom-sdk-go"
)

const cfnStackName string = "Cassiopeia"
const soracomName string = "Cassiopeia"

type SetupCommand struct {
	Meta
}

func (c *SetupCommand) Run(args []string) int {
	// Create CloudTransit(Kinesis Stream and IAM Role by CloudFormation)
	svc := cloudformation.New(session.New(), &aws.Config{Region: aws.String("ap-northeast-1")})
	params := &cloudformation.ListStacksInput{
		StackStatusFilter: []*string{
			aws.String("CREATE_COMPLETE"),
		},
	}
	lso, err := svc.ListStacks(params)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	var flag bool = false
	for _, v := range lso.StackSummaries {
		if *v.StackName == cfnStackName {
			flag = true
			break
		}
	}
	if !flag {
		params := &cloudformation.CreateStackInput{
			StackName:    aws.String(cfnStackName),
			Capabilities: []*string{aws.String("CAPABILITY_IAM")},
			Parameters: []*cloudformation.Parameter{{
				ParameterKey:     aws.String("ShardCount"),
				ParameterValue:   aws.String("1"),
				UsePreviousValue: aws.Bool(true),
			}},
			TemplateBody: aws.String(`
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Cassiopeia datastore and credentials stack",
  "Parameters": {
    "ShardCount": {
      "Description": "Number of Shards.",
      "Type": "Number",
      "Default": "1"
    }
  },
  "Resources": {
    "CloudTransit": {
      "Type": "AWS::Kinesis::Stream",
      "Properties": {
        "ShardCount": {
          "Ref": "ShardCount"
        }
      }
    },
    "EdgeTransitUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "Policies" : [ {
           "PolicyName" : "AllowKinesisPutRecord",
           "PolicyDocument" : {
              "Version": "2012-10-17",
              "Statement" : [ {
                 "Effect" : "Allow",
                 "Action" : "kinesis:Put*",
                 "Resource" : [ {
                    "Fn::GetAtt" : [ "CloudTransit", "Arn" ]
                 } ]
              } ]
           }
        } ]
      }
    },
    "ProcessorUser": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "Policies" : [ {
          "PolicyName" : "AllowKinesisGetRecord",
          "PolicyDocument" : {
            "Version": "2012-10-17",
            "Statement" : [
              {
                "Effect" : "Allow",
                "Action" : "kinesis:Get*",
                "Resource" : { "Fn::GetAtt" : [ "CloudTransit", "Arn" ] }
              },
              {
                "Effect": "Allow",
                "Action": [
                  "logs:CreateLogGroup",
                  "logs:CreateLogStream",
                  "logs:PutLogEvents"
                ],
                "Resource": "*"
              }
            ]
          }
        } ]
      }
    },
    "EdgeTransitAccessKey": {
       "Type" : "AWS::IAM::AccessKey",
       "Properties" : {
          "UserName" : { "Ref" : "EdgeTransitUser" }
       }
    },
    "ProcessorAccessKey": {
       "Type" : "AWS::IAM::AccessKey",
       "Properties" : {
          "UserName" : { "Ref" : "ProcessorUser" }
       }
    }
  },
  "Outputs": {
    "CloudTransit": { "Value": { "Ref": "CloudTransit" } },
    "EdgeTransitAccessKey": { "Value": { "Ref": "EdgeTransitAccessKey" } },
    "EdgeTransitSecretKey": { "Value": { "Fn::GetAtt" : [ "EdgeTransitAccessKey", "SecretAccessKey" ] } },
    "ProcessorAccessKey": { "Value": { "Ref": "ProcessorAccessKey" } },
    "ProcessorSecretKey": { "Value": { "Fn::GetAtt" : [ "ProcessorAccessKey", "SecretAccessKey" ] } }
  }
}
`),
		}
		_, err = svc.CreateStack(params)
		if err != nil {
			c.Ui.Error(err.Error())
			return 1
		}
		c.Ui.Info("CloudTransit creating.")
	} else {
		c.Ui.Info("CloudTransit already exists.")
	}

	ct := map[string]string{}
	// Wait for the cloud transit has created.
	for {
		params := &cloudformation.DescribeStacksInput{
			StackName: aws.String(cfnStackName),
		}
		resp, err := svc.DescribeStacks(params)
		if err != nil {
			c.Ui.Error(err.Error())
			return 1
		}
		if *resp.Stacks[0].StackStatus == "CREATE_COMPLETE" {
			for _, v := range resp.Stacks[0].Outputs {
				ct[*v.OutputKey] = *v.OutputValue
			}
			break
		}
		c.Ui.Info(".")
		// fmt.Print(".")
		time.Sleep(30 * time.Second)
	}

	// Setup EdgeTransit
	ac := soracom.NewAPIClient(nil)
	email := os.Getenv("SORACOM_EMAIL")
	password := os.Getenv("SORACOM_PASSWORD")
	if email == "" {
		c.Ui.Error("SORACOM_EMAIL env var is required")
		return 1
	}
	if password == "" {
		c.Ui.Error("SORACOM_PASSWORD env var is required")
		return 1
	}

	err = ac.Auth(email, password)
	if err != nil {
		c.Ui.Error("SORACOM Auth err: %v\n" + err.Error())
		return 1
	}

	// Set AWS Credential into SORACOM Credential.
	o := &soracom.CredentialOptions{
		Type:        "aws-credentials",
		Description: "Cassiopeia credential",
		Credentials: soracom.Credentials{
			AccessKeyId:     ct["EdgeTransitAccessKey"],
			SecretAccessKey: ct["EdgeTransitSecretKey"],
		},
	}

	cr, err := ac.CreateCredentialWithName(soracomName, o)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	c.Ui.Info("EdgeTransit(SORACOM) Credential: " + cr.CredentialId + " created.")

	g, err := ac.CreateGroupWithName(soracomName)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	c.Ui.Info("EdgeTransit(SORACOM) Configuration: " + soracomName + " created.")
	gc := []soracom.GroupConfig{
		{
			Key:   "enabled",
			Value: "true",
		}, {
			Key:   "credentialsId",
			Value: cr.CredentialId,
		}, {
			Key: "destination",
			Value: soracom.FunnelDestinationConfig{
				Provider:    "aws",
				Service:     "kinesis",
				ResourceUrl: "https://kinesis.ap-northeast-1.amazonaws.com/" + ct["CloudTransit"],
			},
		}, {
			Key:   "contentType",
			Value: "",
		},
	}
	_, err = ac.UpdateGroupConfigurations(g.GroupID, "SoracomFunnel", gc)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	c.Ui.Info("EdgeTransit Configuration updated.")

	// Setup Analyzer(Local/Docker)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	var buf bytes.Buffer
	opts := docker.PullImageOptions{
		Repository:   "sebp/elk",
		Tag:          "latest",
		OutputStream: &buf,
	}
	err = client.PullImage(opts, docker.AuthConfiguration{})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	return 0
}

func (c *SetupCommand) Synopsis() string {
	return "Initialize(Create) components"
}
func (c *SetupCommand) Help() string {
	helpText := `
Usage: cas setup [options]

	Initialize(Create) components.

Options:

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>