<commit_before>// Copyright 2020 The Ebiten Authors
//
// 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 graphicscommand

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/token"
	"strings"

	"github.com/hajimehoshi/ebiten/v2/internal/graphics"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
	"github.com/hajimehoshi/ebiten/v2/internal/shader"
	"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)

var shaderSuffix string

func init() {
	shaderSuffix = `
var __imageDstTextureSize vec2

// imageSrcTextureSize returns the destination image's texture size in pixels.
func imageDstTextureSize() vec2 {
	return __imageDstTextureSize
}
`

	shaderSuffix += fmt.Sprintf(`
var __textureSizes [%[1]d]vec2

// imageSrcTextureSize returns the source image's texture size in pixels.
// As an image is a part of internal texture, the texture is usually bigger than the image.
// The texture's size is useful when you want to calculate pixels from texels.
func imageSrcTextureSize() vec2 {
	return __textureSizes[0]
}

// The unit is the source texture's texel.
var __textureDestinationRegionOrigin vec2

// The unit is the source texture's texel.
var __textureDestinationRegionSize vec2

// imageDstRegionOnTexture returns the destination image's region (the origin and the size) on its texture.
// The unit is the source texture's texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageDstRegionOnTexture() (vec2, vec2) {
	return __textureDestinationRegionOrigin, __textureDestinationRegionSize
}

// The unit is the source texture's texel.
var __textureSourceOffsets [%[2]d]vec2

// The unit is the source texture's texel.
var __textureSourceRegionOrigin vec2

// The unit is the source texture's texel.
var __textureSourceRegionSize vec2

// imageSrcRegionOnTexture returns the source image's region (the origin and the size) on its texture.
// The unit is the source texture's texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageSrcRegionOnTexture() (vec2, vec2) {
	return __textureSourceRegionOrigin, __textureSourceRegionSize
}
`, graphics.ShaderImageNum, graphics.ShaderImageNum-1)

	for i := 0; i < graphics.ShaderImageNum; i++ {
		pos := "pos"
		if i >= 1 {
			// Convert the position in texture0's texels to the target texture texels.
			pos = fmt.Sprintf("(pos + __textureSourceOffsets[%d]) * __textureSizes[0] / __textureSizes[%d]", i-1, i)
		}
		// __t%d is a special variable for a texture variable.
		shaderSuffix += fmt.Sprintf(`
func imageSrc%[1]dUnsafeAt(pos vec2) vec4 {
	// pos is the position in texels of the source texture (= 0th image's texture).
	return texture2D(__t%[1]d, %[2]s)
}

func imageSrc%[1]dAt(pos vec2) vec4 {
	// pos is the position in texels of the source texture (= 0th image's texture).
	return texture2D(__t%[1]d, %[2]s) *
		step(__textureSourceRegionOrigin.x, pos.x) *
		(1 - step(__textureSourceRegionOrigin.x + __textureSourceRegionSize.x, pos.x)) *
		step(__textureSourceRegionOrigin.y, pos.y) *
		(1 - step(__textureSourceRegionOrigin.y + __textureSourceRegionSize.y, pos.y))
}
`, i, pos)
	}
}

func compileShader(graphicsDriver graphicsdriver.Graphics, src []byte) (*shaderir.Program, error) {
	var buf bytes.Buffer
	buf.Write(src)
	buf.WriteString(shaderSuffix)
	if graphicsDriver.FramebufferYDirection() != graphicsDriver.NDCYDirection() {
		buf.WriteString(`
func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) {
	return mat4(
		2/__imageDstTextureSize.x, 0, 0, 0,
		0, -2/__imageDstTextureSize.y, 0, 0,
		0, 0, 1, 0,
		-1, 1, 0, 1,
	) * vec4(position, 0, 1), texCoord, color
}
`)
	} else {
		buf.WriteString(`
func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) {
	return mat4(
		2/__imageDstTextureSize.x, 0, 0, 0,
		0, 2/__imageDstTextureSize.y, 0, 0,
		0, 0, 1, 0,
		-1, -1, 0, 1,
	) * vec4(position, 0, 1), texCoord, color
}
`)
	}

	fs := token.NewFileSet()
	f, err := parser.ParseFile(fs, "", buf.Bytes(), parser.AllErrors)
	if err != nil {
		return nil, err
	}

	const (
		vert = "__vertex"
		frag = "Fragment"
	)
	ir, err := shader.Compile(fs, f, vert, frag, graphics.ShaderImageNum)
	if err != nil {
		return nil, err
	}

	if ir.VertexFunc.Block == nil {
		return nil, fmt.Errorf("graphicscommand: vertex shader entry point '%s' is missing", vert)
	}
	if ir.FragmentFunc.Block == nil {
		return nil, fmt.Errorf("graphicscommand: fragment shader entry point '%s' is missing", frag)
	}

	return ir, nil
}

type Shader struct {
	shader graphicsdriver.Shader

	uniformNames []string
	uniformTypes []shaderir.Type
}

func NewShader(src []byte) *Shader {
	s := &Shader{}
	c := &newShaderCommand{
		result: s,
		src:    src,
	}
	theCommandQueue.Enqueue(c)
	return s
}

func (s *Shader) Dispose() {
	c := &disposeShaderCommand{
		target: s,
	}
	theCommandQueue.Enqueue(c)
}

func (s *Shader) convertUniforms(uniforms map[string]interface{}) [][]float32 {
	if s.shader == nil {
		panic("graphicscommand: shader is not compiled yet")
	}

	type index struct {
		resultIndex        int
		shaderUniformIndex int
	}

	names := map[string]index{}
	var idx int
	for i, n := range s.uniformNames {
		if strings.HasPrefix(n, "__") {
			continue
		}
		names[n] = index{
			resultIndex:        idx,
			shaderUniformIndex: i,
		}
		idx++
	}

	us := make([][]float32, len(names))
	for name, idx := range names {
		if v, ok := uniforms[name]; ok {
			switch v := v.(type) {
			case float32:
				us[idx.resultIndex] = []float32{v}
			case []float32:
				us[idx.resultIndex] = v
			default:
				panic(fmt.Sprintf("graphicscommand: unexpected uniform value type: %s, %T", name, v))
			}
			continue
		}

		t := s.uniformTypes[idx.shaderUniformIndex]
		us[idx.resultIndex] = make([]float32, t.FloatNum())
	}

	// TODO: Panic if uniforms include an invalid name

	return us
}
<commit_msg>internal/graphicscommand: cache uniform name locations and types<commit_after>// Copyright 2020 The Ebiten Authors
//
// 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 graphicscommand

import (
	"bytes"
	"fmt"
	"go/parser"
	"go/token"
	"strings"

	"github.com/hajimehoshi/ebiten/v2/internal/graphics"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
	"github.com/hajimehoshi/ebiten/v2/internal/shader"
	"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)

var shaderSuffix string

func init() {
	shaderSuffix = `
var __imageDstTextureSize vec2

// imageSrcTextureSize returns the destination image's texture size in pixels.
func imageDstTextureSize() vec2 {
	return __imageDstTextureSize
}
`

	shaderSuffix += fmt.Sprintf(`
var __textureSizes [%[1]d]vec2

// imageSrcTextureSize returns the source image's texture size in pixels.
// As an image is a part of internal texture, the texture is usually bigger than the image.
// The texture's size is useful when you want to calculate pixels from texels.
func imageSrcTextureSize() vec2 {
	return __textureSizes[0]
}

// The unit is the source texture's texel.
var __textureDestinationRegionOrigin vec2

// The unit is the source texture's texel.
var __textureDestinationRegionSize vec2

// imageDstRegionOnTexture returns the destination image's region (the origin and the size) on its texture.
// The unit is the source texture's texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageDstRegionOnTexture() (vec2, vec2) {
	return __textureDestinationRegionOrigin, __textureDestinationRegionSize
}

// The unit is the source texture's texel.
var __textureSourceOffsets [%[2]d]vec2

// The unit is the source texture's texel.
var __textureSourceRegionOrigin vec2

// The unit is the source texture's texel.
var __textureSourceRegionSize vec2

// imageSrcRegionOnTexture returns the source image's region (the origin and the size) on its texture.
// The unit is the source texture's texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageSrcRegionOnTexture() (vec2, vec2) {
	return __textureSourceRegionOrigin, __textureSourceRegionSize
}
`, graphics.ShaderImageNum, graphics.ShaderImageNum-1)

	for i := 0; i < graphics.ShaderImageNum; i++ {
		pos := "pos"
		if i >= 1 {
			// Convert the position in texture0's texels to the target texture texels.
			pos = fmt.Sprintf("(pos + __textureSourceOffsets[%d]) * __textureSizes[0] / __textureSizes[%d]", i-1, i)
		}
		// __t%d is a special variable for a texture variable.
		shaderSuffix += fmt.Sprintf(`
func imageSrc%[1]dUnsafeAt(pos vec2) vec4 {
	// pos is the position in texels of the source texture (= 0th image's texture).
	return texture2D(__t%[1]d, %[2]s)
}

func imageSrc%[1]dAt(pos vec2) vec4 {
	// pos is the position in texels of the source texture (= 0th image's texture).
	return texture2D(__t%[1]d, %[2]s) *
		step(__textureSourceRegionOrigin.x, pos.x) *
		(1 - step(__textureSourceRegionOrigin.x + __textureSourceRegionSize.x, pos.x)) *
		step(__textureSourceRegionOrigin.y, pos.y) *
		(1 - step(__textureSourceRegionOrigin.y + __textureSourceRegionSize.y, pos.y))
}
`, i, pos)
	}
}

func compileShader(graphicsDriver graphicsdriver.Graphics, src []byte) (*shaderir.Program, error) {
	var buf bytes.Buffer
	buf.Write(src)
	buf.WriteString(shaderSuffix)
	if graphicsDriver.FramebufferYDirection() != graphicsDriver.NDCYDirection() {
		buf.WriteString(`
func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) {
	return mat4(
		2/__imageDstTextureSize.x, 0, 0, 0,
		0, -2/__imageDstTextureSize.y, 0, 0,
		0, 0, 1, 0,
		-1, 1, 0, 1,
	) * vec4(position, 0, 1), texCoord, color
}
`)
	} else {
		buf.WriteString(`
func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) {
	return mat4(
		2/__imageDstTextureSize.x, 0, 0, 0,
		0, 2/__imageDstTextureSize.y, 0, 0,
		0, 0, 1, 0,
		-1, -1, 0, 1,
	) * vec4(position, 0, 1), texCoord, color
}
`)
	}

	fs := token.NewFileSet()
	f, err := parser.ParseFile(fs, "", buf.Bytes(), parser.AllErrors)
	if err != nil {
		return nil, err
	}

	const (
		vert = "__vertex"
		frag = "Fragment"
	)
	ir, err := shader.Compile(fs, f, vert, frag, graphics.ShaderImageNum)
	if err != nil {
		return nil, err
	}

	if ir.VertexFunc.Block == nil {
		return nil, fmt.Errorf("graphicscommand: vertex shader entry point '%s' is missing", vert)
	}
	if ir.FragmentFunc.Block == nil {
		return nil, fmt.Errorf("graphicscommand: fragment shader entry point '%s' is missing", frag)
	}

	return ir, nil
}

type Shader struct {
	shader graphicsdriver.Shader

	uniformNames       []string
	uniformTypes       []shaderir.Type
	uniformNameToIndex map[string]int
	uniformNameToType  map[string]shaderir.Type
}

func NewShader(src []byte) *Shader {
	s := &Shader{}
	c := &newShaderCommand{
		result: s,
		src:    src,
	}
	theCommandQueue.Enqueue(c)
	return s
}

func (s *Shader) Dispose() {
	c := &disposeShaderCommand{
		target: s,
	}
	theCommandQueue.Enqueue(c)
}

func (s *Shader) convertUniforms(uniforms map[string]interface{}) [][]float32 {
	if s.shader == nil {
		panic("graphicscommand: shader is not compiled yet")
	}

	if s.uniformNameToIndex == nil {
		s.uniformNameToIndex = map[string]int{}
		s.uniformNameToType = map[string]shaderir.Type{}

		var idx int
		for i, n := range s.uniformNames {
			if strings.HasPrefix(n, "__") {
				continue
			}
			s.uniformNameToIndex[n] = idx
			s.uniformNameToType[n] = s.uniformTypes[i]
			idx++
		}
	}

	us := make([][]float32, len(s.uniformNameToIndex))
	for name, idx := range s.uniformNameToIndex {
		if v, ok := uniforms[name]; ok {
			switch v := v.(type) {
			case float32:
				us[idx] = []float32{v}
			case []float32:
				us[idx] = v
			default:
				panic(fmt.Sprintf("graphicscommand: unexpected uniform value type: %s, %T", name, v))
			}
			continue
		}
		t := s.uniformNameToType[name]
		us[idx] = make([]float32, t.FloatNum())
	}

	// TODO: Panic if uniforms include an invalid name

	return us
}
<|endoftext|>


<commit_before>package pathutil_test

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/adrg/xdg/internal/pathutil"
	"github.com/stretchr/testify/require"
)

func TestExists(t *testing.T) {
	tempDir := os.TempDir()

	// Test regular file.
	pathFile := filepath.Join(tempDir, "regular")
	f, err := os.Create(pathFile)
	require.NoError(t, err)
	require.NoError(t, f.Close())
	require.True(t, pathutil.Exists(pathFile))

	// Test symlink.
	pathSymlink := filepath.Join(tempDir, "symlink")
	require.NoError(t, os.Symlink(pathFile, pathSymlink))
	require.True(t, pathutil.Exists(pathSymlink))

	// Test non-existent file.
	require.NoError(t, os.Remove(pathFile))
	require.False(t, pathutil.Exists(pathFile))
	require.False(t, pathutil.Exists(pathSymlink))
	require.NoError(t, os.Remove(pathSymlink))
	require.False(t, pathutil.Exists(pathSymlink))
}
<commit_msg>Add test case for internal pathutil.Create function<commit_after>package pathutil_test

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/adrg/xdg/internal/pathutil"
	"github.com/stretchr/testify/require"
)

func TestExists(t *testing.T) {
	tempDir := os.TempDir()

	// Test regular file.
	pathFile := filepath.Join(tempDir, "regular")
	f, err := os.Create(pathFile)
	require.NoError(t, err)
	require.NoError(t, f.Close())
	require.True(t, pathutil.Exists(pathFile))

	// Test symlink.
	pathSymlink := filepath.Join(tempDir, "symlink")
	require.NoError(t, os.Symlink(pathFile, pathSymlink))
	require.True(t, pathutil.Exists(pathSymlink))

	// Test non-existent file.
	require.NoError(t, os.Remove(pathFile))
	require.False(t, pathutil.Exists(pathFile))
	require.False(t, pathutil.Exists(pathSymlink))
	require.NoError(t, os.Remove(pathSymlink))
	require.False(t, pathutil.Exists(pathSymlink))
}

func TestCreate(t *testing.T) {
	tempDir := os.TempDir()

	// Test path selection order.
	p, err := pathutil.Create("test", []string{tempDir, "\000a"})
	require.NoError(t, err)
	require.Equal(t, filepath.Join(tempDir, "test"), p)

	p, err = pathutil.Create("test", []string{"\000a", tempDir})
	require.NoError(t, err)
	require.Equal(t, filepath.Join(tempDir, "test"), p)

	// Test relative parent directories.
	expected := filepath.Join(tempDir, "appname", "config", "test")
	p, err = pathutil.Create(filepath.Join("appname", "config", "test"), []string{"\000a", tempDir})
	require.NoError(t, err)
	require.Equal(t, expected, p)
	t.Log(expected)
	require.NoError(t, os.RemoveAll(filepath.Dir(expected)))

	expected = filepath.Join(tempDir, "appname", "test")
	p, err = pathutil.Create(filepath.Join("appname", "test"), []string{"\000a", tempDir})
	require.NoError(t, err)
	require.Equal(t, expected, p)
	t.Log(expected)
	require.NoError(t, os.RemoveAll(filepath.Dir(expected)))

	// Test invalid paths.
	_, err = pathutil.Create(filepath.Join("appname", "test"), []string{"\000a"})
	require.Error(t, err)

	_, err = pathutil.Create("test", []string{filepath.Join(tempDir, "\000a")})
	require.Error(t, err)
}
<|endoftext|>


<commit_before>package completion

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode"

	"../conio"
	"../readline"
)

type Element struct {
	InsertStr string
	ListupStr string
}

type List struct {
	AllLine string
	List    []Element
	RawWord string // have quotation
	Word    string
	Pos     int
}

func listUpComplete(this *readline.Buffer) (*List, rune, error) {
	var err error
	rv := new(List)

	// environment completion.
	rv.AllLine = this.String()
	rv.List, rv.Pos, err = listUpEnv(rv.AllLine)
	default_delimiter := rune(readline.Delimiters[0])
	if len(rv.List) > 0 && rv.Pos >= 0 && err == nil {
		rv.RawWord = rv.AllLine[rv.Pos:]
		rv.Word = rv.RawWord
		return rv, default_delimiter, nil
	}

	// filename or commandname completion
	rv.RawWord, rv.Pos = this.CurrentWord()
	found_delimter := false
	rv.Word = strings.Map(func(c rune) rune {
		if strings.ContainsRune(readline.Delimiters, c) {
			if !found_delimter {
				default_delimiter = c
			}
			found_delimter = true
			return -1
		} else {
			return c
		}
	}, rv.RawWord)

	start := strings.LastIndexAny(rv.Word, ";=") + 1

	if rv.Pos > 0 {
		rv.List, err = listUpFiles(rv.Word[start:])
	} else {
		rv.List, err = listUpCommands(rv.Word[start:])
	}

	for i := 0; i < len(rv.List); i++ {
		rv.List[i].InsertStr = rv.Word[:start] + rv.List[i].InsertStr
	}
	for _, f := range HookToList {
		rv, err = f(this, rv)
		if err != nil {
			break
		}
	}
	return rv, default_delimiter, err
}

func toComplete(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.InsertStr
	}
	return result
}

func toDisplay(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.ListupStr
	}
	return result
}

func KeyFuncCompletionList(ctx context.Context, this *readline.Buffer) readline.Result {
	comp, _, err := listUpComplete(this)
	if comp == nil {
		return readline.CONTINUE
	}
	fmt.Fprint(readline.Console, "\n")
	if err != nil {
		fmt.Fprintf(readline.Console, "(warning) %s\n", err.Error())
	}
	conio.BoxPrint(ctx, toDisplay(comp.List), readline.Console)
	this.RepaintAll()
	return readline.CONTINUE
}

func CommonPrefix(list []string) string {
	if len(list) < 1 {
		return ""
	}
	common := list[0]
	for _, f := range list[1:] {
		cr := strings.NewReader(common)
		fr := strings.NewReader(f)
		i := 0
		var buffer bytes.Buffer
		for {
			ch, _, cerr := cr.ReadRune()
			fh, _, ferr := fr.ReadRune()
			if cerr != nil || ferr != nil || unicode.ToUpper(ch) != unicode.ToUpper(fh) {
				break
			}
			buffer.WriteRune(ch)
			i++
		}
		common = buffer.String()
	}
	return common
}

func endWithRoot(path string) bool {
	return len(path) >= 1 && os.IsPathSeparator(path[len(path)-1])
}

func KeyFuncCompletion(this *readline.Buffer) readline.Result {
	comp, default_delimiter, err := listUpComplete(this)
	if comp.List == nil || len(comp.List) <= 0 {
		return readline.CONTINUE
	}

	slashToBackSlash := true
	firstFoundSlashPos := strings.IndexRune(comp.Word, '/')
	firstFoundBackSlashPos := strings.IndexRune(comp.Word, os.PathSeparator)
	if firstFoundSlashPos >= 0 && (firstFoundBackSlashPos == -1 || firstFoundSlashPos < firstFoundBackSlashPos) {
		slashToBackSlash = false
	}

	complete_list := toComplete(comp.List)
	commonStr := CommonPrefix(complete_list)
	quotechar := byte(0)
	if i := strings.IndexAny(comp.Word, readline.Delimiters); i >= 0 {
		quotechar = comp.Word[i]
	} else {
		for _, node := range complete_list {
			if strings.ContainsAny(node, " &") {
				quotechar = byte(default_delimiter)
				break
			}
		}
	}
	if quotechar != 0 {
		buffer := make([]byte, 0, len(commonStr)+3)
		if len(commonStr) >= 2 && commonStr[0] == '~' && os.IsPathSeparator(commonStr[1]) {
			buffer = append(buffer, commonStr[:2]...)
			buffer = append(buffer, quotechar)
			buffer = append(buffer, commonStr[2:]...)
		} else {
			buffer = append(buffer, quotechar)
			buffer = append(buffer, commonStr...)
		}
		if len(comp.List) == 1 && !endWithRoot(comp.List[0].InsertStr) {
			buffer = append(buffer, quotechar)
		}
		commonStr = string(buffer)
	}
	if len(comp.List) == 1 && !endWithRoot(commonStr) {
		commonStr += " "
	}
	if slashToBackSlash {
		commonStr = filepath.FromSlash(commonStr)
	}
	if comp.RawWord == commonStr {
		fmt.Fprint(readline.Console, "\n")
		if err != nil {
			fmt.Fprintf(readline.Console, "(warning) %s\n", err.Error())
		}
		conio.BoxPrint(nil, toDisplay(comp.List), readline.Console)
		this.RepaintAll()
		return readline.CONTINUE
	}
	this.ReplaceAndRepaint(comp.Pos, commonStr)
	return readline.CONTINUE
}
<commit_msg>Completion: ~\Go[TAB] -> [OLD] ~\"Google Drive" [NEW] ~"\Google drive"<commit_after>package completion

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode"

	"../conio"
	"../readline"
)

type Element struct {
	InsertStr string
	ListupStr string
}

type List struct {
	AllLine string
	List    []Element
	RawWord string // have quotation
	Word    string
	Pos     int
}

func listUpComplete(this *readline.Buffer) (*List, rune, error) {
	var err error
	rv := new(List)

	// environment completion.
	rv.AllLine = this.String()
	rv.List, rv.Pos, err = listUpEnv(rv.AllLine)
	default_delimiter := rune(readline.Delimiters[0])
	if len(rv.List) > 0 && rv.Pos >= 0 && err == nil {
		rv.RawWord = rv.AllLine[rv.Pos:]
		rv.Word = rv.RawWord
		return rv, default_delimiter, nil
	}

	// filename or commandname completion
	rv.RawWord, rv.Pos = this.CurrentWord()
	found_delimter := false
	rv.Word = strings.Map(func(c rune) rune {
		if strings.ContainsRune(readline.Delimiters, c) {
			if !found_delimter {
				default_delimiter = c
			}
			found_delimter = true
			return -1
		} else {
			return c
		}
	}, rv.RawWord)

	start := strings.LastIndexAny(rv.Word, ";=") + 1

	if rv.Pos > 0 {
		rv.List, err = listUpFiles(rv.Word[start:])
	} else {
		rv.List, err = listUpCommands(rv.Word[start:])
	}

	for i := 0; i < len(rv.List); i++ {
		rv.List[i].InsertStr = rv.Word[:start] + rv.List[i].InsertStr
	}
	for _, f := range HookToList {
		rv, err = f(this, rv)
		if err != nil {
			break
		}
	}
	return rv, default_delimiter, err
}

func toComplete(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.InsertStr
	}
	return result
}

func toDisplay(source []Element) []string {
	result := make([]string, len(source))
	for key, val := range source {
		result[key] = val.ListupStr
	}
	return result
}

func KeyFuncCompletionList(ctx context.Context, this *readline.Buffer) readline.Result {
	comp, _, err := listUpComplete(this)
	if comp == nil {
		return readline.CONTINUE
	}
	fmt.Fprint(readline.Console, "\n")
	if err != nil {
		fmt.Fprintf(readline.Console, "(warning) %s\n", err.Error())
	}
	conio.BoxPrint(ctx, toDisplay(comp.List), readline.Console)
	this.RepaintAll()
	return readline.CONTINUE
}

func CommonPrefix(list []string) string {
	if len(list) < 1 {
		return ""
	}
	common := list[0]
	for _, f := range list[1:] {
		cr := strings.NewReader(common)
		fr := strings.NewReader(f)
		i := 0
		var buffer bytes.Buffer
		for {
			ch, _, cerr := cr.ReadRune()
			fh, _, ferr := fr.ReadRune()
			if cerr != nil || ferr != nil || unicode.ToUpper(ch) != unicode.ToUpper(fh) {
				break
			}
			buffer.WriteRune(ch)
			i++
		}
		common = buffer.String()
	}
	return common
}

func endWithRoot(path string) bool {
	return len(path) >= 1 && os.IsPathSeparator(path[len(path)-1])
}

func KeyFuncCompletion(this *readline.Buffer) readline.Result {
	comp, default_delimiter, err := listUpComplete(this)
	if comp.List == nil || len(comp.List) <= 0 {
		return readline.CONTINUE
	}

	slashToBackSlash := true
	firstFoundSlashPos := strings.IndexRune(comp.Word, '/')
	firstFoundBackSlashPos := strings.IndexRune(comp.Word, os.PathSeparator)
	if firstFoundSlashPos >= 0 && (firstFoundBackSlashPos == -1 || firstFoundSlashPos < firstFoundBackSlashPos) {
		slashToBackSlash = false
	}

	complete_list := toComplete(comp.List)
	commonStr := CommonPrefix(complete_list)
	quotechar := byte(0)
	if i := strings.IndexAny(comp.Word, readline.Delimiters); i >= 0 {
		quotechar = comp.Word[i]
	} else {
		for _, node := range complete_list {
			if strings.ContainsAny(node, " &") {
				quotechar = byte(default_delimiter)
				break
			}
		}
	}
	if quotechar != 0 {
		buffer := make([]byte, 0, len(commonStr)+3)
		if len(commonStr) >= 2 && commonStr[0] == '~' && os.IsPathSeparator(commonStr[1]) {
			buffer = append(buffer, commonStr[:1]...)
			buffer = append(buffer, quotechar)
			buffer = append(buffer, commonStr[1:]...)
		} else {
			buffer = append(buffer, quotechar)
			buffer = append(buffer, commonStr...)
		}
		if len(comp.List) == 1 && !endWithRoot(comp.List[0].InsertStr) {
			buffer = append(buffer, quotechar)
		}
		commonStr = string(buffer)
	}
	if len(comp.List) == 1 && !endWithRoot(commonStr) {
		commonStr += " "
	}
	if slashToBackSlash {
		commonStr = filepath.FromSlash(commonStr)
	}
	if comp.RawWord == commonStr {
		fmt.Fprint(readline.Console, "\n")
		if err != nil {
			fmt.Fprintf(readline.Console, "(warning) %s\n", err.Error())
		}
		conio.BoxPrint(nil, toDisplay(comp.List), readline.Console)
		this.RepaintAll()
		return readline.CONTINUE
	}
	this.ReplaceAndRepaint(comp.Pos, commonStr)
	return readline.CONTINUE
}
<|endoftext|>


<commit_before>package pipelineserver

import (
	"fmt"
	"sync"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	"golang.org/x/net/context"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pps"
	"go.pedge.io/protolog"
)

type pipelineController struct {
	pfsAPIClient      pfs.APIClient
	jobAPIClient      pps.JobAPIClient
	pipelineAPIClient pps.PipelineAPIClient
	pipelineInfo      *pps.PipelineInfo

	ctx       context.Context
	cancel    context.CancelFunc
	waitGroup *sync.WaitGroup
}

func newPipelineController(
	pfsAPIClient pfs.APIClient,
	jobAPIClient pps.JobAPIClient,
	pipelineAPIClient pps.PipelineAPIClient,
	pipelineInfo *pps.PipelineInfo,
) *pipelineController {
	ctx, cancel := context.WithCancel(context.Background())
	return &pipelineController{
		pfsAPIClient,
		jobAPIClient,
		pipelineAPIClient,
		pipelineInfo,
		ctx,
		cancel,
		&sync.WaitGroup{},
	}
}

func (p *pipelineController) Start() error {
	// TODO: do not get all jobs each time, need a limit call on persist, more
	// generally, need all persist calls to have a limit
	jobInfos, err := p.jobAPIClient.ListJob(context.Background(), &pps.ListJobRequest{Pipeline: p.pipelineInfo.Pipeline})
	if err != nil {
		return err
	}
	lastCommit := &pfs.Commit{
		Repo: p.pipelineInfo.Input,
		// TODO: use initial commit id when moved to pfs package
		Id: "scratch",
	}
	if len(jobInfos.JobInfo) > 0 {
		lastCommit = jobInfos.JobInfo[0].Input
	}
	p.waitGroup.Add(1)
	go func() {
		defer p.waitGroup.Done()
		p.run(lastCommit)
	}()
	protolog.Infof("pachyderm.pps.pipelinserver: started pipeline controller for pipeline %s\n", p.pipelineInfo.Pipeline.Name)
	return nil
}

func (p *pipelineController) Cancel() error {
	p.cancel()
	// does not block until run is complete, but run will be in the process of cancelling
	<-p.ctx.Done()
	// wait until run completes
	p.waitGroup.Wait()
	return ignoreCanceledError(p.ctx.Err())
}

func (p *pipelineController) run(lastCommit *pfs.Commit) {
	for {
		// http://blog.golang.org/context
		commitErrorPairC := make(chan commitErrorPair, 1)
		go func() { commitErrorPairC <- p.runInner(p.ctx, lastCommit) }()
		select {
		case <-p.ctx.Done():
			_ = <-commitErrorPairC
			logIfError(p.ctx.Err())
			return
		case commitErrorPair := <-commitErrorPairC:
			// TODO: this will call with the same arguments over and over, there needs to be a better design here
			if !logIfError(commitErrorPair.Err) {
				lastCommit = commitErrorPair.Commit
			}
		}
	}
}

type commitErrorPair struct {
	Commit *pfs.Commit
	Err    error
}

func (p *pipelineController) runInner(ctx context.Context, lastCommit *pfs.Commit) commitErrorPair {
	listCommitRequest := &pfs.ListCommitRequest{
		Repo:       lastCommit.Repo,
		CommitType: pfs.CommitType_COMMIT_TYPE_READ,
		From:       lastCommit,
		Block:      true,
	}
	commitInfos, err := p.pfsAPIClient.ListCommit(ctx, listCommitRequest)
	if err != nil {
		return commitErrorPair{Err: err}
	}
	if len(commitInfos.CommitInfo) == 0 {
		return commitErrorPair{Err: fmt.Errorf("pachyderm.pps.pipelineserver: we expected at least one *pfs.CommitInfo returned from blocking call, but no *pfs.CommitInfo structs were returned for %v", lastCommit)}
	}
	// going in reverse order, oldest to newest
	for _, commitInfo := range commitInfos.CommitInfo {
		protolog.Infof("pachyderm.pps.pipelineserver: got new commit for pipeline %s: %s\n", p.pipelineInfo.Pipeline.Name, commitInfo.Commit)
		if err := p.createJobForCommitInfo(ctx, commitInfo); err != nil {
			return commitErrorPair{Err: err}
		}
	}
	return commitErrorPair{Commit: commitInfos.CommitInfo[len(commitInfos.CommitInfo)-1].Commit}
}

func (p *pipelineController) createJobForCommitInfo(ctx context.Context, commitInfo *pfs.CommitInfo) error {
	parentOutputCommit, err := p.getParentOutputCommit(ctx, commitInfo)
	if err != nil {
		return err
	}
	_, err = p.jobAPIClient.CreateJob(
		ctx,
		&pps.CreateJobRequest{
			Spec: &pps.CreateJobRequest_Pipeline{
				Pipeline: p.pipelineInfo.Pipeline,
			},
			Input:        commitInfo.Commit,
			OutputParent: parentOutputCommit,
		},
	)
	return err
}

func (p *pipelineController) getParentOutputCommit(ctx context.Context, commitInfo *pfs.CommitInfo) (*pfs.Commit, error) {
	for commitInfo.ParentCommit != nil && commitInfo.ParentCommit.Id != pfs.InitialCommitID {
		outputCommit, err := p.getOutputCommit(ctx, commitInfo.ParentCommit)
		if err != nil {
			return nil, err
		}
		if outputCommit != nil {
			return outputCommit, nil
		}
	}
	return &pfs.Commit{
		Repo: commitInfo.Commit.Repo,
		Id:   pfs.InitialCommitID,
	}, nil
}

func (p *pipelineController) getOutputCommit(ctx context.Context, inputCommit *pfs.Commit) (*pfs.Commit, error) {
	jobInfos, err := p.jobAPIClient.ListJob(
		ctx,
		&pps.ListJobRequest{
			Pipeline: p.pipelineInfo.Pipeline,
			Input:    inputCommit,
		},
	)
	if err != nil {
		return nil, err
	}
	// newest to oldest assumed
	for _, jobInfo := range jobInfos.JobInfo {
		if jobInfo.Output != nil && containsSuccessJobStatus(jobInfo.JobStatus) {
			return jobInfo.Output, nil
		}
	}
	return nil, nil
}

// TODO: not assuming that last status is success
func containsSuccessJobStatus(jobStatuses []*pps.JobStatus) bool {
	for _, jobStatus := range jobStatuses {
		if jobStatus.Type == pps.JobStatusType_JOB_STATUS_TYPE_SUCCESS {
			return true
		}
	}
	return false
}

func logIfError(err error) bool {
	if err = ignoreCanceledError(err); err != nil {
		protolog.Errorf("pachyderm.pps.pipelineserver: error in pipeline controller: %s\n", err.Error())
		return true
	}
	return false
}

func ignoreCanceledError(err error) error {
	if err != context.Canceled && grpc.Code(err) != codes.Canceled {
		return err
	}
	return nil
}
<commit_msg>Remove unused pipeline controller file.<commit_after><|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/oct2pus/botutil/embed"
	"github.com/oct2pus/botutil/etc"
	"github.com/oct2pus/botutil/logging"
)

// Prefix Const
const (
	prefix = "jade:"
)

// 'global' variables
var (
	// command line argument
	Token string
	self  *discordgo.User
	color int
)

// BooruSearch contains all relevant information pulled from a booru search
type BooruSearch struct {
	Posts []struct {
		FileURL string `xml:"file_url,attr"`
		Source  string `xml:"source,attr,omitempty"`
	} `xml:"post"`
}

// DogSearch contains the returned value from a dog.ceo api call
type DogSearch struct {
	Status  string `json:"status"`
	Message string `json:"message"`
}

// initalize variables
func init() {
	// command line argument
	flag.StringVar(&Token, "t", "", "Bot Token")
	flag.Parse()

	// error logging
	logging.CreateLog()

	// bot embed color
	color = 0x4bec13
}

// Main
func main() {

	// Create a new Discord session using the provided bot token.
	// token must be prefaced with "Bot "
	bot, err := discordgo.New("Bot " + Token)
	if err != nil {
		fmt.Println("error creating Discord session,", err)
		return
	}

	// Bot Event Handlers
	bot.AddHandler(messageCreate)
	bot.AddHandler(ready)

	// Open a websocket connection to Discord and begin listening.
	err = bot.Open()

	if logging.CheckError(err) {
		return
	}

	// Wait here until CTRL-C or other term signal is received.
	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Cleanly close down the Discord session.
	bot.Close()
}

// This function is called when the bot connects to discord
func ready(session *discordgo.Session, discordReady *discordgo.Ready) {
	session.UpdateStatus(0, "prefix: \""+prefix+" \"")
	self = discordReady.User

	fmt.Println("Guilds: ", len(discordReady.Guilds))
}

// messageCreate determines if the bot needs to do something
func messageCreate(session *discordgo.Session,
	message *discordgo.MessageCreate) {

	messageSlice := etc.StringSlice(message.Message.Content)
	// Ignore all messages created by the bot itself
	if message.Author.Bot == true {
		return
	}

	// commands
	if messageSlice[0] == prefix && len(messageSlice) > 1 {
		switch messageSlice[1] {
		case "roll", "lroll", "hroll":
			session.ChannelMessageSend(message.ChannelID,
				"i gave vriska all my dice, you should check her out here!"+
					"<https://discordapp.com/oauth2/authorize?client_id=49"+
					"7943811700424704&scope=bot&permissions=281600>")
		case "otp", "ship":
			if len(messageSlice) > 2 {
				session.ChannelMessageSend(message.ChannelID,
					getOTP(messageSlice[2:]))
			} else {
				session.ChannelMessageSend(message.ChannelID,
					"what ship do you want me to evaluate? :?")
			}
		case "avatar":
			session.ChannelMessageSendEmbed(message.ChannelID,
				getUserAvatar(message.Message))
		case "mspa", "booru":
			mspaEmbed, err := searchBooru(messageSlice[2:])
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					mspaEmbed)
			}
		case "discord":
			session.ChannelMessageSend(message.ChannelID,
				"https://discord.gg/PGVh2M8")
		case "dog":
			dogEmbed, err := searchDogs(messageSlice[2:])
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					dogEmbed)
			}
		case "doge":
			dogEmbed, err := searchDogs([]string{"shiba"})
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					dogEmbed)
			}
		case "invite":
			session.ChannelMessageSend(message.ChannelID,
				"<https://discordapp.com/oauth2/authorize?client_id="+
					"331204502277586945&scope=bot&permissions=379968>")
		case "commands", "command", "help":
			//TODO: This could be automated
			session.ChannelMessageSend(message.ChannelID,
				"my commands currently are\n-`avatar`\n-`mspa`, `booru`\n"+
					"-`dog`\n-`otp`, `ship`\n-`discord`\n-`invite`\n-`help`,"+
					" `commands`, `command`\n-`help`\n-`about`, `credits`")
		case "about", "credits":
			session.ChannelMessageSendEmbed(message.ChannelID,
				embed.CreditsEmbed("Jadebot",
					"Chuchumi ( http://chuchumi.tumblr.com/ )",
					"sun gun#0373 ( http://taiyoooh.tumblr.com )",
					"Dzuk#1671 ( https://noct.zone/ )",
					color))
		default:
			session.ChannelMessageSend(message.ChannelID,
				"i don't quite understand, maybe you should ask for `help` ;P")

		}
	}

	// text responses
	textResponse, shouldRespond := getTextResponse(message.Content)

	if shouldRespond {
		session.ChannelMessageSend(message.ChannelID, textResponse)
	}

	if etc.IsMentioned(message.Mentions, self) {
		session.ChannelMessageSend(message.ChannelID,
			"hello! :D\nby the way my prefix is '`jade: `'"+
				". just incase you wanted to know! :p")
	}
}

// getUserAvatar gets the mentioned used Avatar
// TODO: Remove later-y
func getUserAvatar(message *discordgo.Message) *discordgo.MessageEmbed {
	var emb *discordgo.MessageEmbed

	// should be functionally the same if its empty or nil, if something broke
	// here assume it has to do with the nil/empty slice distinction
	if len(message.Mentions) == 0 {
		emb = embed.ImageEmbed("Avatar", "", message.Author.AvatarURL("1024"),
			"User: "+message.Author.Username+"#"+message.Author.Discriminator,
			color)
	} else {
		emb = embed.ImageEmbed("Avatar", "",
			message.Mentions[0].AvatarURL("1024"), message.Mentions[0].Username+
				"#"+message.Mentions[0].Discriminator,
			color)
	}

	return emb
}

func searchBooru(input []string) (*discordgo.MessageEmbed, error) {
	// Building our search URL
	url := "http://mspabooru.com//index.php?page=dapi&s=post&q=index"
	pid := "0"    // page id, aka what page you are on, a page is 25 images
	limit := "25" // how many images to get

	url += "&pid=" + pid + "&limit=" + limit

	if len(input) > 0 {
		url += "&tags="
		for _, ele := range input {
			url += ele + "+"
		}
		url = strings.TrimSuffix(url, "+")
	}

	// hardcoded 'do not use' tags, allowing these outside of nsfw chats is
	// against ToS, remove stuff at your own peril.
	url += "+-*cest+-gore+-erasure+-vomit+-bondage+-dubcon+-mind_control+" +
		"-undergarments+-rating:questionable+-rating:explicit+-3d+-deleteme"

	// http Get request for values

	response, err := http.Get(url)
	if logging.CheckError(err) {
		return nil, errors.New("please don't enter gibberish to try and" +
			" and break me :(")
	}

	data, err2 := ioutil.ReadAll(response.Body)
	if logging.CheckError(err2) {
		return nil, errors.New("please stop trying to hurt me :(")
	}

	var booruSearch BooruSearch
	xml.Unmarshal(data, &booruSearch)

	if len(booruSearch.Posts) == 0 {
		return nil, errors.New("no posts found :(\n" +
			"if you were trying to find a ship, make sure your shipname was" +
			" entered correctly :o\n here is a list of all ship names on " +
			" the booru" +
			"\n<https://docs.google.com/spreadsheets/d/1IR5mmxNxgwAqH0_VENC0" +
			"KOaTgSXE_azPts8qwqz9xMk>")
	} else {

		// randomly pick a result
		rand.Seed(time.Now().UnixNano())

		randNum := rand.Intn(len(booruSearch.Posts))

		return embed.ImageEmbed("Source", booruSearch.Posts[randNum].Source,
			booruSearch.Posts[randNum].FileURL,
			"Warning: Some sources will be broken or NSFW", color), nil
	}
}

func searchDogs(input []string) (*discordgo.MessageEmbed, error) {

	for i, ele := range input {
		input[i] = strings.ToLower(ele)
	}

	var url string

	switch len(input) {
	case 0:
		url = "https://dog.ceo/api/breeds/image/random"
	case 1:
		url = "https://dog.ceo/api/breed/" + input[0] + "/images/random"
	default:
		url = "https://dog.ceo/api/breed/" + input[1] + "/" + input[0] +
			"/images/random"
	}

	var doge DogSearch

	response, err := http.Get(url)
	if logging.CheckError(err) {
		return nil, errors.New("something horrible went wrong when i was" +
			" searching for pups, try again")
	}

	data, err2 := ioutil.ReadAll(response.Body)
	if logging.CheckError(err2) {
		// TODO: Write an actual error message here
		return nil, errors.New("something really, really bad happened")
	}

	json.Unmarshal(data, &doge)

	if doge.Status != "success" {
		return nil, errors.New("i could not find that breed :(\n" +
			"here is a list of breeds i can find!\n" +
			"<https://dog.ceo/dog-api/breeds-list>")
	}

	return embed.ImageEmbed("Source", doge.Message, doge.Message,
		strings.Join(input, " "), color), nil

}

// rates ships based on semi-arbitrary text input
func getOTP(input []string) string {
	asString := strings.Join(input, " ")
	percent := etc.ANG(asString, 11)
	result := "I think " + asString + " has a **" + strconv.Itoa(int(percent)) +
		"/10** chance of being canon!"
	return result
}

// checks messages for contents, returns a response if it contains one
// emojis are sourced from the 'jade.moe' server
func getTextResponse(message string) (string, bool) {
	response := ""
	contentFound := false

	switch {
	case strings.Contains(message, "owo"):
		response = "oh woah whats this? :o"
		contentFound = true
	case strings.Contains(message, "love you jade"):
		response = "i love you too!! :D"
		contentFound = true
	case strings.Contains(message, "good dog"):
		response = "best friend!"
		contentFound = true
	case strings.Contains(message, "teef"):
		response = "<:jadeteefs:317080214364618753>"
		contentFound = true
	case strings.Contains(message, "kissjade"):
		response = "<:jb_embarrassed:432756486406537217><:jade_hearts:4326851" +
			"08085129246>"
		contentFound = true
	case strings.Contains(message, "pats"):
		response = "<:jb_headpats:432962465437843466>"
		contentFound = true
	case strings.Contains(message, ":think"), strings.Contains(message, "🤔"):
		response = "<:jadethinking:395982297490522122>"
		contentFound = true
	}

	return response, contentFound
}
<commit_msg>removed unneccessary else statement<commit_after>package main

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/oct2pus/botutil/embed"
	"github.com/oct2pus/botutil/etc"
	"github.com/oct2pus/botutil/logging"
)

// Prefix Const
const (
	prefix = "jade:"
)

// 'global' variables
var (
	// command line argument
	Token string
	self  *discordgo.User
	color int
)

// BooruSearch contains all relevant information pulled from a booru search
type BooruSearch struct {
	Posts []struct {
		FileURL string `xml:"file_url,attr"`
		Source  string `xml:"source,attr,omitempty"`
	} `xml:"post"`
}

// DogSearch contains the returned value from a dog.ceo api call
type DogSearch struct {
	Status  string `json:"status"`
	Message string `json:"message"`
}

// initalize variables
func init() {
	// command line argument
	flag.StringVar(&Token, "t", "", "Bot Token")
	flag.Parse()

	// error logging
	logging.CreateLog()

	// bot embed color
	color = 0x4bec13
}

// Main
func main() {

	// Create a new Discord session using the provided bot token.
	// token must be prefaced with "Bot "
	bot, err := discordgo.New("Bot " + Token)
	if err != nil {
		fmt.Println("error creating Discord session,", err)
		return
	}

	// Bot Event Handlers
	bot.AddHandler(messageCreate)
	bot.AddHandler(ready)

	// Open a websocket connection to Discord and begin listening.
	err = bot.Open()

	if logging.CheckError(err) {
		return
	}

	// Wait here until CTRL-C or other term signal is received.
	fmt.Println("Bot is now running.  Press CTRL-C to exit.")
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Cleanly close down the Discord session.
	bot.Close()
}

// This function is called when the bot connects to discord
func ready(session *discordgo.Session, discordReady *discordgo.Ready) {
	session.UpdateStatus(0, "prefix: \""+prefix+" \"")
	self = discordReady.User

	fmt.Println("Guilds: ", len(discordReady.Guilds))
}

// messageCreate determines if the bot needs to do something
func messageCreate(session *discordgo.Session,
	message *discordgo.MessageCreate) {

	messageSlice := etc.StringSlice(message.Message.Content)
	// Ignore all messages created by the bot itself
	if message.Author.Bot == true {
		return
	}

	// commands
	if messageSlice[0] == prefix && len(messageSlice) > 1 {
		switch messageSlice[1] {
		case "roll", "lroll", "hroll":
			session.ChannelMessageSend(message.ChannelID,
				"i gave vriska all my dice, you should check her out here!"+
					"<https://discordapp.com/oauth2/authorize?client_id=49"+
					"7943811700424704&scope=bot&permissions=281600>")
		case "otp", "ship":
			if len(messageSlice) > 2 {
				session.ChannelMessageSend(message.ChannelID,
					getOTP(messageSlice[2:]))
			} else {
				session.ChannelMessageSend(message.ChannelID,
					"what ship do you want me to evaluate? :?")
			}
		case "avatar":
			session.ChannelMessageSendEmbed(message.ChannelID,
				getUserAvatar(message.Message))
		case "mspa", "booru":
			mspaEmbed, err := searchBooru(messageSlice[2:])
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					mspaEmbed)
			}
		case "discord":
			session.ChannelMessageSend(message.ChannelID,
				"https://discord.gg/PGVh2M8")
		case "dog":
			dogEmbed, err := searchDogs(messageSlice[2:])
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					dogEmbed)
			}
		case "doge":
			dogEmbed, err := searchDogs([]string{"shiba"})
			if err != nil {
				session.ChannelMessageSend(message.ChannelID,
					err.Error())
			} else {
				session.ChannelMessageSendEmbed(message.ChannelID,
					dogEmbed)
			}
		case "invite":
			session.ChannelMessageSend(message.ChannelID,
				"<https://discordapp.com/oauth2/authorize?client_id="+
					"331204502277586945&scope=bot&permissions=379968>")
		case "commands", "command", "help":
			//TODO: This could be automated
			session.ChannelMessageSend(message.ChannelID,
				"my commands currently are\n-`avatar`\n-`mspa`, `booru`\n"+
					"-`dog`\n-`otp`, `ship`\n-`discord`\n-`invite`\n-`help`,"+
					" `commands`, `command`\n-`help`\n-`about`, `credits`")
		case "about", "credits":
			session.ChannelMessageSendEmbed(message.ChannelID,
				embed.CreditsEmbed("Jadebot",
					"Chuchumi ( http://chuchumi.tumblr.com/ )",
					"sun gun#0373 ( http://taiyoooh.tumblr.com )",
					"Dzuk#1671 ( https://noct.zone/ )",
					color))
		default:
			session.ChannelMessageSend(message.ChannelID,
				"i don't quite understand, maybe you should ask for `help` ;P")

		}
	}

	// text responses
	textResponse, shouldRespond := getTextResponse(message.Content)

	if shouldRespond {
		session.ChannelMessageSend(message.ChannelID, textResponse)
	}

	if etc.IsMentioned(message.Mentions, self) {
		session.ChannelMessageSend(message.ChannelID,
			"hello! :D\nby the way my prefix is '`jade: `'"+
				". just incase you wanted to know! :p")
	}
}

// getUserAvatar gets the mentioned used Avatar
// TODO: Remove later-y
func getUserAvatar(message *discordgo.Message) *discordgo.MessageEmbed {
	var emb *discordgo.MessageEmbed

	// should be functionally the same if its empty or nil, if something broke
	// here assume it has to do with the nil/empty slice distinction
	if len(message.Mentions) == 0 {
		emb = embed.ImageEmbed("Avatar", "", message.Author.AvatarURL("1024"),
			"User: "+message.Author.Username+"#"+message.Author.Discriminator,
			color)
	} else {
		emb = embed.ImageEmbed("Avatar", "",
			message.Mentions[0].AvatarURL("1024"), message.Mentions[0].Username+
				"#"+message.Mentions[0].Discriminator,
			color)
	}

	return emb
}

func searchBooru(input []string) (*discordgo.MessageEmbed, error) {
	// Building our search URL
	url := "http://mspabooru.com//index.php?page=dapi&s=post&q=index"
	pid := "0"    // page id, aka what page you are on, a page is 25 images
	limit := "25" // how many images to get

	url += "&pid=" + pid + "&limit=" + limit

	if len(input) > 0 {
		url += "&tags="
		for _, ele := range input {
			url += ele + "+"
		}
		url = strings.TrimSuffix(url, "+")
	}

	// hardcoded 'do not use' tags, allowing these outside of nsfw chats is
	// against ToS, remove stuff at your own peril.
	url += "+-*cest+-gore+-erasure+-vomit+-bondage+-dubcon+-mind_control+" +
		"-undergarments+-rating:questionable+-rating:explicit+-3d+-deleteme"

	// http Get request for values

	response, err := http.Get(url)
	if logging.CheckError(err) {
		return nil, errors.New("please don't enter gibberish to try and" +
			" and break me :(")
	}

	data, err2 := ioutil.ReadAll(response.Body)
	if logging.CheckError(err2) {
		return nil, errors.New("please stop trying to hurt me :(")
	}

	var booruSearch BooruSearch
	xml.Unmarshal(data, &booruSearch)

	if len(booruSearch.Posts) == 0 {
		return nil, errors.New("no posts found :(\n" +
			"if you were trying to find a ship, make sure your shipname was" +
			" entered correctly :o\n here is a list of all ship names on " +
			" the booru" +
			"\n<https://docs.google.com/spreadsheets/d/1IR5mmxNxgwAqH0_VENC0" +
			"KOaTgSXE_azPts8qwqz9xMk>")
	}
	// randomly pick a result
	rand.Seed(time.Now().UnixNano())

	randNum := rand.Intn(len(booruSearch.Posts))

	return embed.ImageEmbed("Source", booruSearch.Posts[randNum].Source,
		booruSearch.Posts[randNum].FileURL,
		"Warning: Some sources will be broken or NSFW", color), nil
}

func searchDogs(input []string) (*discordgo.MessageEmbed, error) {

	for i, ele := range input {
		input[i] = strings.ToLower(ele)
	}

	var url string

	switch len(input) {
	case 0:
		url = "https://dog.ceo/api/breeds/image/random"
	case 1:
		url = "https://dog.ceo/api/breed/" + input[0] + "/images/random"
	default:
		url = "https://dog.ceo/api/breed/" + input[1] + "/" + input[0] +
			"/images/random"
	}

	var doge DogSearch

	response, err := http.Get(url)
	if logging.CheckError(err) {
		return nil, errors.New("something horrible went wrong when i was" +
			" searching for pups, try again")
	}

	data, err2 := ioutil.ReadAll(response.Body)
	if logging.CheckError(err2) {
		// TODO: Write an actual error message here
		return nil, errors.New("something really, really bad happened")
	}

	json.Unmarshal(data, &doge)

	if doge.Status != "success" {
		return nil, errors.New("i could not find that breed :(\n" +
			"here is a list of breeds i can find!\n" +
			"<https://dog.ceo/dog-api/breeds-list>")
	}

	return embed.ImageEmbed("Source", doge.Message, doge.Message,
		strings.Join(input, " "), color), nil

}

// rates ships based on semi-arbitrary text input
func getOTP(input []string) string {
	asString := strings.Join(input, " ")
	percent := etc.ANG(asString, 11)
	result := "I think " + asString + " has a **" + strconv.Itoa(int(percent)) +
		"/10** chance of being canon!"
	return result
}

// checks messages for contents, returns a response if it contains one
// emojis are sourced from the 'jade.moe' server
func getTextResponse(message string) (string, bool) {
	response := ""
	contentFound := false

	switch {
	case strings.Contains(message, "owo"):
		response = "oh woah whats this? :o"
		contentFound = true
	case strings.Contains(message, "love you jade"):
		response = "i love you too!! :D"
		contentFound = true
	case strings.Contains(message, "good dog"):
		response = "best friend!"
		contentFound = true
	case strings.Contains(message, "teef"):
		response = "<:jadeteefs:317080214364618753>"
		contentFound = true
	case strings.Contains(message, "kissjade"):
		response = "<:jb_embarrassed:432756486406537217><:jade_hearts:4326851" +
			"08085129246>"
		contentFound = true
	case strings.Contains(message, "pats"):
		response = "<:jb_headpats:432962465437843466>"
		contentFound = true
	case strings.Contains(message, ":think"), strings.Contains(message, "🤔"):
		response = "<:jadethinking:395982297490522122>"
		contentFound = true
	}

	return response, contentFound
}
<|endoftext|>


<commit_before>package travel

import (
	"fmt"
	"os"

	"github.com/akerl/voyager/cartogram"

	"github.com/akerl/speculate/creds"
	"github.com/akerl/speculate/executors"
)

type hop struct {
	Profile string
	Account string
	Role    string
	Mfa     bool
}

type voyage struct {
	pack    cartogram.Pack
	account cartogram.Account
	role    string
	hops    []hop
	creds   creds.Creds
}

// Itinerary describes a travel request
type Itinerary struct {
	Args        []string
	RoleName    string
	SessionName string
	Policy      string
	Lifetime    int64
	MfaCode     string
	MfaSerial   string
}

// Travel loads creds from a full set of parameters
func Travel(i Itinerary) (creds.Creds, error) {
	var c creds.Creds
	v := voyage{}

	if err := v.loadPack(); err != nil {
		return c, err
	}
	if err := v.loadAccount(i.Args); err != nil {
		return c, err
	}
	if err := v.loadRole(i.RoleName); err != nil {
		return c, err
	}
	if err := v.loadHops(); err != nil {
		return c, err
	}
	if err := v.loadCreds(i); err != nil {
		return c, err
	}
	return v.creds, nil
}

func (v *voyage) loadPack() error {
	v.pack = make(cartogram.Pack)
	return v.pack.Load()
}

func (v *voyage) loadAccount(args []string) error {
	var err error
	v.account, err = v.pack.Find(args)
	return err
}

func (v *voyage) loadRole(roleName string) error {
	var err error
	v.role, err = v.account.PickRole(roleName)
	return err
}

func (v *voyage) loadHops() error {
	if err := parseHops(&v.hops, v.pack, v.account, v.role); err != nil {
		return err
	}
	for i, j := 0, len(v.hops)-1; i < j; i, j = i+1, j-1 {
		v.hops[i], v.hops[j] = v.hops[j], v.hops[i]
	}
	return nil
}

func (v *voyage) loadCreds(i Itinerary) error {
	var c creds.Creds
	var err error

	profileHop, stack := v.hops[0], v.hops[1:]
	for varName := range creds.Translations["envvar"] {
		os.Unsetenv(varName)
	}
	os.Setenv("AWS_PROFILE", profileHop.Profile)

	last := len(stack) - 1
	for index, thisHop := range stack {
		a := executors.Assumption{}
		if err := a.SetAccountID(thisHop.Account); err != nil {
			return err
		}
		if err := a.SetRoleName(thisHop.Role); err != nil {
			return err
		}
		if err := a.SetSessionName(i.SessionName); err != nil {
			return err
		}
		if i.Lifetime != 0 {
			if err := a.SetLifetime(i.Lifetime); err != nil {
				return err
			}
		}
		if index == last {
			if err := a.SetPolicy(i.Policy); err != nil {
				return err
			}
		}
		if thisHop.Mfa {
			if err := a.SetMfa(true); err != nil {
				return err
			}
			if err := a.SetMfaSerial(i.MfaSerial); err != nil {
				return err
			}
			if err := a.SetMfaCode(i.MfaCode); err != nil {
				return err
			}
		}
		c, err = a.ExecuteWithCreds(c)
		c.Region = thisHop.Account.Region
		if err != nil {
			return err
		}
	}
	v.creds = c
	return nil
}

func parseHops(stack *[]hop, cp cartogram.Pack, a cartogram.Account, r string) error {
	*stack = append(*stack, hop{Account: a.Account, Role: r, Mfa: a.Roles[r].Mfa})
	accountMatch := cartogram.AccountRegex.FindStringSubmatch(a.Source)
	if len(accountMatch) != 4 {
		*stack = append(*stack, hop{Profile: a.Source})
		return nil
	}
	sAccountID := accountMatch[1]
	sRole := accountMatch[3]
	found, sAccount := cp.Lookup(sAccountID)
	if !found {
		return fmt.Errorf("Failed to resolve hop for %s", sAccountID)
	}
	return parseHops(stack, cp, sAccount, sRole)
}
<commit_msg>fix Region handling<commit_after>package travel

import (
	"fmt"
	"os"

	"github.com/akerl/voyager/cartogram"

	"github.com/akerl/speculate/creds"
	"github.com/akerl/speculate/executors"
)

type hop struct {
	Profile string
	Account string
	Region  string
	Role    string
	Mfa     bool
}

type voyage struct {
	pack    cartogram.Pack
	account cartogram.Account
	role    string
	hops    []hop
	creds   creds.Creds
}

// Itinerary describes a travel request
type Itinerary struct {
	Args        []string
	RoleName    string
	SessionName string
	Policy      string
	Lifetime    int64
	MfaCode     string
	MfaSerial   string
}

// Travel loads creds from a full set of parameters
func Travel(i Itinerary) (creds.Creds, error) {
	var c creds.Creds
	v := voyage{}

	if err := v.loadPack(); err != nil {
		return c, err
	}
	if err := v.loadAccount(i.Args); err != nil {
		return c, err
	}
	if err := v.loadRole(i.RoleName); err != nil {
		return c, err
	}
	if err := v.loadHops(); err != nil {
		return c, err
	}
	if err := v.loadCreds(i); err != nil {
		return c, err
	}
	return v.creds, nil
}

func (v *voyage) loadPack() error {
	v.pack = make(cartogram.Pack)
	return v.pack.Load()
}

func (v *voyage) loadAccount(args []string) error {
	var err error
	v.account, err = v.pack.Find(args)
	return err
}

func (v *voyage) loadRole(roleName string) error {
	var err error
	v.role, err = v.account.PickRole(roleName)
	return err
}

func (v *voyage) loadHops() error {
	if err := parseHops(&v.hops, v.pack, v.account, v.role); err != nil {
		return err
	}
	for i, j := 0, len(v.hops)-1; i < j; i, j = i+1, j-1 {
		v.hops[i], v.hops[j] = v.hops[j], v.hops[i]
	}
	return nil
}

func (v *voyage) loadCreds(i Itinerary) error {
	var c creds.Creds
	var err error

	profileHop, stack := v.hops[0], v.hops[1:]
	for varName := range creds.Translations["envvar"] {
		os.Unsetenv(varName)
	}
	os.Setenv("AWS_PROFILE", profileHop.Profile)

	last := len(stack) - 1
	for index, thisHop := range stack {
		a := executors.Assumption{}
		if err := a.SetAccountID(thisHop.Account); err != nil {
			return err
		}
		if err := a.SetRoleName(thisHop.Role); err != nil {
			return err
		}
		if err := a.SetSessionName(i.SessionName); err != nil {
			return err
		}
		if i.Lifetime != 0 {
			if err := a.SetLifetime(i.Lifetime); err != nil {
				return err
			}
		}
		if index == last {
			if err := a.SetPolicy(i.Policy); err != nil {
				return err
			}
		}
		if thisHop.Mfa {
			if err := a.SetMfa(true); err != nil {
				return err
			}
			if err := a.SetMfaSerial(i.MfaSerial); err != nil {
				return err
			}
			if err := a.SetMfaCode(i.MfaCode); err != nil {
				return err
			}
		}
		c, err = a.ExecuteWithCreds(c)
		c.Region = thisHop.Region
		if err != nil {
			return err
		}
	}
	v.creds = c
	return nil
}

func parseHops(stack *[]hop, cp cartogram.Pack, a cartogram.Account, r string) error {
	*stack = append(
		*stack,
		hop{
			Account: a.Account,
			Region:  a.Region,
			Role:    r,
			Mfa:     a.Roles[r].Mfa,
		},
	)
	accountMatch := cartogram.AccountRegex.FindStringSubmatch(a.Source)
	if len(accountMatch) != 4 {
		*stack = append(*stack, hop{Profile: a.Source})
		return nil
	}
	sAccountID := accountMatch[1]
	sRole := accountMatch[3]
	found, sAccount := cp.Lookup(sAccountID)
	if !found {
		return fmt.Errorf("Failed to resolve hop for %s", sAccountID)
	}
	return parseHops(stack, cp, sAccount, sRole)
}
<|endoftext|>


<commit_before>package iosupport

import (
	"bufio"
	"errors"
	"io"
	"regexp"
	"sort"
	"strconv"
)

// TsvLine describes the line's details from a TSV
type TsvLine struct {
	Index       int
	Comparables []string
	Offset      int64
	Limit       int
}
type tsvLines []TsvLine

// Internal use
type seeker struct {
	sc     *Scanner
	offset int64
}

// TsvIndexer contains all stuff for indexing columns from a TSV
type TsvIndexer struct {
	parser        *TsvParser // directly embedded in TsvParser?
	Header        bool
	Separator     byte
	Fields        []string
	FieldsIndex   map[string]int
	Lines         tsvLines
	seekers       []seeker
	scannerFunc   func() *Scanner
	LineThreshold int
}

// NewTsvIndexer instanciates a new TsvIndexer
func NewTsvIndexer(scannerFunc func() *Scanner, header bool, separator string, fields []string) *TsvIndexer {
	sc := scannerFunc()
	sc.Reset()
	sc.KeepNewlineSequence(true)
	return &TsvIndexer{
		parser:        NewTsvParser(sc, UnescapeSeparator(separator)),
		Header:        header,
		Separator:     UnescapeSeparator(separator),
		Fields:        fields,
		FieldsIndex:   make(map[string]int),
		scannerFunc:   scannerFunc,
		LineThreshold: 2500000,
		seekers:       []seeker{seeker{sc, 0}},
	}
}

// CloseIO closes all opened IO
func (ti *TsvIndexer) CloseIO() {
	ti.parser.sc.f.Close()
	ti.releaseSeekers()
}

// Analyze parses the TSV and generates the indexes
func (ti *TsvIndexer) Analyze() error {
	if !ti.Header {
		re := regexp.MustCompile(`var(\d+)`)
		for _, field := range ti.Fields {
			if len(re.FindStringSubmatch(field)) < 2 {
				return errors.New("Field " + field + " do not match with pattern /var\\d+/")
			}
		}
	}
	for ti.parser.ScanRow() {
		if ti.parser.Err() != nil {
			return ti.parser.Err()
		}
		ti.tsvLineAppender(ti.parser.Row(), ti.parser.Line(), ti.parser.Offset(), ti.parser.Limit())
	}
	ti.parser.Reset()

	ti.createSeekers(len(ti.Lines), func(index int) int64 {
		return ti.Lines[index].Offset
	}) // For transfer part
	return nil
}

// Sort sorts TsvLine on its comparables
func (ti *TsvIndexer) Sort() {

	sort.Sort(ti.Lines)
}

// Transfer writes sorted TSV into a new file
func (ti *TsvIndexer) Transfer(output io.Writer) error {
	w := bufio.NewWriter(output)

	// For all sorted lines contained in the TSV
	for _, line := range ti.Lines {
		token, err := ti.selectSeeker(line.Offset).sc.ReadAt(line.Offset, line.Limit) // Reads the current line
		if err != nil {
			return err
		}
		if _, err := w.Write(token); err != nil { // writes the current line into the sorted TSV output
			return err
		}
	}
	if err := w.Flush(); err != nil {
		return err
	}
	ti.releaseSeekers()
	return nil
}

// ------------------ //
// Sort stuff         //
// ------------------ //

func (slice tsvLines) Len() int {
	return len(slice)
}

func (slice tsvLines) Less(i, j int) bool {
	b := false
	for x, comparable := range slice[i].Comparables {
		b = b || comparable < slice[j].Comparables[x]
	}
	return b
}

func (slice tsvLines) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ------------------ //
// Transfer stuff     //
// ------------------ //

// createSeekers creates seekers for increase the speed of random accesses of the read file
func (ti *TsvIndexer) createSeekers(nol int, offset func(int) int64) {
	if nol < ti.LineThreshold {
		return
	}

	nbOfThresholds := nol / ti.LineThreshold
	lineOffset := nol / (nbOfThresholds + 1)
	lineIndex := 0
	for i := 0; i < nbOfThresholds; i++ {
		lineIndex += lineOffset
		ti.appendSeeker(offset(lineIndex))
	}
}

// appendSeeker appends a new seeker based on the given offset. Seekers must be appened ordering by the offset
func (ti *TsvIndexer) appendSeeker(offset int64) {
	sc := ti.scannerFunc()
	ti.seekers = append(ti.seekers, seeker{sc, offset})
}

// releaseSeekers closes internal opened file
func (ti *TsvIndexer) releaseSeekers() {
	for _, seeker := range ti.seekers {
		seeker.sc.f.Close()
	}
}

// selectSeeker returns the nearest inferior seeker
// e.g. A file with 10,000,000 lines
//    s0 -> offset 0
//    s1 -> offset 2,500,000
//    s2 -> offset 5,000,000
//    s3 -> offset 7,500,000
// offset 666 returns seeker s0
// offset 9,999,999 returns seeker s3
func (ti *TsvIndexer) selectSeeker(offset int64) seeker {
	for i, seeker := range ti.seekers {
		if seeker.offset > offset {
			return ti.seekers[i-1]
		}
	}
	return ti.seekers[len(ti.seekers)-1]
}

// ------------------ //
// Analyze stuff      //
// ------------------ //

func (ti *TsvIndexer) tsvLineAppender(row [][]byte, index int, offset int64, limit int) error {
	ti.Lines = append(ti.Lines, TsvLine{index, []string{}, offset, limit})
	if index == 0 && ti.Header {
		if err := ti.findFieldsIndex(row); err != nil {
			return err
		}
		// Build empty comparable
		// When comparables are sorted, this one (the header) remains the first line
		for i := 0; i < len(ti.Fields); i++ {
			ti.appendComparable([]byte{}, index)
		}
	} else if index == 0 {
		// Without header, fields are named like the following pattern /var\d+/
		// \d+ is used for the index of the variable
		//
		// e.g. `var1,var2,var3` with `var1` had the index 0
		re := regexp.MustCompile(`var(\d+)`)
		for _, field := range ti.Fields {
			i, err := strconv.Atoi(re.FindStringSubmatch(field)[1])
			if err != nil {
				return err
			}
			ti.FieldsIndex[field] = i - 1
			ti.appendComparable(row[i-1], index) // The first row contains data (/!\ it is not an header)
		}
	} else {
		for _, field := range ti.Fields {
			ti.appendComparable(row[ti.FieldsIndex[field]], index)
		}
	}
	return nil
}

func (ti *TsvIndexer) appendComparable(comparable []byte, index int) {
	cp := make([]byte, len(comparable), len(comparable))
	copy(cp, comparable) // Freeing the underlying array (https://blog.golang.org/go-slices-usage-and-internals - chapter: A possible "gotcha")
	ti.Lines[index].Comparables = append(ti.Lines[index].Comparables, string(cp))
}

// Append to TsvIndexer.FieldsIndex the index in the row of all TsvIndexer.Fields
func (ti *TsvIndexer) findFieldsIndex(row [][]byte) error {
	for i, head := range row {
		for _, field := range ti.Fields {
			if string(head) == field {
				ti.FieldsIndex[field] = i
				break
			}
		}
	}
	if len(ti.Fields) != len(ti.FieldsIndex) {
		return errors.New("Invalid separator or sort fields")
	}
	return nil
}
<commit_msg>Remove useless struct field for better memory usage<commit_after>package iosupport

import (
	"bufio"
	"errors"
	"io"
	"regexp"
	"sort"
	"strconv"
)

// TsvLine describes the line's details from a TSV
type TsvLine struct {
	Comparables []string
	Offset      int64
	Limit       int
}
type tsvLines []TsvLine

// Internal use
type seeker struct {
	sc     *Scanner
	offset int64
}

// TsvIndexer contains all stuff for indexing columns from a TSV
type TsvIndexer struct {
	parser        *TsvParser // directly embedded in TsvParser?
	Header        bool
	Separator     byte
	Fields        []string
	FieldsIndex   map[string]int
	Lines         tsvLines
	seekers       []seeker
	scannerFunc   func() *Scanner
	LineThreshold int
}

// NewTsvIndexer instanciates a new TsvIndexer
func NewTsvIndexer(scannerFunc func() *Scanner, header bool, separator string, fields []string) *TsvIndexer {
	sc := scannerFunc()
	sc.Reset()
	sc.KeepNewlineSequence(true)
	return &TsvIndexer{
		parser:        NewTsvParser(sc, UnescapeSeparator(separator)),
		Header:        header,
		Separator:     UnescapeSeparator(separator),
		Fields:        fields,
		FieldsIndex:   make(map[string]int),
		scannerFunc:   scannerFunc,
		LineThreshold: 2500000,
		seekers:       []seeker{seeker{sc, 0}},
	}
}

// CloseIO closes all opened IO
func (ti *TsvIndexer) CloseIO() {
	ti.parser.sc.f.Close()
	ti.releaseSeekers()
}

// Analyze parses the TSV and generates the indexes
func (ti *TsvIndexer) Analyze() error {
	if !ti.Header {
		re := regexp.MustCompile(`var(\d+)`)
		for _, field := range ti.Fields {
			if len(re.FindStringSubmatch(field)) < 2 {
				return errors.New("Field " + field + " do not match with pattern /var\\d+/")
			}
		}
	}
	for ti.parser.ScanRow() {
		if ti.parser.Err() != nil {
			return ti.parser.Err()
		}
		ti.tsvLineAppender(ti.parser.Row(), ti.parser.Line(), ti.parser.Offset(), ti.parser.Limit())
	}
	ti.parser.Reset()

	ti.createSeekers(len(ti.Lines), func(index int) int64 {
		return ti.Lines[index].Offset
	}) // For transfer part
	return nil
}

// Sort sorts TsvLine on its comparables
func (ti *TsvIndexer) Sort() {

	sort.Sort(ti.Lines)
}

// Transfer writes sorted TSV into a new file
func (ti *TsvIndexer) Transfer(output io.Writer) error {
	w := bufio.NewWriter(output)

	// For all sorted lines contained in the TSV
	for _, line := range ti.Lines {
		token, err := ti.selectSeeker(line.Offset).sc.ReadAt(line.Offset, line.Limit) // Reads the current line
		if err != nil {
			return err
		}
		if _, err := w.Write(token); err != nil { // writes the current line into the sorted TSV output
			return err
		}
	}
	if err := w.Flush(); err != nil {
		return err
	}
	ti.releaseSeekers()
	return nil
}

// ------------------ //
// Sort stuff         //
// ------------------ //

func (slice tsvLines) Len() int {
	return len(slice)
}

func (slice tsvLines) Less(i, j int) bool {
	b := false
	for x, comparable := range slice[i].Comparables {
		b = b || comparable < slice[j].Comparables[x]
	}
	return b
}

func (slice tsvLines) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ------------------ //
// Transfer stuff     //
// ------------------ //

// createSeekers creates seekers for increase the speed of random accesses of the read file
func (ti *TsvIndexer) createSeekers(nol int, offset func(int) int64) {
	if nol < ti.LineThreshold {
		return
	}

	nbOfThresholds := nol / ti.LineThreshold
	lineOffset := nol / (nbOfThresholds + 1)
	lineIndex := 0
	for i := 0; i < nbOfThresholds; i++ {
		lineIndex += lineOffset
		ti.appendSeeker(offset(lineIndex))
	}
}

// appendSeeker appends a new seeker based on the given offset. Seekers must be appened ordering by the offset
func (ti *TsvIndexer) appendSeeker(offset int64) {
	sc := ti.scannerFunc()
	ti.seekers = append(ti.seekers, seeker{sc, offset})
}

// releaseSeekers closes internal opened file
func (ti *TsvIndexer) releaseSeekers() {
	for _, seeker := range ti.seekers {
		seeker.sc.f.Close()
	}
}

// selectSeeker returns the nearest inferior seeker
// e.g. A file with 10,000,000 lines
//    s0 -> offset 0
//    s1 -> offset 2,500,000
//    s2 -> offset 5,000,000
//    s3 -> offset 7,500,000
// offset 666 returns seeker s0
// offset 9,999,999 returns seeker s3
func (ti *TsvIndexer) selectSeeker(offset int64) seeker {
	for i, seeker := range ti.seekers {
		if seeker.offset > offset {
			return ti.seekers[i-1]
		}
	}
	return ti.seekers[len(ti.seekers)-1]
}

// ------------------ //
// Analyze stuff      //
// ------------------ //

func (ti *TsvIndexer) tsvLineAppender(row [][]byte, index int, offset int64, limit int) error {
	ti.Lines = append(ti.Lines, TsvLine{[]string{}, offset, limit})
	if index == 0 && ti.Header {
		if err := ti.findFieldsIndex(row); err != nil {
			return err
		}
		// Build empty comparable
		// When comparables are sorted, this one (the header) remains the first line
		for i := 0; i < len(ti.Fields); i++ {
			ti.appendComparable([]byte{}, index)
		}
	} else if index == 0 {
		// Without header, fields are named like the following pattern /var\d+/
		// \d+ is used for the index of the variable
		//
		// e.g. `var1,var2,var3` with `var1` had the index 0
		re := regexp.MustCompile(`var(\d+)`)
		for _, field := range ti.Fields {
			i, err := strconv.Atoi(re.FindStringSubmatch(field)[1])
			if err != nil {
				return err
			}
			ti.FieldsIndex[field] = i - 1
			ti.appendComparable(row[i-1], index) // The first row contains data (/!\ it is not an header)
		}
	} else {
		for _, field := range ti.Fields {
			ti.appendComparable(row[ti.FieldsIndex[field]], index)
		}
	}
	return nil
}

func (ti *TsvIndexer) appendComparable(comparable []byte, index int) {
	cp := make([]byte, len(comparable), len(comparable))
	copy(cp, comparable) // Freeing the underlying array (https://blog.golang.org/go-slices-usage-and-internals - chapter: A possible "gotcha")
	ti.Lines[index].Comparables = append(ti.Lines[index].Comparables, string(cp))
}

// Append to TsvIndexer.FieldsIndex the index in the row of all TsvIndexer.Fields
func (ti *TsvIndexer) findFieldsIndex(row [][]byte) error {
	for i, head := range row {
		for _, field := range ti.Fields {
			if string(head) == field {
				ti.FieldsIndex[field] = i
				break
			}
		}
	}
	if len(ti.Fields) != len(ti.FieldsIndex) {
		return errors.New("Invalid separator or sort fields")
	}
	return nil
}
<|endoftext|>


<commit_before>package host

import (
	"strconv"
	"time"

	"github.com/flynn/go-dockerclient"
)

type Job struct {
	ID string

	// The ID of the container to run
	Container string
	// Job attributes (all host rules must match successfully)
	Attributes map[string]string
	// Resource requirements (decremented from host resources)
	Resources map[string]int
	// Number of TCP ports required by the job
	// TODO: move to Attrs/Resources?
	TCPPorts int

	Config     *docker.Config
	HostConfig *docker.HostConfig
}

type ResourceValue struct {
	Value      int  `json:"value"`
	Overcommit bool `json:"overcommit"`
}

type Host struct {
	ID string

	// Currently running jobs
	Jobs []*Job
	// All rules must match job attributes
	Rules []Rule
	// Currently available resources
	Resources map[string]ResourceValue
	// Host attributes
	Attributes map[string]string
}

func (h *Host) Compatible(job *Job) bool {
	for _, r := range h.Rules {
		if !r.Match(job.Attributes) {
			return false
		}
	}
	return true
}

func (h *Host) Fits(job *Job) bool {
	for k, v := range job.Resources {
		res, ok := h.Resources[k]
		if !ok || !res.Overcommit && res.Value < v {
			return false
		}
	}
	return true
}

func (h *Host) Add(job *Job) bool {
	if !h.Compatible(job) {
		return false
	}
	for k, v := range job.Resources {
		res, ok := h.Resources[k]
		if !ok || !res.Overcommit && res.Value < v {
			return false
		}
		res.Value -= v
		h.Resources[k] = res
	}
	h.Jobs = append(h.Jobs, job)
	return true
}

type AddJobsReq struct {
	// If true, commit all jobs that fit; if false, reject entire request if a single job doesn't fit
	Incremental bool
	// map of host id -> new jobs
	HostJobs map[string][]*Job
}

type AddJobsRes struct {
	// The state of the cluster after the operation
	State map[string]Host
	// If the request was incremental, the jobs that were not scheduled
	RemainingJobs []*Job
	// true if the request was atomic and all jobs were committed
	Success bool
}

type RuleOperator uint8

const (
	OpEq RuleOperator = iota
	OpNotEq
	OpGt
	OpGtEq
	OpLt
	OpLtEq
)

type Rule struct {
	Key   string
	Op    RuleOperator
	Value string
}

func (r *Rule) Match(h map[string]string) bool {
	v, ok := h[r.Key]
	if !ok {
		return r.Op == OpEq && r.Value == "nil"
	}
	switch r.Op {
	case OpEq:
		return r.Value == v
	case OpNotEq:
		return r.Value != v
	}

	// TODO: cache these somewhere
	left, _ := strconv.Atoi(v)
	right, _ := strconv.Atoi(r.Value)
	switch r.Op {
	case OpGt:
		return left > right
	case OpGtEq:
		return left >= right
	case OpLt:
		return left < right
	case OpLtEq:
		return left <= right
	default:
		// invalid op
		return false
	}
}

type Event struct {
	Event string
	JobID string
}

type ActiveJob struct {
	Job *Job

	ContainerID string
	Status      JobStatus
	StartedAt   time.Time
	EndedAt     time.Time
	ExitCode    int
	Error       error
}

type AttachReq struct {
	JobID  string
	Flags  AttachFlag
	Height int
	Width  int
}

type AttachFlag uint8

const (
	AttachFlagStdout AttachFlag = 1 << iota
	AttachFlagStderr
	AttachFlagStdin
	AttachFlagLogs
	AttachFlagStream
)

type JobStatus uint8

func (s JobStatus) String() string {
	return map[JobStatus]string{
		StatusStarting: "starting",
		StatusRunning:  "running",
		StatusDone:     "done",
		StatusCrashed:  "crashed",
		StatusFailed:   "failed",
	}[s]
}

const (
	StatusStarting JobStatus = iota
	StatusRunning
	StatusDone
	StatusCrashed
	StatusFailed
)

const (
	AttachSuccess byte = iota
	AttachWaiting
	AttachError
)
<commit_msg>host: Remove unused Job.Container field<commit_after>package host

import (
	"strconv"
	"time"

	"github.com/flynn/go-dockerclient"
)

type Job struct {
	ID string

	// Job attributes (all host rules must match successfully)
	Attributes map[string]string
	// Resource requirements (decremented from host resources)
	Resources map[string]int
	// Number of TCP ports required by the job
	// TODO: move to Attrs/Resources?
	TCPPorts int

	Config     *docker.Config
	HostConfig *docker.HostConfig
}

type ResourceValue struct {
	Value      int  `json:"value"`
	Overcommit bool `json:"overcommit"`
}

type Host struct {
	ID string

	// Currently running jobs
	Jobs []*Job
	// All rules must match job attributes
	Rules []Rule
	// Currently available resources
	Resources map[string]ResourceValue
	// Host attributes
	Attributes map[string]string
}

func (h *Host) Compatible(job *Job) bool {
	for _, r := range h.Rules {
		if !r.Match(job.Attributes) {
			return false
		}
	}
	return true
}

func (h *Host) Fits(job *Job) bool {
	for k, v := range job.Resources {
		res, ok := h.Resources[k]
		if !ok || !res.Overcommit && res.Value < v {
			return false
		}
	}
	return true
}

func (h *Host) Add(job *Job) bool {
	if !h.Compatible(job) {
		return false
	}
	for k, v := range job.Resources {
		res, ok := h.Resources[k]
		if !ok || !res.Overcommit && res.Value < v {
			return false
		}
		res.Value -= v
		h.Resources[k] = res
	}
	h.Jobs = append(h.Jobs, job)
	return true
}

type AddJobsReq struct {
	// If true, commit all jobs that fit; if false, reject entire request if a single job doesn't fit
	Incremental bool
	// map of host id -> new jobs
	HostJobs map[string][]*Job
}

type AddJobsRes struct {
	// The state of the cluster after the operation
	State map[string]Host
	// If the request was incremental, the jobs that were not scheduled
	RemainingJobs []*Job
	// true if the request was atomic and all jobs were committed
	Success bool
}

type RuleOperator uint8

const (
	OpEq RuleOperator = iota
	OpNotEq
	OpGt
	OpGtEq
	OpLt
	OpLtEq
)

type Rule struct {
	Key   string
	Op    RuleOperator
	Value string
}

func (r *Rule) Match(h map[string]string) bool {
	v, ok := h[r.Key]
	if !ok {
		return r.Op == OpEq && r.Value == "nil"
	}
	switch r.Op {
	case OpEq:
		return r.Value == v
	case OpNotEq:
		return r.Value != v
	}

	// TODO: cache these somewhere
	left, _ := strconv.Atoi(v)
	right, _ := strconv.Atoi(r.Value)
	switch r.Op {
	case OpGt:
		return left > right
	case OpGtEq:
		return left >= right
	case OpLt:
		return left < right
	case OpLtEq:
		return left <= right
	default:
		// invalid op
		return false
	}
}

type Event struct {
	Event string
	JobID string
}

type ActiveJob struct {
	Job *Job

	ContainerID string
	Status      JobStatus
	StartedAt   time.Time
	EndedAt     time.Time
	ExitCode    int
	Error       error
}

type AttachReq struct {
	JobID  string
	Flags  AttachFlag
	Height int
	Width  int
}

type AttachFlag uint8

const (
	AttachFlagStdout AttachFlag = 1 << iota
	AttachFlagStderr
	AttachFlagStdin
	AttachFlagLogs
	AttachFlagStream
)

type JobStatus uint8

func (s JobStatus) String() string {
	return map[JobStatus]string{
		StatusStarting: "starting",
		StatusRunning:  "running",
		StatusDone:     "done",
		StatusCrashed:  "crashed",
		StatusFailed:   "failed",
	}[s]
}

const (
	StatusStarting JobStatus = iota
	StatusRunning
	StatusDone
	StatusCrashed
	StatusFailed
)

const (
	AttachSuccess byte = iota
	AttachWaiting
	AttachError
)
<|endoftext|>


<commit_before>package terraform

// The main version number that is being run at the moment.
const Version = "0.6.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"
<commit_msg>v0.6.0<commit_after>package terraform

// The main version number that is being run at the moment.
const Version = "0.6.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.7.4"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<commit_msg>release: clean up after v0.7.4<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.7.5"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package ov

import (
	"fmt"
	"os"
	"testing"

	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
	"github.com/stretchr/testify/assert"
)

// get server hardware test
func TestServerHardware(t *testing.T) {
	var (
		d           *OVTest
		c           *ov.OVClient
		testData    utils.Nstring
		expectsData string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testData = utils.Nstring(d.Tc.GetTestData(d.Env, "ServerHardwareURI").(string))
		expectsData = d.Tc.GetExpectsData(d.Env, "SerialNumber").(string)
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		data, err := c.GetServerHardwareByUri(testData)
		log.Debugf("%+v", data)
		assert.NoError(t, err, "GetServerHardwareByUri threw error -> %s", err)
		// fmt.Printf("data.Connections -> %+v\n", data)
		assert.Equal(t, expectsData, data.SerialNumber.String())

	}
}

func TestGetServerHardwareByName(t *testing.T) {
	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testServerHardware, err := c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardwareByName thew an error -> %s", err)
		assert.Equal(t, testName, testServerHardware.Name)

		testServerHardware, err = c.GetServerHardwareByName("bad")
		assert.NoError(t, err, "GetServerHardwareByName with fake name -> %s", err)
		assert.Equal(t, "", testServerHardware.Name)

	} else {
		d, c = getTestDriverU("test_server_hardware")
		testName = d.Tc.GetTestData(d.Env, "Name").(string)
		data, err := c.GetServerHardwareByName(testName)
		assert.Error(t, err, fmt.Sprintf("ALL ok, no error, caught as expected: %s,%+v\n", err, data))
	}
}

// get server hardware test
func TestGetAvailableHardware(t *testing.T) {
	var (
		d               *OVTest
		c               *ov.OVClient
		testHwType_URI  utils.Nstring
		testHWGroup_URI utils.Nstring
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testHwType_URI = utils.Nstring(d.Tc.GetTestData(d.Env, "HardwareTypeURI").(string))
		testHWGroup_URI = utils.Nstring(d.Tc.GetTestData(d.Env, "GroupURI").(string))
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		data, err := c.GetAvailableHardware(testHwType_URI, testHWGroup_URI)
		assert.NoError(t, err, "GetAvailableHardware threw error -> %s", err)
		// fmt.Printf("data.Connections -> %+v\n", data)
		log.Debugf("Abailable server -> %+v", data)
		log.Infof("Server Name -> %+v", data.Name)
		assert.NotEqual(t, "", data.Name)

	}
}

// TestGetIloIPAddress verify get ip address for hardware
func TestGetIloIPAddress(t *testing.T) {

	var (
		d           *OVTest
		c           *ov.OVClient
		testData    utils.Nstring
		expectsData string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testData = utils.Nstring(d.Tc.GetTestData(d.Env, "ServerHardwareURI").(string))
		expectsData = d.Tc.GetExpectsData(d.Env, "IloIPAddress").(string)
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		s, err := c.GetServerHardwareByUri(testData)
		assert.NoError(t, err, "GetServerHardwareByUri threw error -> %s", err)
		ip := s.GetIloIPAddress()
		log.Debugf("server -> %+v", s)
		log.Debugf("ip -> %+v", ip)
		assert.Equal(t, expectsData, ip)

	}

}

// TestAddRackServer verify adds hardware to the appliance
func TestAddRackServers(t *testing.T) {

	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		// find out if the test server hardware already exist
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testSh, err := c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "Create Server Hardware error -> %s", err)

		if testSh.URI.IsNil() {
			testSh = ov.ServerHardware{
				Hostname:           d.Tc.GetTestData(d.Env, "Hostname").(string),
				Username:           d.Tc.GetTestData(d.Env, "Username").(string),
				Password:           d.Tc.GetTestData(d.Env, "Password").(string),
				ConfigurationState: d.Tc.GetTestData(d.Env, "ConfigurationState").(string),
				LicensingIntent:    d.Tc.GetTestData(d.Env, "LicensingIntent").(string),
			}
			servHard, err := c.AddRackServer(testSh)
			assert.NoError(t, err, "Add server hardware error -> %s", err)

			err = c.AddRackServer(testSh)
			assert.Error(t, err, "AddRackServer should give error because hardware already exists, err-> %s", err)

		} else {
			log.Warnf("already exist, so skipping AddRackServer test for %s", testName)
		}

		// reload the test profile that we just created
		testSh, err = c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardware error -> %s", err)
	}

}

// TestAddMultipleRackServers verify adds multiple hardwares
func TestAddMultipleRackServers(t *testing.T) {

	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		// find out if the test server hardware already exist
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testSh = ov.ServerHardware{
			MpHostsAndRanges:   d.Tc.GetTestData(d.Env, "MpHostsAndRanges").(string),
			Username:           d.Tc.GetTestData(d.Env, "Username").(string),
			Password:           d.Tc.GetTestData(d.Env, "Password").(string),
			ConfigurationState: d.Tc.GetTestData(d.Env, "ConfigurationState").(string),
			LicensingIntent:    d.Tc.GetTestData(d.Env, "LicensingIntent").(string),
		}
		servHard, err := c.AddMultipleRackServers(testSh)
		assert.NoError(t, err, "Add server hardware error -> %s", err)

		err = c.AddMultipleRackServers(testSh)
		ssert.Error(t, err, "AddRackServer should give error because hardware already exists, err-> %s", err)

		// reload the test profile that we just created
		testSh, err = c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardware error -> %s", err)
	}

}
<commit_msg>Fix test<commit_after>package ov

import (
	"fmt"
	"os"
	"testing"

	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
	"github.com/stretchr/testify/assert"
)

// get server hardware test
func TestServerHardware(t *testing.T) {
	var (
		d           *OVTest
		c           *ov.OVClient
		testData    utils.Nstring
		expectsData string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testData = utils.Nstring(d.Tc.GetTestData(d.Env, "ServerHardwareURI").(string))
		expectsData = d.Tc.GetExpectsData(d.Env, "SerialNumber").(string)
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		data, err := c.GetServerHardwareByUri(testData)
		log.Debugf("%+v", data)
		assert.NoError(t, err, "GetServerHardwareByUri threw error -> %s", err)
		// fmt.Printf("data.Connections -> %+v\n", data)
		assert.Equal(t, expectsData, data.SerialNumber.String())

	}
}

func TestGetServerHardwareByName(t *testing.T) {
	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testServerHardware, err := c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardwareByName thew an error -> %s", err)
		assert.Equal(t, testName, testServerHardware.Name)

		testServerHardware, err = c.GetServerHardwareByName("bad")
		assert.NoError(t, err, "GetServerHardwareByName with fake name -> %s", err)
		assert.Equal(t, "", testServerHardware.Name)

	} else {
		d, c = getTestDriverU("test_server_hardware")
		testName = d.Tc.GetTestData(d.Env, "Name").(string)
		data, err := c.GetServerHardwareByName(testName)
		assert.Error(t, err, fmt.Sprintf("ALL ok, no error, caught as expected: %s,%+v\n", err, data))
	}
}

// get server hardware test
func TestGetAvailableHardware(t *testing.T) {
	var (
		d               *OVTest
		c               *ov.OVClient
		testHwType_URI  utils.Nstring
		testHWGroup_URI utils.Nstring
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testHwType_URI = utils.Nstring(d.Tc.GetTestData(d.Env, "HardwareTypeURI").(string))
		testHWGroup_URI = utils.Nstring(d.Tc.GetTestData(d.Env, "GroupURI").(string))
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		data, err := c.GetAvailableHardware(testHwType_URI, testHWGroup_URI)
		assert.NoError(t, err, "GetAvailableHardware threw error -> %s", err)
		// fmt.Printf("data.Connections -> %+v\n", data)
		log.Debugf("Abailable server -> %+v", data)
		log.Infof("Server Name -> %+v", data.Name)
		assert.NotEqual(t, "", data.Name)

	}
}

// TestGetIloIPAddress verify get ip address for hardware
func TestGetIloIPAddress(t *testing.T) {

	var (
		d           *OVTest
		c           *ov.OVClient
		testData    utils.Nstring
		expectsData string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("dev")
		testData = utils.Nstring(d.Tc.GetTestData(d.Env, "ServerHardwareURI").(string))
		expectsData = d.Tc.GetExpectsData(d.Env, "IloIPAddress").(string)
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		s, err := c.GetServerHardwareByUri(testData)
		assert.NoError(t, err, "GetServerHardwareByUri threw error -> %s", err)
		ip := s.GetIloIPAddress()
		log.Debugf("server -> %+v", s)
		log.Debugf("ip -> %+v", ip)
		assert.Equal(t, expectsData, ip)

	}

}

// TestAddRackServer verify adds hardware to the appliance
func TestAddRackServers(t *testing.T) {

	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		// find out if the test server hardware already exist
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testSh, err := c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "Create Server Hardware error -> %s", err)

		if testSh.URI.IsNil() {
			testSh = ov.ServerHardware{
				Hostname:           d.Tc.GetTestData(d.Env, "Hostname").(string),
				Username:           d.Tc.GetTestData(d.Env, "Username").(string),
				Password:           d.Tc.GetTestData(d.Env, "Password").(string),
				ConfigurationState: d.Tc.GetTestData(d.Env, "ConfigurationState").(string),
				LicensingIntent:    d.Tc.GetTestData(d.Env, "LicensingIntent").(string),
			}
			err := c.AddRackServer(testSh)
			assert.NoError(t, err, "Add server hardware error -> %s", err)

			err = c.AddRackServer(testSh)
			assert.Error(t, err, "AddRackServer should give error because hardware already exists, err-> %s", err)

		} else {
			log.Warnf("already exist, so skipping AddRackServer test for %s", testName)
		}

		// reload the test profile that we just created
		testSh, err = c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardware error -> %s", err)
	}

}

// TestAddMultipleRackServers verify adds multiple hardwares
func TestAddMultipleRackServers(t *testing.T) {

	var (
		d        *OVTest
		c        *ov.OVClient
		testName string
	)
	if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" {
		d, c = getTestDriverA("test_server_hardware")
		if c == nil {
			t.Fatalf("Failed to execute getTestDriver() ")
		}
		// find out if the test server hardware already exist
		testName = d.Tc.GetTestData(d.Env, "Name").(string)

		testSh := ov.ServerHardware{
			MpHostsAndRanges:   d.Tc.GetTestData(d.Env, "MpHostsAndRanges").String(),
			Username:           d.Tc.GetTestData(d.Env, "Username").(string),
			Password:           d.Tc.GetTestData(d.Env, "Password").(string),
			ConfigurationState: d.Tc.GetTestData(d.Env, "ConfigurationState").(string),
			LicensingIntent:    d.Tc.GetTestData(d.Env, "LicensingIntent").(string),
		}
		err := c.AddMultipleRackServers(testSh)
		assert.NoError(t, err, "Add server hardware error -> %s", err)

		err = c.AddMultipleRackServers(testSh)
		assert.Error(t, err, "AddRackServer should give error because hardware already exists, err-> %s", err)

		// reload the test profile that we just created
		testSh, err = c.GetServerHardwareByName(testName)
		assert.NoError(t, err, "GetServerHardware error -> %s", err)
	}

}
<|endoftext|>