<commit_before>// +build windows

package i18n_test

import (
	"os"
	"path/filepath"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/i18n"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	"github.com/pivotal-cf-experimental/jibber_jabber"

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

var _ = Describe("i18n.Init() function", func() {
	var (
		configRepo core_config.ReadWriter
	)

	BeforeEach(func() {
		i18n.Resources_path = filepath.Join("cf", "i18n", "test_fixtures")
		configRepo = testconfig.NewRepositoryWithDefaults()
	})

	Describe("When a user has a locale configuration set", func() {
		Context("creates a valid T function", func() {
			BeforeEach(func() {
				configRepo.SetLocale("en_US")
			})

			It("returns a usable T function for simple strings", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Hello world!")
				Ω("Hello world!").Should(Equal(translation))
			})

			It("returns a usable T function for complex strings (interpolated)", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Deleting domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{"DomainName": "foo.com", "Username": "Anand"})
				Ω("Deleting domain foo.com as Anand...").Should(Equal(translation))
			})
		})
	})

	Describe("When a user does not have a locale configuration set", func() {
		BeforeEach(func() {
			//All these tests require the system language to be English
			Ω(jibber_jabber.DetectIETF()).Should(Equal("en-US"))
		})

		Context("creates a valid T function", func() {
			BeforeEach(func() {
				os.Setenv("LC_ALL", "en_US.UTF-8")
			})

			It("returns a usable T function for simple strings", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Change user password")
				Ω("Change user password").Should(Equal(translation))
			})

			It("returns a usable T function for complex strings (interpolated)", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Deleting domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{"DomainName": "foo", "Username": "Anand"})
				Ω("Deleting domain foo as Anand...").Should(Equal(translation))
			})
		})

		It("matches zh_CN to zh_Hans", func() {
			os.Setenv("LC_ALL", "zh_CN.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("buildpack未找到").Should(Equal(translation))
		})

		It("matches zh_TW to zh_Hant", func() {
			os.Setenv("LC_ALL", "zh_TW.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("(Hant)No buildpacks found").Should(Equal(translation))
		})

		It("matches zh_HK to zh_Hant", func() {
			os.Setenv("LC_ALL", "zh_HK.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("(Hant)No buildpacks found").Should(Equal(translation))
		})
	})
})
<commit_msg>fix failing HK/TW Windows 32 unit test<commit_after>// +build windows

package i18n_test

import (
	"os"
	"path/filepath"

	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/i18n"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	"github.com/pivotal-cf-experimental/jibber_jabber"

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

var _ = Describe("i18n.Init() function", func() {
	var (
		configRepo core_config.ReadWriter
	)

	BeforeEach(func() {
		i18n.Resources_path = filepath.Join("cf", "i18n", "test_fixtures")
		configRepo = testconfig.NewRepositoryWithDefaults()
	})

	Describe("When a user has a locale configuration set", func() {
		Context("creates a valid T function", func() {
			BeforeEach(func() {
				configRepo.SetLocale("en_US")
			})

			It("returns a usable T function for simple strings", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Hello world!")
				Ω("Hello world!").Should(Equal(translation))
			})

			It("returns a usable T function for complex strings (interpolated)", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Deleting domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{"DomainName": "foo.com", "Username": "Anand"})
				Ω("Deleting domain foo.com as Anand...").Should(Equal(translation))
			})
		})
	})

	Describe("When a user does not have a locale configuration set", func() {
		BeforeEach(func() {
			os.Setenv("LC_ALL", "en_US.UTF-8")

			//All these tests require the system language to be English
			Ω(jibber_jabber.DetectIETF()).Should(Equal("en-US"))
		})

		Context("creates a valid T function", func() {
			It("returns a usable T function for simple strings", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Change user password")
				Ω("Change user password").Should(Equal(translation))
			})

			It("returns a usable T function for complex strings (interpolated)", func() {
				T := i18n.Init(configRepo)
				Ω(T).ShouldNot(BeNil())

				translation := T("Deleting domain {{.DomainName}} as {{.Username}}...", map[string]interface{}{"DomainName": "foo", "Username": "Anand"})
				Ω("Deleting domain foo as Anand...").Should(Equal(translation))
			})
		})

	})

	Describe("When locale is HK/TW", func() {
		It("matches zh_CN to zh_Hans", func() {
			os.Setenv("LC_ALL", "zh_CN.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("buildpack未找到").Should(Equal(translation))
		})

		It("matches zh_TW to zh_Hant", func() {
			os.Setenv("LC_ALL", "zh_TW.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("(Hant)No buildpacks found").Should(Equal(translation))
		})

		It("matches zh_HK to zh_Hant", func() {
			os.Setenv("LC_ALL", "zh_HK.UTF-8")
			T := i18n.Init(configRepo)
			Ω(T).ShouldNot(BeNil())

			translation := T("No buildpacks found")
			Ω("(Hant)No buildpacks found").Should(Equal(translation))
		})
	})
})
<|endoftext|>


<commit_before>package routing

import (
	"net/http"
	"time"

	"github.com/leanovate/microtools/logging"
)

var flowIDHeaderNames = []string{"X-Flow-Id"}

type loggingResponseWriter struct {
	status        int
	responseBytes int
	underlying    http.ResponseWriter
}

func (l *loggingResponseWriter) Header() http.Header {
	return l.underlying.Header()
}

func (l *loggingResponseWriter) Write(bytes []byte) (int, error) {
	n, err := l.underlying.Write(bytes)
	if err != nil {
		l.responseBytes += n
	}
	return n, err
}

func (l *loggingResponseWriter) WriteHeader(status int) {
	l.status = status
	l.underlying.WriteHeader(status)
}

// LoggingHandler is a http.Handler that logs and delegates all requests.
type LoggingHandler struct {
	delegate http.Handler
	logger   logging.Logger
}

// NewLoggingHandler create a new LoggingHandler.
func NewLoggingHandler(delegate http.Handler, logger logging.Logger) http.Handler {
	return &LoggingHandler{
		delegate: delegate,
		logger:   logger,
	}
}

func (l *LoggingHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	start := time.Now()
	loggingResp := &loggingResponseWriter{
		status:     -1,
		underlying: resp,
	}
	l.delegate.ServeHTTP(loggingResp, req)
	elapsed := time.Since(start)
	flowID := flowIDFromHeaders(req)
	log := l.logger.WithContext(map[string]interface{}{
		"method":  req.Method,
		"uri":     req.RequestURI,
		"status":  loggingResp.status,
		"time":    elapsed.String(),
		"millis":  float64(elapsed.Nanoseconds()) / 1000000.0,
		"bytes":   loggingResp.responseBytes,
		"flow_id": flowID,
	})
	if loggingResp.status < 300 {
		log.Info("Request: Success")
	} else if loggingResp.status < 400 {
		log.Info("Request: Redirect")
	} else if loggingResp.status < 500 {
		log.Warn("Request: Client error")
	} else {
		log.Error("Request: Server error")
	}
}

func flowIDFromHeaders(req *http.Request) string {
	for _, headerName := range flowIDHeaderNames {
		if flowID := req.Header.Get(headerName); flowID != "" {
			return flowID
		}
	}
	return ""
}
<commit_msg>[feat] add User-Agent to log file<commit_after>package routing

import (
	"net/http"
	"time"

	"github.com/leanovate/microtools/logging"
)

var flowIDHeaderNames = []string{"X-Flow-Id"}

type loggingResponseWriter struct {
	status        int
	responseBytes int
	underlying    http.ResponseWriter
}

func (l *loggingResponseWriter) Header() http.Header {
	return l.underlying.Header()
}

func (l *loggingResponseWriter) Write(bytes []byte) (int, error) {
	n, err := l.underlying.Write(bytes)
	if err != nil {
		l.responseBytes += n
	}
	return n, err
}

func (l *loggingResponseWriter) WriteHeader(status int) {
	l.status = status
	l.underlying.WriteHeader(status)
}

// LoggingHandler is a http.Handler that logs and delegates all requests.
type LoggingHandler struct {
	delegate http.Handler
	logger   logging.Logger
}

// NewLoggingHandler create a new LoggingHandler.
func NewLoggingHandler(delegate http.Handler, logger logging.Logger) http.Handler {
	return &LoggingHandler{
		delegate: delegate,
		logger:   logger,
	}
}

func (l *LoggingHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	start := time.Now()
	loggingResp := &loggingResponseWriter{
		status:     -1,
		underlying: resp,
	}
	l.delegate.ServeHTTP(loggingResp, req)
	elapsed := time.Since(start)
	flowID := flowIDFromHeaders(req)
	log := l.logger.WithContext(map[string]interface{}{
		"method":     req.Method,
		"uri":        req.RequestURI,
		"status":     loggingResp.status,
		"time":       elapsed.String(),
		"millis":     float64(elapsed.Nanoseconds()) / 1000000.0,
		"bytes":      loggingResp.responseBytes,
		"flow_id":    flowID,
		"user_agent": req.Header.Get("User-Agent"),
	})
	if loggingResp.status < 300 {
		log.Info("Request: Success")
	} else if loggingResp.status < 400 {
		log.Info("Request: Redirect")
	} else if loggingResp.status < 500 {
		log.Warn("Request: Client error")
	} else {
		log.Error("Request: Server error")
	}
}

func flowIDFromHeaders(req *http.Request) string {
	for _, headerName := range flowIDHeaderNames {
		if flowID := req.Header.Get(headerName); flowID != "" {
			return flowID
		}
	}
	return ""
}
<|endoftext|>


<commit_before>//A simple tool for converting png, gif & jpg images into tiles useful for gameboy programming, with possible further applications.
//In the simplest case, tiles are to be read left to right then top to bottom, and each tile is to be individually converted into GBC 2-bit format.
//Future versions may include ability to write more than one tile together, e.g., so that each tile of a 16x16 image are writted one after the other.
//Color palettes are determined on a tile by tile basis. Colors are ordered by sum of RGB highest → lowest, with B > G > R being used for ties.
//Additional colors are set to black, and an error printed. With -t enabled the first color on each tile will be treated as transparency (color 0),
//overriding color sorting in this instance.
package main

import ("flag"
	"os"
 	"image"
	"log"
	"fmt"
	"image/color"
 	_ "image/png"
 	_ "image/jpeg"
	_ "image/gif")

	//Organise settings flags
	var dim uint
	var dimX uint
	var dimY uint
	var offset uint
	var offsetX uint
	var offsetY uint
	var spacing uint
	var spacingX uint
	var spacingY uint
	var spriteMode bool
	var outFormat string

type sImage interface {
	image.Image
	SubImage(r image.Rectangle) image.Image
}

func main() {
	var file *os.File
	var err error

	flag.UintVar(&dim, "d", 8, "Square dimension of each tile. Use only for square. Non multiple-of-8 values may cause undefined behaviour")
	flag.UintVar(&dimX, "w", 8, "Width of each tile")
	flag.UintVar(&dimY, "h", 8, "Height of each tile")
	flag.UintVar(&offset, "o", 0, "Offset of the first tile from both the top and left edge")
	flag.UintVar(&offsetX, "x", 0, "Horizontal offset of first tile from left")
	flag.UintVar(&offsetY, "y", 0, "Vertical offset of first tile from top")
	flag.UintVar(&spacing, "s", 0, "Distance between tiles")
	flag.UintVar(&spacingX, "sx", 0, "Horizontal distance between tiles")
	flag.UintVar(&spacingY, "sy", 0, "Vertical distance between tiles")
	flag.BoolVar(&spriteMode, "t", false, "Sets first color in tile as transparency (color 0)")
	flag.StringVar(&outFormat, "f", "0x%X, ", "C Style format for output data (printed in a loop for each byte")
	flag.Parse();

	//if dimX, dimY are unset
	if dimX == dimY && dimY == 8 {
		//use the value from dim instead
		dimY = dim
		dimX = dim
	}
	if offsetX == offsetY && offsetY == 0 {
		offsetX = offset
		offsetY = offset
	}
	if spacingX == spacingY && spacingY == 0 {
		spacingX = spacing
		spacingY = spacing
	}

	//Program uses arg0 as read directory for input
	var fname = flag.Arg(0)

	//Default behaviour is read from stdin
	if fname == "-" || fname == "" {
		//read from standard input
		file = os.Stdin
	} else {
		//read from file
		file, err = os.Open(fname)
		if err != nil {
			log.Fatal(err)
		}
	}

	//decode file into image
	var outputData []byte
	tileset, format, err := image.Decode(file)
	if err == nil {
		log.Println(fname, "decoded from format", format)
	} else {
		log.Fatal(err)
	}
	tilesetSize := tileset.Bounds()

	//iterate through every tile fully contained within image
	for y := offsetY; y + dimY - 1 < uint(tilesetSize.Max.Y); y += dimY + spacingY {
		for x := offsetX; x + dimX - 1 < uint(tilesetSize.Max.X); x += dimX + spacingX {
			tile := tileset.(sImage).SubImage(image.Rect(int(x),int(y),int(x+dimX),int(y+dimY)))
			//Elipsis explodes the slice
			outputData = append(outputData, Encode(tile)...)
			//append slice to data
		}
	}
	//output data to file or stdOut
	var outFile *os.File
	if flag.Arg(1) == "-" || flag.Arg(1) == "" {
		outFile = os.Stdout
		log.Println("Outputting to stdout")
	} else {
		outFile, err = os.Create(flag.Arg(1))
		if err != nil {
			log.Fatal(err)
		}
		log.Println("Outputting to file")
	}
	for i := 0; i < len(outputData); i++ {
		if i%16 == 0 && i != 0 {
			_, err = outFile.WriteString("\n")
		}
		_, err = fmt.Fprintf(outFile, outFormat, []byte{outputData[i]})
		if err != nil {
			log.Fatal(err)
		}
		//_, err = outFile.WriteString(delimiter)
		//if err != nil {
		//	log.Fatal(err)
		//}
	}
	return
}

func Encode(tile image.Image) []byte {
	var palette [4]color.Color
	for i := range palette {
		palette[i] = color.Gray{0}
	}
	//var paletteMap map[color.Color]byte
	var colCount byte = 0;
	//Lets just see if Go supports this
	size := tile.Bounds()
	//Not a huge fan of using the globals here but size.Max.Y-size.Min.Y is hella messy
	var rawData = make([]byte, dimX*dimY)
	var data = make([]byte, dimX*dimY/4)
	//list all colors. Drop any colors more than 4
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x:= size.Min.X; x < size.Max.X; x++ {
			color := tile.At(x,y)
			colorFound := false
			for i := 0; i<int(colCount); i++ {
				if color == palette[i] {
					colorFound = true
					break
				}
			}
			if !colorFound {
				palette[colCount] = color
				colCount++
			}
			if colCount >= 4 {
				break
			}
		}
		if colCount >= 4 {
			break
		}
	}

	//sort colors (checking for -t)
	var min int = 0 //unnecessarily large because casting is annoying
	if spriteMode {
		min = 1
	}
	//Since it's such a small list, we're not checking if swapping is still
	//occurring
	for i := 0; i<4; i++ {
		for j := min; j<3-i; j++ {
			r0, g0, b0, _ := palette[j].RGBA()
			r1, g1, b1, _ := palette[j+1].RGBA()
			if r1 + g1 + b1 > r0 + g0 + b0 {
				palette[j], palette[j+1] = palette[j+1], palette[j]
			} else if r1 + g1 + b1 == r0 + g0 + b0 {
				if g1 + b1 > g0 + b0 {
					palette[j], palette[j+1] = palette[j+1], palette[j]
				} else if g1 + b1 == g0 + b0 {
					if b1 > b0 {
						palette[j], palette[j+1] = palette[j+1], palette[j]
					}
				}
			}
			//compare
		}
	}

	//create slice of color indices
	var pixelCount uint
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x:= size.Min.X; x < size.Max.X; x++ {
			var i byte
			for i = 0; i < 4; i++ {
				if tile.At(x,y) == palette[i] {
					break
				}
			}
			rawData[pixelCount] = i
			pixelCount++
		}
	}
	//loop until you find your color
	//set the index in the slice
	//"Encode" into gameboy format
	//for each row
	for i := 0; i < int(dimX*dimY/8); i += 1 {
		//for each pixel in the row
		for n:= 0; n<8; n++ {
			//I hope this works
			//First byte is less significant bits of first row
			data[2*i] = ((rawData[8*i+n] & 1) << (7-byte(n))) | data[2*i]
			//Second byte is more significant bits of second row
			data[2*i+1] = ((rawData[8*i+n] & 2) >> 1 << (7-byte(n))) | data[2*i+1]
		}
	}
	return data
}
<commit_msg>Reorganises some code / manages some comments<commit_after>//A simple tool for converting png, gif & jpg images into tiles useful for gameboy programming, with possible further applications.
//In the simplest case, tiles are to be read left to right then top to bottom, and each tile is to be individually converted into GBC 2-bit format.
//Future versions may include ability to write more than one tile together, e.g., so that each tile of a 16x16 image are writted one after the other.
//Color palettes are determined on a tile by tile basis. Colors are ordered by sum of RGB highest → lowest, with B > G > R being used for ties.
//Additional colors are set to black, and an error printed. With -t enabled the first color on each tile will be treated as transparency (color 0),
//overriding color sorting in this instance.
package main

import ("flag"
	"os"
 	"image"
	"log"
	"fmt"
	"image/color"
 	_ "image/png"
 	_ "image/jpeg"
	_ "image/gif")

	//Organise settings flags
	var dim uint
	var dimX uint
	var dimY uint
	var offset uint
	var offsetX uint
	var offsetY uint
	var spacing uint
	var spacingX uint
	var spacingY uint
	var spriteMode bool
	var outFormat string

type sImage interface {
	image.Image
	SubImage(r image.Rectangle) image.Image
}

type palette [4]color.Color

var palettes []palette

func main() {
	var file *os.File
	var err error

	flag.UintVar(&dim, "d", 8, "Square dimension of each tile. Use only for square. Non multiple-of-8 values may cause undefined behaviour")
	flag.UintVar(&dimX, "w", 8, "Width of each tile")
	flag.UintVar(&dimY, "h", 8, "Height of each tile")
	flag.UintVar(&offset, "o", 0, "Offset of the first tile from both the top and left edge")
	flag.UintVar(&offsetX, "x", 0, "Horizontal offset of first tile from left")
	flag.UintVar(&offsetY, "y", 0, "Vertical offset of first tile from top")
	flag.UintVar(&spacing, "s", 0, "Distance between tiles")
	flag.UintVar(&spacingX, "sx", 0, "Horizontal distance between tiles")
	flag.UintVar(&spacingY, "sy", 0, "Vertical distance between tiles")
	flag.BoolVar(&spriteMode, "t", false, "Sets first color in tile as transparency (color 0)")
	flag.StringVar(&outFormat, "f", "0x%X, ", "C Style format for output data (printed in a loop for each byte")
	flag.Parse();

	//if dimX, dimY are unset
	if dimX == dimY && dimY == 8 {
		//use the value from dim instead
		dimY = dim
		dimX = dim
	}
	if offsetX == offsetY && offsetY == 0 {
		offsetX = offset
		offsetY = offset
	}
	if spacingX == spacingY && spacingY == 0 {
		spacingX = spacing
		spacingY = spacing
	}

	//Program uses arg0 as read directory for input
	var fname = flag.Arg(0)

	//Default behaviour is read from stdin
	if fname == "-" || fname == "" {
		//read from standard input
		file = os.Stdin
	} else {
		//read from file
		file, err = os.Open(fname)
		if err != nil {
			log.Fatal(err)
		}
	}

	//decode file into image
	var outputData []byte
	tileset, format, err := image.Decode(file)
	if err == nil {
		log.Println(fname, "decoded from format", format)
	} else {
		log.Fatal(err)
	}
	tilesetSize := tileset.Bounds()

	//iterate through every tile fully contained within image
	for y := offsetY; y + dimY - 1 < uint(tilesetSize.Max.Y); y += dimY + spacingY {
		for x := offsetX; x + dimX - 1 < uint(tilesetSize.Max.X); x += dimX + spacingX {
			tile := tileset.(sImage).SubImage(image.Rect(int(x),int(y),int(x+dimX),int(y+dimY)))
			//Elipsis explodes the slice
			outputData = append(outputData, Encode(tile)...)
			//append slice to data
		}
	}
	//output data to file or stdOut
	var outFile *os.File
	if flag.Arg(1) == "-" || flag.Arg(1) == "" {
		outFile = os.Stdout
		log.Println("Outputting to stdout")
	} else {
		outFile, err = os.Create(flag.Arg(1))
		if err != nil {
			log.Fatal(err)
		}
		log.Println("Outputting to file")
	}
	for i := 0; i < len(outputData); i++ {
		if i%16 == 0 && i != 0 {
			_, err = outFile.WriteString("\n")
		}
		_, err = fmt.Fprintf(outFile, outFormat, []byte{outputData[i]})
		if err != nil {
			log.Fatal(err)
		}
		//_, err = outFile.WriteString(delimiter)
		//if err != nil {
		//	log.Fatal(err)
		//}
	}
	return
}

func Encode(tile image.Image) []byte {
	var tilePalette palette
	for i := range tilePalette {
		tilePalette[i] = color.Gray{0}
	}
	//Could we do better with a map?
	//var tilePaletteMap map[color.Color]byte
	var colCount byte = 0;
	size := tile.Bounds()
	//Not a huge fan of using the globals here but size.Max.Y-size.Min.Y is
	//hella messy, and we really don't have a case where dim != 8
	var rawData = make([]byte, dimX*dimY)
	var data = make([]byte, dimX*dimY/4)
	//list all colors. Drop any colors more than 4
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x:= size.Min.X; x < size.Max.X; x++ {
			color := tile.At(x,y)
			colorFound := false
			for i := 0; i<int(colCount); i++ {
				if color == tilePalette[i] {
					colorFound = true
					break
				}
			}
			if !colorFound {
				tilePalette[colCount] = color
				colCount++
			}
			if colCount >= 4 {
				break
			}
		}
		if colCount >= 4 {
			break
		}
	}

	//sort colors (checking for -t)
	tilePalette = sortPalette(tilePalette)

	//create slice of color indices
	var pixelCount uint
	for y := size.Min.Y; y < size.Max.Y; y++ {
		for x:= size.Min.X; x < size.Max.X; x++ {
			var i byte
			for i = 0; i < 4; i++ {
				if tile.At(x,y) == tilePalette[i] {
					break
				}
			}
			rawData[pixelCount] = i
			pixelCount++
		}
	}
	//loop until you find your color
	//set the index in the slice
	//"Encode" into gameboy format
	//for each row
	for i := 0; i < int(dimX*dimY/8); i += 1 {
		//for each pixel in the row
		for n:= 0; n<8; n++ {
			//I hope this works
			//First byte is less significant bits of first row
			data[2*i] = ((rawData[8*i+n] & 1) << (7-byte(n))) | data[2*i]
			//Second byte is more significant bits of second row
			data[2*i+1] = ((rawData[8*i+n] & 2) >> 1 << (7-byte(n))) | data[2*i+1]
		}
	}
	return data
}

//sortPalette(p palette) sorts the colors in a palette approximately from
//brightest to dimmest using a simple bubblesort
func sortPalette(p palette) palette {
	//Since it's such a small list, we're not checking if swapping is still
	//occurring, just sorting through to max time. More efficient sorting
	//would be nice but likely isn't worth the effort
	var min int = 0 //unnecessarily large type because casting is annoying
	//Spritemode leaves the first color identified where it is, no sorting
	if spriteMode {
		min = 1
	}
	for i := 0; i<4; i++ {
		for j := min; j<3-i; j++ {
			r0, g0, b0, _ := p[j].RGBA()
			r1, g1, b1, _ := p[j+1].RGBA()
			if r1 + g1 + b1 > r0 + g0 + b0 {
				p[j], p[j+1] = p[j+1], p[j]
			} else if r1 + g1 + b1 == r0 + g0 + b0 {
				if g1 + b1 > g0 + b0 {
					p[j], p[j+1] = p[j+1], p[j]
				} else if g1 + b1 == g0 + b0 {
					if b1 > b0 {
						p[j], p[j+1] = p[j+1], p[j]
					}
				}
			}
		}
	}
	return p
}
<|endoftext|>


<commit_before><commit_msg>Use Search stub in cli<commit_after><|endoftext|>


<commit_before>package utils

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"regexp"
	"strings"

	"github.com/TimothyYe/godns/internal/settings"
	dnsResolver "github.com/TimothyYe/godns/pkg/resolver"
	"github.com/miekg/dns"
	log "github.com/sirupsen/logrus"
)

// GetIPFromInterface gets IP address from the specific interface.
func GetIPFromInterface(configuration *settings.Settings) (string, error) {
	ifaces, err := net.InterfaceByName(configuration.IPInterface)
	if err != nil {
		log.Error("can't get network device "+configuration.IPInterface+":", err)
		return "", err
	}

	addrs, err := ifaces.Addrs()
	if err != nil {
		log.Error("can't get address from "+configuration.IPInterface+":", err)
		return "", err
	}

	for _, addr := range addrs {
		var ip net.IP
		switch v := addr.(type) {
		case *net.IPNet:
			ip = v.IP
		case *net.IPAddr:
			ip = v.IP
		}
		if ip == nil {
			continue
		}

		if ip.IsPrivate() {
			continue
		}

		if isIPv4(ip.String()) {
			if strings.ToUpper(configuration.IPType) != IPV4 {
				continue
			}
		} else {
			if strings.ToUpper(configuration.IPType) != IPV6 {
				continue
			}
		}

		if ip.String() != "" {
			return ip.String(), nil
		}
	}
	return "", errors.New("can't get a vaild address from " + configuration.IPInterface)
}

func isIPv4(ip string) bool {
	return strings.Count(ip, ":") < 2
}

// GetCurrentIP gets an IP from either internet or specific interface, depending on configuration.
func GetCurrentIP(configuration *settings.Settings) (string, error) {
	var err error
	var ip string

	if len(configuration.IPUrls) > 0 || len(configuration.IPV6Urls) > 0 {
		ip, err = GetIPOnline(configuration)
		if err != nil {
			log.Error("get ip online failed. Fallback to get ip from interface if possible.")
		} else {
			return ip, nil
		}
	}

	if configuration.IPInterface != "" {
		ip, err = GetIPFromInterface(configuration)
		if err != nil {
			log.Error("get ip from interface failed. There is no more ways to try.")
		} else {
			return ip, nil
		}
	}

	return "", err
}

// GetIPOnline gets public IP from internet.
func GetIPOnline(configuration *settings.Settings) (string, error) {
	client := &http.Client{}
	var reqURLs []string
	var onlineIP string

	if configuration.IPType == "" || strings.ToUpper(configuration.IPType) == IPV4 {
		reqURLs = configuration.IPUrls
	} else {
		reqURLs = configuration.IPV6Urls
	}

	for _, reqURL := range reqURLs {

		req, _ := http.NewRequest("GET", reqURL, nil)

		if configuration.UserAgent != "" {
			req.Header.Set("User-Agent", configuration.UserAgent)
		}

		response, err := client.Do(req)

		if err != nil {
			log.Error("Cannot get IP:", err)
			continue
		}

		defer response.Body.Close()

		if response.StatusCode != http.StatusOK {
			log.Error(fmt.Sprintf("request %v got httpCode:%v", reqURL, response.StatusCode))
			continue
		}

		body, _ := io.ReadAll(response.Body)
		ipReg := regexp.MustCompile(IPPattern)
		onlineIP := ipReg.FindString(string(body))
		if onlineIP == "" {
			log.Error(fmt.Sprintf("request:%v failed to get online IP", reqURL))
			continue
		} else {
			log.Debug("get ip success by:", reqURL)
			break
		}
	}

	if onlineIP == "" {
		return "", errors.New("All IP API are failed to get online IP")
	}

	return onlineIP, nil
}

// ResolveDNS will query DNS for a given hostname.
func ResolveDNS(hostname, resolver, ipType string) (string, error) {
	var dnsType uint16
	if ipType == "" || strings.ToUpper(ipType) == IPV4 {
		dnsType = dns.TypeA
	} else {
		dnsType = dns.TypeAAAA
	}

	// If no DNS server is set in config file, falls back to default resolver.
	if resolver == "" {
		dnsAdress, err := net.LookupHost(hostname)
		if err != nil {
			return "<nil>", err
		}

		return dnsAdress[0], nil
	}
	res := dnsResolver.New([]string{resolver})
	// In case of i/o timeout
	res.RetryTimes = 5

	ip, err := res.LookupHost(hostname, dnsType)
	if err != nil {
		return "<nil>", err
	}

	return ip[0].String(), nil
}
<commit_msg>fix get online ip issue<commit_after>package utils

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"regexp"
	"strings"

	"github.com/TimothyYe/godns/internal/settings"
	dnsResolver "github.com/TimothyYe/godns/pkg/resolver"
	"github.com/miekg/dns"
	log "github.com/sirupsen/logrus"
)

// GetIPFromInterface gets IP address from the specific interface.
func GetIPFromInterface(configuration *settings.Settings) (string, error) {
	ifaces, err := net.InterfaceByName(configuration.IPInterface)
	if err != nil {
		log.Error("can't get network device "+configuration.IPInterface+":", err)
		return "", err
	}

	addrs, err := ifaces.Addrs()
	if err != nil {
		log.Error("can't get address from "+configuration.IPInterface+":", err)
		return "", err
	}

	for _, addr := range addrs {
		var ip net.IP
		switch v := addr.(type) {
		case *net.IPNet:
			ip = v.IP
		case *net.IPAddr:
			ip = v.IP
		}
		if ip == nil {
			continue
		}

		if ip.IsPrivate() {
			continue
		}

		if isIPv4(ip.String()) {
			if strings.ToUpper(configuration.IPType) != IPV4 {
				continue
			}
		} else {
			if strings.ToUpper(configuration.IPType) != IPV6 {
				continue
			}
		}

		if ip.String() != "" {
			return ip.String(), nil
		}
	}
	return "", errors.New("can't get a vaild address from " + configuration.IPInterface)
}

func isIPv4(ip string) bool {
	return strings.Count(ip, ":") < 2
}

// GetCurrentIP gets an IP from either internet or specific interface, depending on configuration.
func GetCurrentIP(configuration *settings.Settings) (string, error) {
	var err error
	var ip string

	if len(configuration.IPUrls) > 0 || len(configuration.IPV6Urls) > 0 {
		ip, err = GetIPOnline(configuration)
		if err != nil {
			log.Error("get ip online failed. Fallback to get ip from interface if possible.")
		} else {
			return ip, nil
		}
	}

	if configuration.IPInterface != "" {
		ip, err = GetIPFromInterface(configuration)
		if err != nil {
			log.Error("get ip from interface failed. There is no more ways to try.")
		} else {
			return ip, nil
		}
	}

	return "", err
}

// GetIPOnline gets public IP from internet.
func GetIPOnline(configuration *settings.Settings) (string, error) {
	client := &http.Client{}
	var reqURLs []string
	var onlineIP string

	if configuration.IPType == "" || strings.ToUpper(configuration.IPType) == IPV4 {
		reqURLs = configuration.IPUrls
	} else {
		reqURLs = configuration.IPV6Urls
	}

	for _, reqURL := range reqURLs {

		req, _ := http.NewRequest("GET", reqURL, nil)

		if configuration.UserAgent != "" {
			req.Header.Set("User-Agent", configuration.UserAgent)
		}

		response, err := client.Do(req)

		if err != nil {
			log.Error("Cannot get IP:", err)
			continue
		}

		defer response.Body.Close()

		if response.StatusCode != http.StatusOK {
			log.Error(fmt.Sprintf("request %v got httpCode:%v", reqURL, response.StatusCode))
			continue
		}

		body, _ := io.ReadAll(response.Body)
		ipReg := regexp.MustCompile(IPPattern)
		onlineIP = ipReg.FindString(string(body))
		if onlineIP == "" {
			log.Error(fmt.Sprintf("request:%v failed to get online IP", reqURL))
			continue
		} else {
			log.Debugf("get ip success by: %s, online IP: %s", reqURL, onlineIP)
			break
		}
	}

	if onlineIP == "" {
		return "", errors.New("All IP API are failed to get online IP")
	}

	return onlineIP, nil
}

// ResolveDNS will query DNS for a given hostname.
func ResolveDNS(hostname, resolver, ipType string) (string, error) {
	var dnsType uint16
	if ipType == "" || strings.ToUpper(ipType) == IPV4 {
		dnsType = dns.TypeA
	} else {
		dnsType = dns.TypeAAAA
	}

	// If no DNS server is set in config file, falls back to default resolver.
	if resolver == "" {
		dnsAdress, err := net.LookupHost(hostname)
		if err != nil {
			return "<nil>", err
		}

		return dnsAdress[0], nil
	}
	res := dnsResolver.New([]string{resolver})
	// In case of i/o timeout
	res.RetryTimes = 5

	ip, err := res.LookupHost(hostname, dnsType)
	if err != nil {
		return "<nil>", err
	}

	return ip[0].String(), nil
}
<|endoftext|>


<commit_before>package appdefaults

const (
	Address   = "npipe:////./pipe/buildkitd"
	Root      = ".buildstate"
	ConfigDir = ""
)

func UserAddress() string {
	return Address
}

func EnsureUserAddressDir() error {
	return nil
}

func UserRoot() string {
	return Root
}

func UserConfigDir() string {
	return ConfigDir
}
<commit_msg>Set sensible defaults for Windows installations<commit_after>package appdefaults

import (
	"os"
	"path/filepath"
)

const (
	Address = "npipe:////./pipe/buildkitd"
)

var (
	Root      = filepath.Join(os.Getenv("ProgramData"), "buildkitd", ".buildstate")
	ConfigDir = filepath.Join(os.Getenv("ProgramData"), "buildkitd")
)

func UserAddress() string {
	return Address
}

func EnsureUserAddressDir() error {
	return nil
}

func UserRoot() string {
	return Root
}

func UserConfigDir() string {
	return ConfigDir
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/rainforestapp/rainforest-cli/rainforest"
	"github.com/urfave/cli"
)

const (
	// Version of the app in SemVer
	version = "2.0.2-beta.1"
	// This is the default spec folder for RFML tests
	defaultSpecFolder = "./spec/rainforest"
)

var (
	// Build info to be set while building using:
	// go build -ldflags "-X main.build=build"
	build string

	// Release channel to be set while building using:
	// go build -ldflags "-X main.releaseChannel=channel"
	releaseChannel string

	// Rainforest API client
	api *rainforest.Client

	// default output for printing resource tables
	tablesOut io.Writer = os.Stdout

	// Run status polling interval
	runStatusPollInterval = time.Second * 5

	// Batch size (number of rows) for tabular var upload
	tabularBatchSize = 50
	// Concurrent connections when uploading CSV rows
	tabularConcurrency = 1
	// Maximum concurrent connections with Rainforest server
	rfmlDownloadConcurrency = 4
	// Concurrent connections when uploading RFML files
	rfmlUploadConcurrency = 4
)

// cliContext is an interface providing context of running application
// i.e. command line options and flags. One of the types that provides the interface is
// cli.Context, the other is fakeCLIContext which is used for testing.
type cliContext interface {
	String(flag string) (val string)
	StringSlice(flag string) (vals []string)
	Bool(flag string) (val bool)
	Int(flag string) (val int)

	Args() (args cli.Args)
}

// Create custom writer which will use timestamps
type logWriter struct{}

func (l *logWriter) Write(p []byte) (int, error) {
	log.Printf("%s", p)
	return len(p), nil
}

// main is an entry point of the app. It sets up the new cli app, and defines the API.
func main() {
	updateFinishedChan := make(chan struct{})
	app := cli.NewApp()
	app.Usage = "Rainforest QA CLI - https://www.rainforestqa.com/"
	app.Version = version
	if releaseChannel != "" {
		app.Version = fmt.Sprintf("%v - %v channel", app.Version, releaseChannel)
	}
	if build != "" {
		app.Version = fmt.Sprintf("%v - build: %v", app.Version, build)
	}

	// Use our custom writer to print our errors with timestamps
	cli.ErrWriter = &logWriter{}

	// Before running any of the commands we init the API Client & update
	app.Before = func(c *cli.Context) error {
		go autoUpdate(c, updateFinishedChan)

		api = rainforest.NewClient(c.String("token"))

		// Set the User-Agent that will be used for api calls
		if build != "" {
			api.UserAgent = "rainforest-cli/" + version + " build: " + build
		} else {
			api.UserAgent = "rainforest-cli/" + version
		}

		return nil
	}

	// Wait for the update to finish if it's still going on
	app.After = func(c *cli.Context) error {
		<-updateFinishedChan
		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "token, t",
			Usage:  "API token. You can find it at https://app.rainforestqa.com/settings/integrations",
			EnvVar: "RAINFOREST_API_TOKEN",
		},
		cli.BoolFlag{
			Name:  "skip-update",
			Usage: "Used to disable auto-updating of the cli",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:    "run",
			Aliases: []string{"r"},
			Usage:   "Run your tests on Rainforest",
			Action:  startRun,
			Description: "Runs your tests on Rainforest platform. " +
				"You need to specify list of test IDs to run or use keyword 'all'. " +
				"Alternatively you can use one of the filtering options.",
			ArgsUsage: "[test IDs]",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "tag",
					Usage: "filter tests by `TAG`. Can be used multiple times for filtering by multiple tags.",
				},
				cli.StringFlag{
					Name:  "site, site-id",
					Usage: "filter tests by a specific site. You can see a list of your `SITE-ID`s with sites command.",
				},
				cli.StringFlag{
					Name:  "folder",
					Usage: "filter tests by a specific folder. You can see a list of your `FOLDER-ID`s with folders command.",
				},
				cli.StringSliceFlag{
					Name: "browser, browsers",
					Usage: "specify the `BROWSER` you wish to run against. This overrides test level settings." +
						"Can be used multiple times to run against multiple browsers.",
				},
				cli.StringFlag{
					Name:  "environment-id",
					Usage: "run your tests using specified `ENVIRONMENT`. Otherwise it will use your default one.",
				},
				cli.StringFlag{
					Name:  "crowd",
					Value: "default",
					Usage: "run your tests using specified `CROWD`. Available choices are: default or on_premise_crowd. " +
						"Contact your CSM for more details.",
				},
				cli.StringFlag{
					Name: "conflict",
					Usage: "use the abort option to abort any runs in the same environment or " +
						"use the abort-all option to abort all runs in progress.",
				},
				cli.BoolFlag{
					Name: "bg, background",
					Usage: "run in the background. This option makes cli return after succesfully starting a run, " +
						"without waiting for the run results.",
				},
				cli.BoolFlag{
					Name: "fail-fast, ff",
					Usage: "fail the build as soon as the first failed result comes in. " +
						"If you don't pass this it will wait until 100% of the run is done. Use with --fg.",
				},
				cli.StringFlag{
					Name: "custom-url",
					Usage: "use a custom `URL` for this run. Example use case: an ad-hoc QA environment with Fourchette. " +
						"You will need to specify a site_id too for this to work.",
				},
				cli.BoolFlag{
					Name: "git-trigger",
					Usage: "only trigger a run when the last commit (for a git repo in the current working directory) " +
						"contains @rainforest and a list of one or more tags. rainforest-cli exits with 0 otherwise.",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "add arbitrary `DESCRIPTION` to the run.",
				},
				cli.StringFlag{
					Name:  "junit-file",
					Usage: "Create a JUnit XML report `FILE` with the specified name. Must be run in foreground mode.",
				},
				cli.StringFlag{
					Name:  "import-variable-name",
					Usage: "`NAME` of the tabular variable to be created or updated.",
				},
				cli.StringFlag{
					Name:  "import-variable-csv-file",
					Usage: "`PATH` to the CSV file to be uploaded.",
				},
				cli.BoolFlag{
					Name:  "overwrite-variable",
					Usage: "If the flag is set, named variable will be updated.",
				},
				cli.BoolFlag{
					Name:  "single-use",
					Usage: "This option marks uploaded variable as single-use",
				},
				cli.StringFlag{
					Name:  "wait, reattach",
					Usage: "monitor existing run with `RUN_ID` instead of starting a new one.",
				},
			},
		},
		{
			Name:      "new",
			Usage:     "Create a new RFML test",
			ArgsUsage: "[name]",
			Description: "Create new Rainforest test in RFML format (Rainforest Markup Language). " +
				"You may also specify a custom test title or file name.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  defaultSpecFolder,
					Usage:  "`PATH` at which to create new test.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
			},
			Action: newRFMLTest,
		},
		{
			Name:      "validate",
			Usage:     "Validate your RFML tests",
			ArgsUsage: "[path to RFML file]",
			Description: "Validate your test for syntax. " +
				"If no filepath is given it validates all RFML tests and performs additional checks for RFML ID validity and more. " +
				"If API token is set it'll validate your tests against server data as well.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` where to look for a tests to validate.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
			},
			Action: validateRFML,
		},
		{
			Name:      "upload",
			Usage:     "Upload your RFML tests",
			ArgsUsage: "[path to RFML file]",
			Description: "Uploads specified test to Rainforest. " +
				"If no filepath is given it uploads all RFML tests.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` where to look for a tests to upload.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
				cli.BoolFlag{
					Name:  "synchronous-upload",
					Usage: "uploads your test in a synchronous manner i.e. not using concurrency.",
				},
			},
			Action: uploadRFML,
		},
		{
			Name:        "rm",
			Usage:       "Remove an RFML test locally and remotely",
			ArgsUsage:   "[path to RFML file]",
			Description: "Remove RFML file and remove test from Rainforest test suite.",
			Action:      deleteRFML,
		},
		{
			Name: "download",
			// Left for legacy reason, should nuke?
			Aliases:   []string{"export"},
			Usage:     "Download your remote Rainforest tests to RFML",
			ArgsUsage: "[test IDs]",
			Description: "Download your remote tests from Rainforest to RFML. " +
				"You may specify list of test IDs or download all tests by default. " +
				"Alternatively you can use one of the filtering options.",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "tag",
					Usage: "filter tests by `TAG`. Can be used multiple times for filtering by multiple tags.",
				},
				cli.IntFlag{
					Name:  "site, site-id",
					Usage: "filter tests by a specific site. You can see a list of your `SITE-ID`s with sites command.",
				},
				cli.IntFlag{
					Name:  "folder, folder-id",
					Usage: "filter tests by a specific folder. You can see a list of your `FOLDER-ID`s with folders command.",
				},
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` at which to save all the downloaded tests.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
				cli.BoolFlag{
					Name:  "embed-tests",
					Usage: "download your tests without extracting the steps of an embedded test.",
				},
			},
			Action: func(c *cli.Context) error {
				return downloadRFML(c, api)
			},
		},
		{
			Name:        "csv-upload",
			Usage:       "Create or update tabular var from CSV.",
			Description: "Upload a CSV file to create or update tabular variables.",
			ArgsUsage:   "[path to CSV file]",
			Flags: []cli.Flag{
				cli.StringFlag{
					// Alternative name left for legacy reason.
					Name:  "name, import-variable-name",
					Usage: "`NAME` of the tabular variable to be created or updated.",
				},
				cli.BoolFlag{
					Name:  "overwrite-variable, overwrite",
					Usage: "If the flag is set, named variable will be updated.",
				},
				cli.BoolFlag{
					Name:  "single-use",
					Usage: "This option marks uploaded variable as single-use",
				},
				// Left here for legacy reason, but imho we should move that to args
				cli.StringFlag{
					Name:  "csv-file, import-variable-csv-file",
					Usage: "DEPRECATED: `PATH` to the CSV file to be uploaded. Since v2 please provide the path as an argument.",
				},
			},
			Action: func(c *cli.Context) error {
				return csvUpload(c, api)
			},
		},
		{
			Name:  "report",
			Usage: "Create a report from your run results",
			Description: "Creates a report from your specified run." +
				"You can specify output file using options, otherwise report will be generated to STDOUT",
			ArgsUsage: "[run ID]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "junit-file",
					Usage: "`PATH` of file to which write a JUnit report for the specified run.",
				},
				cli.StringFlag{
					Name:  "run-id",
					Usage: "DEPRECATED: ID of a run for which to generate results. Since v2 please provide the run ID as an argument.",
				},
			},
			Action: createReport,
		},
		{
			Name:  "sites",
			Usage: "Lists available sites",
			Action: func(c *cli.Context) error {
				return printSites(api)
			},
		},
		{
			Name:  "folders",
			Usage: "Lists available folders",
			Action: func(c *cli.Context) error {
				return printFolders(api)
			},
		},
		{
			Name:  "browsers",
			Usage: "Lists available browsers",
			Action: func(c *cli.Context) error {
				return printBrowsers(api)
			},
		},
		{
			Name:      "update",
			Usage:     "Updates application to the latest version on specified release channel (stable/beta)",
			ArgsUsage: "[CHANNEL]",
			Action:    updateCmd,
		},
	}

	app.Run(shuffleFlags(os.Args))
}

// shuffleFlags moves global flags to the beginning of args array (where they are supposed to be),
// so they are picked up by the cli package, even though they are supplied as a command argument.
// might not be needed if upstream makes this change as well
func shuffleFlags(originalArgs []string) []string {
	globalOptions := []string{}
	rest := []string{}

	// We need to skip the filename as its arg[0] that's why iteration starts at 1
	// then filter out global flags and put them into separate array than the rest of arg
	for i := 1; i < len(originalArgs); i++ {
		option := originalArgs[i]
		if option == "--token" || option == "-t" {
			if i+1 < len(originalArgs) && originalArgs[i+1][:1] != "-" {
				globalOptions = append(globalOptions, originalArgs[i:i+2]...)
				i++
			} else {
				log.Fatalln("No token specified with --token flag")
			}
		} else if option == "--skip-update" {
			globalOptions = append(globalOptions, option)
		} else {
			rest = append(rest, option)
		}
	}

	shuffledFlags := []string{originalArgs[0]}
	shuffledFlags = append(shuffledFlags, globalOptions...)
	shuffledFlags = append(shuffledFlags, rest...)

	return shuffledFlags
}
<commit_msg>v2.0.2 beta -> stable<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/rainforestapp/rainforest-cli/rainforest"
	"github.com/urfave/cli"
)

const (
	// Version of the app in SemVer
	version = "2.0.2"
	// This is the default spec folder for RFML tests
	defaultSpecFolder = "./spec/rainforest"
)

var (
	// Build info to be set while building using:
	// go build -ldflags "-X main.build=build"
	build string

	// Release channel to be set while building using:
	// go build -ldflags "-X main.releaseChannel=channel"
	releaseChannel string

	// Rainforest API client
	api *rainforest.Client

	// default output for printing resource tables
	tablesOut io.Writer = os.Stdout

	// Run status polling interval
	runStatusPollInterval = time.Second * 5

	// Batch size (number of rows) for tabular var upload
	tabularBatchSize = 50
	// Concurrent connections when uploading CSV rows
	tabularConcurrency = 1
	// Maximum concurrent connections with Rainforest server
	rfmlDownloadConcurrency = 4
	// Concurrent connections when uploading RFML files
	rfmlUploadConcurrency = 4
)

// cliContext is an interface providing context of running application
// i.e. command line options and flags. One of the types that provides the interface is
// cli.Context, the other is fakeCLIContext which is used for testing.
type cliContext interface {
	String(flag string) (val string)
	StringSlice(flag string) (vals []string)
	Bool(flag string) (val bool)
	Int(flag string) (val int)

	Args() (args cli.Args)
}

// Create custom writer which will use timestamps
type logWriter struct{}

func (l *logWriter) Write(p []byte) (int, error) {
	log.Printf("%s", p)
	return len(p), nil
}

// main is an entry point of the app. It sets up the new cli app, and defines the API.
func main() {
	updateFinishedChan := make(chan struct{})
	app := cli.NewApp()
	app.Usage = "Rainforest QA CLI - https://www.rainforestqa.com/"
	app.Version = version
	if releaseChannel != "" {
		app.Version = fmt.Sprintf("%v - %v channel", app.Version, releaseChannel)
	}
	if build != "" {
		app.Version = fmt.Sprintf("%v - build: %v", app.Version, build)
	}

	// Use our custom writer to print our errors with timestamps
	cli.ErrWriter = &logWriter{}

	// Before running any of the commands we init the API Client & update
	app.Before = func(c *cli.Context) error {
		go autoUpdate(c, updateFinishedChan)

		api = rainforest.NewClient(c.String("token"))

		// Set the User-Agent that will be used for api calls
		if build != "" {
			api.UserAgent = "rainforest-cli/" + version + " build: " + build
		} else {
			api.UserAgent = "rainforest-cli/" + version
		}

		return nil
	}

	// Wait for the update to finish if it's still going on
	app.After = func(c *cli.Context) error {
		<-updateFinishedChan
		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "token, t",
			Usage:  "API token. You can find it at https://app.rainforestqa.com/settings/integrations",
			EnvVar: "RAINFOREST_API_TOKEN",
		},
		cli.BoolFlag{
			Name:  "skip-update",
			Usage: "Used to disable auto-updating of the cli",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:    "run",
			Aliases: []string{"r"},
			Usage:   "Run your tests on Rainforest",
			Action:  startRun,
			Description: "Runs your tests on Rainforest platform. " +
				"You need to specify list of test IDs to run or use keyword 'all'. " +
				"Alternatively you can use one of the filtering options.",
			ArgsUsage: "[test IDs]",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "tag",
					Usage: "filter tests by `TAG`. Can be used multiple times for filtering by multiple tags.",
				},
				cli.StringFlag{
					Name:  "site, site-id",
					Usage: "filter tests by a specific site. You can see a list of your `SITE-ID`s with sites command.",
				},
				cli.StringFlag{
					Name:  "folder",
					Usage: "filter tests by a specific folder. You can see a list of your `FOLDER-ID`s with folders command.",
				},
				cli.StringSliceFlag{
					Name: "browser, browsers",
					Usage: "specify the `BROWSER` you wish to run against. This overrides test level settings." +
						"Can be used multiple times to run against multiple browsers.",
				},
				cli.StringFlag{
					Name:  "environment-id",
					Usage: "run your tests using specified `ENVIRONMENT`. Otherwise it will use your default one.",
				},
				cli.StringFlag{
					Name:  "crowd",
					Value: "default",
					Usage: "run your tests using specified `CROWD`. Available choices are: default or on_premise_crowd. " +
						"Contact your CSM for more details.",
				},
				cli.StringFlag{
					Name: "conflict",
					Usage: "use the abort option to abort any runs in the same environment or " +
						"use the abort-all option to abort all runs in progress.",
				},
				cli.BoolFlag{
					Name: "bg, background",
					Usage: "run in the background. This option makes cli return after succesfully starting a run, " +
						"without waiting for the run results.",
				},
				cli.BoolFlag{
					Name: "fail-fast, ff",
					Usage: "fail the build as soon as the first failed result comes in. " +
						"If you don't pass this it will wait until 100% of the run is done. Use with --fg.",
				},
				cli.StringFlag{
					Name: "custom-url",
					Usage: "use a custom `URL` for this run. Example use case: an ad-hoc QA environment with Fourchette. " +
						"You will need to specify a site_id too for this to work.",
				},
				cli.BoolFlag{
					Name: "git-trigger",
					Usage: "only trigger a run when the last commit (for a git repo in the current working directory) " +
						"contains @rainforest and a list of one or more tags. rainforest-cli exits with 0 otherwise.",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "add arbitrary `DESCRIPTION` to the run.",
				},
				cli.StringFlag{
					Name:  "junit-file",
					Usage: "Create a JUnit XML report `FILE` with the specified name. Must be run in foreground mode.",
				},
				cli.StringFlag{
					Name:  "import-variable-name",
					Usage: "`NAME` of the tabular variable to be created or updated.",
				},
				cli.StringFlag{
					Name:  "import-variable-csv-file",
					Usage: "`PATH` to the CSV file to be uploaded.",
				},
				cli.BoolFlag{
					Name:  "overwrite-variable",
					Usage: "If the flag is set, named variable will be updated.",
				},
				cli.BoolFlag{
					Name:  "single-use",
					Usage: "This option marks uploaded variable as single-use",
				},
				cli.StringFlag{
					Name:  "wait, reattach",
					Usage: "monitor existing run with `RUN_ID` instead of starting a new one.",
				},
			},
		},
		{
			Name:      "new",
			Usage:     "Create a new RFML test",
			ArgsUsage: "[name]",
			Description: "Create new Rainforest test in RFML format (Rainforest Markup Language). " +
				"You may also specify a custom test title or file name.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  defaultSpecFolder,
					Usage:  "`PATH` at which to create new test.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
			},
			Action: newRFMLTest,
		},
		{
			Name:      "validate",
			Usage:     "Validate your RFML tests",
			ArgsUsage: "[path to RFML file]",
			Description: "Validate your test for syntax. " +
				"If no filepath is given it validates all RFML tests and performs additional checks for RFML ID validity and more. " +
				"If API token is set it'll validate your tests against server data as well.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` where to look for a tests to validate.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
			},
			Action: validateRFML,
		},
		{
			Name:      "upload",
			Usage:     "Upload your RFML tests",
			ArgsUsage: "[path to RFML file]",
			Description: "Uploads specified test to Rainforest. " +
				"If no filepath is given it uploads all RFML tests.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` where to look for a tests to upload.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
				cli.BoolFlag{
					Name:  "synchronous-upload",
					Usage: "uploads your test in a synchronous manner i.e. not using concurrency.",
				},
			},
			Action: uploadRFML,
		},
		{
			Name:        "rm",
			Usage:       "Remove an RFML test locally and remotely",
			ArgsUsage:   "[path to RFML file]",
			Description: "Remove RFML file and remove test from Rainforest test suite.",
			Action:      deleteRFML,
		},
		{
			Name: "download",
			// Left for legacy reason, should nuke?
			Aliases:   []string{"export"},
			Usage:     "Download your remote Rainforest tests to RFML",
			ArgsUsage: "[test IDs]",
			Description: "Download your remote tests from Rainforest to RFML. " +
				"You may specify list of test IDs or download all tests by default. " +
				"Alternatively you can use one of the filtering options.",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "tag",
					Usage: "filter tests by `TAG`. Can be used multiple times for filtering by multiple tags.",
				},
				cli.IntFlag{
					Name:  "site, site-id",
					Usage: "filter tests by a specific site. You can see a list of your `SITE-ID`s with sites command.",
				},
				cli.IntFlag{
					Name:  "folder, folder-id",
					Usage: "filter tests by a specific folder. You can see a list of your `FOLDER-ID`s with folders command.",
				},
				cli.StringFlag{
					Name:   "test-folder",
					Value:  "./spec/rainforest/",
					Usage:  "`PATH` at which to save all the downloaded tests.",
					EnvVar: "RAINFOREST_TEST_FOLDER",
				},
				cli.BoolFlag{
					Name:  "embed-tests",
					Usage: "download your tests without extracting the steps of an embedded test.",
				},
			},
			Action: func(c *cli.Context) error {
				return downloadRFML(c, api)
			},
		},
		{
			Name:        "csv-upload",
			Usage:       "Create or update tabular var from CSV.",
			Description: "Upload a CSV file to create or update tabular variables.",
			ArgsUsage:   "[path to CSV file]",
			Flags: []cli.Flag{
				cli.StringFlag{
					// Alternative name left for legacy reason.
					Name:  "name, import-variable-name",
					Usage: "`NAME` of the tabular variable to be created or updated.",
				},
				cli.BoolFlag{
					Name:  "overwrite-variable, overwrite",
					Usage: "If the flag is set, named variable will be updated.",
				},
				cli.BoolFlag{
					Name:  "single-use",
					Usage: "This option marks uploaded variable as single-use",
				},
				// Left here for legacy reason, but imho we should move that to args
				cli.StringFlag{
					Name:  "csv-file, import-variable-csv-file",
					Usage: "DEPRECATED: `PATH` to the CSV file to be uploaded. Since v2 please provide the path as an argument.",
				},
			},
			Action: func(c *cli.Context) error {
				return csvUpload(c, api)
			},
		},
		{
			Name:  "report",
			Usage: "Create a report from your run results",
			Description: "Creates a report from your specified run." +
				"You can specify output file using options, otherwise report will be generated to STDOUT",
			ArgsUsage: "[run ID]",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "junit-file",
					Usage: "`PATH` of file to which write a JUnit report for the specified run.",
				},
				cli.StringFlag{
					Name:  "run-id",
					Usage: "DEPRECATED: ID of a run for which to generate results. Since v2 please provide the run ID as an argument.",
				},
			},
			Action: createReport,
		},
		{
			Name:  "sites",
			Usage: "Lists available sites",
			Action: func(c *cli.Context) error {
				return printSites(api)
			},
		},
		{
			Name:  "folders",
			Usage: "Lists available folders",
			Action: func(c *cli.Context) error {
				return printFolders(api)
			},
		},
		{
			Name:  "browsers",
			Usage: "Lists available browsers",
			Action: func(c *cli.Context) error {
				return printBrowsers(api)
			},
		},
		{
			Name:      "update",
			Usage:     "Updates application to the latest version on specified release channel (stable/beta)",
			ArgsUsage: "[CHANNEL]",
			Action:    updateCmd,
		},
	}

	app.Run(shuffleFlags(os.Args))
}

// shuffleFlags moves global flags to the beginning of args array (where they are supposed to be),
// so they are picked up by the cli package, even though they are supplied as a command argument.
// might not be needed if upstream makes this change as well
func shuffleFlags(originalArgs []string) []string {
	globalOptions := []string{}
	rest := []string{}

	// We need to skip the filename as its arg[0] that's why iteration starts at 1
	// then filter out global flags and put them into separate array than the rest of arg
	for i := 1; i < len(originalArgs); i++ {
		option := originalArgs[i]
		if option == "--token" || option == "-t" {
			if i+1 < len(originalArgs) && originalArgs[i+1][:1] != "-" {
				globalOptions = append(globalOptions, originalArgs[i:i+2]...)
				i++
			} else {
				log.Fatalln("No token specified with --token flag")
			}
		} else if option == "--skip-update" {
			globalOptions = append(globalOptions, option)
		} else {
			rest = append(rest, option)
		}
	}

	shuffledFlags := []string{originalArgs[0]}
	shuffledFlags = append(shuffledFlags, globalOptions...)
	shuffledFlags = append(shuffledFlags, rest...)

	return shuffledFlags
}
<|endoftext|>


<commit_before>package rancher

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project"
	"github.com/rancher/go-rancher/v2"
)

type RancherVolumesFactory struct {
	Context *Context
}

func (f *RancherVolumesFactory) Create(projectName string, volumeConfigs map[string]*config.VolumeConfig, serviceConfigs *config.ServiceConfigs, volumeEnabled bool) (project.Volumes, error) {
	volumes := make([]*Volume, 0, len(volumeConfigs))
	for name, config := range volumeConfigs {
		volume := NewVolume(projectName, name, config, f.Context)
		volumes = append(volumes, volume)
	}
	return &Volumes{
		volumes:       volumes,
		volumeEnabled: volumeEnabled,
		Context:       f.Context,
	}, nil
}

type Volumes struct {
	volumes       []*Volume
	volumeEnabled bool
	Context       *Context
}

func (v *Volumes) Initialize(ctx context.Context) error {
	if !v.volumeEnabled {
		return nil
	}
	for _, volume := range v.volumes {
		if err := volume.EnsureItExists(ctx); err != nil {
			return err
		}
	}

	return nil
}

func (v *Volumes) Remove(ctx context.Context) error {
	if !v.volumeEnabled {
		return nil
	}
	for _, volume := range v.volumes {
		if err := volume.Remove(ctx); err != nil {
			return err
		}
	}
	return nil
}

type Volume struct {
	context       *Context
	name          string
	projectName   string
	driver        string
	driverOptions map[string]string
	external      bool
	perContainer  bool
}

func (v *Volume) Inspect(ctx context.Context) (*client.VolumeTemplate, error) {
	volumes, err := v.context.Client.VolumeTemplate.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":    v.name,
			"stackId": v.context.Stack.Id,
		},
	})
	if err != nil {
		return nil, err
	}

	if len(volumes.Data) > 0 {
		return &volumes.Data[0], nil
	}

	return nil, nil
}

func (v *Volume) Remove(ctx context.Context) error {
	volumeResource, err := v.Inspect(ctx)
	if err != nil {
		return err
	}
	err = v.context.Client.VolumeTemplate.Delete(volumeResource)
	return err
}

func (v *Volume) EnsureItExists(ctx context.Context) error {
	volumeResource, err := v.Inspect(ctx)
	if err != nil {
		return err
	}
	if v.external && volumeResource == nil {
		return fmt.Errorf("Volume %s declared as external, but could not be found. Please create the volume manually and try again.", v.name)
	}
	if volumeResource == nil {
		return v.create(ctx)
	}
	if v.driver != "" && volumeResource.Driver != v.driver {
		return fmt.Errorf("Volume %q needs to be recreated - driver has changed", v.name)
	}
	return nil
}

func (v *Volume) create(ctx context.Context) error {
	driverOptions := map[string]interface{}{}
	for k, v := range v.driverOptions {
		driverOptions[k] = v
	}
	_, err := v.context.Client.VolumeTemplate.Create(&client.VolumeTemplate{
		Name:         v.name,
		Driver:       v.driver,
		DriverOpts:   driverOptions,
		StackId:      v.context.Stack.Id,
		PerContainer: v.perContainer,
	})
	return err
}

func NewVolume(projectName, name string, config *config.VolumeConfig, context *Context) *Volume {
	return &Volume{
		context:       context,
		name:          name,
		projectName:   projectName,
		driver:        config.Driver,
		driverOptions: config.DriverOpts,
		external:      config.External.External,
		perContainer:  config.PerContainer,
	}
}
<commit_msg>Don't filter by stackId for external volumes<commit_after>package rancher

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project"
	"github.com/rancher/go-rancher/v2"
)

type RancherVolumesFactory struct {
	Context *Context
}

func (f *RancherVolumesFactory) Create(projectName string, volumeConfigs map[string]*config.VolumeConfig, serviceConfigs *config.ServiceConfigs, volumeEnabled bool) (project.Volumes, error) {
	volumes := make([]*Volume, 0, len(volumeConfigs))
	for name, config := range volumeConfigs {
		volume := NewVolume(projectName, name, config, f.Context)
		volumes = append(volumes, volume)
	}
	return &Volumes{
		volumes:       volumes,
		volumeEnabled: volumeEnabled,
		Context:       f.Context,
	}, nil
}

type Volumes struct {
	volumes       []*Volume
	volumeEnabled bool
	Context       *Context
}

func (v *Volumes) Initialize(ctx context.Context) error {
	if !v.volumeEnabled {
		return nil
	}
	for _, volume := range v.volumes {
		if err := volume.EnsureItExists(ctx); err != nil {
			return err
		}
	}

	return nil
}

func (v *Volumes) Remove(ctx context.Context) error {
	if !v.volumeEnabled {
		return nil
	}
	for _, volume := range v.volumes {
		if err := volume.Remove(ctx); err != nil {
			return err
		}
	}
	return nil
}

type Volume struct {
	context       *Context
	name          string
	projectName   string
	driver        string
	driverOptions map[string]string
	external      bool
	perContainer  bool
}

func (v *Volume) Inspect(ctx context.Context) (*client.VolumeTemplate, error) {
	filters := map[string]interface{}{
		"name": v.name,
	}
	if !v.external {
		filters["stackId"] = v.context.Stack.Id
	}
	volumes, err := v.context.Client.VolumeTemplate.List(&client.ListOpts{
		Filters: filters,
	})
	if err != nil {
		return nil, err
	}

	if len(volumes.Data) > 0 {
		return &volumes.Data[0], nil
	}

	return nil, nil
}

func (v *Volume) Remove(ctx context.Context) error {
	volumeResource, err := v.Inspect(ctx)
	if err != nil {
		return err
	}
	err = v.context.Client.VolumeTemplate.Delete(volumeResource)
	return err
}

func (v *Volume) EnsureItExists(ctx context.Context) error {
	volumeResource, err := v.Inspect(ctx)
	if err != nil {
		return err
	}
	if v.external && volumeResource == nil {
		return fmt.Errorf("Volume %s declared as external, but could not be found. Please create the volume manually and try again.", v.name)
	}
	if volumeResource == nil {
		return v.create(ctx)
	}
	if v.driver != "" && volumeResource.Driver != v.driver {
		return fmt.Errorf("Volume %q needs to be recreated - driver has changed", v.name)
	}
	return nil
}

func (v *Volume) create(ctx context.Context) error {
	driverOptions := map[string]interface{}{}
	for k, v := range v.driverOptions {
		driverOptions[k] = v
	}
	_, err := v.context.Client.VolumeTemplate.Create(&client.VolumeTemplate{
		Name:         v.name,
		Driver:       v.driver,
		DriverOpts:   driverOptions,
		StackId:      v.context.Stack.Id,
		PerContainer: v.perContainer,
	})
	return err
}

func NewVolume(projectName, name string, config *config.VolumeConfig, context *Context) *Volume {
	return &Volume{
		context:       context,
		name:          name,
		projectName:   projectName,
		driver:        config.Driver,
		driverOptions: config.DriverOpts,
		external:      config.External.External,
		perContainer:  config.PerContainer,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/coreos/locksmith/version"
	"os"
	"strings"
	"text/template"
)

var (
	cmdHelp = &Command{
		Name:        "help",
		Summary:     "Show a list of commands or help for one command",
		Usage:       "[COMMAND]",
		Description: "Show a list of commands or detailed help for one command",
		Run:         runHelp,
	}

	globalUsageTemplate  *template.Template
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			// trim leading/trailing whitespace and split into slice of lines
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"printOption": func(name, defvalue, usage string) string {
			prefix := "--"
			if len(name) == 1 {
				prefix = "-"
			}
			return fmt.Sprintf("\t%s%s=%s\t%s", prefix, name, defvalue, usage)
		},
	}
)

func init() {
	globalUsageTemplate = template.Must(template.New("global_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Executable .Description}}

USAGE:
{{printf "\t%s" .Executable}} [global options] <command> [command options] [arguments...]

VERSION:
{{printf "\t%s" .Version}}

COMMANDS:{{range .Commands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}

GLOBAL OPTIONS:{{range .Flags}}
{{printOption .Name .DefValue .Usage}}{{end}}

Run "{{.Executable}} help <command>" for more details on a specific command.
`[1:]))
	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Cmd.Name .Cmd.Summary}}

USAGE:
{{printf "\t%s %s %s" .Executable .Cmd.Name .Cmd.Usage}}

DESCRIPTION:
{{range $line := descToLines .Cmd.Description}}{{printf "\t%s" $line}}
{{end}}
{{if .CmdFlags}}OPTIONS:{{range .CmdFlags}}
{{printOption .Name .DefValue .Usage}}{{end}}

{{end}}For help on global options run "{{.Executable}} help"
`[1:]))
}

func runHelp(args []string) (exit int) {
	if len(args) < 1 {
		printGlobalUsage()
		return
	}

	var cmd *Command

	for _, c := range commands {
		if c.Name == args[0] {
			cmd = c
			break
		}
	}

	if cmd == nil {
		fmt.Println("Unrecognized command:", args[0])
		return 1
	}

	printCommandUsage(cmd)
	return
}

func printGlobalUsage() {
	globalUsageTemplate.Execute(os.Stdout, struct {
		Executable  string
		Commands    []*Command
		Flags       []*flag.Flag
		Description string
		Version     string
	}{
		cliName,
		commands,
		getAllFlags(),
		cliDescription,
		version.Version,
	})
}

func printCommandUsage(cmd *Command) {
	commandUsageTemplate.Execute(os.Stdout, struct {
		Executable string
		Cmd        *Command
		CmdFlags   []*flag.Flag
	}{
		cliName,
		cmd,
		getFlags(&cmd.Flags),
	})
}
<commit_msg>fix(locksmithctl): use a tabwriter for help<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/coreos/locksmith/version"
	"os"
	"strings"
	"text/template"
)

var (
	cmdHelp = &Command{
		Name:        "help",
		Summary:     "Show a list of commands or help for one command",
		Usage:       "[COMMAND]",
		Description: "Show a list of commands or detailed help for one command",
		Run:         runHelp,
	}

	globalUsageTemplate  *template.Template
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			// trim leading/trailing whitespace and split into slice of lines
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"printOption": func(name, defvalue, usage string) string {
			prefix := "--"
			if len(name) == 1 {
				prefix = "-"
			}
			return fmt.Sprintf("\t%s%s=%s\t%s", prefix, name, defvalue, usage)
		},
	}
)

func init() {
	globalUsageTemplate = template.Must(template.New("global_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Executable .Description}}

USAGE:
{{printf "\t%s" .Executable}} [global options] <command> [command options] [arguments...]

VERSION:
{{printf "\t%s" .Version}}

COMMANDS:{{range .Commands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}

GLOBAL OPTIONS:{{range .Flags}}
{{printOption .Name .DefValue .Usage}}{{end}}

Run "{{.Executable}} help <command>" for more details on a specific command.
`[1:]))
	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Cmd.Name .Cmd.Summary}}

USAGE:
{{printf "\t%s %s %s" .Executable .Cmd.Name .Cmd.Usage}}

DESCRIPTION:
{{range $line := descToLines .Cmd.Description}}{{printf "\t%s" $line}}
{{end}}
{{if .CmdFlags}}OPTIONS:{{range .CmdFlags}}
{{printOption .Name .DefValue .Usage}}{{end}}

{{end}}For help on global options run "{{.Executable}} help"
`[1:]))
}

func runHelp(args []string) (exit int) {
	if len(args) < 1 {
		printGlobalUsage()
		return
	}

	var cmd *Command

	for _, c := range commands {
		if c.Name == args[0] {
			cmd = c
			break
		}
	}

	if cmd == nil {
		fmt.Println("Unrecognized command:", args[0])
		return 1
	}

	printCommandUsage(cmd)
	return
}

func printGlobalUsage() {
	globalUsageTemplate.Execute(out, struct {
		Executable  string
		Commands    []*Command
		Flags       []*flag.Flag
		Description string
		Version     string
	}{
		cliName,
		commands,
		getAllFlags(),
		cliDescription,
		version.Version,
	})
}

func printCommandUsage(cmd *Command) {
	commandUsageTemplate.Execute(os.Stdout, struct {
		Executable string
		Cmd        *Command
		CmdFlags   []*flag.Flag
	}{
		cliName,
		cmd,
		getFlags(&cmd.Flags),
	})
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package errors_test

import (
	stderrors "errors"
	"fmt"
	"reflect"
	"runtime"
	"testing"

	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/errors"
)

// errorInfo holds information about a single error type: a satisfier
// function, wrapping and variable arguments constructors and message
// suffix.
type errorInfo struct {
	satisfier       func(error) bool
	argsConstructor func(string, ...interface{}) error
	wrapConstructor func(error, string) error
	suffix          string
}

// allErrors holds information for all defined errors. When adding new
// errors, add them here as well to include them in tests.
var allErrors = []*errorInfo{
	&errorInfo{errors.IsNotFound, errors.NotFoundf, errors.NewNotFound, " not found"},
	&errorInfo{errors.IsUnauthorized, errors.Unauthorizedf, errors.NewUnauthorized, ""},
	&errorInfo{errors.IsNotImplemented, errors.NotImplementedf, errors.NewNotImplemented, " not implemented"},
	&errorInfo{errors.IsAlreadyExists, errors.AlreadyExistsf, errors.NewAlreadyExists, " already exists"},
	&errorInfo{errors.IsNotSupported, errors.NotSupportedf, errors.NewNotSupported, " not supported"},
}

type errorsSuite struct{}

var _ = gc.Suite(&errorsSuite{})

func Test(t *testing.T) {
	gc.TestingT(t)
}

func (t *errorInfo) satisfierName() string {
	value := reflect.ValueOf(t.satisfier)
	f := runtime.FuncForPC(value.Pointer())
	return f.Name()
}

func (t *errorInfo) equal(t0 *errorInfo) bool {
	if t0 == nil {
		return false
	}
	return t.satisfierName() == t0.satisfierName()
}

type errorTest struct {
	err     error
	message string
	errInfo *errorInfo
}

func contextf(err error, format string, args ...interface{}) error {
	errors.Contextf(&err, format, args...)
	return err
}

func maskf(err error, format string, args ...interface{}) error {
	errors.Maskf(&err, format, args...)
	return err
}

func mustSatisfy(c *gc.C, err error, errInfo *errorInfo) {
	if errInfo != nil {
		msg := fmt.Sprintf("%#v must satisfy %v", err, errInfo.satisfierName())
		c.Check(err, jc.Satisfies, errInfo.satisfier, gc.Commentf(msg))
	}
}

func mustNotSatisfy(c *gc.C, err error, errInfo *errorInfo) {
	if errInfo != nil {
		msg := fmt.Sprintf("%#v must not satisfy %v", err, errInfo.satisfierName())
		c.Check(err, gc.Not(jc.Satisfies), errInfo.satisfier, gc.Commentf(msg))
	}
}

func checkErrorMatches(c *gc.C, err error, message string, errInfo *errorInfo) {
	if err == nil {
		c.Check(err, gc.IsNil)
		c.Check(errInfo, gc.IsNil)
		c.Check(message, gc.Equals, "<nil>")
	} else {
		c.Check(err, gc.ErrorMatches, message)
	}
}

func (*errorsSuite) TestMaskf(c *gc.C) {
	// Ensure Maskf masks all known errors and their satisfiers don't
	// succeed.
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			maskf(nil, "masked"),
			"<nil>",
			nil,
		}, {
			maskf(stderrors.New("blast"), "masked"),
			"masked: blast",
			nil,
		}, {
			maskf(errInfo.argsConstructor("foo %d", 42), "masked %d", 69),
			"masked 69: foo 42" + errInfo.suffix,
			errInfo,
		}, {
			maskf(errInfo.argsConstructor(""), "masked"),
			"masked: " + errInfo.suffix,
			errInfo,
		}, {
			maskf(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "masked"),
			"masked: woo: pow!",
			errInfo,
		}}...)
	}

	for i, t := range errorTests {
		c.Logf("test %d: %T: %v", i, t.err, t.err)
		checkErrorMatches(c, t.err, t.message, t.errInfo)
		mustNotSatisfy(c, t.err, t.errInfo)

		// Check all other satisfiers to make sure none match.
		for _, otherErrInfo := range allErrors {
			mustNotSatisfy(c, t.err, otherErrInfo)
		}
	}
}

func (*errorsSuite) TestContextf(c *gc.C) {
	// Ensure Contextf masks only unknown error types, but passes through known ones.
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			contextf(nil, "prefix"),
			"<nil>",
			nil,
		}, {
			contextf(stderrors.New("blast"), "prefix"),
			"prefix: blast",
			nil,
		}, {
			contextf(errInfo.argsConstructor("foo %d", 42), "prefix %d", 69),
			"prefix 69: foo 42" + errInfo.suffix,
			errInfo,
		}, {
			contextf(errInfo.argsConstructor(""), "prefix"),
			"prefix: " + errInfo.suffix,
			errInfo,
		}, {
			contextf(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "prefix"),
			"prefix: woo: pow!",
			errInfo,
		}}...)
	}

	for i, t := range errorTests {
		if t.err == nil {
			c.Logf("test %d: nil: %v", i, t.err)
			c.Check(t.message, gc.Equals, "<nil>")
			c.Check(t.errInfo, gc.IsNil)
			continue
		}
		c.Logf("test %d: %T: %v", i, t.err, t.err)
		checkErrorMatches(c, t.err, t.message, t.errInfo)
		mustSatisfy(c, t.err, t.errInfo)

		// Check all other satisfiers to make sure none match.
		for _, otherErrInfo := range allErrors {
			if otherErrInfo.equal(t.errInfo) {
				continue
			}
			mustNotSatisfy(c, t.err, otherErrInfo)
		}
	}
}

func (*errorsSuite) TestAllErrors(c *gc.C) {
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			nil,
			"<nil>",
			nil,
		}, {
			errInfo.argsConstructor("foo %d", 42),
			"foo 42" + errInfo.suffix,
			errInfo,
		}, {
			errInfo.argsConstructor(""),
			errInfo.suffix,
			errInfo,
		}, {
			errInfo.wrapConstructor(stderrors.New("pow!"), "prefix"),
			"prefix: pow!",
			errInfo,
		}, {
			errInfo.wrapConstructor(stderrors.New("pow!"), ""),
			"pow!",
			errInfo,
		}, {
			errInfo.wrapConstructor(nil, "prefix"),
			"prefix",
			errInfo,
		}}...)
	}

	for i, t := range errorTests {
		if t.err == nil {
			c.Logf("test %d: nil: %v", i, t.err)
			c.Check(t.message, gc.Equals, "<nil>")
			c.Check(t.errInfo, gc.IsNil)
			continue
		}
		c.Logf("test %d: %T: %v", i, t.err, t.err)
		c.Check(t.err, gc.ErrorMatches, t.message)
		c.Check(t.errInfo, gc.NotNil)
		testSatisfierName := t.errInfo.satisfierName()
		c.Check(t.err,
			jc.Satisfies,
			t.errInfo.satisfier,
			gc.Commentf("%#v must satisfy %v", t.err, testSatisfierName))

		// Check all other satisfiers to make sure none match.
		for _, errInfo := range allErrors {
			if errInfo.satisfierName() == testSatisfierName {
				continue
			}
			c.Check(t.err,
				gc.Not(jc.Satisfies),
				errInfo.satisfier,
				gc.Commentf("%#v must not satisfy %v", t.err, errInfo.satisfierName()))
		}
	}
}
<commit_msg>Changes after review<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package errors_test

import (
	stderrors "errors"
	"fmt"
	"reflect"
	"runtime"
	"testing"

	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/errors"
)

// errorInfo holds information about a single error type: a satisfier
// function, wrapping and variable arguments constructors and message
// suffix.
type errorInfo struct {
	satisfier       func(error) bool
	argsConstructor func(string, ...interface{}) error
	wrapConstructor func(error, string) error
	suffix          string
}

// allErrors holds information for all defined errors. When adding new
// errors, add them here as well to include them in tests.
var allErrors = []*errorInfo{
	&errorInfo{errors.IsNotFound, errors.NotFoundf, errors.NewNotFound, " not found"},
	&errorInfo{errors.IsUnauthorized, errors.Unauthorizedf, errors.NewUnauthorized, ""},
	&errorInfo{errors.IsNotImplemented, errors.NotImplementedf, errors.NewNotImplemented, " not implemented"},
	&errorInfo{errors.IsAlreadyExists, errors.AlreadyExistsf, errors.NewAlreadyExists, " already exists"},
	&errorInfo{errors.IsNotSupported, errors.NotSupportedf, errors.NewNotSupported, " not supported"},
}

type errorsSuite struct{}

var _ = gc.Suite(&errorsSuite{})

func Test(t *testing.T) {
	gc.TestingT(t)
}

func (t *errorInfo) satisfierName() string {
	value := reflect.ValueOf(t.satisfier)
	f := runtime.FuncForPC(value.Pointer())
	return f.Name()
}

func (t *errorInfo) equal(t0 *errorInfo) bool {
	if t0 == nil {
		return false
	}
	return t.satisfierName() == t0.satisfierName()
}

type errorTest struct {
	err     error
	message string
	errInfo *errorInfo
}

func contextf(err error, format string, args ...interface{}) error {
	errors.Contextf(&err, format, args...)
	return err
}

func maskf(err error, format string, args ...interface{}) error {
	errors.Maskf(&err, format, args...)
	return err
}

func mustSatisfy(c *gc.C, err error, errInfo *errorInfo) {
	if errInfo != nil {
		msg := fmt.Sprintf("%#v must satisfy %v", err, errInfo.satisfierName())
		c.Check(err, jc.Satisfies, errInfo.satisfier, gc.Commentf(msg))
	}
}

func mustNotSatisfy(c *gc.C, err error, errInfo *errorInfo) {
	if errInfo != nil {
		msg := fmt.Sprintf("%#v must not satisfy %v", err, errInfo.satisfierName())
		c.Check(err, gc.Not(jc.Satisfies), errInfo.satisfier, gc.Commentf(msg))
	}
}

func checkErrorMatches(c *gc.C, err error, message string, errInfo *errorInfo) {
	if message == "<nil>" {
		c.Check(err, gc.IsNil)
		c.Check(errInfo, gc.IsNil)
	} else {
		c.Check(err, gc.ErrorMatches, message)
	}
}

func runErrorTests(c *gc.C, errorTests []errorTest, checkMustSatisfy bool) {
	for i, t := range errorTests {
		c.Logf("test %d: %T: %v", i, t.err, t.err)
		checkErrorMatches(c, t.err, t.message, t.errInfo)
		if checkMustSatisfy {
			mustSatisfy(c, t.err, t.errInfo)
		}

		// Check all other satisfiers to make sure none match.
		for _, otherErrInfo := range allErrors {
			if checkMustSatisfy && otherErrInfo.equal(t.errInfo) {
				continue
			}
			mustNotSatisfy(c, t.err, otherErrInfo)
		}
	}
}

func (*errorsSuite) TestMaskf(c *gc.C) {
	// Ensure Maskf masks all known errors and their satisfiers don't
	// succeed.
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			maskf(nil, "masked"),
			"<nil>",
			nil,
		}, {
			maskf(stderrors.New("blast"), "masked"),
			"masked: blast",
			nil,
		}, {
			maskf(errInfo.argsConstructor("foo %d", 42), "masked %d", 69),
			"masked 69: foo 42" + errInfo.suffix,
			errInfo,
		}, {
			maskf(errInfo.argsConstructor(""), "masked"),
			"masked: " + errInfo.suffix,
			errInfo,
		}, {
			maskf(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "masked"),
			"masked: woo: pow!",
			errInfo,
		}}...)
	}

	runErrorTests(c, errorTests, false)
}

func (*errorsSuite) TestContextf(c *gc.C) {
	// Ensure Contextf masks only unknown error types, but passes through known ones.
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			contextf(nil, "prefix"),
			"<nil>",
			nil,
		}, {
			contextf(stderrors.New("blast"), "prefix"),
			"prefix: blast",
			nil,
		}, {
			contextf(errInfo.argsConstructor("foo %d", 42), "prefix %d", 69),
			"prefix 69: foo 42" + errInfo.suffix,
			errInfo,
		}, {
			contextf(errInfo.argsConstructor(""), "prefix"),
			"prefix: " + errInfo.suffix,
			errInfo,
		}, {
			contextf(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "prefix"),
			"prefix: woo: pow!",
			errInfo,
		}}...)
	}

	runErrorTests(c, errorTests, true)
}

func (*errorsSuite) TestAllErrors(c *gc.C) {
	errorTests := []errorTest{}
	for _, errInfo := range allErrors {
		errorTests = append(errorTests, []errorTest{{
			nil,
			"<nil>",
			nil,
		}, {
			errInfo.argsConstructor("foo %d", 42),
			"foo 42" + errInfo.suffix,
			errInfo,
		}, {
			errInfo.argsConstructor(""),
			errInfo.suffix,
			errInfo,
		}, {
			errInfo.wrapConstructor(stderrors.New("pow!"), "prefix"),
			"prefix: pow!",
			errInfo,
		}, {
			errInfo.wrapConstructor(stderrors.New("pow!"), ""),
			"pow!",
			errInfo,
		}, {
			errInfo.wrapConstructor(nil, "prefix"),
			"prefix",
			errInfo,
		}}...)
	}

	runErrorTests(c, errorTests, true)
}
<|endoftext|>


<commit_before>package main

import "fmt"

const url = "https://s3-ap-northeast-1.amazonaws.com/splatoon-data.nintendo.net/stages_info.json"

var mapNames map[string]string

func init() {
	mapNames = map[string]string{
		"eefffc33ee1956b7b70e250d5835aa67be9152d42bc76aa8874987ebdfc19944": "Urchin Underpass",
		"b8067d2839476ec39072e371b4c59fa85454cdb618515af080ca6080772f3264": "Port Mackerel",
		"50c01bca5b3117f4f7893df86d2e2d95435dbb1aae1da6831b8e74838859bc7d": "Saltspray Rig",
		"9a1736540c3fde7e409cb9c7e333441157d88dfe8ce92bc6aafcb9f79c56cb3d": "Blackbelly Skatepark",
		"d7bf0ca4466e980f994ef7b32faeb71d80611a28c5b9feef84a00e3c4c9d7bc1": "Walleye Warehouse",
		"8c69b7c9a81369b5cfd22adbf41c13a8df01969ff3d0e531a8bcb042156bc549": "Arowana Mall",
		"1ac0981d03c18576d9517f40461b66a472168a8f14f6a8714142af9805df7b8c": "Bluefin Depot",
		"c52a7ab7202a576ee18d94be687d97190e90fdcc25fc4b1591c1a8e0c1c299a5": "Kelp Dome",
		"6a6c3a958712adedcceb34f719e220ab0d840d8753e5f51b089d363bd1763c91": "Moray Towers",
	}
}

func englishIfy(s *Stage) string {
	name, ok := mapNames[s.ID]
	if !ok {
		return fmt.Sprintf("Please tell Xena the name of stage id \"%s\" with jpn name %s", s.ID, s.Name)
	}

	return name
}
<commit_msg>Add flouder heights<commit_after>package main

import "fmt"

const url = "https://s3-ap-northeast-1.amazonaws.com/splatoon-data.nintendo.net/stages_info.json"

var mapNames map[string]string

func init() {
	mapNames = map[string]string{
		"eefffc33ee1956b7b70e250d5835aa67be9152d42bc76aa8874987ebdfc19944": "Urchin Underpass",
		"b8067d2839476ec39072e371b4c59fa85454cdb618515af080ca6080772f3264": "Port Mackerel",
		"50c01bca5b3117f4f7893df86d2e2d95435dbb1aae1da6831b8e74838859bc7d": "Saltspray Rig",
		"9a1736540c3fde7e409cb9c7e333441157d88dfe8ce92bc6aafcb9f79c56cb3d": "Blackbelly Skatepark",
		"d7bf0ca4466e980f994ef7b32faeb71d80611a28c5b9feef84a00e3c4c9d7bc1": "Walleye Warehouse",
		"8c69b7c9a81369b5cfd22adbf41c13a8df01969ff3d0e531a8bcb042156bc549": "Arowana Mall",
		"1ac0981d03c18576d9517f40461b66a472168a8f14f6a8714142af9805df7b8c": "Bluefin Depot",
		"c52a7ab7202a576ee18d94be687d97190e90fdcc25fc4b1591c1a8e0c1c299a5": "Kelp Dome",
		"6a6c3a958712adedcceb34f719e220ab0d840d8753e5f51b089d363bd1763c91": "Moray Towers",
		"a54716422edf71ac0b3d20fbb4ba5970a7a78ba304fcf935aaf69254d61ca709": "Flounder Heights",
	}
}

func englishIfy(s *Stage) string {
	name, ok := mapNames[s.ID]
	if !ok {
		return fmt.Sprintf("Please tell Xena the name of stage id \"%s\" with jpn name %s", s.ID, s.Name)
	}

	return name
}
<|endoftext|>


<commit_before>package ssdp

// Advertiser is a server to advertise a service.
type Advertiser struct {
}

// Advertise starts advertisement of service.
func Advertise(st, usn, location, server string, maxAge int) (*Advertiser, error) {
	// TODO:
	return nil, nil
}

// Close stops advertisement.
func (a *Advertiser) Close() error {
	// TODO:
	return nil
}

// Alive announces ssdp:alive message.
func (a *Advertiser) Alive() error {
	// TODO:
	return nil
}

// Bye announces ssdp:byebye message.
func (a *Advertiser) Bye() error {
	// TODO:
	return nil
}
<commit_msg>member of advertiser<commit_after>package ssdp

// Advertiser is a server to advertise a service.
type Advertiser struct {
	st       string
	usn      string
	location string
	server   string
	maxAge   int
}

// Advertise starts advertisement of service.
func Advertise(st, usn, location, server string, maxAge int) (*Advertiser, error) {
	// TODO:
	return &Advertiser{
		st:       st,
		usn:      usn,
		location: location,
		server:   server,
		maxAge:   maxAge,
	}, nil
}

// Close stops advertisement.
func (a *Advertiser) Close() error {
	// TODO:
	return nil
}

// Alive announces ssdp:alive message.
func (a *Advertiser) Alive() error {
	// TODO:
	return nil
}

// Bye announces ssdp:byebye message.
func (a *Advertiser) Bye() error {
	// TODO:
	return nil
}
<|endoftext|>


<commit_before>package task

import (
	"fmt"
	"neon/build"
	"neon/util"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

func init() {
	build.TaskMap["execute"] = build.TaskDescriptor{
		Constructor: Execute,
		Help: `Execute a command and return output and value.

Arguments:

- execute: command to run.
- output: name of the variable to store trimed output into.

Examples:

    # execute ls command and get result in 'files' variable
    - execute: 'ls'
	  output:  'files'`,
	}
}

func Execute(target *build.Target, args util.Object) (build.Task, error) {
	fields := []string{"execute", "output"}
	if err := CheckFields(args, fields, fields); err != nil {
		return nil, err
	}
	execute, ok := args["execute"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task execute must be a string")
	}
	output, ok := args["output"].(string)
	if !ok {
		return nil, fmt.Errorf("argument output of task execute must be a string")
	}
	return func() error {
		cmd, err := target.Build.Context.ReplaceProperties(execute)
		if err != nil {
			return fmt.Errorf("processing execute argument: %v", err)
		}
		var command *exec.Cmd
		if runtime.GOOS == "windows" {
			command = exec.Command("cmd.exe", "/C", cmd)
		} else {
			command = exec.Command("sh", "-c", cmd)
		}
		dir, err := os.Getwd()
		if err != nil {
			return fmt.Errorf("getting current working directory: %v", err)
		}
		command.Dir = dir
		command.Env, err = target.Build.Context.GetEnvironment()
		if err != nil {
			return fmt.Errorf("building environment: %v", err)
		}
		bytes, err := command.CombinedOutput()
		target.Build.Context.SetProperty(output, strings.TrimSpace(string(bytes)))
		if err != nil {
			return fmt.Errorf("executing command: %v", err)
		}
		return nil
	}, nil
}
<commit_msg>Fixed indentation<commit_after>package task

import (
	"fmt"
	"neon/build"
	"neon/util"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

func init() {
	build.TaskMap["execute"] = build.TaskDescriptor{
		Constructor: Execute,
		Help: `Execute a command and return output and value.

Arguments:

- execute: command to run.
- output: name of the variable to store trimed output into.

Examples:

    # execute ls command and get result in 'files' variable
    - execute: 'ls'
      output:  'files'`,
	}
}

func Execute(target *build.Target, args util.Object) (build.Task, error) {
	fields := []string{"execute", "output"}
	if err := CheckFields(args, fields, fields); err != nil {
		return nil, err
	}
	execute, ok := args["execute"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task execute must be a string")
	}
	output, ok := args["output"].(string)
	if !ok {
		return nil, fmt.Errorf("argument output of task execute must be a string")
	}
	return func() error {
		cmd, err := target.Build.Context.ReplaceProperties(execute)
		if err != nil {
			return fmt.Errorf("processing execute argument: %v", err)
		}
		var command *exec.Cmd
		if runtime.GOOS == "windows" {
			command = exec.Command("cmd.exe", "/C", cmd)
		} else {
			command = exec.Command("sh", "-c", cmd)
		}
		dir, err := os.Getwd()
		if err != nil {
			return fmt.Errorf("getting current working directory: %v", err)
		}
		command.Dir = dir
		command.Env, err = target.Build.Context.GetEnvironment()
		if err != nil {
			return fmt.Errorf("building environment: %v", err)
		}
		bytes, err := command.CombinedOutput()
		target.Build.Context.SetProperty(output, strings.TrimSpace(string(bytes)))
		if err != nil {
			return fmt.Errorf("executing command: %v", err)
		}
		return nil
	}, nil
}
<|endoftext|>