<commit_before>package genddl

import (
	"go/ast"
	"go/token"
	"go/types"
	"io"
	"reflect"
	"strconv"
	"strings"

	"github.com/mackee/go-genddl/index"
)

type TableMap struct {
	Name          string
	Columns       []*ColumnMap
	ColumnIndexes []*IndexMap
	Indexes       []indexer
	Tables        map[*ast.StructType]string
}

func NewTableMap(name string, structType *ast.StructType, funcs []*ast.FuncDecl, tables map[*ast.StructType]string, ti *types.Info, innerIndexDef, uniqueWithName bool) *TableMap {
	tableMap := new(TableMap)
	tableMap.Name = name

	tableMap.Indexes = retrieveIndexesByFuncs(funcs, structType, innerIndexDef, uniqueWithName)
	tableMap.Tables = tables

	for _, field := range structType.Fields.List {
		tableMap.addColumnOrIndex(field, ti)
	}

	return tableMap
}

func retrieveIndexesByFuncs(funcs []*ast.FuncDecl, me *ast.StructType, innerIndexDef, uniqueWithName bool) []indexer {
	var f *ast.FuncDecl
	for _, funcDecl := range funcs {
		if funcDecl.Name.String() != indexFuncName {
			continue
		}
		res := funcDecl.Type.Results.List[0]
		ra, ok := res.Type.(*ast.ArrayType)
		if !ok {
			continue
		}
		if ra.Len != nil {
			continue
		}
		se, ok := ra.Elt.(*ast.SelectorExpr)
		if !ok {
			continue
		}
		if se.Sel.String() != indexReturnSliceType {
			continue
		}
		f = funcDecl
	}
	if f == nil {
		return nil
	}
	body := f.Body
	var rt *ast.ReturnStmt
	ast.Inspect(body, func(n ast.Node) bool {
		switch t := n.(type) {
		case *ast.ReturnStmt:
			rt = t
			return false
		default:
			return true
		}
	})

	sis := make([]indexer, 0)
	for _, lit := range rt.Results {
		cl, ok := lit.(*ast.CompositeLit)
		if !ok {
			continue
		}
	OUTER:
		for _, elt := range cl.Elts {
			var si indexIdent
			switch n := elt.(type) {
			case *ast.CallExpr:
				se, ok := n.Fun.(*ast.SelectorExpr)
				if !ok {
					break OUTER
				}
				methodName := se.Sel.Name
				switch methodName {
				case "PrimaryKey":
					si = indexIdent{
						Struct: me,
						Type:   indexPrimaryKey,
						Column: retrieveIndexColumnByExpr(n.Args),
					}
				case "Unique":
					si = indexIdent{
						Struct:         me,
						Type:           indexUnique,
						Column:         retrieveIndexColumnByExpr(n.Args),
						UniqueWithName: uniqueWithName,
					}
				case "Complex":
					si = indexIdent{
						Struct:            me,
						Type:              indexComplex,
						Column:            retrieveIndexColumnByExpr(n.Args),
						InnerComplexIndex: innerIndexDef,
					}
				case "ForeignKey":
					options := make([]index.ForeignKeyOption, 0)
					if len(n.Args) >= 2 {
						options = retrieveIndexForeignKeyOptionByExpr(n.Args[2:])
					}
					si = indexIdent{
						Struct:            me,
						Type:              indexForeign,
						Column:            retrieveIndexColumnByExpr([]ast.Expr{n.Args[0]}),
						References:        retrieveIndexColumnByExpr([]ast.Expr{n.Args[1]}),
						ForeignKeyOptions: options,
					}
				default:
					break OUTER
				}
				sis = append(sis, si)
			case *ast.BasicLit:
				if n.Kind != token.STRING {
					break OUTER
				}
				v := n.Value
				v, _ = strconv.Unquote(v)
				sis = append(sis, rawIndex(v))
			}
		}
	}
	return sis
}

func retrieveIndexColumnByExpr(exprs []ast.Expr) []indexColumn {
	sc := make([]indexColumn, 0)
OUTER:
	for _, expr := range exprs {
		switch e := expr.(type) {
		case *ast.SelectorExpr:
			var st *ast.StructType
			var structName string
			if ident, ok := e.X.(*ast.Ident); ok {
				if sf, ok := ident.Obj.Decl.(*ast.Field); ok {
					sident, ok := sf.Type.(*ast.Ident)
					if !ok {
						continue OUTER
					}
					structName = sident.Name
					st, ok = typeNameStructMap[structName]
					if !ok {
						continue OUTER
					}
				} else if as, ok := ident.Obj.Decl.(*ast.AssignStmt); ok {
					cl, ok := as.Rhs[0].(*ast.CompositeLit)
					if !ok {
						continue OUTER
					}
					cident, ok := cl.Type.(*ast.Ident)
					if !ok {
						continue OUTER
					}
					structName = cident.Name
					st, ok = typeNameStructMap[structName]
					if !ok {
						continue OUTER
					}
				} else {
					continue OUTER
				}
			} else if cl, ok := e.X.(*ast.CompositeLit); ok {
				cident, ok := cl.Type.(*ast.Ident)
				if !ok {
					continue OUTER
				}
				structName = cident.Name
				st, ok = typeNameStructMap[structName]
				if !ok {
					continue OUTER
				}
			} else {
				continue OUTER
			}

			fieldName := e.Sel.Name
			var selField *ast.Field
			for _, field := range st.Fields.List {
				if field.Names[0].Name == fieldName {
					selField = field
					break
				}
			}
			column := unresolvedIndexColumn{
				StructName: structName,
				Struct:     st,
				Field:      selField,
			}
			sc = append(sc, column)
		}
	}
	return sc
}

func retrieveIndexForeignKeyOptionByExpr(exprs []ast.Expr) []index.ForeignKeyOption {
	options := make([]index.ForeignKeyOption, 0, len(exprs))
	for _, expr := range exprs {
		se, ok := expr.(*ast.SelectorExpr)
		if !ok {
			continue
		}
		xident, ok := se.X.(*ast.Ident)
		if !ok {
			continue
		}
		if xident.Name != "index" {
			continue
		}
		for i := 0; i <= int(index.ForeignKeyOptionConstMax); i++ {
			if se.Sel.Name == index.ForeignKeyOption(i).String() {
				options = append(options, index.ForeignKeyOption(i))
				break
			}
		}
	}
	return options
}

func (tm *TableMap) WriteDDL(w io.Writer, dialect Dialect) error {
	tableName := dialect.QuoteField(strings.TrimSpace(tm.Name))

	_, err := io.WriteString(w, "DROP TABLE IF EXISTS "+tableName+";\n\n")
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, "CREATE TABLE "+tableName+" (\n")
	if err != nil {
		return err
	}

	innerIndexes := make([]indexer, 0, len(tm.Indexes))
	outerIndexes := make([]indexer, 0, len(tm.Indexes)/2)
	for _, index := range tm.Indexes {
		if index.IsOuterOfCreateTable() {
			outerIndexes = append(outerIndexes, index)
		} else {
			innerIndexes = append(innerIndexes, index)
		}
	}
	comma := ",\n"
	remainLines := len(tm.Columns) + len(innerIndexes)
	for _, cm := range tm.Columns {
		remainLines--
		if remainLines == 0 {
			comma = "\n"
		}

		columnName := dialect.QuoteField(cm.Name)
		columnType := dialect.ToSqlType(cm)

		_, err = io.WriteString(w, "    "+columnName+" "+columnType+comma)
		if err != nil {
			return err
		}
	}

	for _, sf := range innerIndexes {
		remainLines--
		if remainLines == 0 {
			comma = "\n"
		}
		str := sf.Index(dialect, tm.Tables)
		_, err := io.WriteString(w, str+comma)
		if err != nil {
			return err
		}
	}

	suffix := dialect.CreateTableSuffix()
	_, err = io.WriteString(w, ") "+suffix+";\n")
	if err != nil {
		return err
	}

	for _, sf := range outerIndexes {
		str := sf.Index(dialect, tm.Tables)
		_, err := io.WriteString(w, str+";\n")
		if err != nil {
			return err
		}
	}

	_, err = io.WriteString(w, "\n")
	if err != nil {
		return err
	}

	return nil
}

func (tm *TableMap) addColumnOrIndex(field *ast.Field, ti *types.Info) {
	if field.Tag == nil {
		return
	}
	tagMap := tm.parseTag(field.Tag.Value)

	tm.addColumn(field, tagMap, ti)
	tm.addIndex(field, tagMap)
}

type ColumnMap struct {
	Name     string
	TypeName string
	TagMap   map[string]string
}

var supportedTypes = map[string]struct{}{
	"time.Time":                               {},
	"database/sql.NullBool":                   {},
	"database/sql.NullInt16":                  {},
	"database/sql.NullInt32":                  {},
	"database/sql.NullInt64":                  {},
	"database/sql.NullFloat64":                {},
	"database/sql.NullString":                 {},
	"database/sql.NullByte":                   {},
	"database/sql.NullTime":                   {},
	"github.com/go-sql-driver/mysql.NullTime": {},
}

func (tm *TableMap) addColumn(field *ast.Field, tagMap map[string]string, ti *types.Info) {
	columnMap := new(ColumnMap)

	if name, ok := tagMap["db"]; ok {
		columnMap.Name = name
	} else {
		return
	}
	var typeName string
	t := ti.TypeOf(field.Type)
	for {
		if _, ok := supportedTypes[t.String()]; ok {
			nt := t.(*types.Named)
			typeName = strings.Join([]string{nt.Obj().Pkg().Name(), nt.Obj().Name()}, ".")
			break
		}
		if ta, ok := t.(*types.Named); ok {
			t = ta.Underlying()
			continue
		} else {
			typeName = t.String()
			break
		}
	}
	columnMap.TypeName = typeName

	columnMap.TagMap = tagMap

	tm.Columns = append(tm.Columns, columnMap)
}

type IndexMap struct {
	Name       string
	Columns    []string
	Unique     bool
	PrimaryKey bool
	TagMap     map[string]string
}

func (tm *TableMap) addIndex(field *ast.Field, tagMap map[string]string) {
	indexMap := new(IndexMap)

	if name, ok := tagMap["index"]; ok {
		indexMap.Name = name
	} else if name, ok := tagMap["unique"]; ok {
		indexMap.Name = name
		indexMap.Unique = true
	} else if name, ok := tagMap["primarykey"]; ok {
		indexMap.Name = name
		indexMap.PrimaryKey = true
	} else {
		return
	}

	indexMap.TagMap = tagMap

	tm.ColumnIndexes = append(tm.ColumnIndexes, indexMap)
}

func (tm *TableMap) parseTag(v string) map[string]string {
	st := reflect.StructTag(strings.Replace(v, "`", "", 2))
	dbTag := st.Get("db")
	tags := strings.Split(dbTag, ",")
	tagMap := map[string]string{}

	tagMap["db"] = tags[0]
	for _, tag := range tags[1:] {
		kv := strings.Split(tag, "=")
		key := strings.TrimSpace(kv[0])
		if len(kv) == 1 {
			tagMap[key] = ""
			continue
		}
		tagMap[key] = strings.TrimSpace(kv[1])
	}

	return tagMap
}
<commit_msg>fix: ignore field<commit_after>package genddl

import (
	"go/ast"
	"go/token"
	"go/types"
	"io"
	"reflect"
	"strconv"
	"strings"

	"github.com/mackee/go-genddl/index"
)

type TableMap struct {
	Name          string
	Columns       []*ColumnMap
	ColumnIndexes []*IndexMap
	Indexes       []indexer
	Tables        map[*ast.StructType]string
}

func NewTableMap(name string, structType *ast.StructType, funcs []*ast.FuncDecl, tables map[*ast.StructType]string, ti *types.Info, innerIndexDef, uniqueWithName bool) *TableMap {
	tableMap := new(TableMap)
	tableMap.Name = name

	tableMap.Indexes = retrieveIndexesByFuncs(funcs, structType, innerIndexDef, uniqueWithName)
	tableMap.Tables = tables

	for _, field := range structType.Fields.List {
		tableMap.addColumnOrIndex(field, ti)
	}

	return tableMap
}

func retrieveIndexesByFuncs(funcs []*ast.FuncDecl, me *ast.StructType, innerIndexDef, uniqueWithName bool) []indexer {
	var f *ast.FuncDecl
	for _, funcDecl := range funcs {
		if funcDecl.Name.String() != indexFuncName {
			continue
		}
		res := funcDecl.Type.Results.List[0]
		ra, ok := res.Type.(*ast.ArrayType)
		if !ok {
			continue
		}
		if ra.Len != nil {
			continue
		}
		se, ok := ra.Elt.(*ast.SelectorExpr)
		if !ok {
			continue
		}
		if se.Sel.String() != indexReturnSliceType {
			continue
		}
		f = funcDecl
	}
	if f == nil {
		return nil
	}
	body := f.Body
	var rt *ast.ReturnStmt
	ast.Inspect(body, func(n ast.Node) bool {
		switch t := n.(type) {
		case *ast.ReturnStmt:
			rt = t
			return false
		default:
			return true
		}
	})

	sis := make([]indexer, 0)
	for _, lit := range rt.Results {
		cl, ok := lit.(*ast.CompositeLit)
		if !ok {
			continue
		}
	OUTER:
		for _, elt := range cl.Elts {
			var si indexIdent
			switch n := elt.(type) {
			case *ast.CallExpr:
				se, ok := n.Fun.(*ast.SelectorExpr)
				if !ok {
					break OUTER
				}
				methodName := se.Sel.Name
				switch methodName {
				case "PrimaryKey":
					si = indexIdent{
						Struct: me,
						Type:   indexPrimaryKey,
						Column: retrieveIndexColumnByExpr(n.Args),
					}
				case "Unique":
					si = indexIdent{
						Struct:         me,
						Type:           indexUnique,
						Column:         retrieveIndexColumnByExpr(n.Args),
						UniqueWithName: uniqueWithName,
					}
				case "Complex":
					si = indexIdent{
						Struct:            me,
						Type:              indexComplex,
						Column:            retrieveIndexColumnByExpr(n.Args),
						InnerComplexIndex: innerIndexDef,
					}
				case "ForeignKey":
					options := make([]index.ForeignKeyOption, 0)
					if len(n.Args) >= 2 {
						options = retrieveIndexForeignKeyOptionByExpr(n.Args[2:])
					}
					si = indexIdent{
						Struct:            me,
						Type:              indexForeign,
						Column:            retrieveIndexColumnByExpr([]ast.Expr{n.Args[0]}),
						References:        retrieveIndexColumnByExpr([]ast.Expr{n.Args[1]}),
						ForeignKeyOptions: options,
					}
				default:
					break OUTER
				}
				sis = append(sis, si)
			case *ast.BasicLit:
				if n.Kind != token.STRING {
					break OUTER
				}
				v := n.Value
				v, _ = strconv.Unquote(v)
				sis = append(sis, rawIndex(v))
			}
		}
	}
	return sis
}

func retrieveIndexColumnByExpr(exprs []ast.Expr) []indexColumn {
	sc := make([]indexColumn, 0)
OUTER:
	for _, expr := range exprs {
		switch e := expr.(type) {
		case *ast.SelectorExpr:
			var st *ast.StructType
			var structName string
			if ident, ok := e.X.(*ast.Ident); ok {
				if sf, ok := ident.Obj.Decl.(*ast.Field); ok {
					sident, ok := sf.Type.(*ast.Ident)
					if !ok {
						continue OUTER
					}
					structName = sident.Name
					st, ok = typeNameStructMap[structName]
					if !ok {
						continue OUTER
					}
				} else if as, ok := ident.Obj.Decl.(*ast.AssignStmt); ok {
					cl, ok := as.Rhs[0].(*ast.CompositeLit)
					if !ok {
						continue OUTER
					}
					cident, ok := cl.Type.(*ast.Ident)
					if !ok {
						continue OUTER
					}
					structName = cident.Name
					st, ok = typeNameStructMap[structName]
					if !ok {
						continue OUTER
					}
				} else {
					continue OUTER
				}
			} else if cl, ok := e.X.(*ast.CompositeLit); ok {
				cident, ok := cl.Type.(*ast.Ident)
				if !ok {
					continue OUTER
				}
				structName = cident.Name
				st, ok = typeNameStructMap[structName]
				if !ok {
					continue OUTER
				}
			} else {
				continue OUTER
			}

			fieldName := e.Sel.Name
			var selField *ast.Field
			for _, field := range st.Fields.List {
				if field.Names[0].Name == fieldName {
					selField = field
					break
				}
			}
			column := unresolvedIndexColumn{
				StructName: structName,
				Struct:     st,
				Field:      selField,
			}
			sc = append(sc, column)
		}
	}
	return sc
}

func retrieveIndexForeignKeyOptionByExpr(exprs []ast.Expr) []index.ForeignKeyOption {
	options := make([]index.ForeignKeyOption, 0, len(exprs))
	for _, expr := range exprs {
		se, ok := expr.(*ast.SelectorExpr)
		if !ok {
			continue
		}
		xident, ok := se.X.(*ast.Ident)
		if !ok {
			continue
		}
		if xident.Name != "index" {
			continue
		}
		for i := 0; i <= int(index.ForeignKeyOptionConstMax); i++ {
			if se.Sel.Name == index.ForeignKeyOption(i).String() {
				options = append(options, index.ForeignKeyOption(i))
				break
			}
		}
	}
	return options
}

func (tm *TableMap) WriteDDL(w io.Writer, dialect Dialect) error {
	tableName := dialect.QuoteField(strings.TrimSpace(tm.Name))

	_, err := io.WriteString(w, "DROP TABLE IF EXISTS "+tableName+";\n\n")
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, "CREATE TABLE "+tableName+" (\n")
	if err != nil {
		return err
	}

	innerIndexes := make([]indexer, 0, len(tm.Indexes))
	outerIndexes := make([]indexer, 0, len(tm.Indexes)/2)
	for _, index := range tm.Indexes {
		if index.IsOuterOfCreateTable() {
			outerIndexes = append(outerIndexes, index)
		} else {
			innerIndexes = append(innerIndexes, index)
		}
	}
	comma := ",\n"
	remainLines := len(tm.Columns) + len(innerIndexes)
	for _, cm := range tm.Columns {
		remainLines--
		if remainLines == 0 {
			comma = "\n"
		}

		columnName := dialect.QuoteField(cm.Name)
		columnType := dialect.ToSqlType(cm)

		_, err = io.WriteString(w, "    "+columnName+" "+columnType+comma)
		if err != nil {
			return err
		}
	}

	for _, sf := range innerIndexes {
		remainLines--
		if remainLines == 0 {
			comma = "\n"
		}
		str := sf.Index(dialect, tm.Tables)
		_, err := io.WriteString(w, str+comma)
		if err != nil {
			return err
		}
	}

	suffix := dialect.CreateTableSuffix()
	_, err = io.WriteString(w, ") "+suffix+";\n")
	if err != nil {
		return err
	}

	for _, sf := range outerIndexes {
		str := sf.Index(dialect, tm.Tables)
		_, err := io.WriteString(w, str+";\n")
		if err != nil {
			return err
		}
	}

	_, err = io.WriteString(w, "\n")
	if err != nil {
		return err
	}

	return nil
}

func (tm *TableMap) addColumnOrIndex(field *ast.Field, ti *types.Info) {
	if field.Tag == nil {
		return
	}
	tagMap := tm.parseTag(field.Tag.Value)

	tm.addColumn(field, tagMap, ti)
	tm.addIndex(field, tagMap)
}

type ColumnMap struct {
	Name     string
	TypeName string
	TagMap   map[string]string
}

var supportedTypes = map[string]struct{}{
	"time.Time":                               {},
	"database/sql.NullBool":                   {},
	"database/sql.NullInt16":                  {},
	"database/sql.NullInt32":                  {},
	"database/sql.NullInt64":                  {},
	"database/sql.NullFloat64":                {},
	"database/sql.NullString":                 {},
	"database/sql.NullByte":                   {},
	"database/sql.NullTime":                   {},
	"github.com/go-sql-driver/mysql.NullTime": {},
}

func (tm *TableMap) addColumn(field *ast.Field, tagMap map[string]string, ti *types.Info) {
	columnMap := new(ColumnMap)

	if name := tagMap["db"]; name != "" && name != "-" {
		columnMap.Name = name
	} else {
		return
	}
	var typeName string
	t := ti.TypeOf(field.Type)
	for {
		if _, ok := supportedTypes[t.String()]; ok {
			nt := t.(*types.Named)
			typeName = strings.Join([]string{nt.Obj().Pkg().Name(), nt.Obj().Name()}, ".")
			break
		}
		if ta, ok := t.(*types.Named); ok {
			t = ta.Underlying()
			continue
		} else {
			typeName = t.String()
			break
		}
	}
	columnMap.TypeName = typeName

	columnMap.TagMap = tagMap

	tm.Columns = append(tm.Columns, columnMap)
}

type IndexMap struct {
	Name       string
	Columns    []string
	Unique     bool
	PrimaryKey bool
	TagMap     map[string]string
}

func (tm *TableMap) addIndex(field *ast.Field, tagMap map[string]string) {
	indexMap := new(IndexMap)

	if name, ok := tagMap["index"]; ok {
		indexMap.Name = name
	} else if name, ok := tagMap["unique"]; ok {
		indexMap.Name = name
		indexMap.Unique = true
	} else if name, ok := tagMap["primarykey"]; ok {
		indexMap.Name = name
		indexMap.PrimaryKey = true
	} else {
		return
	}

	indexMap.TagMap = tagMap

	tm.ColumnIndexes = append(tm.ColumnIndexes, indexMap)
}

func (tm *TableMap) parseTag(v string) map[string]string {
	st := reflect.StructTag(strings.Replace(v, "`", "", 2))
	dbTag := st.Get("db")
	tags := strings.Split(dbTag, ",")
	tagMap := map[string]string{}

	tagMap["db"] = tags[0]
	for _, tag := range tags[1:] {
		kv := strings.Split(tag, "=")
		key := strings.TrimSpace(kv[0])
		if len(kv) == 1 {
			tagMap[key] = ""
			continue
		}
		tagMap[key] = strings.TrimSpace(kv[1])
	}

	return tagMap
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) SAS Institute, Inc.
 *
 * 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 rpmutils

const (
	_GENERAL_TAG_BASE = 1000
	NAME              = 1000
	VERSION           = 1001
	RELEASE           = 1002
	EPOCH             = 1003
	SUMMARY           = 1004
	DESCRIPTION       = 1005
	VENDOR            = 1011
	LICENSE           = 1014
	SOURCE            = 1018
	ARCH              = 1022
	PREIN             = 1023
	POSTIN            = 1024
	PREUN             = 1025
	POSTUN            = 1026
	OLDFILENAMES      = 1027
	FILESIZES         = 1028
	FILEMODES         = 1030
	FILERDEVS         = 1033
	FILEMTIMES        = 1034
	FILEDIGESTS       = 1035 // AKA FILEMD5S
	FILELINKTOS       = 1036
	FILEFLAGS         = 1037 // bitmask: RPMFILE_* are bitmasks to interpret
	FILEUSERNAME      = 1039
	FILEGROUPNAME     = 1040
	SOURCERPM         = 1044
	FILEVERIFYFLAGS   = 1045 // bitmask: RPMVERIFY_* are bitmasks to interpret
	PROVIDENAME       = 1047
	REQUIRENAME       = 1049
	REQUIREVERSION    = 1050
	RPMVERSION        = 1064
	TRIGGERSCRIPTS    = 1065
	TRIGGERNAME       = 1066
	TRIGGERVERSION    = 1067
	TRIGGERFLAGS      = 1068 // bitmask: RPMSENSE_* are bitmasks to interpret
	TRIGGERINDEX      = 1069
	VERIFYSCRIPT      = 1079
	PREINPROG         = 1085
	POSTINPROG        = 1086
	PREUNPROG         = 1087
	POSTUNPROG        = 1088
	OBSOLETENAME      = 1090
	PROVIDEVERSION    = 1113
	OBSOLETEFLAGS     = 1114
	OBSOLETEVERSION   = 1115
	VERIFYSCRIPTPROG  = 1091
	TRIGGERSCRIPTPROG = 1092
	DIRINDEXES        = 1116
	BASENAMES         = 1117
	DIRNAMES          = 1118
	PAYLOADFORMAT     = 1124
	PAYLOADCOMPRESSOR = 1125
	FILECOLORS        = 1140
	// BLINK*, FLINK*, and TRIGGERPREIN included from SUSE fork of RPM
	BLINKPKGID   = 1164
	BLINKHDRID   = 1165
	BLINKNEVRA   = 1166
	FLINKPKGID   = 1167
	FLINKHDRID   = 1168
	FLINKNEVRA   = 1169
	TRIGGERPREIN = 1170

	SIG_BASE = 256
	SIG_SHA1 = 269

	// Given that there is overlap between signature tag headers and general tag
	// headers, we offset the signature ones by some amount
	_SIGHEADER_TAG_BASE = 16384
	SIG_SIZE            = _SIGHEADER_TAG_BASE + 1000 // Header + Payload size
	SIG_MD5             = _SIGHEADER_TAG_BASE + 1004 // MD5SUM of header + payload
	SIG_GPG             = _SIGHEADER_TAG_BASE + 1005

	// FILEFLAGS bitmask elements:
	RPMFILE_NONE      = 0
	RPMFILE_CONFIG    = 1 << 0
	RPMFILE_DOC       = 1 << 1
	RPMFILE_ICON      = 1 << 2
	RPMFILE_MISSINGOK = 1 << 3
	RPMFILE_NOREPLACE = 1 << 4
	RPMFILE_SPECFILE  = 1 << 5
	RPMFILE_GHOST     = 1 << 6
	RPMFILE_LICENSE   = 1 << 7
	RPMFILE_README    = 1 << 8
	RPMFILE_EXCLUDE   = 1 << 9
	RPMFILE_UNPATCHED = 1 << 10
	RPMFILE_PUBKEY    = 1 << 11
	RPMFILE_POLICY    = 1 << 12

	// FILEVERIFYFLAGS bitmask elements:
	RPMVERIFY_NONE       = 0
	RPMVERIFY_MD5        = 1 << 0
	RPMVERIFY_FILEDIGEST = 1 << 0
	RPMVERIFY_FILESIZE   = 1 << 1
	RPMVERIFY_LINKTO     = 1 << 2
	RPMVERIFY_USER       = 1 << 3
	RPMVERIFY_GROUP      = 1 << 4
	RPMVERIFY_MTIME      = 1 << 5
	RPMVERIFY_MODE       = 1 << 6
	RPMVERIFY_RDEV       = 1 << 7
	RPMVERIFY_CAPS       = 1 << 8
	RPMVERIFY_CONTEXTS   = 1 << 15

	// TRIGGERFLAGS bitmask elements -- not all rpmsenseFlags make sense
	// in TRIGGERFLAGS
	RPMSENSE_ANY           = 0
	RPMSENSE_LESS          = 1 << 1
	RPMSENSE_GREATER       = 1 << 2
	RPMSENSE_EQUAL         = 1 << 3
	RPMSENSE_TRIGGERIN     = 1 << 16
	RPMSENSE_TRIGGERUN     = 1 << 17
	RPMSENSE_TRIGGERPOSTUN = 1 << 18
	RPMSENSE_TRIGGERPREIN  = 1 << 25
)
<commit_msg>add requires and provides flags tags<commit_after>/*
 * Copyright (c) SAS Institute, Inc.
 *
 * 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 rpmutils

const (
	_GENERAL_TAG_BASE = 1000
	NAME              = 1000
	VERSION           = 1001
	RELEASE           = 1002
	EPOCH             = 1003
	SUMMARY           = 1004
	DESCRIPTION       = 1005
	VENDOR            = 1011
	LICENSE           = 1014
	SOURCE            = 1018
	ARCH              = 1022
	PREIN             = 1023
	POSTIN            = 1024
	PREUN             = 1025
	POSTUN            = 1026
	OLDFILENAMES      = 1027
	FILESIZES         = 1028
	FILEMODES         = 1030
	FILERDEVS         = 1033
	FILEMTIMES        = 1034
	FILEDIGESTS       = 1035 // AKA FILEMD5S
	FILELINKTOS       = 1036
	FILEFLAGS         = 1037 // bitmask: RPMFILE_* are bitmasks to interpret
	FILEUSERNAME      = 1039
	FILEGROUPNAME     = 1040
	SOURCERPM         = 1044
	FILEVERIFYFLAGS   = 1045 // bitmask: RPMVERIFY_* are bitmasks to interpret
	PROVIDENAME       = 1047
	REQUIREFLAGS      = 1048
	REQUIRENAME       = 1049
	REQUIREVERSION    = 1050
	RPMVERSION        = 1064
	TRIGGERSCRIPTS    = 1065
	TRIGGERNAME       = 1066
	TRIGGERVERSION    = 1067
	TRIGGERFLAGS      = 1068 // bitmask: RPMSENSE_* are bitmasks to interpret
	TRIGGERINDEX      = 1069
	VERIFYSCRIPT      = 1079
	PREINPROG         = 1085
	POSTINPROG        = 1086
	PREUNPROG         = 1087
	POSTUNPROG        = 1088
	OBSOLETENAME      = 1090
	PROVIDEFLAGS      = 1112
	PROVIDEVERSION    = 1113
	OBSOLETEFLAGS     = 1114
	OBSOLETEVERSION   = 1115
	VERIFYSCRIPTPROG  = 1091
	TRIGGERSCRIPTPROG = 1092
	DIRINDEXES        = 1116
	BASENAMES         = 1117
	DIRNAMES          = 1118
	PAYLOADFORMAT     = 1124
	PAYLOADCOMPRESSOR = 1125
	FILECOLORS        = 1140
	// BLINK*, FLINK*, and TRIGGERPREIN included from SUSE fork of RPM
	BLINKPKGID   = 1164
	BLINKHDRID   = 1165
	BLINKNEVRA   = 1166
	FLINKPKGID   = 1167
	FLINKHDRID   = 1168
	FLINKNEVRA   = 1169
	TRIGGERPREIN = 1170

	SIG_BASE = 256
	SIG_SHA1 = 269

	// Given that there is overlap between signature tag headers and general tag
	// headers, we offset the signature ones by some amount
	_SIGHEADER_TAG_BASE = 16384
	SIG_SIZE            = _SIGHEADER_TAG_BASE + 1000 // Header + Payload size
	SIG_MD5             = _SIGHEADER_TAG_BASE + 1004 // MD5SUM of header + payload
	SIG_GPG             = _SIGHEADER_TAG_BASE + 1005

	// FILEFLAGS bitmask elements:
	RPMFILE_NONE      = 0
	RPMFILE_CONFIG    = 1 << 0
	RPMFILE_DOC       = 1 << 1
	RPMFILE_ICON      = 1 << 2
	RPMFILE_MISSINGOK = 1 << 3
	RPMFILE_NOREPLACE = 1 << 4
	RPMFILE_SPECFILE  = 1 << 5
	RPMFILE_GHOST     = 1 << 6
	RPMFILE_LICENSE   = 1 << 7
	RPMFILE_README    = 1 << 8
	RPMFILE_EXCLUDE   = 1 << 9
	RPMFILE_UNPATCHED = 1 << 10
	RPMFILE_PUBKEY    = 1 << 11
	RPMFILE_POLICY    = 1 << 12

	// FILEVERIFYFLAGS bitmask elements:
	RPMVERIFY_NONE       = 0
	RPMVERIFY_MD5        = 1 << 0
	RPMVERIFY_FILEDIGEST = 1 << 0
	RPMVERIFY_FILESIZE   = 1 << 1
	RPMVERIFY_LINKTO     = 1 << 2
	RPMVERIFY_USER       = 1 << 3
	RPMVERIFY_GROUP      = 1 << 4
	RPMVERIFY_MTIME      = 1 << 5
	RPMVERIFY_MODE       = 1 << 6
	RPMVERIFY_RDEV       = 1 << 7
	RPMVERIFY_CAPS       = 1 << 8
	RPMVERIFY_CONTEXTS   = 1 << 15

	// TRIGGERFLAGS bitmask elements -- not all rpmsenseFlags make sense
	// in TRIGGERFLAGS
	RPMSENSE_ANY           = 0
	RPMSENSE_LESS          = 1 << 1
	RPMSENSE_GREATER       = 1 << 2
	RPMSENSE_EQUAL         = 1 << 3
	RPMSENSE_TRIGGERIN     = 1 << 16
	RPMSENSE_TRIGGERUN     = 1 << 17
	RPMSENSE_TRIGGERPOSTUN = 1 << 18
	RPMSENSE_TRIGGERPREIN  = 1 << 25
)
<|endoftext|>


<commit_before>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tags helper functions

package circonusgometrics

import (
	"encoding/base64"
	"fmt"
	"sort"
	"strings"
	"unicode"
)

// Tag defines an individual tag
type Tag struct {
	Category string
	Value    string
}

// Tags defines a list of tags
type Tags []Tag

// SetMetricTags sets the tags for the named metric and flags a check update is needed
func (m *CirconusMetrics) SetMetricTags(name string, tags []string) bool {
	return m.check.AddMetricTags(name, tags, false)
}

// AddMetricTags appends tags to any existing tags for the named metric and flags a check update is needed
func (m *CirconusMetrics) AddMetricTags(name string, tags []string) bool {
	return m.check.AddMetricTags(name, tags, true)
}

// MetricNameWithStreamTags will encode supplied stream tags into supplied metric name, if metric name *does not* already have stream tags
func MetricNameWithStreamTags(metric string, tags Tags) string {
	if len(tags) == 0 {
		return metric
	}

	if strings.Contains(metric, "|ST[") {
		return metric
	}

	taglist := EncodeMetricStreamTags(tags)
	if taglist != "" {
		return metric + "|ST[" + taglist + "]"
	}

	return metric
}

// EncodeMetricStreamTags encodes Tags into a string suitable for use with
// stream tags. Tags directly embedded into metric names using the
// `metric_name|ST[<tags>]` syntax.
func EncodeMetricStreamTags(tags Tags) string {
	if len(tags) == 0 {
		return ""
	}

	tmpTags := EncodeMetricTags(tags)
	if len(tmpTags) == 0 {
		return ""
	}

	tagList := make([]string, len(tmpTags))
	for i, tag := range tmpTags {
		tagParts := strings.Split(tag, ":")
		if len(tagParts) != 2 {
			continue // invalid tag, skip it
		}
		tagList[i] = fmt.Sprintf(
			`b"%s":b"%s"`,
			base64.StdEncoding.EncodeToString([]byte(tagParts[0])),
			base64.StdEncoding.EncodeToString([]byte(tagParts[1])))
	}

	return strings.Join(tagList, ",")
}

// EncodeMetricTags encodes Tags into an array of strings. The format
// check_bundle.metircs.metric.tags needs. This helper is intended to work
// with legacy check bundle metrics. Tags directly on named metrics are being
// deprecated in favor of stream tags.
func EncodeMetricTags(tags Tags) []string {
	if len(tags) == 0 {
		return []string{}
	}

	uniqueTags := make(map[string]bool)
	for _, t := range tags {
		tc := strings.Map(removeSpaces, strings.ToLower(t.Category))
		tv := strings.Map(removeSpaces, strings.ToLower(t.Value))
		if tc == "" || tv == "" {
			continue // invalid tag, skip it
		}
		tag := tc + ":" + tv
		uniqueTags[tag] = true
	}
	tagList := make([]string, len(uniqueTags))
	idx := 0
	for t := range uniqueTags {
		tagList[idx] = t
		idx++
	}
	sort.Strings(tagList)
	return tagList
}

func removeSpaces(r rune) rune {
	if unicode.IsSpace(r) {
		return -1
	}
	return r
}
<commit_msg>doc: clarify helper funcction comments<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tags helper functions

package circonusgometrics

import (
	"encoding/base64"
	"fmt"
	"sort"
	"strings"
	"unicode"
)

// Tag defines an individual tag
type Tag struct {
	Category string
	Value    string
}

// Tags defines a list of tags
type Tags []Tag

// SetMetricTags sets the tags for the named metric and flags a check update is needed
// Note: does not work with checks using metric_filters (the default) use metric
// `*WithTags` helper methods or manual manage stream tags in metric names.
func (m *CirconusMetrics) SetMetricTags(name string, tags []string) bool {
	return m.check.AddMetricTags(name, tags, false)
}

// AddMetricTags appends tags to any existing tags for the named metric and flags a check update is needed
// Note: does not work with checks using metric_filters (the default) use metric
// `*WithTags` helper methods or manual manage stream tags in metric names.
func (m *CirconusMetrics) AddMetricTags(name string, tags []string) bool {
	return m.check.AddMetricTags(name, tags, true)
}

// MetricNameWithStreamTags will encode tags as stream tags into supplied metric name.
// Note: if metric name already has stream tags it is assumed the metric name and
// embedded stream tags are being managed manually and calling this method will nave no effect.
func MetricNameWithStreamTags(metric string, tags Tags) string {
	if len(tags) == 0 {
		return metric
	}

	if strings.Contains(metric, "|ST[") {
		return metric
	}

	taglist := EncodeMetricStreamTags(tags)
	if taglist != "" {
		return metric + "|ST[" + taglist + "]"
	}

	return metric
}

// EncodeMetricStreamTags encodes Tags into a string suitable for use with
// stream tags. Tags directly embedded into metric names using the
// `metric_name|ST[<tags>]` syntax.
func EncodeMetricStreamTags(tags Tags) string {
	if len(tags) == 0 {
		return ""
	}

	tmpTags := EncodeMetricTags(tags)
	if len(tmpTags) == 0 {
		return ""
	}

	tagList := make([]string, len(tmpTags))
	for i, tag := range tmpTags {
		tagParts := strings.Split(tag, ":")
		if len(tagParts) != 2 {
			continue // invalid tag, skip it
		}
		tagList[i] = fmt.Sprintf(
			`b"%s":b"%s"`,
			base64.StdEncoding.EncodeToString([]byte(tagParts[0])),
			base64.StdEncoding.EncodeToString([]byte(tagParts[1])))
	}

	return strings.Join(tagList, ",")
}

// EncodeMetricTags encodes Tags into an array of strings. The format
// check_bundle.metircs.metric.tags needs. This helper is intended to work
// with legacy check bundle metrics. Tags directly on named metrics are being
// deprecated in favor of stream tags.
func EncodeMetricTags(tags Tags) []string {
	if len(tags) == 0 {
		return []string{}
	}

	uniqueTags := make(map[string]bool)
	for _, t := range tags {
		tc := strings.Map(removeSpaces, strings.ToLower(t.Category))
		tv := strings.Map(removeSpaces, strings.ToLower(t.Value))
		if tc == "" || tv == "" {
			continue // invalid tag, skip it
		}
		tag := tc + ":" + tv
		uniqueTags[tag] = true
	}
	tagList := make([]string, len(uniqueTags))
	idx := 0
	for t := range uniqueTags {
		tagList[idx] = t
		idx++
	}
	sort.Strings(tagList)
	return tagList
}

func removeSpaces(r rune) rune {
	if unicode.IsSpace(r) {
		return -1
	}
	return r
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"xmpp"
)

var (
	addr       = ""
	skipverify = false
	jid        = ""
	pass       = ""
)

func init() {
	flag.StringVar(&addr, "addr", "", "XMPP server address, <host>:<port>. Optional")
	flag.BoolVar(&skipverify, "skipverify", false, "Skip TLS certificate verification.")
	flag.StringVar(&jid, "jid", "", "User's JID, e.g. alice@wonderland.lit/chat.")
	flag.StringVar(&pass, "pass", "", "User's password.")
}

func main() {

	// Parse args
	flag.Parse()
	jid, _ := xmpp.ParseJID(jid)

	// Lookup home server TCP addr if not explicitly set.
	if addr == "" {
		if addrs, err := xmpp.HomeServerAddrs(jid); err != nil {
			log.Fatal(err)
		} else {
			addr = addrs[0]
		}
	}

	// Create stream.
	stream, err := xmpp.NewStream(addr)
	if err != nil {
		log.Fatal(err)
	}

	// Configure stream as client.
	config := xmpp.ClientConfig{InsecureSkipVerify: skipverify}
	x, err := xmpp.NewClientXMPP(stream, jid, pass, &config)
	if err != nil {
		log.Fatal(err)
	}

	// Signal presence.
	x.Send(xmpp.Presence{})

	// Log anything that arrives.
	for {
		stanza, err := x.Recv()
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("recv: %T %v", stanza, stanza)
	}
}
<commit_msg>Oops, fix tail.go for new Stream config.<commit_after>package main

import (
	"flag"
	"log"
	"xmpp"
)

var (
	addr       = ""
	skipverify = false
	jid        = ""
	pass       = ""
)

func init() {
	flag.StringVar(&addr, "addr", "", "XMPP server address, <host>:<port>. Optional")
	flag.BoolVar(&skipverify, "skipverify", false, "Skip TLS certificate verification.")
	flag.StringVar(&jid, "jid", "", "User's JID, e.g. alice@wonderland.lit/chat.")
	flag.StringVar(&pass, "pass", "", "User's password.")
}

func main() {

	// Parse args
	flag.Parse()
	jid, _ := xmpp.ParseJID(jid)

	// Lookup home server TCP addr if not explicitly set.
	if addr == "" {
		if addrs, err := xmpp.HomeServerAddrs(jid); err != nil {
			log.Fatal(err)
		} else {
			addr = addrs[0]
		}
	}

	// Create stream.
	stream, err := xmpp.NewStream(addr, nil)
	if err != nil {
		log.Fatal(err)
	}

	// Configure stream as client.
	config := xmpp.ClientConfig{InsecureSkipVerify: skipverify}
	x, err := xmpp.NewClientXMPP(stream, jid, pass, &config)
	if err != nil {
		log.Fatal(err)
	}

	// Signal presence.
	x.Send(xmpp.Presence{})

	// Log anything that arrives.
	for {
		stanza, err := x.Recv()
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("recv: %T %v", stanza, stanza)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

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

var (
	dockerClient *docker.Client
	initError    error
)

func init() {
	dockerClient, initError = docker.NewClientFromEnv()
}

type TaskFactory struct {
	configs map[string]TaskConfig
}

type Task struct {
	context TestContext
	client  *docker.Client
	Name    string
	config  TaskConfig
}

func NewTaskFactory(configs []TaskConfig) (*TaskFactory, error) {
	if initError != nil {
		return nil, fmt.Errorf("Could not initialize docker client! %s", initError)
	}

	configMap := map[string]TaskConfig{}
	for _, cfg := range configs {
		configMap[cfg.Name] = cfg
	}
	return &TaskFactory{
		configs: configMap,
	}, nil
}

func (t *TaskFactory) Task(context TestContext, taskName string) Task {
	config := t.configs[taskName]
	return Task{
		config:  config,
		context: context,
		client:  dockerClient,
		Name:    config.Name,
	}
}

type ReportWriter struct {
	reporter TaskReporter
	taskName string
}

func (r ReportWriter) Write(p []byte) (int, error) {
	r.reporter.TaskOutput(r.taskName, string(p))
	return len(p), nil
}

func (t Task) Execute(reporter TaskReporter) (int, error) {
	createOptions := docker.CreateContainerOptions{
		Name: t.containerName(),
		Config: &docker.Config{
			Image:      t.config.Image,
			Cmd:        append([]string{t.config.Run.Path}, t.config.Run.Args...),
			WorkingDir: "/delmo",
		},
	}
	container, err := t.client.CreateContainer(createOptions)
	if err != nil {
		if strings.Contains(err.Error(), "container already exists") {
			t.Cleanup()
			container, err = t.client.CreateContainer(createOptions)
			if err != nil {
				return 1, fmt.Errorf("Failed to re-create container %s; aborting", createOptions.Name)
			}
		} else {
			return 1, fmt.Errorf("Failed to create container from image %s: %s", t.config.Image, err)
		}
	}

	hostConfig := &docker.HostConfig{
		Binds: []string{fmt.Sprintf("%s:%s", t.context.DockerHostSyncDir, "/delmo")},
	}
	err = t.client.StartContainer(container.ID, hostConfig)
	if err != nil {
		return 1, err
	}

	returnValue, err := t.client.WaitContainer(container.ID)
	if err != nil {
		return 1, err
	}

	stream := ReportWriter{
		taskName: t.config.Name,
		reporter: reporter,
	}

	logOptions := docker.LogsOptions{
		Container:    container.ID,
		OutputStream: stream,
		ErrorStream:  stream,
		Stdout:       true,
		Stderr:       true,
	}
	err = t.client.Logs(logOptions)
	if err != nil {
		return 1, err
	}

	removeOptions := docker.RemoveContainerOptions{
		ID:            container.ID,
		RemoveVolumes: true,
		Force:         true,
	}
	t.client.RemoveContainer(removeOptions)

	return returnValue, nil
}

func (t *Task) Cleanup() error {
	containers, err := t.client.ListContainers(docker.ListContainersOptions{
		All: true,
		Filters: map[string][]string{
			"name": []string{t.containerName()},
		},
	})
	if err != nil {
		return fmt.Errorf("Failed to query list of containers: %s", err)
	}

	if len(containers) == 0 {
		return nil
	}

	for _, container := range containers {
		err = t.client.RemoveContainer(docker.RemoveContainerOptions{
			ID:    container.ID,
			Force: true,
		})
		if err != nil {
			return fmt.Errorf("Failed to purge container %s: %s", container.ID, err)
		}
	}
	return nil
}

func (t *Task) containerName() string {
	return fmt.Sprintf("%s__%s", t.context.TestName, t.config.Name)
}
<commit_msg>Remove task<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/depili/go-rgb-led-matrix/bdf"
	"github.com/depili/go-rgb-led-matrix/matrix"
	"time"
)

func main() {
	font, err := bdf.Parse("fonts/7x13B.bdf")
	if err != nil {
		panic(err)
	}
	fmt.Printf("Font loaded: %d chars\n", font.Chars)
	glyph := font.GetGlyph(rune(65))
	fmt.Printf("A: height: %d len: %d\n", glyph.Height, len(glyph.Bitmap))
	for _, row := range glyph.Bitmap {
		for _, b := range row {
			if b {
				fmt.Printf("X")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Printf("\n")
	}

	text := "Testi ÄÖ"
	bitmap := font.TextBitmap(text)
	for _, row := range bitmap {
		for _, b := range row {
			if b {
				fmt.Printf("X")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Printf("\n")
	}

	m := matrix.Init("tcp://192.168.0.30:5555", 32, 128)
	var color [3]byte
	color[0] = 0
	color[1] = 255
	color[2] = 0
	m.Fill(color)
	m.Send()
	time.Sleep(500 * time.Millisecond)
	color[0] = 255
	color[2] = 255
	m.Fill(matrix.ColorWhite())
	m.Send()
	time.Sleep(500 * time.Millisecond)

	m.InitFlame()
	for i := 0; i < 1000; i++ {
		m.FlameFill()
		m.Send()
		time.Sleep(10 * time.Millisecond)
	}

	m.Close()
}
<commit_msg>Test scrolling text<commit_after>package main

import (
	"fmt"
	"github.com/depili/go-rgb-led-matrix/bdf"
	"github.com/depili/go-rgb-led-matrix/matrix"
	"time"
)

func main() {
	font, err := bdf.Parse("fonts/7x13B.bdf")
	if err != nil {
		panic(err)
	}
	fmt.Printf("Font loaded: %d chars\n", font.Chars)
	glyph := font.GetGlyph(rune(65))
	fmt.Printf("A: height: %d len: %d\n", glyph.Height, len(glyph.Bitmap))
	for _, row := range glyph.Bitmap {
		for _, b := range row {
			if b {
				fmt.Printf("X")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Printf("\n")
	}

	text := "Testi ÄÖ"
	bitmap := font.TextBitmap(text)
	for _, row := range bitmap {
		for _, b := range row {
			if b {
				fmt.Printf("X")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Printf("\n")
	}

	m := matrix.Init("tcp://192.168.0.30:5555", 32, 128)
	defer m.Close()
	var color [3]byte
	color[0] = 0
	color[1] = 255
	color[2] = 0
	m.Fill(color)
	m.Send()
	time.Sleep(500 * time.Millisecond)
	color[0] = 255
	color[2] = 255
	m.Fill(matrix.ColorWhite())
	m.Send()
	time.Sleep(500 * time.Millisecond)

	scroll := "Jotain tässä scrollaa   "
	bitmap = font.TextBitmap(scroll)
	for i := 0; i < 1000; i++ {
		m.Fill(matrix.ColorBlack())
		m.Scroll(bitmap, matrix.ColorWhite(), 5, 15, i, 80)
		m.Send()
		time.Sleep(10 * time.Millisecond)
	}

	m.InitFlame()
	for i := 0; i < 1000; i++ {
		m.FlameFill()
		m.Send()
		time.Sleep(10 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package test

import (
	"bytes"
	"errors"
	"fmt"
	"math"
	"reflect"
	"runtime"
	"strings"
	"testing"
)

// ErrPlain is the default error that is returned for functions in this package.
var ErrPlain = errors.New("error")

////////////////////////////////////////////////////////////////

func fileline(i int) string {
	_, file, line, ok := runtime.Caller(i)
	if !ok {
		return ""
	}
	parts := strings.Split(file, "/")
	file = parts[len(parts)-1]
	return fmt.Sprintf("%s:%d", file, line)
}

func trace() string {
	trace2 := fileline(2)
	trace3 := fileline(3)
	return "\r    " + strings.Repeat(" ", len(fmt.Sprintf("%s:", trace2))) + "\r    " + trace3
}

func message(msgs ...interface{}) string {
	if len(msgs) == 0 {
		return ""
	}
	s := fmt.Sprintln(msgs...)
	s = s[:len(s)-1] // remove newline
	return ": " + s
}

func printable(s string) string {
	s = strings.Replace(s, "\n", `\n`, -1)
	s = strings.Replace(s, "\r", `\r`, -1)
	s = strings.Replace(s, "\t", `\t`, -1)
	s = strings.Replace(s, "\x00", `\0`, -1)
	return s
}

const (
	Red   = "31"
	Green = "32"
)

func color(color string, s interface{}) string {
	return fmt.Sprintf("\033[00;%sm%v\033[00m", color, s)
}

/////////////////////////////////////////////////////////////////

func Fail(t *testing.T, msgs ...interface{}) {
	t.Errorf("%s%s", trace(), message(msgs...))
}

func Error(t *testing.T, err error, msgs ...interface{}) {
	if err != nil {
		t.Errorf("%s%s: %s", trace(), message(msgs...), color(Red, err.Error()))
	}
}

func That(t *testing.T, condition bool, msgs ...interface{}) {
	if !condition {
		t.Errorf("%s%s: false", trace(), message(msgs...))
	}
}

func T(t *testing.T, got, wanted interface{}, msgs ...interface{}) {
	gotType := reflect.TypeOf(got)
	wantedType := reflect.TypeOf(wanted)
	if gotType != wantedType {
		t.Errorf("%s%s: type %v != %v", trace(), message(msgs...), color(Red, gotType), color(Green, wantedType))
		return
	}
	if got == wanted {
		return
	}

	if wantedType != nil {
		if equals, ok := wantedType.MethodByName("Equals"); ok && equals.Type.NumIn() == 2 && equals.Type.NumOut() == 1 && equals.Type.In(0) == wantedType && equals.Type.In(1) == gotType && equals.Type.Out(0).Kind() == reflect.Bool && equals.Func.Call([]reflect.Value{reflect.ValueOf(wanted), reflect.ValueOf(got)})[0].Bool() {
			return
		}
	}
	t.Errorf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted))
}

func Bytes(t *testing.T, got, wanted []byte, msgs ...interface{}) {
	if !bytes.Equal(got, wanted) {
		gotString := printable(string(got))
		wantedString := printable(string(wanted))
		t.Errorf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString))
	}
}

func String(t *testing.T, got, wanted string, msgs ...interface{}) {
	if got != wanted {
		gotString := printable(got)
		wantedString := printable(wanted)
		t.Errorf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString))
	}
}

func Float(t *testing.T, got, wanted float64, msgs ...interface{}) {
	if math.Abs(got-wanted) > 1e-6 {
		t.Errorf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted))
	}
}

func Minify(t *testing.T, input string, err error, got, wanted string, msgs ...interface{}) {
	inputString := printable(input)
	if err != nil {
		t.Errorf("%s%s:\n%s\n%s", trace(), message(msgs...), inputString, color(Red, err.Error()))
		return
	}

	if got != wanted {
		gotString := printable(got)
		wantedString := printable(wanted)
		t.Errorf("%s%s:\n%s\n%s\n%s", trace(), message(msgs...), inputString, color(Red, gotString), color(Green, wantedString))
	}
}
<commit_msg>Errorf -> Fatalf<commit_after>package test

import (
	"bytes"
	"errors"
	"fmt"
	"math"
	"reflect"
	"runtime"
	"strings"
	"testing"
)

// ErrPlain is the default error that is returned for functions in this package.
var ErrPlain = errors.New("error")

////////////////////////////////////////////////////////////////

func fileline(i int) string {
	_, file, line, ok := runtime.Caller(i)
	if !ok {
		return ""
	}
	parts := strings.Split(file, "/")
	file = parts[len(parts)-1]
	return fmt.Sprintf("%s:%d", file, line)
}

func trace() string {
	trace2 := fileline(2)
	trace3 := fileline(3)
	return "\r    " + strings.Repeat(" ", len(fmt.Sprintf("%s:", trace2))) + "\r    " + trace3
}

func message(msgs ...interface{}) string {
	if len(msgs) == 0 {
		return ""
	}
	s := fmt.Sprintln(msgs...)
	s = s[:len(s)-1] // remove newline
	return ": " + s
}

func printable(s string) string {
	s = strings.Replace(s, "\n", `\n`, -1)
	s = strings.Replace(s, "\r", `\r`, -1)
	s = strings.Replace(s, "\t", `\t`, -1)
	s = strings.Replace(s, "\x00", `\0`, -1)
	return s
}

const (
	Red   = "31"
	Green = "32"
)

func color(color string, s interface{}) string {
	return fmt.Sprintf("\033[00;%sm%v\033[00m", color, s)
}

/////////////////////////////////////////////////////////////////

func Fail(t *testing.T, msgs ...interface{}) {
	t.Fatalf("%s%s", trace(), message(msgs...))
}

func Error(t *testing.T, err error, msgs ...interface{}) {
	if err != nil {
		t.Fatalf("%s%s: %s", trace(), message(msgs...), color(Red, err.Error()))
	}
}

func That(t *testing.T, condition bool, msgs ...interface{}) {
	if !condition {
		t.Fatalf("%s%s: false", trace(), message(msgs...))
	}
}

func T(t *testing.T, got, wanted interface{}, msgs ...interface{}) {
	gotType := reflect.TypeOf(got)
	wantedType := reflect.TypeOf(wanted)
	if gotType != wantedType {
		t.Fatalf("%s%s: type %v != %v", trace(), message(msgs...), color(Red, gotType), color(Green, wantedType))
		return
	}
	if got == wanted {
		return
	}

	if wantedType != nil {
		if equals, ok := wantedType.MethodByName("Equals"); ok && equals.Type.NumIn() == 2 && equals.Type.NumOut() == 1 && equals.Type.In(0) == wantedType && equals.Type.In(1) == gotType && equals.Type.Out(0).Kind() == reflect.Bool && equals.Func.Call([]reflect.Value{reflect.ValueOf(wanted), reflect.ValueOf(got)})[0].Bool() {
			return
		}
	}
	t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted))
}

func Bytes(t *testing.T, got, wanted []byte, msgs ...interface{}) {
	if !bytes.Equal(got, wanted) {
		gotString := printable(string(got))
		wantedString := printable(string(wanted))
		t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString))
	}
}

func String(t *testing.T, got, wanted string, msgs ...interface{}) {
	if got != wanted {
		gotString := printable(got)
		wantedString := printable(wanted)
		t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString))
	}
}

func Float(t *testing.T, got, wanted float64, msgs ...interface{}) {
	if math.Abs(got-wanted) > 1e-6 {
		t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted))
	}
}

func Minify(t *testing.T, input string, err error, got, wanted string, msgs ...interface{}) {
	inputString := printable(input)
	if err != nil {
		t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), inputString, color(Red, err.Error()))
		return
	}

	if got != wanted {
		gotString := printable(got)
		wantedString := printable(wanted)
		t.Fatalf("%s%s:\n%s\n%s\n%s", trace(), message(msgs...), inputString, color(Red, gotString), color(Green, wantedString))
	}
}
<|endoftext|>


<commit_before>package channelpipe

import (
	"Fantasia/system"
	"encoding/json"
	"errors"
	"log"
	"os"
	"sync"

	"github.com/bwmarrin/discordgo"
)

// errors
var (
	ErrBindingNotFound      = errors.New("Could not find binding")
	ErrBindingAlreadyExists = errors.New("Binding already exists")
	ErrFeedbackLoop         = errors.New("Both channel IDs are the same, this would cause a feedback loop")
)

// Config ..
type Config struct {
	UseNicknamesDefault  bool
	EmbedMessagesDefault bool
}

// NewConfig ...
func NewConfig() *Config {
	c := &Config{}
	return c
}

// Module ...
type Module struct {
	Sys      *system.System
	Config   *Config
	Bindings []*Binding
	bmu      sync.RWMutex // Bindings mutex
	fmu      sync.Mutex   // file mutex
}

// AddBinding adds a binding
func (m *Module) AddBinding(b *Binding) error {
	m.bmu.Lock()
	defer m.bmu.Unlock()

	if b.Source.ChannelID == b.Sink.ChannelID() {
		return ErrFeedbackLoop
	}

	for _, v := range m.Bindings {
		if v.Equals(b) {
			return ErrBindingAlreadyExists
		}
	}

	m.Bindings = append(m.Bindings, b)
	return nil
}

// RemoveBinding removes a binding
func (m *Module) RemoveBinding(channelID, dstID string) error {
	m.bmu.Lock()
	defer m.bmu.Unlock()

	for i, v := range m.Bindings {
		found := 0

		if channelID == "" {
			found++
		} else if channelID == v.Source.ChannelID {
			found++
		}

		if dstID == "" {
			found++
		} else if dstID == v.Sink.ChannelID() {
			found++
		}

		if found == 2 {
			m.Bindings = append(m.Bindings[:i], m.Bindings[i+1:]...) // Remove binding from slice
			return nil
		}
	}

	return ErrBindingNotFound
}

// SaveBindings saves the bindings to the database
func (m *Module) SaveBindings() error {
	m.bmu.RLock()
	defer m.bmu.RUnlock()

	m.fmu.Lock()
	defer m.fmu.Unlock()

	f, err := os.OpenFile("bindings.json", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Println(err)
		return err
	}

	return json.NewEncoder(f).Encode(m.Bindings)
}

// LoadBindings loads the bindings from disk
func (m *Module) LoadBindings() error {
	m.bmu.Lock()
	m.bmu.Unlock()

	m.fmu.Lock()
	defer m.fmu.Unlock()

	f, err := os.OpenFile("bindings.json", os.O_RDONLY, 0666)
	if err != nil {
		log.Println(err)
		return err
	}

	json.NewDecoder(f).Decode(&m.Bindings)

	return nil
}

// Build ...
func (m *Module) Build(s *system.System) {
	m.Sys = s
	r := s.CommandRouter

	r.On("addbinding", m.CmdAddBinding).Set("", "adds a binding from the current channel to specified destination\n"+
		"Usage: addbinding [channelid] (webhook | channelid)\n"+
		"Ex: `addbinding webhookURL` will bind the current channel's messages to the given webhook")

	r.On("removebinding", m.CmdRemoveBinding).Set("", "Removes a binding from the current channel to the specified destination\n"+
		"usage: `removebinding [channelid] [channelid]`")

	r.On("listbindings", m.CmdListBinding).Set("", "Lists the bindings in the current guild")

	m.LoadBindings()
	go m.Listen()
}

// FeedbackLoopIDs returns a list of IDs that will cause a feedback loop if
// not ignored
func (m *Module) FeedbackLoopIDs(b *Binding) []string {
	ids := []string{}

	for _, v := range m.Bindings {
		if v.Sink.ChannelID() == b.Source.ChannelID &&
			v.Source.ChannelID == b.Sink.ChannelID() {

			ids = append(ids, v.Sink.ID())
		}
	}
	return ids
}

// Listen listens for messages
func (m *Module) Listen() {
	m.Sys.Dream.DG.AddHandler(func(s *discordgo.Session, msg *discordgo.MessageCreate) {
		m.bmu.RLock()
		defer m.bmu.RUnlock()

		for _, b := range m.Bindings {
			if b.IsPaused() { // Do not send messages if the binding is paused
				continue
			}

			for _, v := range m.FeedbackLoopIDs(b) {
				if msg.Author.ID == v {
					return
				}
			}

			if msg.ChannelID == b.Source.ChannelID {
				b.Sink.Send(s, ContentFromMessage(msg.Message))
			}
		}
	})
}
<commit_msg>Don't need a goroutine here<commit_after>package channelpipe

import (
	"Fantasia/system"
	"encoding/json"
	"errors"
	"log"
	"os"
	"sync"

	"github.com/bwmarrin/discordgo"
)

// errors
var (
	ErrBindingNotFound      = errors.New("Could not find binding")
	ErrBindingAlreadyExists = errors.New("Binding already exists")
	ErrFeedbackLoop         = errors.New("Both channel IDs are the same, this would cause a feedback loop")
)

// Config ..
type Config struct {
	UseNicknamesDefault  bool
	EmbedMessagesDefault bool
}

// NewConfig ...
func NewConfig() *Config {
	c := &Config{}
	return c
}

// Module ...
type Module struct {
	Sys      *system.System
	Config   *Config
	Bindings []*Binding
	bmu      sync.RWMutex // Bindings mutex
	fmu      sync.Mutex   // file mutex
}

// AddBinding adds a binding
func (m *Module) AddBinding(b *Binding) error {
	m.bmu.Lock()
	defer m.bmu.Unlock()

	if b.Source.ChannelID == b.Sink.ChannelID() {
		return ErrFeedbackLoop
	}

	for _, v := range m.Bindings {
		if v.Equals(b) {
			return ErrBindingAlreadyExists
		}
	}

	m.Bindings = append(m.Bindings, b)
	return nil
}

// RemoveBinding removes a binding
func (m *Module) RemoveBinding(channelID, dstID string) error {
	m.bmu.Lock()
	defer m.bmu.Unlock()

	for i, v := range m.Bindings {
		found := 0

		if channelID == "" {
			found++
		} else if channelID == v.Source.ChannelID {
			found++
		}

		if dstID == "" {
			found++
		} else if dstID == v.Sink.ChannelID() {
			found++
		}

		if found == 2 {
			m.Bindings = append(m.Bindings[:i], m.Bindings[i+1:]...) // Remove binding from slice
			return nil
		}
	}

	return ErrBindingNotFound
}

// SaveBindings saves the bindings to the database
func (m *Module) SaveBindings() error {
	m.bmu.RLock()
	defer m.bmu.RUnlock()

	m.fmu.Lock()
	defer m.fmu.Unlock()

	f, err := os.OpenFile("bindings.json", os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Println(err)
		return err
	}

	return json.NewEncoder(f).Encode(m.Bindings)
}

// LoadBindings loads the bindings from disk
func (m *Module) LoadBindings() error {
	m.bmu.Lock()
	m.bmu.Unlock()

	m.fmu.Lock()
	defer m.fmu.Unlock()

	f, err := os.OpenFile("bindings.json", os.O_RDONLY, 0666)
	if err != nil {
		log.Println(err)
		return err
	}

	json.NewDecoder(f).Decode(&m.Bindings)

	return nil
}

// Build ...
func (m *Module) Build(s *system.System) {
	m.Sys = s
	r := s.CommandRouter

	r.On("addbinding", m.CmdAddBinding).Set("", "adds a binding from the current channel to specified destination\n"+
		"Usage: addbinding [channelid] (webhook | channelid)\n"+
		"Ex: `addbinding webhookURL` will bind the current channel's messages to the given webhook")

	r.On("removebinding", m.CmdRemoveBinding).Set("", "Removes a binding from the current channel to the specified destination\n"+
		"usage: `removebinding [channelid] [channelid]`")

	r.On("listbindings", m.CmdListBinding).Set("", "Lists the bindings in the current guild")

	m.LoadBindings()
	m.Listen()
}

// FeedbackLoopIDs returns a list of IDs that will cause a feedback loop if
// not ignored
func (m *Module) FeedbackLoopIDs(b *Binding) []string {
	ids := []string{}

	for _, v := range m.Bindings {
		if v.Sink.ChannelID() == b.Source.ChannelID &&
			v.Source.ChannelID == b.Sink.ChannelID() {

			ids = append(ids, v.Sink.ID())
		}
	}
	return ids
}

// Listen listens for messages
func (m *Module) Listen() {
	m.Sys.Dream.DG.AddHandler(func(s *discordgo.Session, msg *discordgo.MessageCreate) {
		m.bmu.RLock()
		defer m.bmu.RUnlock()

		for _, b := range m.Bindings {
			if b.IsPaused() { // Do not send messages if the binding is paused
				continue
			}

			for _, v := range m.FeedbackLoopIDs(b) {
				if msg.Author.ID == v {
					return
				}
			}

			if msg.ChannelID == b.Source.ChannelID {
				b.Sink.Send(s, ContentFromMessage(msg.Message))
			}
		}
	})
}
<|endoftext|>


<commit_before>package resource

import (
	"fmt"
	"io"

	"github.com/hashicorp/hcl/hcl/ast"
)

// Registry contains all known resources
var Registry = make(map[string]RegistryItem)

// Provider type creates new resources from an HCL AST object item
type Provider func(title string, item *ast.ObjectItem) (Resource, error)

// RegistryItem type represents an item from the registry
type RegistryItem struct {
	// Name of the resource type
	Name string

	// Short desription of the resource
	Description string

	// Resource provider
	Provider Provider
}

// Register adds a resource type to the registry
func Register(item RegistryItem) error {
	_, ok := Registry[item.Name]
	if ok {
		return fmt.Errorf("Resource type '%s' is already registered", item.Name)
	}

	Registry[item.Name] = item

	return nil
}

// Resource is the interface type for resources
type Resource interface {
	// ResourceID returns the unique identifier of a resource
	ResourceID() string

	// ResourceType returns the type of the resource
	ResourceType() string

	// ResourceTitle returns the title of the resource
	ResourceTitle() string

	// Returns the resources before which this resource shoud be processed
	WantBefore() []string

	// Returns the resources after which this resource should be processed
	WantAfter() []string

	// Evaluates the resource
	Evaluate(w io.Writer, opts *Options) (State, error)

	// Creates the resource
	Create(w io.Writer, opts *Options) error

	// Deletes the resource
	Delete(w io.Writer, opts *Options) error

	// Updates the resource
	Update(w io.Writer, opts *Options) error
}

// Options sent to resources during processing
type Options struct {
	// The site directory which contains module and data files
	SiteDir string

	// Do not take any action, just report what would be done
	DryRun bool
}

// BaseResource is the base resource type for all resources
// The purpose of this type is to be embedded into other resources
// Partially implements the Resource interface
type BaseResource struct {
	// Type of the resource
	Type string `json:"-"`

	// Title of the resource
	Title string `json:"-"`

	// Desired state of the resource
	State string `hcl:"state" json:"state"`

	// Resources before which this resource should be processed
	Before []string `hcl:"before" json:"before,omitempty"`

	// Resources after which this resource should be processed
	After []string `hcl:"after" json:"after,omitempty"`
}

// ResourceID returns the unique resource id
func (b *BaseResource) ResourceID() string {
	return fmt.Sprintf("%s[%s]", b.Type, b.Title)
}

// ResourceType returns the resource type
func (b *BaseResource) ResourceType() string {
	return b.Type
}

// ResourceTitle returns the resource title
func (b *BaseResource) ResourceTitle() string {
	return b.Title
}

// WantBefore returns the resources before which this resource
// should be processed
func (b *BaseResource) WantBefore() []string {
	return b.Before
}

// WantAfter returns the resources after which this resource
// should be processed
func (b *BaseResource) WantAfter() []string {
	return b.After
}

// Printf works just like fmt.Printf except that it writes to the
// given resource writer object and prepends the
// resource id to the output
func (b *BaseResource) Printf(w io.Writer, format string, a ...interface{}) (int, error) {
	fmt.Fprintf(w, "%s ", b.ResourceID())

	return fmt.Fprintf(w, format, a...)
}
<commit_msg>resource: pass resource.Config when instantiating new resources<commit_after>package resource

import (
	"fmt"
	"io"

	"github.com/hashicorp/hcl/hcl/ast"
)

// Registry contains all known resources
var Registry = make(map[string]RegistryItem)

// Provider type creates new resources from an HCL AST object item
type Provider func(title string, item *ast.ObjectItem, config *Config) (Resource, error)

// RegistryItem type represents an item from the registry
type RegistryItem struct {
	// Name of the resource type
	Name string

	// Short desription of the resource
	Description string

	// Resource provider
	Provider Provider
}

// Register adds a resource type to the registry
func Register(item RegistryItem) error {
	_, ok := Registry[item.Name]
	if ok {
		return fmt.Errorf("Resource type '%s' is already registered", item.Name)
	}

	Registry[item.Name] = item

	return nil
}

// Resource is the interface type for resources
type Resource interface {
	// ResourceID returns the unique identifier of a resource
	ResourceID() string

	// Returns the resources before which this resource shoud be processed
	WantBefore() []string

	// Returns the resources after which this resource should be processed
	WantAfter() []string

	// Evaluates the resource
	Evaluate() (State, error)

	// Creates the resource
	Create() error

	// Deletes the resource
	Delete() error

	// Updates the resource
	Update() error
}

// Config type contains various settings used by the resources
type Config struct {
	// The site directory which contains module and data files
	SiteDir string

	// Writer used by the resources
	Writer io.Writer
}

// BaseResource is the base resource type for all resources
// The purpose of this type is to be embedded into other resources
// Partially implements the Resource interface
type BaseResource struct {
	// Type of the resource
	Type string `hcl:"-"`

	// Title of the resource
	Title string `hcl:"-"`

	// Resource configuration settings
	Config *Config `hcl:"-"`

	// Desired state of the resource
	State string `hcl:"state"`

	// Resources before which this resource should be processed
	Before []string `hcl:"before"`

	// Resources after which this resource should be processed
	After []string `hcl:"after"`
}

// ResourceID returns the unique resource id
func (br *BaseResource) ResourceID() string {
	return fmt.Sprintf("%s[%s]", br.Type, br.Title)
}

// WantBefore returns the resources before which this resource
// should be processed
func (br *BaseResource) WantBefore() []string {
	return br.Before
}

// WantAfter returns the resources after which this resource
// should be processed
func (br *BaseResource) WantAfter() []string {
	return br.After
}

// Printf works just like fmt.Printf except that it writes to the
// given resource writer object and prepends the
// resource id to the output
func (br *BaseResource) Printf(format string, a ...interface{}) (int, error) {
	fmt.Fprintf(br.Config.Writer, "%s ", br.ResourceID())

	return fmt.Fprintf(br.Config.Writer, format, a...)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"testing"
)

const fakeRepoName = "git_testing_directory"

var testingDirectory string

func deleteFakeRepo(t *testing.T) {
	os.Chdir(testingDirectory)
	err := os.RemoveAll(fakeRepoName)
	if err != nil {
		t.Fatalf("Couldn't delete testing directory: %v.", fakeRepoName)
	}
}

func makeFakeRepoWithCommit(t *testing.T, commitMsg string) {
	// create empty directory for repo
	testingDirectory, _ = os.Getwd()
	err := os.Mkdir(fakeRepoName, 0777)
	if err != nil {
		t.Fatal("Couldn't create directory for testing needs.")
	}
	os.Chdir(fakeRepoName)
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't navigate to the directory for testing needs.")
	}

	// initialize repo
	cmd := exec.Command("git", "init")
	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil || !strings.Contains(out.String(), "Initialized") {
		deleteFakeRepo(t)
		t.Fatal("Couldn't initialize git repo for testing needs.")
	}

	// set username and email in local repo
	cmd = exec.Command("git", "config", "user.name", "'Rainforest QA'")
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't set the username in repo.")
	}
	cmd = exec.Command("git", "config", "user.email", "'test@rainforestqa.com'")
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't set the email in repo.")
	}

	// create empty commit
	cmd = exec.Command("git", "commit", "--allow-empty", "-m", commitMsg)
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil || !strings.Contains(out.String(), commitMsg) {
		deleteFakeRepo(t)
		t.Fatal("Couldn't commit to the test repo.")
	}
}

func TestNewGitTrigger(t *testing.T) {
	const commitMsg = "foo barred baz"
	makeFakeRepoWithCommit(t, commitMsg)
	defer deleteFakeRepo(t)
	git, err := newGitTrigger()
	if err != nil {
		t.Error("Unexpected error when doing newGitTrigger()")
	}
	if git.LastCommit != commitMsg {
		t.Errorf("inproperly initialized gitTrigger with newGitTrigger: %v, expected: %v", git.LastCommit, commitMsg)
	}
}

func TestGetLatestCommit(t *testing.T) {
	const commitMsg = "test commit in a test repo"
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	makeFakeRepoWithCommit(t, commitMsg)
	defer deleteFakeRepo(t)
	err := fakeGit.getLatestCommit()
	if err != nil {
		t.Error("Unexpected error when doing getLatestCommit()")
	}
	if fakeGit.LastCommit != commitMsg {
		t.Errorf("got wrong commit from GetLatestCommit got: %v, expected: %v", fakeGit.LastCommit, commitMsg)
	}
}

func TestCheckTrigger(t *testing.T) {
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	var testCases = []struct {
		fakeCommit string
		want       bool
	}{
		{
			fakeCommit: "Testing testing",
			want:       false,
		},
		{
			fakeCommit: "Testing @rainforest testing",
			want:       true,
		},
		{
			fakeCommit: "@rainfnf",
			want:       false,
		},
	}

	for _, tCase := range testCases {
		fakeGit.LastCommit = tCase.fakeCommit
		got := fakeGit.checkTrigger()
		if !reflect.DeepEqual(tCase.want, got) {
			t.Errorf("checkTrigger returned %+v, want %+v", got, tCase.want)
		}
	}
}

func TestGetTags(t *testing.T) {
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	var testCases = []struct {
		fakeCommit string
		want       []string
	}{
		{
			fakeCommit: "Testing testing",
			want:       []string{},
		},
		{
			fakeCommit: "@rainforest #foo, #bar",
			want:       []string{"foo", "bar"},
		},
		{
			fakeCommit: "@rainforest #foo #bar-baz #qwe_asd",
			want:       []string{"foo", "bar-baz", "qwe_asd"},
		},
	}

	for _, tCase := range testCases {
		fakeGit.LastCommit = tCase.fakeCommit
		got := fakeGit.getTags()
		if !reflect.DeepEqual(tCase.want, got) {
			t.Errorf("getTags returned %+v, want %+v", got, tCase.want)
		}
	}
}
<commit_msg>RF-3270 Fix test to not sign commits<commit_after>package main

import (
	"bytes"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"testing"
)

const fakeRepoName = "git_testing_directory"

var testingDirectory string

func deleteFakeRepo(t *testing.T) {
	os.Chdir(testingDirectory)
	err := os.RemoveAll(fakeRepoName)
	if err != nil {
		t.Fatalf("Couldn't delete testing directory: %v.", fakeRepoName)
	}
}

func makeFakeRepoWithCommit(t *testing.T, commitMsg string) {
	// create empty directory for repo
	testingDirectory, _ = os.Getwd()
	err := os.Mkdir(fakeRepoName, 0777)
	if err != nil {
		t.Fatal("Couldn't create directory for testing needs.")
	}
	os.Chdir(fakeRepoName)
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't navigate to the directory for testing needs.")
	}

	// initialize repo
	cmd := exec.Command("git", "init")
	var out bytes.Buffer
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil || !strings.Contains(out.String(), "Initialized") {
		deleteFakeRepo(t)
		t.Fatal("Couldn't initialize git repo for testing needs.")
	}

	// set username and email in local repo
	cmd = exec.Command("git", "config", "user.name", "'Rainforest QA'")
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't set the username in repo.")
	}
	cmd = exec.Command("git", "config", "user.email", "'test@rainforestqa.com'")
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't set the email in repo.")
	}
	cmd = exec.Command("git", "config", "commit.gpgSign", "false")
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil {
		deleteFakeRepo(t)
		t.Fatal("Couldn't set the email in repo.")
	}

	// create empty commit
	cmd = exec.Command("git", "commit", "--allow-empty", "-m", commitMsg)
	out.Reset()
	cmd.Stdout = &out
	err = cmd.Run()
	if err != nil || !strings.Contains(out.String(), commitMsg) {
		deleteFakeRepo(t)
		t.Fatal("Couldn't commit to the test repo.")
	}
}

func TestNewGitTrigger(t *testing.T) {
	const commitMsg = "foo barred baz"
	makeFakeRepoWithCommit(t, commitMsg)
	defer deleteFakeRepo(t)
	git, err := newGitTrigger()
	if err != nil {
		t.Error("Unexpected error when doing newGitTrigger()")
	}
	if git.LastCommit != commitMsg {
		t.Errorf("inproperly initialized gitTrigger with newGitTrigger: %v, expected: %v", git.LastCommit, commitMsg)
	}
}

func TestGetLatestCommit(t *testing.T) {
	const commitMsg = "test commit in a test repo"
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	makeFakeRepoWithCommit(t, commitMsg)
	defer deleteFakeRepo(t)
	err := fakeGit.getLatestCommit()
	if err != nil {
		t.Error("Unexpected error when doing getLatestCommit()")
	}
	if fakeGit.LastCommit != commitMsg {
		t.Errorf("got wrong commit from GetLatestCommit got: %v, expected: %v", fakeGit.LastCommit, commitMsg)
	}
}

func TestCheckTrigger(t *testing.T) {
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	var testCases = []struct {
		fakeCommit string
		want       bool
	}{
		{
			fakeCommit: "Testing testing",
			want:       false,
		},
		{
			fakeCommit: "Testing @rainforest testing",
			want:       true,
		},
		{
			fakeCommit: "@rainfnf",
			want:       false,
		},
	}

	for _, tCase := range testCases {
		fakeGit.LastCommit = tCase.fakeCommit
		got := fakeGit.checkTrigger()
		if !reflect.DeepEqual(tCase.want, got) {
			t.Errorf("checkTrigger returned %+v, want %+v", got, tCase.want)
		}
	}
}

func TestGetTags(t *testing.T) {
	fakeGit := gitTrigger{Trigger: "@rainforest"}
	var testCases = []struct {
		fakeCommit string
		want       []string
	}{
		{
			fakeCommit: "Testing testing",
			want:       []string{},
		},
		{
			fakeCommit: "@rainforest #foo, #bar",
			want:       []string{"foo", "bar"},
		},
		{
			fakeCommit: "@rainforest #foo #bar-baz #qwe_asd",
			want:       []string{"foo", "bar-baz", "qwe_asd"},
		},
	}

	for _, tCase := range testCases {
		fakeGit.LastCommit = tCase.fakeCommit
		got := fakeGit.getTags()
		if !reflect.DeepEqual(tCase.want, got) {
			t.Errorf("getTags returned %+v, want %+v", got, tCase.want)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/crackcomm/go-clitable"
	"github.com/levigross/grequests"
	"github.com/parnurzeal/gorequest"
	r "gopkg.in/dancannon/gorethink.v2"
)

// Version stores the plugin's version
var Version string

// BuildTime stores the plugin's build time
var BuildTime string

const (
	name     = "shadow-server"
	category = "intel"
)

type pluginResults struct {
	ID   string      `json:"id" gorethink:"id,omitempty"`
	Data ResultsData `json:"shadow-server" gorethink:"shadow-server"`
}

// ShadowServer json object
type ShadowServer struct {
	Results ResultsData `json:"shadow-server"`
}

// ResultsData json object
type ResultsData struct {
	Found     bool             `json:"found"`
	SandBox   SandBoxResults   `json:"sandbox"`
	WhiteList WhiteListResults `json:"whitelist"`
}

// SandBoxResults is a shadow-server SandboxApi results JSON object
type SandBoxResults struct {
	MD5       string            `json:"md5"`
	SHA1      string            `json:"sha1"`
	FirstSeen time.Time         `json:"first_seen"`
	LastSeen  time.Time         `json:"last_seen"`
	FileType  string            `json:"type"`
	SSDeep    string            `json:"ssdeep"`
	Antivirus map[string]string `json:"antivirus"`
}

// WhiteListResults is a shadow-server bin-test results JSON object
type WhiteListResults map[string]string

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func hashType(hash string) *grequests.RequestOptions {
	if match, _ := regexp.MatchString("([a-fA-F0-9]{32})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"md5": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{40})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha1": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{64})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha256": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{128})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha512": hash,
			},
		}
	} else {
		return &grequests.RequestOptions{ //, fmt.Errorf("%s is not a valid hash", hash)
		}
	}
}

func parseLookupHashOutput(lookupout string, hash string) ResultsData {
	lookup := ResultsData{}

	lines := strings.Split(lookupout, "\n")

	if len(lines) == 2 {
		if strings.Contains(lines[0], "! No match found") {
			lookup.Found = false
			return lookup
		}
		if strings.Contains(lines[0], "! Whitelisted:") {
			lookup.Found = true
			lookup.WhiteList = WhiteListHash(hash)
			return lookup
		}
	} else if len(lines) == 3 {
		values := strings.Split(lines[0], ",")
		lookup.Found = true
		lookup.WhiteList = WhiteListHash(hash)
		if len(values) == 6 {
			lookup.SandBox.MD5 = strings.Trim(values[0], "\"")
			lookup.SandBox.SHA1 = strings.Trim(values[1], "\"")
			// "2009-07-24 02:09:53"
			const longForm = "2006-01-02 15:04:05"
			timeFirstSeen, _ := time.Parse(longForm, strings.Trim(values[2], "\""))
			lookup.SandBox.FirstSeen = timeFirstSeen
			timeLastSeen, _ := time.Parse(longForm, strings.Trim(values[3], "\""))
			lookup.SandBox.LastSeen = timeLastSeen
			lookup.SandBox.FileType = strings.Trim(values[4], "\"")
			lookup.SandBox.SSDeep = strings.Trim(values[5], "\"")
		}
		if len(lines[1]) == 2 {
			lookup.SandBox.Antivirus = nil
		} else {
			assert(json.Unmarshal([]byte(lines[1]), &lookup.SandBox.Antivirus))
		}
	} else {
		log.Fatal(fmt.Errorf("Unable to parse LookupHashOutput: %#v\n", lookupout))
	}

	return lookup
}

func parseWhiteListOutput(whitelistout string) WhiteListResults {
	whitelist := WhiteListResults{}

	lines := strings.Split(whitelistout, "\n")

	if len(lines) > 1 {

		fields := strings.SplitN(lines[0], " ", 2)

		if len(fields) == 2 {
			if fields[1] == "" {
				return nil
			}
			assert(json.Unmarshal([]byte(fields[1]), &whitelist))
		}
	}
	// fmt.Println("whitelist")
	// fmt.Printf("%#v\n", whitelist)
	return whitelist
}

// WhiteListHash test hash against a list of known software applications
func WhiteListHash(hash string) WhiteListResults {

	resp, err := grequests.Get("http://bin-test.shadowserver.org/api", hashType(hash))

	if err != nil {
		log.Fatalln("Unable to make request: ", err)
	}

	if resp.Ok != true {
		log.Println("Request did not return OK")
	}

	return parseWhiteListOutput(resp.String())
}

// LookupHash retreieves the shadow-server file report for the given hash
func LookupHash(hash string) ResultsData {
	// NOTE: https://godoc.org/github.com/levigross/grequests
	ro := &grequests.RequestOptions{
		Params: map[string]string{
			"query": hash,
		},
	}
	resp, err := grequests.Get("http://innocuous.shadowserver.org/api/", ro)

	if err != nil {
		log.Fatalln("Unable to make request: ", err)
	}

	if resp.Ok != true {
		log.Println("Request did not return OK")
	}
	ssResult := parseLookupHashOutput(resp.String(), hash)
	// fmt.Println(resp.String())
	// fmt.Printf("%#v", ssResult)
	return ssResult
}

func printStatus(resp gorequest.Response, body string, errs []error) {
	fmt.Println(resp.Status)
}

func printMarkDownTable(ss ShadowServer) {
	fmt.Println("#### ShadowServer")
	if ss.Results.WhiteList != nil {
		fmt.Println("##### WhiteList")
		table := clitable.New([]string{"Found", "Filename", "Description", "ProductName"})
		table.AddRow(map[string]interface{}{
			"Found":       ss.Results.Found,
			"Filename":    ss.Results.WhiteList["filename"],
			"Description": ss.Results.WhiteList["description"],
			"ProductName": ss.Results.WhiteList["product_name"],
		})
		table.Markdown = true
		table.Print()
	} else if ss.Results.SandBox.Antivirus != nil {
		fmt.Println("##### AntiVirus")
		fmt.Printf(" - FirstSeen: %s\n", ss.Results.SandBox.FirstSeen.Format("1/02/2006 3:04PM"))
		fmt.Printf(" - LastSeen: %s\n", ss.Results.SandBox.LastSeen.Format("1/02/2006 3:04PM"))
		fmt.Println()
		table := clitable.New([]string{"Vendor", "Signature"})
		for key, value := range ss.Results.SandBox.Antivirus {
			table.AddRow(map[string]interface{}{"Vendor": key, "Signature": value})
		}
		table.Markdown = true
		table.Print()
	} else {
		fmt.Println(" - Not found")
	}
}

// writeToDatabase upserts plugin results into Database
func writeToDatabase(results pluginResults) {

	address := fmt.Sprintf("%s:28015", getopt("MALICE_RETHINKDB", "rethink"))

	// connect to RethinkDB
	session, err := r.Connect(r.ConnectOpts{
		Address:  address,
		Timeout:  5 * time.Second,
		Database: "malice",
	})
	defer session.Close()

	if err == nil {
		res, err := r.Table("samples").Get(results.ID).Run(session)
		assert(err)
		defer res.Close()

		if res.IsNil() {
			// upsert into RethinkDB
			resp, err := r.Table("samples").Insert(results, r.InsertOpts{Conflict: "replace"}).RunWrite(session)
			assert(err)
			log.Debug(resp)
		} else {
			resp, err := r.Table("samples").Get(results.ID).Update(map[string]interface{}{
				"plugins": map[string]interface{}{
					category: map[string]interface{}{
						name: results.Data,
					},
				},
			}).RunWrite(session)
			assert(err)

			log.Debug(resp)
		}

	} else {
		log.Debug(err)
	}
}

var appHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	app := cli.NewApp()
	app.Name = "shadow-server"
	app.Author = "blacktop"
	app.Email = "https://github.com/blacktop"
	app.Version = Version + ", BuildTime: " + BuildTime
	app.Compiled, _ = time.Parse("20060102", BuildTime)
	app.Usage = "Malice ShadowServer Hash Lookup Plugin"
	var rethinkdb string
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:        "rethinkdb",
			Value:       "",
			Usage:       "rethinkdb address for Malice to store results",
			EnvVar:      "MALICE_RETHINKDB",
			Destination: &rethinkdb,
		},
		cli.BoolFlag{
			Name:   "post, p",
			Usage:  "POST results to Malice webhook",
			EnvVar: "MALICE_ENDPOINT",
		},
		cli.BoolFlag{
			Name:   "proxy, x",
			Usage:  "proxy settings for Malice webhook endpoint",
			EnvVar: "MALICE_PROXY",
		},
		cli.BoolFlag{
			Name:  "table, t",
			Usage: "output as Markdown table",
		},
	}
	app.ArgsUsage = "MD5/SHA1 hash of file"
	app.Action = func(c *cli.Context) {
		if c.Args().Present() {
			if c.Bool("verbose") {
				log.SetLevel(log.DebugLevel)
			}
			ssReport := LookupHash(c.Args().First())
			ss := ShadowServer{Results: ssReport}

			// upsert into Database
			writeToDatabase(pluginResults{ID: "FIX_THIS", Data: ss.Results})

			if c.Bool("table") {
				printMarkDownTable(ss)
			} else {
				ssJSON, err := json.Marshal(ss)
				assert(err)
				fmt.Println(string(ssJSON))
			}
		} else {
			log.Fatal(fmt.Errorf("Please supply a MD5/SHA1 hash to query."))
		}
	}

	err := app.Run(os.Args)
	assert(err)
}
<commit_msg>working it<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/crackcomm/go-clitable"
	"github.com/levigross/grequests"
	"github.com/parnurzeal/gorequest"
	"github.com/urfave/cli"
	r "gopkg.in/dancannon/gorethink.v2"
)

// Version stores the plugin's version
var Version string

// BuildTime stores the plugin's build time
var BuildTime string

const (
	name     = "shadow-server"
	category = "intel"
)

type pluginResults struct {
	ID   string      `json:"id" gorethink:"id,omitempty"`
	Data ResultsData `json:"shadow-server" gorethink:"shadow-server"`
}

// ShadowServer json object
type ShadowServer struct {
	Results ResultsData `json:"shadow-server"`
}

// ResultsData json object
type ResultsData struct {
	Found     bool             `json:"found"`
	SandBox   SandBoxResults   `json:"sandbox"`
	WhiteList WhiteListResults `json:"whitelist"`
}

// SandBoxResults is a shadow-server SandboxApi results JSON object
type SandBoxResults struct {
	MD5       string            `json:"md5"`
	SHA1      string            `json:"sha1"`
	FirstSeen time.Time         `json:"first_seen"`
	LastSeen  time.Time         `json:"last_seen"`
	FileType  string            `json:"type"`
	SSDeep    string            `json:"ssdeep"`
	Antivirus map[string]string `json:"antivirus"`
}

// WhiteListResults is a shadow-server bin-test results JSON object
type WhiteListResults map[string]string

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func hashType(hash string) *grequests.RequestOptions {
	if match, _ := regexp.MatchString("([a-fA-F0-9]{32})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"md5": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{40})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha1": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{64})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha256": hash,
			},
		}
	} else if match, _ := regexp.MatchString("([a-fA-F0-9]{128})", hash); match {
		return &grequests.RequestOptions{
			Params: map[string]string{
				"sha512": hash,
			},
		}
	} else {
		return &grequests.RequestOptions{ //, fmt.Errorf("%s is not a valid hash", hash)
		}
	}
}

func parseLookupHashOutput(lookupout string, hash string) ResultsData {
	lookup := ResultsData{}

	lines := strings.Split(lookupout, "\n")

	if len(lines) == 2 {
		if strings.Contains(lines[0], "! No match found") {
			lookup.Found = false
			return lookup
		}
		if strings.Contains(lines[0], "! Whitelisted:") {
			lookup.Found = true
			lookup.WhiteList = WhiteListHash(hash)
			return lookup
		}
	} else if len(lines) == 3 {
		values := strings.Split(lines[0], ",")
		lookup.Found = true
		lookup.WhiteList = WhiteListHash(hash)
		if len(values) == 6 {
			lookup.SandBox.MD5 = strings.Trim(values[0], "\"")
			lookup.SandBox.SHA1 = strings.Trim(values[1], "\"")
			// "2009-07-24 02:09:53"
			const longForm = "2006-01-02 15:04:05"
			timeFirstSeen, _ := time.Parse(longForm, strings.Trim(values[2], "\""))
			lookup.SandBox.FirstSeen = timeFirstSeen
			timeLastSeen, _ := time.Parse(longForm, strings.Trim(values[3], "\""))
			lookup.SandBox.LastSeen = timeLastSeen
			lookup.SandBox.FileType = strings.Trim(values[4], "\"")
			lookup.SandBox.SSDeep = strings.Trim(values[5], "\"")
		}
		if len(lines[1]) == 2 {
			lookup.SandBox.Antivirus = nil
		} else {
			assert(json.Unmarshal([]byte(lines[1]), &lookup.SandBox.Antivirus))
		}
	} else {
		log.Fatal(fmt.Errorf("Unable to parse LookupHashOutput: %#v\n", lookupout))
	}

	return lookup
}

func parseWhiteListOutput(whitelistout string) WhiteListResults {
	whitelist := WhiteListResults{}

	lines := strings.Split(whitelistout, "\n")

	if len(lines) > 1 {

		fields := strings.SplitN(lines[0], " ", 2)

		if len(fields) == 2 {
			if fields[1] == "" {
				return nil
			}
			assert(json.Unmarshal([]byte(fields[1]), &whitelist))
		}
	}
	// fmt.Println("whitelist")
	// fmt.Printf("%#v\n", whitelist)
	return whitelist
}

// WhiteListHash test hash against a list of known software applications
func WhiteListHash(hash string) WhiteListResults {

	resp, err := grequests.Get("http://bin-test.shadowserver.org/api", hashType(hash))

	if err != nil {
		log.Fatalln("Unable to make request: ", err)
	}

	if resp.Ok != true {
		log.Println("Request did not return OK")
	}

	return parseWhiteListOutput(resp.String())
}

// LookupHash retreieves the shadow-server file report for the given hash
func LookupHash(hash string) ResultsData {
	// NOTE: https://godoc.org/github.com/levigross/grequests
	ro := &grequests.RequestOptions{
		Params: map[string]string{
			"query": hash,
		},
	}
	resp, err := grequests.Get("http://innocuous.shadowserver.org/api/", ro)

	if err != nil {
		log.Fatalln("Unable to make request: ", err)
	}

	if resp.Ok != true {
		log.Println("Request did not return OK")
	}
	ssResult := parseLookupHashOutput(resp.String(), hash)
	// fmt.Println(resp.String())
	// fmt.Printf("%#v", ssResult)
	return ssResult
}

func printStatus(resp gorequest.Response, body string, errs []error) {
	fmt.Println(resp.Status)
}

func printMarkDownTable(ss ShadowServer) {
	fmt.Println("#### ShadowServer")
	if ss.Results.WhiteList != nil {
		fmt.Println("##### WhiteList")
		table := clitable.New([]string{"Found", "Filename", "Description", "ProductName"})
		table.AddRow(map[string]interface{}{
			"Found":       ss.Results.Found,
			"Filename":    ss.Results.WhiteList["filename"],
			"Description": ss.Results.WhiteList["description"],
			"ProductName": ss.Results.WhiteList["product_name"],
		})
		table.Markdown = true
		table.Print()
	} else if ss.Results.SandBox.Antivirus != nil {
		fmt.Println("##### AntiVirus")
		fmt.Printf(" - FirstSeen: %s\n", ss.Results.SandBox.FirstSeen.Format("1/02/2006 3:04PM"))
		fmt.Printf(" - LastSeen: %s\n", ss.Results.SandBox.LastSeen.Format("1/02/2006 3:04PM"))
		fmt.Println()
		table := clitable.New([]string{"Vendor", "Signature"})
		for key, value := range ss.Results.SandBox.Antivirus {
			table.AddRow(map[string]interface{}{"Vendor": key, "Signature": value})
		}
		table.Markdown = true
		table.Print()
	} else {
		fmt.Println(" - Not found")
	}
}

// writeToDatabase upserts plugin results into Database
func writeToDatabase(results pluginResults) {

	address := fmt.Sprintf("%s:28015", getopt("MALICE_RETHINKDB", "rethink"))

	// connect to RethinkDB
	session, err := r.Connect(r.ConnectOpts{
		Address:  address,
		Timeout:  5 * time.Second,
		Database: "malice",
	})
	defer session.Close()

	if err == nil {
		res, err := r.Table("samples").Get(results.ID).Run(session)
		assert(err)
		defer res.Close()

		if res.IsNil() {
			// upsert into RethinkDB
			resp, err := r.Table("samples").Insert(results, r.InsertOpts{Conflict: "replace"}).RunWrite(session)
			assert(err)
			log.Debug(resp)
		} else {
			resp, err := r.Table("samples").Get(results.ID).Update(map[string]interface{}{
				"plugins": map[string]interface{}{
					category: map[string]interface{}{
						name: results.Data,
					},
				},
			}).RunWrite(session)
			assert(err)

			log.Debug(resp)
		}

	} else {
		log.Debug(err)
	}
}

var appHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	app := cli.NewApp()
	app.Name = "shadow-server"
	app.Author = "blacktop"
	app.Email = "https://github.com/blacktop"
	app.Version = Version + ", BuildTime: " + BuildTime
	app.Compiled, _ = time.Parse("20060102", BuildTime)
	app.Usage = "Malice ShadowServer Hash Lookup Plugin"
	var rethinkdb string
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:        "rethinkdb",
			Value:       "",
			Usage:       "rethinkdb address for Malice to store results",
			EnvVar:      "MALICE_RETHINKDB",
			Destination: &rethinkdb,
		},
		cli.BoolFlag{
			Name:   "post, p",
			Usage:  "POST results to Malice webhook",
			EnvVar: "MALICE_ENDPOINT",
		},
		cli.BoolFlag{
			Name:   "proxy, x",
			Usage:  "proxy settings for Malice webhook endpoint",
			EnvVar: "MALICE_PROXY",
		},
		cli.BoolFlag{
			Name:  "table, t",
			Usage: "output as Markdown table",
		},
	}
	app.ArgsUsage = "MD5/SHA1 hash of file"
	app.Action = func(c *cli.Context) {
		if c.Args().Present() {
			if c.Bool("verbose") {
				log.SetLevel(log.DebugLevel)
			}
			hash := c.Args().First()
			ssReport := LookupHash(hash)
			ss := ShadowServer{Results: ssReport}

			// upsert into Database
			writeToDatabase(pluginResults{ID: getopt("MALICE_SCANID", hash), Data: ss.Results})

			if c.Bool("table") {
				printMarkDownTable(ss)
			} else {
				ssJSON, err := json.Marshal(ss)
				assert(err)
				fmt.Println(string(ssJSON))
			}
		} else {
			log.Fatal(fmt.Errorf("Please supply a MD5/SHA1 hash to query."))
		}
	}

	err := app.Run(os.Args)
	assert(err)
}
<|endoftext|>


<commit_before>package saml

import (
	"bytes"
	"compress/flate"
	"encoding/base64"
	"io"
	"sync"

	"github.com/lestrrat/go-libxml2/parser"
	"github.com/lestrrat/go-pdebug"
	"github.com/lestrrat/go-xmlsec/crypto"
	"github.com/lestrrat/go-xmlsec/dsig"
)

var b64enc = base64.StdEncoding

var flateWriterPool = sync.Pool{
	New: allocFlateWriter,
}

// wasteful, but oh well
var emptyBuffer = &bytes.Buffer{}

func allocFlateWriter() interface{} {
	// flate.NewWriter (as of this writing) only returns an error
	// if the second argument is invalid. As we are using a standard
	// compression level here, there is no way this can err
	w, _ := flate.NewWriter(emptyBuffer, flate.DefaultCompression)
	return w
}
func getFlateWriter() *flate.Writer {
	return flateWriterPool.Get().(*flate.Writer)
}
func releaseFlateWriter(r *flate.Writer) {
	r.Reset(emptyBuffer) // release the previous io.Writer
	flateWriterPool.Put(r)
}

type serializer interface {
	Serialize() (string, error)
}

func encode(s serializer, key *crypto.Key, compress bool) ([]byte, error) {
	xmlstr, err := s.Serialize()
	if err != nil {
		return nil, err
	}
	if pdebug.Enabled {
		pdebug.Printf("Generated %d bytes of XML", len(xmlstr))
	}

	if key != nil {
		p := parser.New(parser.XMLParseDTDLoad | parser.XMLParseDTDAttr | parser.XMLParseNoEnt)
		doc, err := p.ParseString(xmlstr)
		if err != nil {
			return nil, err
		}

		root, err := doc.DocumentElement()
		if err != nil {
			return nil, err
		}

		// Create a new signature section.
		sig, err := dsig.NewSignature(root, dsig.ExclC14N, dsig.RsaSha1, "")
		if err := sig.AddReference(dsig.Sha1, "", "", ""); err != nil {
			return nil, err
		}

		if err := sig.AddTransform(dsig.Enveloped); err != nil {
			return nil, err
		}

		if err := sig.AddKeyValue(); err != nil {
			return nil, err
		}

		// If the key is setup using X509, add that node
		if key.HasX509() == nil {
			if err := sig.AddX509Data(); err != nil {
				return nil, err
			}
		}

		if pdebug.Enabled {
			pdebug.Printf("Signing using key %p", key)
		}
		if err := sig.Sign(key); err != nil {
			return nil, err
		}

		xmlstr = doc.Dump(false)
		if err != nil {
			return nil, err
		}
	}

	if !compress {
		return []byte(xmlstr), nil
	}

	buf := bytes.Buffer{}

	w := getFlateWriter()
	defer releaseFlateWriter(w)

	w.Reset(&buf)
	if _, err := io.WriteString(w, xmlstr); err != nil {
		return nil, err
	}

	if err := w.Close(); err != nil {
		return nil, err
	}
	if pdebug.Enabled {
		pdebug.Printf("Compressed to %d bytes", buf.Len())
	}

	ret := make([]byte, b64enc.EncodedLen(buf.Len()))
	b64enc.Encode(ret, buf.Bytes())
	if pdebug.Enabled {
		pdebug.Printf("Encoded into %d bytes of base64", len(ret))
	}

	return ret, nil
}
<commit_msg>Check for key<commit_after>package saml

import (
	"bytes"
	"compress/flate"
	"encoding/base64"
	"io"
	"sync"

	"github.com/lestrrat/go-libxml2/parser"
	"github.com/lestrrat/go-pdebug"
	"github.com/lestrrat/go-xmlsec/crypto"
	"github.com/lestrrat/go-xmlsec/dsig"
)

var b64enc = base64.StdEncoding

var flateWriterPool = sync.Pool{
	New: allocFlateWriter,
}

// wasteful, but oh well
var emptyBuffer = &bytes.Buffer{}

func allocFlateWriter() interface{} {
	// flate.NewWriter (as of this writing) only returns an error
	// if the second argument is invalid. As we are using a standard
	// compression level here, there is no way this can err
	w, _ := flate.NewWriter(emptyBuffer, flate.DefaultCompression)
	return w
}
func getFlateWriter() *flate.Writer {
	return flateWriterPool.Get().(*flate.Writer)
}
func releaseFlateWriter(r *flate.Writer) {
	r.Reset(emptyBuffer) // release the previous io.Writer
	flateWriterPool.Put(r)
}

type serializer interface {
	Serialize() (string, error)
}

func encode(s serializer, key *crypto.Key, compress bool) ([]byte, error) {
	xmlstr, err := s.Serialize()
	if err != nil {
		return nil, err
	}
	if pdebug.Enabled {
		pdebug.Printf("Generated %d bytes of XML", len(xmlstr))
	}

	if key != nil {
		p := parser.New(parser.XMLParseDTDLoad | parser.XMLParseDTDAttr | parser.XMLParseNoEnt)
		doc, err := p.ParseString(xmlstr)
		if err != nil {
			return nil, err
		}

		root, err := doc.DocumentElement()
		if err != nil {
			return nil, err
		}

		// Create a new signature section.
		sig, err := dsig.NewSignature(root, dsig.ExclC14N, dsig.RsaSha1, "")
		if err := sig.AddReference(dsig.Sha1, "", "", ""); err != nil {
			return nil, err
		}

		if err := sig.AddTransform(dsig.Enveloped); err != nil {
			return nil, err
		}

		if key.HasRsaKey() == nil || key.HasDsaKey() == nil || key.HasEcdsaKey() == nil {
			if err := sig.AddKeyValue(); err != nil {
				return nil, err
			}
		}

		// If the key is setup using X509, add that node
		if key.HasX509() == nil {
			if err := sig.AddX509Data(); err != nil {
				return nil, err
			}
		}

		if pdebug.Enabled {
			pdebug.Printf("Signing using key %p", key)
		}
		if err := sig.Sign(key); err != nil {
			return nil, err
		}

		xmlstr = doc.Dump(false)
		if err != nil {
			return nil, err
		}
	}

	if !compress {
		return []byte(xmlstr), nil
	}

	buf := bytes.Buffer{}

	w := getFlateWriter()
	defer releaseFlateWriter(w)

	w.Reset(&buf)
	if _, err := io.WriteString(w, xmlstr); err != nil {
		return nil, err
	}

	if err := w.Close(); err != nil {
		return nil, err
	}
	if pdebug.Enabled {
		pdebug.Printf("Compressed to %d bytes", buf.Len())
	}

	ret := make([]byte, b64enc.EncodedLen(buf.Len()))
	b64enc.Encode(ret, buf.Bytes())
	if pdebug.Enabled {
		pdebug.Printf("Encoded into %d bytes of base64", len(ret))
	}

	return ret, nil
}
<|endoftext|>