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

package sensors

/*
#cgo LDFLAGS: -llog -landroid

#include <stdlib.h>
#include <android/sensor.h>

#include "sensors_android.h"
*/
import "C"
import (
	"runtime"
	"unsafe"
)
import "time"

var (
	aStop chan struct{}
)

func init() {
	C.initSensors()
}

func startAccelerometer(fn func(deltaX, deltaY, deltaZ float64)) {
	aStop = make(chan struct{})
	go func() {
		// TODO(jbd): Need to runtime.LockOSThread?
		runtime.LockOSThread()
		C.startAccelerometer()
		for {
			select {
			case <-aStop:
				return
			default:
				ev := C.pollAccelerometer()
				fn(float64(ev.x), float64(ev.y), float64(ev.z))
				C.free(unsafe.Pointer(ev))
			}
			time.Sleep(time.Microsecond)
		}
	}()
}

func stopAccelerometer() {
	aStop <- struct{}{}
	C.destroyAccelerometer()
}
<commit_msg>reformat imports.<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sensors

/*
#cgo LDFLAGS: -llog -landroid

#include <stdlib.h>
#include <android/sensor.h>

#include "sensors_android.h"
*/
import "C"
import (
	"runtime"
	"time"
	"unsafe"
)

var (
	aStop chan struct{}
)

func init() {
	C.initSensors()
}

func startAccelerometer(fn func(deltaX, deltaY, deltaZ float64)) {
	aStop = make(chan struct{})
	go func() {
		// TODO(jbd): Need to runtime.LockOSThread?
		runtime.LockOSThread()
		C.startAccelerometer()
		for {
			select {
			case <-aStop:
				return
			default:
				ev := C.pollAccelerometer()
				fn(float64(ev.x), float64(ev.y), float64(ev.z))
				C.free(unsafe.Pointer(ev))
			}
			time.Sleep(time.Microsecond)
		}
	}()
}

func stopAccelerometer() {
	aStop <- struct{}{}
	C.destroyAccelerometer()
}
<|endoftext|>


<commit_before>package sparse

type BoolSlice struct {
	m     []int64
	msize int64
	size  int64
}

func NewBoolSlice() *BoolSlice {
	return &BoolSlice{
		m:     make([]int64, 1),
		msize: 1,
	}
}

func (bs *BoolSlice) Size() int64 {
	return bs.size
}

func (bs *BoolSlice) Get(idx int64) (v bool) {
	var i, cursor int64

	for ; i < bs.msize; i++ {
		cursor += bs.m[i]
		if idx < cursor {
			return
		}
		v = !v
	}

	return
}

func (bs *BoolSlice) Set(i int64, v bool) {
	// TODO
}

func (bs *BoolSlice) Append(v bool) {
	if (bs.msize&1 == 0) == v {
		bs.m[bs.msize]++
	} else {
		bs.m = append(bs.m, 1)
		bs.msize++
	}
	bs.size++
}

func BoolSliceFromSlice(s []bool) *BoolSlice {
	var idx, msize int64
	var currval bool

	msize = 1

	slen := len(s)

	for i := 0; i < slen; i++ {
		if s[i] != currval {
			msize++
			currval = !currval
		}
	}

	bs := &BoolSlice{
		m:     make([]int64, msize),
		msize: msize,
		size:  int64(slen),
	}

	currval = false
	for i := 0; i < slen; {
		if s[i] == currval {
			bs.m[idx]++
			i++
			continue
		}
		currval = !currval
		idx++
	}

	return bs
}

func (bs *BoolSlice) ToSlice() []bool {
	var i, j, cursor int64
	var currval bool

	b := make([]bool, bs.size)

	for ; i < bs.msize; i++ {
		for j = 0; j < bs.m[i]; j++ {
			b[cursor] = currval
			cursor++
		}
		currval = !currval
	}

	return b
}
<commit_msg>BoolSlice#Append: index error fixed<commit_after>package sparse

type BoolSlice struct {
	m     []int64
	msize int64
	size  int64
}

func NewBoolSlice() *BoolSlice {
	return &BoolSlice{
		m:     make([]int64, 1),
		msize: 1,
	}
}

func (bs *BoolSlice) Size() int64 {
	return bs.size
}

func (bs *BoolSlice) Get(idx int64) (v bool) {
	var i, cursor int64

	for ; i < bs.msize; i++ {
		cursor += bs.m[i]
		if idx < cursor {
			return
		}
		v = !v
	}

	return
}

func (bs *BoolSlice) Set(i int64, v bool) {
	// TODO
}

func (bs *BoolSlice) Append(v bool) {
	if (bs.msize&1 == 0) == v {
		bs.m[bs.msize-1]++
	} else {
		bs.m = append(bs.m, 1)
		bs.msize++
	}
	bs.size++
}

func BoolSliceFromSlice(s []bool) *BoolSlice {
	var idx, msize int64
	var currval bool

	msize = 1

	slen := len(s)

	for i := 0; i < slen; i++ {
		if s[i] != currval {
			msize++
			currval = !currval
		}
	}

	bs := &BoolSlice{
		m:     make([]int64, msize),
		msize: msize,
		size:  int64(slen),
	}

	currval = false
	for i := 0; i < slen; {
		if s[i] == currval {
			bs.m[idx]++
			i++
			continue
		}
		currval = !currval
		idx++
	}

	return bs
}

func (bs *BoolSlice) ToSlice() []bool {
	var i, j, cursor int64
	var currval bool

	b := make([]bool, bs.size)

	for ; i < bs.msize; i++ {
		for j = 0; j < bs.m[i]; j++ {
			b[cursor] = currval
			cursor++
		}
		currval = !currval
	}

	return b
}
<|endoftext|>


<commit_before>package main

import "data-structures/btree/tree"

type IntNode int

func (n IntNode) Less(other tree.Node) bool {
	// TODO: need to handle type assertion error
	return n < other.(IntNode)
}

type StringNode string

func (n StringNode) Less(other tree.Node) bool {
	// TODO: need to handle type assertion error
	return n < other.(StringNode)
}

func main() {
	intBT := tree.New()
	intBT.Insert(IntNode(5))
	intBT.Insert(IntNode(1))
	intBT.Insert(IntNode(7))
	intBT.Insert(IntNode(2))
	intBT.Insert(IntNode(4))
	intBT.Insert(IntNode(6))
	intBT.Insert(IntNode(3))
	intBT.Walk()

	stringBT := tree.New()
	stringBT.Insert(StringNode("ello"))
	stringBT.Insert(StringNode("der"))
	stringBT.Insert(StringNode("ost"))
	stringBT.Insert(StringNode("a"))
	stringBT.Insert(StringNode("cy"))
	stringBT.Insert(StringNode("z"))
	stringBT.Insert(StringNode("j"))
	stringBT.Walk()
}
<commit_msg>- Fixed import path<commit_after>package main

import "github.com/caelifer/data-structures-in-go/btree/tree"

type IntNode int

func (n IntNode) Less(other tree.Node) bool {
	// TODO: need to handle type assertion error
	return n < other.(IntNode)
}

type StringNode string

func (n StringNode) Less(other tree.Node) bool {
	// TODO: need to handle type assertion error
	return n < other.(StringNode)
}

func main() {
	intBT := tree.New()
	intBT.Insert(IntNode(5))
	intBT.Insert(IntNode(1))
	intBT.Insert(IntNode(7))
	intBT.Insert(IntNode(2))
	intBT.Insert(IntNode(4))
	intBT.Insert(IntNode(6))
	intBT.Insert(IntNode(3))
	intBT.Walk()

	stringBT := tree.New()
	stringBT.Insert(StringNode("ello"))
	stringBT.Insert(StringNode("der"))
	stringBT.Insert(StringNode("ost"))
	stringBT.Insert(StringNode("a"))
	stringBT.Insert(StringNode("cy"))
	stringBT.Insert(StringNode("z"))
	stringBT.Insert(StringNode("j"))
	stringBT.Walk()
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/ory/viper"
	"github.com/spf13/cobra"

	bosonFunc "github.com/boson-project/func"
	"github.com/boson-project/func/buildpacks"
	"github.com/boson-project/func/prompt"
)

func init() {
	root.AddCommand(buildCmd)
	buildCmd.Flags().StringP("builder", "b", "default", "Buildpack builder, either an as a an image name or a mapping name as defined in func.yaml")
	buildCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
	buildCmd.Flags().StringP("image", "i", "", "Full image name in the orm [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE")
	buildCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
	buildCmd.Flags().StringP("registry", "r", "", "Registry + namespace part of the image to build, ex 'quay.io/myuser'.  The full image name is automatically determined based on the local directory name. If not provided the registry will be taken from func.yaml (Env: $FUNC_REGISTRY)")

	err := buildCmd.RegisterFlagCompletionFunc("builder", CompleteBuilderList)
	if err != nil {
		fmt.Println("internal: error while calling RegisterFlagCompletionFunc: ", err)
	}
}

var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "Build a function project as a container image",
	Long: `Build a function project as a container image

This command builds the function project in the current directory or in the directory
specified by --path. The result will be a container image that is pushed to a registry.
The func.yaml file is read to determine the image name and registry.
If the project has not already been built, either --registry or --image must be provided
and the image name is stored in the configuration file.
`,
	Example: `
# Build from the local directory, using the given registry as target.
# The full image name will be determined automatically based on the
# project directory name
kn func build --registry quay.io/myuser

# Build from the local directory, specifying the full image name
kn func build --image quay.io/myuser/myfunc

# Re-build, picking up a previously supplied image name from a local func.yml
kn func build

# Build with a custom buildpack builder
kn func build --builder cnbs/sample-builder:bionic
`,
	SuggestFor: []string{"biuld", "buidl", "built"},
	PreRunE:    bindEnv("image", "path", "builder", "registry", "confirm"),
	RunE:       runBuild,
}

func runBuild(cmd *cobra.Command, _ []string) (err error) {
	config := newBuildConfig().Prompt()

	function, err := functionWithOverrides(config.Path, functionOverrides{Builder: config.Builder, Image: config.Image})
	if err != nil {
		return
	}

	// Check if the Function has been initialized
	if !function.Initialized() {
		return fmt.Errorf("the given path '%v' does not contain an initialized function. Please create one at this path before deploying", config.Path)
	}

	// If the Function does not yet have an image name and one was not provided on the command line
	if function.Image == "" {
		//  AND a --registry was not provided, then we need to
		// prompt for a registry from which we can derive an image name.
		if config.Registry == "" {
			fmt.Print("A registry for function images is required (e.g. 'quay.io/boson').\n\n")
			config.Registry = prompt.ForString("Registry for function images", "")
			if config.Registry == "" {
				return fmt.Errorf("unable to determine function image name")
			}
		}

		// We have the registry, so let's use it to derive the Function image name
		config.Image = deriveImage(config.Image, config.Registry, config.Path)
		function.Image = config.Image
	}

	// All set, let's write changes in the config to the disk
	err = function.WriteConfig()
	if err != nil {
		return
	}

	builder := buildpacks.NewBuilder()
	builder.Verbose = config.Verbose

	client := bosonFunc.New(
		bosonFunc.WithVerbose(config.Verbose),
		bosonFunc.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
		bosonFunc.WithBuilder(builder))

	return client.Build(cmd.Context(), config.Path)
}

type buildConfig struct {
	// Image name in full, including registry, repo and tag (overrides
	// image name derivation based on Registry and Function Name)
	Image string

	// Path of the Function implementation on local disk. Defaults to current
	// working directory of the process.
	Path string

	// Push the resulting image to the registry after building.
	Push bool

	// Registry at which interstitial build artifacts should be kept.
	// This setting is ignored if Image is specified, which includes the full
	Registry string

	// Verbose logging.
	Verbose bool

	// Confirm: confirm values arrived upon from environment plus flags plus defaults,
	// with interactive prompting (only applicable when attached to a TTY).
	Confirm bool
	Builder string
}

func newBuildConfig() buildConfig {
	return buildConfig{
		Image:    viper.GetString("image"),
		Path:     viper.GetString("path"),
		Registry: viper.GetString("registry"),
		Verbose:  viper.GetBool("verbose"), // defined on root
		Confirm:  viper.GetBool("confirm"),
		Builder:  viper.GetString("builder"),
	}
}

// Prompt the user with value of config members, allowing for interaractive changes.
// Skipped if not in an interactive terminal (non-TTY), or if --confirm false (agree to
// all prompts) was set (default).
func (c buildConfig) Prompt() buildConfig {
	imageName := deriveImage(c.Image, c.Registry, c.Path)
	if !interactiveTerminal() || !c.Confirm {
		return c
	}
	return buildConfig{
		Path:    prompt.ForString("Path to project directory", c.Path),
		Image:   prompt.ForString("Full image name (e.g. quay.io/boson/node-sample)", imageName, prompt.WithRequired(true)),
		Verbose: c.Verbose,
		// Registry not prompted for as it would be confusing when combined with explicit image.  Instead it is
		// inferred by the derived default for Image, which uses Registry for derivation.
	}
}
<commit_msg>fix: default for `--builder` flag<commit_after>package cmd

import (
	"fmt"

	"github.com/ory/viper"
	"github.com/spf13/cobra"

	bosonFunc "github.com/boson-project/func"
	"github.com/boson-project/func/buildpacks"
	"github.com/boson-project/func/prompt"
)

func init() {
	root.AddCommand(buildCmd)
	buildCmd.Flags().StringP("builder", "b", "", "Buildpack builder, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml for subsequent builds.")
	buildCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
	buildCmd.Flags().StringP("image", "i", "", "Full image name in the orm [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE")
	buildCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
	buildCmd.Flags().StringP("registry", "r", "", "Registry + namespace part of the image to build, ex 'quay.io/myuser'.  The full image name is automatically determined based on the local directory name. If not provided the registry will be taken from func.yaml (Env: $FUNC_REGISTRY)")

	err := buildCmd.RegisterFlagCompletionFunc("builder", CompleteBuilderList)
	if err != nil {
		fmt.Println("internal: error while calling RegisterFlagCompletionFunc: ", err)
	}
}

var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "Build a function project as a container image",
	Long: `Build a function project as a container image

This command builds the function project in the current directory or in the directory
specified by --path. The result will be a container image that is pushed to a registry.
The func.yaml file is read to determine the image name and registry.
If the project has not already been built, either --registry or --image must be provided
and the image name is stored in the configuration file.
`,
	Example: `
# Build from the local directory, using the given registry as target.
# The full image name will be determined automatically based on the
# project directory name
kn func build --registry quay.io/myuser

# Build from the local directory, specifying the full image name
kn func build --image quay.io/myuser/myfunc

# Re-build, picking up a previously supplied image name from a local func.yml
kn func build

# Build with a custom buildpack builder
kn func build --builder cnbs/sample-builder:bionic
`,
	SuggestFor: []string{"biuld", "buidl", "built"},
	PreRunE:    bindEnv("image", "path", "builder", "registry", "confirm"),
	RunE:       runBuild,
}

func runBuild(cmd *cobra.Command, _ []string) (err error) {
	config := newBuildConfig().Prompt()

	function, err := functionWithOverrides(config.Path, functionOverrides{Builder: config.Builder, Image: config.Image})
	if err != nil {
		return
	}

	// Check if the Function has been initialized
	if !function.Initialized() {
		return fmt.Errorf("the given path '%v' does not contain an initialized function. Please create one at this path before deploying", config.Path)
	}

	// If the Function does not yet have an image name and one was not provided on the command line
	if function.Image == "" {
		//  AND a --registry was not provided, then we need to
		// prompt for a registry from which we can derive an image name.
		if config.Registry == "" {
			fmt.Print("A registry for function images is required (e.g. 'quay.io/boson').\n\n")
			config.Registry = prompt.ForString("Registry for function images", "")
			if config.Registry == "" {
				return fmt.Errorf("unable to determine function image name")
			}
		}

		// We have the registry, so let's use it to derive the Function image name
		config.Image = deriveImage(config.Image, config.Registry, config.Path)
		function.Image = config.Image
	}

	// All set, let's write changes in the config to the disk
	err = function.WriteConfig()
	if err != nil {
		return
	}

	builder := buildpacks.NewBuilder()
	builder.Verbose = config.Verbose

	client := bosonFunc.New(
		bosonFunc.WithVerbose(config.Verbose),
		bosonFunc.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
		bosonFunc.WithBuilder(builder))

	return client.Build(cmd.Context(), config.Path)
}

type buildConfig struct {
	// Image name in full, including registry, repo and tag (overrides
	// image name derivation based on Registry and Function Name)
	Image string

	// Path of the Function implementation on local disk. Defaults to current
	// working directory of the process.
	Path string

	// Push the resulting image to the registry after building.
	Push bool

	// Registry at which interstitial build artifacts should be kept.
	// This setting is ignored if Image is specified, which includes the full
	Registry string

	// Verbose logging.
	Verbose bool

	// Confirm: confirm values arrived upon from environment plus flags plus defaults,
	// with interactive prompting (only applicable when attached to a TTY).
	Confirm bool
	Builder string
}

func newBuildConfig() buildConfig {
	return buildConfig{
		Image:    viper.GetString("image"),
		Path:     viper.GetString("path"),
		Registry: viper.GetString("registry"),
		Verbose:  viper.GetBool("verbose"), // defined on root
		Confirm:  viper.GetBool("confirm"),
		Builder:  viper.GetString("builder"),
	}
}

// Prompt the user with value of config members, allowing for interaractive changes.
// Skipped if not in an interactive terminal (non-TTY), or if --confirm false (agree to
// all prompts) was set (default).
func (c buildConfig) Prompt() buildConfig {
	imageName := deriveImage(c.Image, c.Registry, c.Path)
	if !interactiveTerminal() || !c.Confirm {
		return c
	}
	return buildConfig{
		Path:    prompt.ForString("Path to project directory", c.Path),
		Image:   prompt.ForString("Full image name (e.g. quay.io/boson/node-sample)", imageName, prompt.WithRequired(true)),
		Verbose: c.Verbose,
		// Registry not prompted for as it would be confusing when combined with explicit image.  Instead it is
		// inferred by the derived default for Image, which uses Registry for derivation.
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Prometheus Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/pkg/errors"
	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/prometheus/promu/pkg/repository"
	"github.com/prometheus/promu/util/sh"
)

var (
	buildcmd        = app.Command("build", "Build a Go project")
	buildCgoFlagSet bool
	buildCgoFlag    = buildcmd.Flag("cgo", "Enable CGO").
			PreAction(func(c *kingpin.ParseContext) error {
			buildCgoFlagSet = true
			return nil
		}).Bool()
	prefixFlagSet bool
	prefixFlag    = buildcmd.Flag("prefix", "Specific dir to store binaries (default is .)").
			PreAction(func(c *kingpin.ParseContext) error {
			prefixFlagSet = true
			return nil
		}).String()
	binariesArg = buildcmd.Arg("binary-names", "Comma separated list of binaries to build").Default("all").Strings()
)

// Check if binary names passed to build command are in the config.
// Returns an array of Binary to build, or error.
func validateBinaryNames(binaryNames []string, cfgBinaries []Binary) ([]Binary, error) {
	var binaries []Binary

OUTER:
	for _, binaryName := range binaryNames {
		for _, binary := range cfgBinaries {
			if binaryName == binary.Name {
				binaries = append(binaries, binary)
				continue OUTER
			}
		}
		return nil, fmt.Errorf("binary %s not found in config", binaryName)
	}
	return binaries, nil
}

func buildBinary(ext string, prefix string, ldflags string, binary Binary) {
	info("Building binary: " + binary.Name)
	binaryName := fmt.Sprintf("%s%s", binary.Name, ext)
	fmt.Printf(" >   %s\n", binaryName)

	repoPath := config.Repository.Path
	flags := config.Build.Flags

	params := []string{"build",
		"-o", path.Join(prefix, binaryName),
		"-ldflags", ldflags,
	}

	params = append(params, sh.SplitParameters(flags)...)
	params = append(params, path.Join(repoPath, binary.Path))
	info("Building binary: " + "go " + strings.Join(params, " "))
	if err := sh.RunCommand("go", params...); err != nil {
		fatal(errors.Wrap(err, "command failed: "+strings.Join(params, " ")))
	}
}

func buildAll(ext string, prefix string, ldflags string, binaries []Binary) {
	for _, binary := range binaries {
		buildBinary(ext, prefix, ldflags, binary)
	}
}

func runBuild(binariesString string) {
	//Check required configuration
	if len(strings.TrimSpace(config.Repository.Path)) == 0 {
		log.Fatalf("missing required '%s' configuration", "repository.path")
	}
	if buildCgoFlagSet {
		config.Go.CGo = *buildCgoFlag
	}
	if prefixFlagSet {
		config.Build.Prefix = *prefixFlag
	}

	var (
		cgo    = config.Go.CGo
		prefix = config.Build.Prefix

		ext      string
		binaries = config.Build.Binaries
		ldflags  string
	)

	if goos == "windows" {
		ext = ".exe"
	}

	ldflags = getLdflags(projInfo)

	os.Setenv("CGO_ENABLED", "0")
	if cgo {
		os.Setenv("CGO_ENABLED", "1")
	}
	defer os.Unsetenv("CGO_ENABLED")

	if binariesString == "all" {
		buildAll(ext, prefix, ldflags, binaries)
		return
	}

	binariesArray := strings.Split(binariesString, ",")
	binariesToBuild, err := validateBinaryNames(binariesArray, binaries)
	if err != nil {
		fatal(errors.Wrap(err, "validation of given binary names for build command failed"))
	}

	for _, binary := range binariesToBuild {
		buildBinary(ext, prefix, ldflags, binary)
	}
}

func getLdflags(info repository.Info) string {
	var ldflags []string

	if len(strings.TrimSpace(config.Build.LDFlags)) > 0 {
		var buildDate time.Time
		unixBuildDate, err := strconv.ParseInt(os.Getenv("SOURCE_DATE_EPOCH"), 10, 64)
		if err == nil {
			buildDate = time.Unix(unixBuildDate, 0)
		} else {
			buildDate = time.Now()
		}
		var (
			tmplOutput = new(bytes.Buffer)
			fnMap      = template.FuncMap{
				"date":     buildDate.UTC().Format,
				"host":     os.Hostname,
				"repoPath": RepoPathFunc,
				"user":     UserFunc,
			}
			ldflagsTmpl = config.Build.LDFlags
		)

		tmpl, err := template.New("ldflags").Funcs(fnMap).Parse(ldflagsTmpl)
		if err != nil {
			fatal(errors.Wrap(err, "Failed to parse ldflags text/template"))
		}

		if err := tmpl.Execute(tmplOutput, info); err != nil {
			fatal(errors.Wrap(err, "Failed to execute ldflags text/template"))
		}

		ldflags = append(ldflags, strings.Split(tmplOutput.String(), "\n")...)
	} else {
		ldflags = append(ldflags, fmt.Sprintf("-X main.Version=%s", info.Version))
	}

	extLDFlags := config.Build.ExtLDFlags
	if config.Build.Static && goos != "darwin" && goos != "solaris" && goos != "illumos" && !stringInSlice("-static", extLDFlags) {
		extLDFlags = append(extLDFlags, "-static")
	}

	if len(extLDFlags) > 0 {
		ldflags = append(ldflags, fmt.Sprintf("-extldflags '%s'", strings.Join(extLDFlags, " ")))
	}

	return strings.Join(ldflags[:], " ")
}

// UserFunc returns the current username.
func UserFunc() (interface{}, error) {
	// os/user.Current() doesn't always work without CGO
	return shellOutput("whoami"), nil
}

// RepoPathFunc returns the repository path.
func RepoPathFunc() interface{} {
	return config.Repository.Path
}
<commit_msg>Validate environment variable value<commit_after>// Copyright © 2016 Prometheus Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"

	"github.com/pkg/errors"
	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/prometheus/promu/pkg/repository"
	"github.com/prometheus/promu/util/sh"
)

var (
	buildcmd        = app.Command("build", "Build a Go project")
	buildCgoFlagSet bool
	buildCgoFlag    = buildcmd.Flag("cgo", "Enable CGO").
			PreAction(func(c *kingpin.ParseContext) error {
			buildCgoFlagSet = true
			return nil
		}).Bool()
	prefixFlagSet bool
	prefixFlag    = buildcmd.Flag("prefix", "Specific dir to store binaries (default is .)").
			PreAction(func(c *kingpin.ParseContext) error {
			prefixFlagSet = true
			return nil
		}).String()
	binariesArg = buildcmd.Arg("binary-names", "Comma separated list of binaries to build").Default("all").Strings()
)

// Check if binary names passed to build command are in the config.
// Returns an array of Binary to build, or error.
func validateBinaryNames(binaryNames []string, cfgBinaries []Binary) ([]Binary, error) {
	var binaries []Binary

OUTER:
	for _, binaryName := range binaryNames {
		for _, binary := range cfgBinaries {
			if binaryName == binary.Name {
				binaries = append(binaries, binary)
				continue OUTER
			}
		}
		return nil, fmt.Errorf("binary %s not found in config", binaryName)
	}
	return binaries, nil
}

func buildBinary(ext string, prefix string, ldflags string, binary Binary) {
	info("Building binary: " + binary.Name)
	binaryName := fmt.Sprintf("%s%s", binary.Name, ext)
	fmt.Printf(" >   %s\n", binaryName)

	repoPath := config.Repository.Path
	flags := config.Build.Flags

	params := []string{"build",
		"-o", path.Join(prefix, binaryName),
		"-ldflags", ldflags,
	}

	params = append(params, sh.SplitParameters(flags)...)
	params = append(params, path.Join(repoPath, binary.Path))
	info("Building binary: " + "go " + strings.Join(params, " "))
	if err := sh.RunCommand("go", params...); err != nil {
		fatal(errors.Wrap(err, "command failed: "+strings.Join(params, " ")))
	}
}

func buildAll(ext string, prefix string, ldflags string, binaries []Binary) {
	for _, binary := range binaries {
		buildBinary(ext, prefix, ldflags, binary)
	}
}

func runBuild(binariesString string) {
	//Check required configuration
	if len(strings.TrimSpace(config.Repository.Path)) == 0 {
		log.Fatalf("missing required '%s' configuration", "repository.path")
	}
	if buildCgoFlagSet {
		config.Go.CGo = *buildCgoFlag
	}
	if prefixFlagSet {
		config.Build.Prefix = *prefixFlag
	}

	var (
		cgo    = config.Go.CGo
		prefix = config.Build.Prefix

		ext      string
		binaries = config.Build.Binaries
		ldflags  string
	)

	if goos == "windows" {
		ext = ".exe"
	}

	ldflags = getLdflags(projInfo)

	os.Setenv("CGO_ENABLED", "0")
	if cgo {
		os.Setenv("CGO_ENABLED", "1")
	}
	defer os.Unsetenv("CGO_ENABLED")

	if binariesString == "all" {
		buildAll(ext, prefix, ldflags, binaries)
		return
	}

	binariesArray := strings.Split(binariesString, ",")
	binariesToBuild, err := validateBinaryNames(binariesArray, binaries)
	if err != nil {
		fatal(errors.Wrap(err, "validation of given binary names for build command failed"))
	}

	for _, binary := range binariesToBuild {
		buildBinary(ext, prefix, ldflags, binary)
	}
}

func getLdflags(info repository.Info) string {
	var ldflags []string

	if len(strings.TrimSpace(config.Build.LDFlags)) > 0 {
		buildDate := getBuildDate()
		var (
			tmplOutput = new(bytes.Buffer)
			fnMap      = template.FuncMap{
				"date":     buildDate.UTC().Format,
				"host":     os.Hostname,
				"repoPath": RepoPathFunc,
				"user":     UserFunc,
			}
			ldflagsTmpl = config.Build.LDFlags
		)

		tmpl, err := template.New("ldflags").Funcs(fnMap).Parse(ldflagsTmpl)
		if err != nil {
			fatal(errors.Wrap(err, "Failed to parse ldflags text/template"))
		}

		if err := tmpl.Execute(tmplOutput, info); err != nil {
			fatal(errors.Wrap(err, "Failed to execute ldflags text/template"))
		}

		ldflags = append(ldflags, strings.Split(tmplOutput.String(), "\n")...)
	} else {
		ldflags = append(ldflags, fmt.Sprintf("-X main.Version=%s", info.Version))
	}

	extLDFlags := config.Build.ExtLDFlags
	if config.Build.Static && goos != "darwin" && goos != "solaris" && goos != "illumos" && !stringInSlice("-static", extLDFlags) {
		extLDFlags = append(extLDFlags, "-static")
	}

	if len(extLDFlags) > 0 {
		ldflags = append(ldflags, fmt.Sprintf("-extldflags '%s'", strings.Join(extLDFlags, " ")))
	}

	return strings.Join(ldflags[:], " ")
}

func getBuildDate() time.Time {
	var buildDate time.Time

	sourceDate := os.Getenv("SOURCE_DATE_EPOCH")
	if sourceDate == "" {
		buildDate = time.Now()
	} else {
		unixBuildDate, err := strconv.ParseInt(sourceDate, 10, 64)
		if err != nil {
			fatal(errors.Wrap(err, "Failed to parse SOURCE_DATE_EPOCH"))
		} else {
			buildDate = time.Unix(unixBuildDate, 0)
		}
	}
	return buildDate
}

// UserFunc returns the current username.
func UserFunc() (interface{}, error) {
	// os/user.Current() doesn't always work without CGO
	return shellOutput("whoami"), nil
}

// RepoPathFunc returns the repository path.
func RepoPathFunc() interface{} {
	return config.Repository.Path
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/kelseyhightower/envconfig"
	"github.com/loadimpact/k6/stats/cloud"
	"github.com/loadimpact/k6/ui"
	"github.com/pkg/errors"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"

	log "github.com/sirupsen/logrus"
)

var (
	exitOnRunning = os.Getenv("K6_EXIT_ON_RUNNING") != ""
)

var cloudCmd = &cobra.Command{
	Use:   "cloud",
	Short: "Run a test on the cloud",
	Long: `Run a test on the cloud.

This will execute the test on the Load Impact cloud service. Use "k6 login cloud" to authenticate.`,
	Example: `
        k6 cloud script.js`[1:],
	Args: exactArgsWithMsg(1, "arg should either be \"-\", if reading script from stdin, or a path to a script file"),
	RunE: func(cmd *cobra.Command, args []string) error {
		_, _ = BannerColor.Fprint(stdout, Banner+"\n\n")
		initBar := ui.ProgressBar{
			Width: 60,
			Left:  func() string { return "    uploading script" },
		}
		fmt.Fprintf(stdout, "%s \r", initBar.String())

		// Runner
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}

		filename := args[0]
		src, err := readSource(filename, pwd, afero.NewOsFs(), os.Stdin)
		if err != nil {
			return err
		}

		runtimeOptions, err := getRuntimeOptions(cmd.Flags())
		if err != nil {
			return err
		}

		r, err := newRunner(src, runType, afero.NewOsFs(), runtimeOptions)
		if err != nil {
			return err
		}

		// Options
		fs := afero.NewOsFs()
		fileConf, _, err := readDiskConfig(fs)
		if err != nil {
			return err
		}
		options, err := getOptions(cmd.Flags())
		if err != nil {
			return err
		}
		cliConf := Config{Options: options}

		envConf, err := readEnvConfig()
		if err != nil {
			return err
		}
		conf := cliConf.Apply(fileConf).Apply(Config{Options: r.GetOptions()}).Apply(envConf).Apply(cliConf)
		r.SetOptions(conf.Options)

		// Cloud config
		cloudConfig := cloud.NewConfig().Apply(conf.Collectors.Cloud)
		if err := envconfig.Process("k6", &cloudConfig); err != nil {
			return err
		}
		if !cloudConfig.Token.Valid {
			return errors.New("Not logged in, please use `k6 login cloud`.")
		}

		// Start cloud test run
		client := cloud.NewClient(cloudConfig.Token.String, cloudConfig.Host.String, Version)

		arc := r.MakeArchive()
		if err := client.ValidateOptions(arc.Options); err != nil {
			return err
		}

		if val, ok := arc.Options.External["loadimpact"]; ok {
			if err := json.Unmarshal(val, &cloudConfig); err != nil {
				return err
			}
		}
		name := cloudConfig.Name.String
		if !cloudConfig.Name.Valid || cloudConfig.Name.String == "" {
			name = filepath.Base(filename)
		}

		refID, err := client.StartCloudTestRun(name, cloudConfig.ProjectID.Int64, arc)
		if err != nil {
			return err
		}

		testURL := cloud.URLForResults(refID, cloudConfig)
		fmt.Fprint(stdout, "\n\n")
		fmt.Fprintf(stdout, "     execution: %s\n", ui.ValueColor.Sprint("cloud"))
		fmt.Fprintf(stdout, "     script: %s\n", ui.ValueColor.Sprint(filename))
		fmt.Fprintf(stdout, "     output: %s\n", ui.ValueColor.Sprint(testURL))
		fmt.Fprint(stdout, "\n")

		// The quiet option hides the progress bar and disallow aborting the test
		if quiet {
			return nil
		}

		// Trap Interrupts, SIGINTs and SIGTERMs.
		sigC := make(chan os.Signal, 1)
		signal.Notify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(sigC)

		var progressErr error
		testProgress := &cloud.TestProgressResponse{}
		progress := ui.ProgressBar{
			Width: 60,
			Left: func() string {
				return "  " + testProgress.RunStatusText
			},
		}

		ticker := time.NewTicker(time.Millisecond * 2000)
		shouldExitLoop := false

	runningLoop:
		for {
			select {
			case <-ticker.C:
				testProgress, progressErr = client.GetTestProgress(refID)
				if progressErr == nil {
					if (testProgress.RunStatus > 2) || (exitOnRunning && testProgress.RunStatus == 2) {
						shouldExitLoop = true
					}
					progress.Progress = testProgress.Progress
					fmt.Fprintf(stdout, "%s\x1b[0K\r", progress.String())
				} else {
					log.WithError(progressErr).Error("Test progress error")
				}
				if shouldExitLoop {
					break runningLoop
				}
			case sig := <-sigC:
				log.WithField("sig", sig).Debug("Exiting in response to signal")
				err := client.StopCloudTestRun(refID)
				if err != nil {
					log.WithError(err).Error("Stop cloud test error")
				}
				shouldExitLoop = true
			}
		}
		fmt.Fprintf(stdout, "     test status: %s\n", ui.ValueColor.Sprint(testProgress.RunStatusText))

		if testProgress.ResultStatus == 1 {
			return ExitCode{errors.New("The test has failed"), 99}
		}

		return nil
	},
}

func init() {
	RootCmd.AddCommand(cloudCmd)
	cloudCmd.Flags().SortFlags = false
	cloudCmd.Flags().AddFlagSet(optionFlagSet())
	cloudCmd.Flags().AddFlagSet(runtimeOptionFlagSet(false))
	cloudCmd.Flags().BoolVar(&exitOnRunning, "exit-on-running", exitOnRunning, "exits when test reaches the running status")
}
<commit_msg>Fix nil pointer and improve code readability<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/kelseyhightower/envconfig"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/stats/cloud"
	"github.com/loadimpact/k6/ui"
	"github.com/pkg/errors"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"

	log "github.com/sirupsen/logrus"
)

var (
	exitOnRunning = os.Getenv("K6_EXIT_ON_RUNNING") != ""
)

var cloudCmd = &cobra.Command{
	Use:   "cloud",
	Short: "Run a test on the cloud",
	Long: `Run a test on the cloud.

This will execute the test on the Load Impact cloud service. Use "k6 login cloud" to authenticate.`,
	Example: `
        k6 cloud script.js`[1:],
	Args: exactArgsWithMsg(1, "arg should either be \"-\", if reading script from stdin, or a path to a script file"),
	RunE: func(cmd *cobra.Command, args []string) error {
		_, _ = BannerColor.Fprint(stdout, Banner+"\n\n")
		initBar := ui.ProgressBar{
			Width: 60,
			Left:  func() string { return "    uploading script" },
		}
		fmt.Fprintf(stdout, "%s \r", initBar.String())

		// Runner
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}

		filename := args[0]
		src, err := readSource(filename, pwd, afero.NewOsFs(), os.Stdin)
		if err != nil {
			return err
		}

		runtimeOptions, err := getRuntimeOptions(cmd.Flags())
		if err != nil {
			return err
		}

		r, err := newRunner(src, runType, afero.NewOsFs(), runtimeOptions)
		if err != nil {
			return err
		}

		// Options
		fs := afero.NewOsFs()
		fileConf, _, err := readDiskConfig(fs)
		if err != nil {
			return err
		}
		options, err := getOptions(cmd.Flags())
		if err != nil {
			return err
		}
		cliConf := Config{Options: options}

		envConf, err := readEnvConfig()
		if err != nil {
			return err
		}
		conf := cliConf.Apply(fileConf).Apply(Config{Options: r.GetOptions()}).Apply(envConf).Apply(cliConf)
		r.SetOptions(conf.Options)

		// Cloud config
		cloudConfig := cloud.NewConfig().Apply(conf.Collectors.Cloud)
		if err := envconfig.Process("k6", &cloudConfig); err != nil {
			return err
		}
		if !cloudConfig.Token.Valid {
			return errors.New("Not logged in, please use `k6 login cloud`.")
		}

		// Start cloud test run
		client := cloud.NewClient(cloudConfig.Token.String, cloudConfig.Host.String, Version)

		arc := r.MakeArchive()
		if err := client.ValidateOptions(arc.Options); err != nil {
			return err
		}

		if val, ok := arc.Options.External["loadimpact"]; ok {
			if err := json.Unmarshal(val, &cloudConfig); err != nil {
				return err
			}
		}
		name := cloudConfig.Name.String
		if !cloudConfig.Name.Valid || cloudConfig.Name.String == "" {
			name = filepath.Base(filename)
		}

		refID, err := client.StartCloudTestRun(name, cloudConfig.ProjectID.Int64, arc)
		if err != nil {
			return err
		}

		testURL := cloud.URLForResults(refID, cloudConfig)
		fmt.Fprint(stdout, "\n\n")
		fmt.Fprintf(stdout, "     execution: %s\n", ui.ValueColor.Sprint("cloud"))
		fmt.Fprintf(stdout, "     script: %s\n", ui.ValueColor.Sprint(filename))
		fmt.Fprintf(stdout, "     output: %s\n", ui.ValueColor.Sprint(testURL))
		fmt.Fprint(stdout, "\n")

		// The quiet option hides the progress bar and disallow aborting the test
		if quiet {
			return nil
		}

		// Trap Interrupts, SIGINTs and SIGTERMs.
		sigC := make(chan os.Signal, 1)
		signal.Notify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(sigC)

		var progressErr error
		testProgress := &cloud.TestProgressResponse{}
		progress := ui.ProgressBar{
			Width: 60,
			Left: func() string {
				return "  " + testProgress.RunStatusText
			},
		}

		ticker := time.NewTicker(time.Millisecond * 2000)
		shouldExitLoop := false

	runningLoop:
		for {
			select {
			case <-ticker.C:
				testProgress, progressErr = client.GetTestProgress(refID)
				if progressErr == nil {
					if (testProgress.RunStatus > lib.RunStatusRunning) || (exitOnRunning && testProgress.RunStatus == lib.RunStatusRunning) {
						shouldExitLoop = true
					}
					progress.Progress = testProgress.Progress
					fmt.Fprintf(stdout, "%s\x1b[0K\r", progress.String())
				} else {
					log.WithError(progressErr).Error("Test progress error")
				}
				if shouldExitLoop {
					break runningLoop
				}
			case sig := <-sigC:
				log.WithField("sig", sig).Print("Exiting in response to signal...")
				err := client.StopCloudTestRun(refID)
				if err != nil {
					log.WithError(err).Error("Stop cloud test error")
				}
				shouldExitLoop = true // Exit after the next GetTestProgress call
			}
		}

		if testProgress == nil {
			return ExitCode{errors.New("Test progress error"), 98}
		}

		fmt.Fprintf(stdout, "     test status: %s\n", ui.ValueColor.Sprint(testProgress.RunStatusText))

		if testProgress.ResultStatus == cloud.ResultStatusFailed {
			return ExitCode{errors.New("The test has failed"), 99}
		}

		return nil
	},
}

func init() {
	RootCmd.AddCommand(cloudCmd)
	cloudCmd.Flags().SortFlags = false
	cloudCmd.Flags().AddFlagSet(optionFlagSet())
	cloudCmd.Flags().AddFlagSet(runtimeOptionFlagSet(false))
	cloudCmd.Flags().BoolVar(&exitOnRunning, "exit-on-running", exitOnRunning, "exits when test reaches the running status")
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	yaml "gopkg.in/yaml.v2"

	"github.com/alecthomas/chroma/quick"
	"github.com/alecthomas/template"
	"github.com/s2gatev/lingo/checker"
	"github.com/spf13/cobra"
)

func init() {
	Guide.PersistentFlags().StringVar(
		&configFile, "config", defaultConfigFilename, "config file")

	Root.AddCommand(Guide)
}

// Guide is a command handler that displays a guidebook of rules applicable
// for the current project.
var Guide = &cobra.Command{
	Use:   "guide",
	Short: "Read a guide with the lingo of the project",
	Run: func(cmd *cobra.Command, args []string) {
		configData, err := ioutil.ReadFile(configFile)
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		var config Config
		if err := yaml.Unmarshal(configData, &config); err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		var checkers []checker.NodeChecker
		for slug, config := range config.Checkers {
			c := checker.Get(slug, config)
			if c == nil {
				// TODO: handle error gracefully
				panic("unknown checker: " + slug)
			}

			checkers = append(checkers, c)
		}

		configPath, err := filepath.Abs(configFile)
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		project := filepath.Base(filepath.Dir(configPath))

		var items []guideItem
		for _, checker := range checkers {
			item := guideItem{
				Title:       checker.Title(),
				Description: checker.Description(),
			}

			for _, example := range checker.Examples() {
				var good bytes.Buffer
				err = quick.Highlight(&good, example.Good, "go", "html", "github")
				if err != nil {
					// TODO: handle error gracefully
					panic(err)
				}

				var bad bytes.Buffer
				err = quick.Highlight(&bad, example.Bad, "go", "html", "github")
				if err != nil {
					// TODO: handle error gracefully
					panic(err)
				}

				item.Examples = append(item.Examples, guideItemExample{
					Good: good.String(),
					Bad:  bad.String(),
				})
			}

			items = append(items, item)
		}

		dir, err := ioutil.TempDir("", "lingo")
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		guide, err := os.Create(filepath.Join(dir, "guide.html"))
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}
		defer guide.Close()

		code := `package main

import "fmt"

func main() {
	fmt.Println("Hello World!")
}
`

		var highlighted bytes.Buffer
		err = quick.Highlight(&highlighted, code, "go", "html", "github")
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		data := map[string]interface{}{
			"Project": project,
			"Items":   items,
			"Code":    highlighted.String(),
		}

		if err := guideTemplate.Execute(guide, data); err != nil {
			return
		}

		if err := openBrowser("file://" + guide.Name()); err != nil {
			return
		}
	},
}

// openBrowser tries to open the URL in a browser.
func openBrowser(url string) error {
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}

	return exec.Command(args[0], append(args[1:], url)...).Run()
}

type guideItemExample struct {

	// Good is an example of sticking to the rule.
	Good string

	// Bad is a counter-example that shows how to not apply the rule.
	Bad string
}

type guideItem struct {

	// Title is the title of the item.
	Title string

	// Description is the detailed description of the item.
	Description string

	// Examples is a set of examples of applying item.
	Examples []guideItemExample
}

var guideTemplate = template.Must(template.New("html").Parse(guideContent))

const guideContent = `
<!DOCTYPE html>

		<title>{{.Project}}'s lingo</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

{{.Project}}'s lingo

			{{range .Items}}

{{.Title}}

{{.Description}}

				{{range .Examples}}

Bad

{{.Bad}}

Good

{{.Good}}

				{{end}}

			{{end}}

`
<commit_msg>Improve design of guide page<commit_after>package cmd

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	yaml "gopkg.in/yaml.v2"

	"github.com/alecthomas/chroma/quick"
	"github.com/alecthomas/template"
	"github.com/s2gatev/lingo/checker"
	"github.com/spf13/cobra"
)

func init() {
	Guide.PersistentFlags().StringVar(
		&configFile, "config", defaultConfigFilename, "config file")

	Root.AddCommand(Guide)
}

// Guide is a command handler that displays a guidebook of rules applicable
// for the current project.
var Guide = &cobra.Command{
	Use:   "guide",
	Short: "Read a guide with the lingo of the project",
	Run: func(cmd *cobra.Command, args []string) {
		configData, err := ioutil.ReadFile(configFile)
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		var config Config
		if err := yaml.Unmarshal(configData, &config); err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		var checkers []checker.NodeChecker
		for slug, config := range config.Checkers {
			c := checker.Get(slug, config)
			if c == nil {
				// TODO: handle error gracefully
				panic("unknown checker: " + slug)
			}

			checkers = append(checkers, c)
		}

		configPath, err := filepath.Abs(configFile)
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		project := filepath.Base(filepath.Dir(configPath))

		var items []guideItem
		for _, checker := range checkers {
			item := guideItem{
				Title:       checker.Title(),
				Description: checker.Description(),
			}

			for _, example := range checker.Examples() {
				var good bytes.Buffer
				err = quick.Highlight(&good, example.Good, "go", "html", "github")
				if err != nil {
					// TODO: handle error gracefully
					panic(err)
				}

				var bad bytes.Buffer
				err = quick.Highlight(&bad, example.Bad, "go", "html", "github")
				if err != nil {
					// TODO: handle error gracefully
					panic(err)
				}

				item.Examples = append(item.Examples, guideItemExample{
					Good: good.String(),
					Bad:  bad.String(),
				})
			}

			items = append(items, item)
		}

		dir, err := ioutil.TempDir("", "lingo")
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		guide, err := os.Create(filepath.Join(dir, "guide.html"))
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}
		defer guide.Close()

		code := `package main

import "fmt"

func main() {
	fmt.Println("Hello World!")
}
`

		var highlighted bytes.Buffer
		err = quick.Highlight(&highlighted, code, "go", "html", "github")
		if err != nil {
			// TODO: handle error gracefully
			panic(err)
		}

		data := map[string]interface{}{
			"Project": project,
			"Items":   items,
			"Code":    highlighted.String(),
		}

		if err := guideTemplate.Execute(guide, data); err != nil {
			return
		}

		if err := openBrowser("file://" + guide.Name()); err != nil {
			return
		}
	},
}

// openBrowser tries to open the URL in a browser.
func openBrowser(url string) error {
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}

	return exec.Command(args[0], append(args[1:], url)...).Run()
}

type guideItemExample struct {

	// Good is an example of sticking to the rule.
	Good string

	// Bad is a counter-example that shows how to not apply the rule.
	Bad string
}

type guideItem struct {

	// Title is the title of the item.
	Title string

	// Description is the detailed description of the item.
	Description string

	// Examples is a set of examples of applying item.
	Examples []guideItemExample
}

var guideTemplate = template.Must(template.New("html").Parse(guideContent))

const guideContent = `
<!DOCTYPE html>

		<title>{{.Project}}'s lingo</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

{{.Project}}'s lingo

				{{range .Items}}

{{.Title}}

{{.Description}}

					{{range .Examples}}

Bad

{{.Bad}}

Good

{{.Good}}

					{{end}}

				{{end}}

`
<|endoftext|>


<commit_before>package cmd

import (
	"crypto/x509"
	"encoding/hex"
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/adamdecaf/cert-manage/tools/_x509"
	"github.com/adamdecaf/cert-manage/tools/file"
)

const (
	fingerprintPreviewLength = 16
)

// PrintCerts outputs the slice of certificates in `format` to stdout
// Format can be 'table' and any other value will output them in more detail
func printCerts(certs []*x509.Certificate, format string) {
	if len(certs) == 0 {
		fmt.Println("No certififcates to display")
		os.Exit(1)
	}

	if format == "table" {
		printCertsInTable(certs)
	} else {
		printCertsToStdout(certs)
	}
}

// printCertsInTable outputs a nicely formatted table of the certs found. This uses golang's
// native text/tabwriter package to align based on the rows given to it.
func printCertsInTable(certs []*x509.Certificate) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintln(w, "Subject\tIssuer\tPublic Key Algorithm\tSHA256 Fingerprint\tNot Before\tNot After")
	defer func() {
		err := w.Flush()
		if err != nil {
			fmt.Printf("error flushing output table - %s\n", err)
		}
	}()

	rows := make([]string, len(certs))
	for i := range certs {
		fingerprint := _x509.GetHexSHA256Fingerprint(*certs[i])

		c1 := certs[i].Subject.CommonName
		c2 := certs[i].Issuer.CommonName
		c3 := _x509.StringifyPubKeyAlgo(certs[i].PublicKeyAlgorithm)
		c4 := fingerprint[:fingerprintPreviewLength]

		c5 := certs[i].NotBefore.Format("2006-01-02")
		c6 := certs[i].NotAfter.Format("2006-01-02")

		rows[i] = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", c1, c2, c3, c4, c5, c6)
	}

	file.SortNames(rows)
	for i := range rows {
		fmt.Fprintln(w, rows[i])
	}
}

// printCertsToStdout very verbosly prints out the ecah certificate's information
// to stdout. This isn't very useful for machine parsing or small screen displays.
func printCertsToStdout(certs []*x509.Certificate) {
	for i := range certs {
		fmt.Printf("Certificate\n")
		fmt.Printf("  SHA1 Fingerprint - %s\n", _x509.GetHexSHA1Fingerprint(*certs[i]))
		fmt.Printf("  SHA256 Fingerprint - %s\n", _x509.GetHexSHA256Fingerprint(*certs[i]))
		fmt.Printf("  Signature - %s\n", hex.EncodeToString(certs[i].Signature))
		fmt.Printf("  Signature Algorithm: %s\n", certs[i].SignatureAlgorithm.String())
		fmt.Printf("  SerialNumber: %d\n", certs[i].SerialNumber)
		fmt.Printf("  Public Key Algorithm - %v\n", _x509.StringifyPubKeyAlgo(certs[i].PublicKeyAlgorithm))
		fmt.Printf("  Issuer CommonName - %s, SerialNumber - %s\n", certs[i].Issuer.CommonName, certs[i].Issuer.SerialNumber)
		fmt.Printf("  Subject CommonName - %s, SerialNumber - %s\n", certs[i].Subject.CommonName, certs[i].Subject.SerialNumber)
		fmt.Printf("  NotBefore - %s, NotAfter - %s\n", certs[i].NotBefore, certs[i].NotAfter)
		fmt.Printf("  IsCA - %t\n", certs[i].IsCA)
		fmt.Printf("  MaxPathLen - %d\n", certs[i].MaxPathLen)

		fmt.Printf("  DNSNames\n")
		for j := range certs[i].DNSNames {
			fmt.Printf("    %s\n", certs[i].DNSNames[j])
		}

		fmt.Printf("  EmailAddresses\n")
		for j := range certs[i].EmailAddresses {
			fmt.Printf("    %s\n", certs[i].EmailAddresses[j])
		}

		fmt.Printf("  IPAddresses\n")
		for j := range certs[i].IPAddresses {
			fmt.Printf("    %s\n", certs[i].IPAddresses[j])
		}

		fmt.Printf("  PermittedDNSDomains\n")
		for j := range certs[i].PermittedDNSDomains {
			fmt.Printf("    %s\n", certs[i].PermittedDNSDomains[j])
		}

		fmt.Printf("  CRLDistributionPoints\n")
		for j := range certs[i].CRLDistributionPoints {
			fmt.Printf("    %s\n", certs[i].CRLDistributionPoints[j])
		}
	}
}
<commit_msg>cmd: Better format any pkix.Name from a certificate<commit_after>package cmd

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/hex"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/adamdecaf/cert-manage/tools/_x509"
	"github.com/adamdecaf/cert-manage/tools/file"
)

const (
	fingerprintPreviewLength = 16
)

// PrintCerts outputs the slice of certificates in `format` to stdout
// Format can be 'table' and any other value will output them in more detail
func printCerts(certs []*x509.Certificate, format string) {
	if len(certs) == 0 {
		fmt.Println("No certififcates to display")
		os.Exit(1)
	}

	if format == "table" {
		printCertsInTable(certs)
	} else {
		printCertsToStdout(certs)
	}
}

// printCertsInTable outputs a nicely formatted table of the certs found. This uses golang's
// native text/tabwriter package to align based on the rows given to it.
func printCertsInTable(certs []*x509.Certificate) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintln(w, "Subject\tIssuer\tPublic Key Algorithm\tSHA256 Fingerprint\tNot Before\tNot After")
	defer func() {
		err := w.Flush()
		if err != nil {
			fmt.Printf("error flushing output table - %s\n", err)
		}
	}()

	rows := make([]string, len(certs))
	for i := range certs {
		fingerprint := _x509.GetHexSHA256Fingerprint(*certs[i])

		c1 := fmtPkixName(certs[i].Subject)
		c2 := fmtPkixName(certs[i].Issuer)
		c3 := _x509.StringifyPubKeyAlgo(certs[i].PublicKeyAlgorithm)
		c4 := fingerprint[:fingerprintPreviewLength]

		c5 := certs[i].NotBefore.Format("2006-01-02")
		c6 := certs[i].NotAfter.Format("2006-01-02")

		rows[i] = fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", c1, c2, c3, c4, c5, c6)
	}

	file.SortNames(rows)
	for i := range rows {
		fmt.Fprintln(w, rows[i])
	}
}

// printCertsToStdout very verbosly prints out the ecah certificate's information
// to stdout. This isn't very useful for machine parsing or small screen displays.
func printCertsToStdout(certs []*x509.Certificate) {
	for i := range certs {
		fmt.Printf("Certificate\n")
		fmt.Printf("  SHA1 Fingerprint - %s\n", _x509.GetHexSHA1Fingerprint(*certs[i]))
		fmt.Printf("  SHA256 Fingerprint - %s\n", _x509.GetHexSHA256Fingerprint(*certs[i]))
		fmt.Printf("  Signature - %s\n", hex.EncodeToString(certs[i].Signature))
		fmt.Printf("  Signature Algorithm: %s\n", certs[i].SignatureAlgorithm.String())
		fmt.Printf("  SerialNumber: %d\n", certs[i].SerialNumber)
		fmt.Printf("  Public Key Algorithm - %v\n", _x509.StringifyPubKeyAlgo(certs[i].PublicKeyAlgorithm))
		fmt.Printf("  Subject: %s\n", fmtPkixName(certs[i].Subject))
		fmt.Printf("  Issuer: %s\n", fmtPkixName(certs[i].Issuer))
		fmt.Printf("  NotBefore - %s, NotAfter - %s\n", certs[i].NotBefore, certs[i].NotAfter)
		fmt.Printf("  IsCA - %t\n", certs[i].IsCA)
		fmt.Printf("  MaxPathLen - %d\n", certs[i].MaxPathLen)

		fmt.Printf("  DNSNames\n")
		for j := range certs[i].DNSNames {
			fmt.Printf("    %s\n", certs[i].DNSNames[j])
		}

		fmt.Printf("  EmailAddresses\n")
		for j := range certs[i].EmailAddresses {
			fmt.Printf("    %s\n", certs[i].EmailAddresses[j])
		}

		fmt.Printf("  IPAddresses\n")
		for j := range certs[i].IPAddresses {
			fmt.Printf("    %s\n", certs[i].IPAddresses[j])
		}

		fmt.Printf("  PermittedDNSDomains\n")
		for j := range certs[i].PermittedDNSDomains {
			fmt.Printf("    %s\n", certs[i].PermittedDNSDomains[j])
		}

		fmt.Printf("  CRLDistributionPoints\n")
		for j := range certs[i].CRLDistributionPoints {
			fmt.Printf("    %s\n", certs[i].CRLDistributionPoints[j])
		}
	}
}

func fmtPkixName(name pkix.Name) string {
	if len(name.OrganizationalUnit) > 0 {
		return fmt.Sprintf("%s, %s", strings.Join(name.Organization, " "), name.OrganizationalUnit[0])
	}
	return strings.Join(name.Organization, " ")
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"testing"

	rpcpb "github.com/google/shipshape/shipshape/proto/shipshape_rpc_proto"
)

var (
	// There are two ways to specify test flags when using Bazel:
	// 1) In the BUILD file with an args stanza in the _test rule.
	// 2) On the command line using --test_arg (i.e. bazel test --test_arg=-shipshape_test_docker_tag=TAG ...).
	//
	// As of 9 Oct 2015, there are multiple Bazel targets that use --shipshape_test_docker_tag (:shipshape_test_prod
	// and :shipshape_test_local) but there are no targets that set local Kythe.
	dockerTag  = flag.String("shipshape_test_docker_tag", "", "the docker tag for the images to use for testing")
	localKythe = flag.Bool("shipshape_test_local_kythe", false, "if true, don't pull the Kythe docker image")
)

func countFailures(resp rpcpb.ShipshapeResponse) int {
	failures := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		failures += len(analyzeResp.Failure)
	}
	return failures
}

func countNotes(resp rpcpb.ShipshapeResponse) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		notes += len(analyzeResp.Note)
	}
	return notes
}

func countCategoryNotes(resp rpcpb.ShipshapeResponse, category string) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		for _, note := range analyzeResp.Note {
			if *note.Category == category {
				notes += 1
			}
		}
	}
	return notes
}

func TestExternalAnalyzers(t *testing.T) {
	// Replaces part of the e2e test
	// Create a fake maven project with android failures

	// Run CLI using a .shipshape file
}

func TestBuiltInAnalyzersPreBuild(t *testing.T) {
	options := Options{
		File:                "shipshape/cli/testdata/workspace1",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponses rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponses.AnalyzeResponse = append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	returnedNotesCount, err := New(options).Run()
	if err != nil {
		t.Fatal(err)
	}
	testName := "TestBuiltInAnalyzerPreBuild"

	if got, want := countFailures(allResponses), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if countedNotes := countNotes(allResponses); returnedNotesCount != countedNotes {
		t.Errorf("%v: Inconsistent note count: returned %v, counted %v (proto data: %v", testName, returnedNotesCount, countedNotes, allResponses)
	}
	if got, want := returnedNotesCount, 39; got != want {
		t.Errorf("%v: Wrong number of notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PostMessage"), 2; got != want {
		t.Errorf("%v: Wrong number of PostMessage notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PyLint"), 33; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
}

func TestBuiltInAnalyzersPostBuild(t *testing.T) {
	// Replaces part of the e2e test
	// Test with a kythe maven build
	// PostMessage and ErrorProne
}

func TestStreamsMode(t *testing.T) {
	// Test whether it works in streams mode
	// Before creating this, ensure that streams mode
	// is actually still something we need to support.
}

func TestChangingDirectories(t *testing.T) {
	// Run on parent directory
	options := Options{
		File:                "shipshape/cli/testdata/workspace2",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponsesParent rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponsesParent.AnalyzeResponse =
			append(allResponsesParent.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	if _, err := New(options).Run(); err != nil {
		t.Fatal(err)
	}
	testName := "TestChangingDirectories - ParentDir"
	if got, want := countFailures(allResponsesParent), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent)
	}
	if got, want := countCategoryNotes(allResponsesParent, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent)
	}
	if got, want := countCategoryNotes(allResponsesParent, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent)
	}
	if got, want := countCategoryNotes(allResponsesParent, "PyLint"), 22; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent)
	}

	// Moving down, running on child directory
	options = Options{
		File:                "shipshape/cli/testdata/workspace2/subworkspace1",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponsesChild rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponsesChild.AnalyzeResponse =
			append(allResponsesChild.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	if _, err := New(options).Run(); err != nil {
		t.Fatal(err)
	}
	testName = "TestChangingDirectories - ChildDir"
	if got, want := countFailures(allResponsesChild), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesChild)
	}
	if got, want := countCategoryNotes(allResponsesChild, "JSHint"), 0; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesChild)
	}
	if got, want := countCategoryNotes(allResponsesChild, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesChild)
	}
	if got, want := countCategoryNotes(allResponsesChild, "PyLint"), 0; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesChild)
	}

	// Moving sideways, running on the sibling child directory
	options = Options{
		File:                "shipshape/cli/testdata/workspace2/subworkspace2",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponsesSibling rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponsesSibling.AnalyzeResponse =
			append(allResponsesSibling.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	if _, err := New(options).Run(); err != nil {
		t.Fatal(err)
	}
	testName = "TestChangingDirectories - SiblingDir"
	if got, want := countFailures(allResponsesSibling), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesSibling)
	}
	if got, want := countCategoryNotes(allResponsesSibling, "JSHint"), 0; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesSibling)
	}
	if got, want := countCategoryNotes(allResponsesSibling, "go vet"), 0; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesSibling)
	}
	if got, want := countCategoryNotes(allResponsesSibling, "PyLint"), 22; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesSibling)
	}

	// Moving up, run on the parent directory again
	options = Options{
		File:                "shipshape/cli/testdata/workspace2",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponsesParent2 rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponsesParent2.AnalyzeResponse =
			append(allResponsesParent2.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	if _, err := New(options).Run(); err != nil {
		t.Fatal(err)
	}
	testName = "TestChangingDirectories - ParentDir again"
	if got, want := countFailures(allResponsesParent2), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent2)
	}
	if got, want := countCategoryNotes(allResponsesParent2, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent2)
	}
	if got, want := countCategoryNotes(allResponsesParent2, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent2)
	}
	if got, want := countCategoryNotes(allResponsesParent2, "PyLint"), 22; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
			testName, got, want, allResponsesParent2)
	}

	// TODO(emso): Add a test running on a single file, use workspace2/test.js
}

func dumpLogs() {

}

func checkOutput(category string, numResults int) {

}
<commit_msg>Refactors test and adds file test<commit_after>package cli

import (
	"flag"
	"testing"

	rpcpb "github.com/google/shipshape/shipshape/proto/shipshape_rpc_proto"
)

var (
	// There are two ways to specify test flags when using Bazel:
	// 1) In the BUILD file with an args stanza in the _test rule.
	// 2) On the command line using --test_arg (i.e. bazel test --test_arg=-shipshape_test_docker_tag=TAG ...).
	//
	// As of 9 Oct 2015, there are multiple Bazel targets that use --shipshape_test_docker_tag (:shipshape_test_prod
	// and :shipshape_test_local) but there are no targets that set local Kythe.
	dockerTag  = flag.String("shipshape_test_docker_tag", "", "the docker tag for the images to use for testing")
	localKythe = flag.Bool("shipshape_test_local_kythe", false, "if true, don't pull the Kythe docker image")
)

func countFailures(resp rpcpb.ShipshapeResponse) int {
	failures := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		failures += len(analyzeResp.Failure)
	}
	return failures
}

func countNotes(resp rpcpb.ShipshapeResponse) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		notes += len(analyzeResp.Note)
	}
	return notes
}

func countCategoryNotes(resp rpcpb.ShipshapeResponse, category string) int {
	notes := 0
	for _, analyzeResp := range resp.AnalyzeResponse {
		for _, note := range analyzeResp.Note {
			if *note.Category == category {
				notes += 1
			}
		}
	}
	return notes
}

func TestExternalAnalyzers(t *testing.T) {
	// Replaces part of the e2e test
	// Create a fake maven project with android failures

	// Run CLI using a .shipshape file
}

func TestBuiltInAnalyzersPreBuild(t *testing.T) {
	options := Options{
		File:                "shipshape/cli/testdata/workspace1",
		ThirdPartyAnalyzers: []string{},
		Build:               "",
		TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
		Dind:                false,
		Event:               DefaultEvent,
		Repo:                DefaultRepo,
		StayUp:              true,
		Tag:                 *dockerTag,
		LocalKythe:          *localKythe,
	}
	var allResponses rpcpb.ShipshapeResponse
	options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
		allResponses.AnalyzeResponse = append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
		return nil
	}
	returnedNotesCount, err := New(options).Run()
	if err != nil {
		t.Fatal(err)
	}
	testName := "TestBuiltInAnalyzerPreBuild"

	if got, want := countFailures(allResponses), 0; got != want {
		t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if countedNotes := countNotes(allResponses); returnedNotesCount != countedNotes {
		t.Errorf("%v: Inconsistent note count: returned %v, counted %v (proto data: %v", testName, returnedNotesCount, countedNotes, allResponses)
	}
	if got, want := returnedNotesCount, 39; got != want {
		t.Errorf("%v: Wrong number of notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PostMessage"), 2; got != want {
		t.Errorf("%v: Wrong number of PostMessage notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "JSHint"), 3; got != want {
		t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "go vet"), 1; got != want {
		t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
	if got, want := countCategoryNotes(allResponses, "PyLint"), 33; got != want {
		t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)", testName, got, want, allResponses)
	}
}

func TestBuiltInAnalyzersPostBuild(t *testing.T) {
	// Replaces part of the e2e test
	// Test with a kythe maven build
	// PostMessage and ErrorProne
}

func TestStreamsMode(t *testing.T) {
	// Test whether it works in streams mode
	// Before creating this, ensure that streams mode
	// is actually still something we need to support.
}

func TestChangingDirs(t *testing.T) {
	tests := []struct {
		name           string
		file           string
		expectedJSHint int
		expectedGovet  int
		expectedPyLint int
	}{
		{
			name:           "TestChangingDirs:ChildDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace1",
			expectedJSHint: 0,
			expectedGovet:  1,
			expectedPyLint: 0,
		},
		{
			name:           "TestChangingDirs:SiblingDir",
			file:           "shipshape/cli/testdata/workspace2/subworkspace2",
			expectedJSHint: 0,
			expectedGovet:  0,
			expectedPyLint: 22,
		},
		{
			name:           "TestChangingDirs:ParentDir",
			file:           "shipshape/cli/testdata/workspace2",
			expectedJSHint: 3,
			expectedGovet:  1,
			expectedPyLint: 22,
		},
		{
			name:           "TestChangingDirs:File",
			file:           "shipshape/cli/testdata/workspace2/test.js",
			expectedJSHint: 3,
			expectedGovet:  0,
			expectedPyLint: 0,
		},
	}
	for _, test := range tests {
		options := Options{
			File:                test.file,
			ThirdPartyAnalyzers: []string{},
			Build:               "",
			TriggerCats:         []string{"PostMessage", "JSHint", "go vet", "PyLint"},
			Dind:                false,
			Event:               DefaultEvent,
			Repo:                DefaultRepo,
			StayUp:              true,
			Tag:                 *dockerTag,
			LocalKythe:          *localKythe,
		}
		var allResponses rpcpb.ShipshapeResponse
		options.HandleResponse = func(shipshapeResp *rpcpb.ShipshapeResponse, _ string) error {
			allResponses.AnalyzeResponse =
				append(allResponses.AnalyzeResponse, shipshapeResp.AnalyzeResponse...)
			return nil
		}
		testName := test.name
		if _, err := New(options).Run(); err != nil {
			t.Errorf("%v: Failure on service call; err: %v", testName, err)
			continue
		}
		if got, want := countFailures(allResponses), 0; got != want {
			t.Errorf("%v: Wrong number of failures; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "JSHint"), test.expectedJSHint; got != want {
			t.Errorf("%v: Wrong number of JSHint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "go vet"), test.expectedGovet; got != want {
			t.Errorf("%v: Wrong number of go vet notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
		if got, want := countCategoryNotes(allResponses, "PyLint"), test.expectedPyLint; got != want {
			t.Errorf("%v: Wrong number of PyLint notes; got %v, want %v (proto data: %v)",
				testName, got, want, allResponses)
		}
	}
}

func dumpLogs() {

}

func checkOutput(category string, numResults int) {

}
<|endoftext|>