<commit_before>// Copyright (c) 2013 Mathieu Turcotte
// Licensed under the MIT license.

// This packages implement functions to read the source map format described
// in the "Source Map Revision 3 Proposal" available at http://goo.gl/bcVlcK
package sourcemap

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"sort"
)

const maxEntryValue = 5    // Maximum number of values within a single entry.
const lineSeparator = ';'  // Line separator in the "mappings" field.
const entrySeparator = ',' // Entry separator withing a line in the "mappings" field.

// Represents the mapping to a line/column/name in the original file.
type OriginalMapping struct {
	File   string
	Line   int
	Column int
	Name   string
}

// A struct into which the source map data is unmarshalled.
type SourceMap struct {
	Version        int
	File           string
	SourceRoot     string
	Sources        []string
	SourcesContent []string
	Names          []string
	Mappings       Mappings
}

// Given a line and a column number in the generated code, find a mapping in
// the original source. The line and column parameters are 1-based. If no
// mapping can be found for a given line, a mapping on the previous line is
// returned.
func (s *SourceMap) GetSourceMapping(linum, column int) (mapping OriginalMapping, err error) {
	linum--
	column--

	if linum < 0 || linum > len(s.Mappings.Lines) {
		err = fmt.Errorf("invalid line number: %v", linum+1)
		return
	}

	if column < 0 {
		err = fmt.Errorf("invalid column number: %v", column+1)
		return
	}

	line := s.Mappings.Lines[linum]

	if len(line) == 0 || line[0].GeneratedColumn > column {
		return s.getPreviousLineMapping(linum)
	}

	index := sort.Search(len(line), func(i int) bool {
		return line[i].GeneratedColumn <= column
	})

	entry := line[index]
	s.populateMapping(&mapping, entry)

	return
}

func (s *SourceMap) getPreviousLineMapping(linum int) (mapping OriginalMapping, err error) {
	for {
		linum--

		if linum < 0 {
			err = fmt.Errorf("cannot find previous line mapping")
			return
		}

		line := s.Mappings.Lines[linum]

		if len(line) > 0 {
			entry := line[len(line)-1]
			s.populateMapping(&mapping, entry)
			return
		}
	}
}

func (s *SourceMap) populateMapping(mapping *OriginalMapping, entry Entry) {
	mapping.File = s.Sources[entry.SourceFileId]
	mapping.Line = entry.SourceLine + 1
	mapping.Column = entry.SourceColumn + 1

	if entry.NameId >= 0 {
		mapping.Name = s.Names[entry.NameId]
	}
}

// Represents a section of the generated source that can be mapped back to the
// original source.
type Entry struct {
	GeneratedColumn int // 0-based column of this entry in the generated source.
	SourceFileId    int // Index of the source file in the "sources" list.
	SourceLine      int // 0-based line number of this entry in the source file.
	SourceColumn    int // 0-based column number of this entry in the source file.
	NameId          int // Index of the symbol name in the "names" list.
}

// Represents a line in the generated source. A line is composed of entries
// containing information about the original source file.
type Line []Entry

// The parsed representation of a source map mapping. Slots in the lines slice
// will be null if the line does not have any entries.
type Mappings struct {
	Lines []Line
}

// Struct to hold the state while parsing the "mappings" field.
type unmarshalState struct {
	gencol int // 0-based index of the generated column.
	source int // 0-based index into the "sources" list.
	line   int // 0-based starting line in the original source.
	column int // 0-based starting column of the line in the source.
	name   int // 0-based index into the "names" list.
}

func (m *Mappings) UnmarshalJSON(data []byte) error {
	m.Lines = make([]Line, 0, 256)

	// Instead of splitting the input string into multiple
	reader := bytes.NewReader(data)

	state := unmarshalState{}
	line := make(Line, 0, 10)
	for reader.Len() > 0 {
		if consume(reader, lineSeparator) {
			m.Lines = append(m.Lines, line)
			line = make(Line, 0, 10)
			state.gencol = 0
		} else {
			i := 0
			var values [maxEntryValue]int
			for !entryCompleted(reader) {
				if val, err := decodeVQL(reader); err != nil {
					return err
				} else {
					values[i] = val
					i++
				}
			}

			entry, err := newEntry(&state, values, i)
			if err != nil {
				return err
			}

			line = append(line, entry)
			consume(reader, entrySeparator)
		}
	}

	return nil
}

func consume(r *bytes.Reader, wanted byte) bool {
	if r.Len() > 0 {
		b, _ := r.ReadByte()
		if b == wanted {
			return true
		}
		r.UnreadByte()
	}
	return false
}

func entryCompleted(r *bytes.Reader) bool {
	if r.Len() > 0 {
		b, _ := r.ReadByte()
		r.UnreadByte()
		return b == lineSeparator || b == entrySeparator
	}
	return true
}

func newEntry(s *unmarshalState, values [maxEntryValue]int,
	numValues int) (e Entry, err error) {
	e = Entry{-1, -1, -1, -1, -1}

	switch numValues {
	case 1:
		// Unmapped section of the generated file.
		e.GeneratedColumn = values[0] + s.gencol
		s.gencol = e.GeneratedColumn
	case 4:
		// Mapped section of the generated file.
		e.GeneratedColumn = values[0] + s.gencol
		e.SourceFileId = values[1] + s.source
		e.SourceLine = values[2] + s.line
		e.SourceColumn = values[3] + s.column
		s.gencol = e.GeneratedColumn
		s.source = e.SourceFileId
		s.line = e.SourceLine
		s.column = e.SourceColumn
	case 5:
		// Mapped section of the generated file with an associated name.
		e.GeneratedColumn = values[0] + s.gencol
		e.SourceFileId = values[1] + s.source
		e.SourceLine = values[2] + s.line
		e.SourceColumn = values[3] + s.column
		e.NameId = values[4] + s.name
		s.gencol = e.GeneratedColumn
		s.source = e.SourceFileId
		s.line = e.SourceLine
		s.column = e.SourceColumn
		s.name = e.NameId
	default:
		err = fmt.Errorf("unexpected number of values in entry: %v", numValues)
	}

	return
}

// Reads a source map.
func Read(reader io.Reader) (s SourceMap, err error) {
	dec := json.NewDecoder(reader)
	if err = dec.Decode(&s); err != nil {
		return
	}

	if s.Version != 3 {
		err = fmt.Errorf("unsupported version: %v", s.Version)
	}

	return
}
<commit_msg>Introduce jsonSourceMap struct to read raw JSON.<commit_after>// Copyright (c) 2013 Mathieu Turcotte
// Licensed under the MIT license.

// This packages implement functions to read the source map format described
// in the "Source Map Revision 3 Proposal" available at http://goo.gl/bcVlcK
package sourcemap

import (
	"encoding/json"
	"fmt"
	"io"
	"sort"
	"strings"
)

const maxEntryValue = 5    // Maximum number of values within a single entry.
const lineSeparator = ';'  // Line separator in the "mappings" field.
const entrySeparator = ',' // Entry separator withing a line in the "mappings" field.

// Represents the mapping to a line/column/name in the original file.
type OriginalMapping struct {
	File   string
	Line   int
	Column int
	Name   string
}

// A struct representing the decoded source map.
type SourceMap struct {
	Version        int
	File           string
	SourceRoot     string
	Sources        []string
	SourcesContent []string
	Names          []string
	Mappings       []Line
}

// A struct into which the source map JSON data is unmarshalled.
type jsonSourceMap struct {
	Version        int
	File           string
	SourceRoot     string
	Sources        []string
	SourcesContent []string
	Names          []string
	Mappings       string
}

// Given a line and a column number in the generated code, find a mapping in
// the original source. The line and column parameters are 1-based. If no
// mapping can be found for a given line, a mapping on the previous line is
// returned.
func (s *SourceMap) GetSourceMapping(linum, column int) (mapping OriginalMapping, err error) {
	linum--
	column--

	if linum < 0 || linum > len(s.Mappings) {
		err = fmt.Errorf("invalid line number: %v", linum+1)
		return
	}

	if column < 0 {
		err = fmt.Errorf("invalid column number: %v", column+1)
		return
	}

	line := s.Mappings[linum]

	if len(line) == 0 || line[0].GeneratedColumn > column {
		return s.getPreviousLineMapping(linum)
	}

	index := sort.Search(len(line), func(i int) bool {
		return line[i].GeneratedColumn <= column
	})

	entry := line[index]
	s.populateMapping(&mapping, entry)

	return
}

func (s *SourceMap) getPreviousLineMapping(linum int) (mapping OriginalMapping, err error) {
	for {
		linum--

		if linum < 0 {
			err = fmt.Errorf("cannot find previous line mapping")
			return
		}

		line := s.Mappings[linum]

		if len(line) > 0 {
			entry := line[len(line)-1]
			s.populateMapping(&mapping, entry)
			return
		}
	}
}

func (s *SourceMap) populateMapping(mapping *OriginalMapping, entry Entry) {
	mapping.File = s.Sources[entry.SourceFileId]
	mapping.Line = entry.SourceLine + 1
	mapping.Column = entry.SourceColumn + 1

	if entry.NameId >= 0 {
		mapping.Name = s.Names[entry.NameId]
	}
}

// Represents a section of the generated source that can be mapped back to the
// original source.
type Entry struct {
	GeneratedColumn int // 0-based column of this entry in the generated source.
	SourceFileId    int // Index of the source file in the "sources" list.
	SourceLine      int // 0-based line number of this entry in the source file.
	SourceColumn    int // 0-based column number of this entry in the source file.
	NameId          int // Index of the symbol name in the "names" list.
}

// Represents a line in the generated source. A line is composed of entries
// containing information about the original source file.
type Line []Entry

// Struct to hold the state while parsing the "mappings" field.
type unmarshalState struct {
	gencol int // 0-based index of the generated column.
	source int // 0-based index into the "sources" list.
	line   int // 0-based starting line in the original source.
	column int // 0-based starting column of the line in the source.
	name   int // 0-based index into the "names" list.
}

func parseMappings(data string) (lines []Line, err error) {
	lines = make([]Line, 0, 256)
	reader := strings.NewReader(data)
	state := unmarshalState{}
	line := make(Line, 0, 10)
	for reader.Len() > 0 {
		if consume(reader, lineSeparator) {
			lines = append(lines, line)
			line = make(Line, 0, 10)
			state.gencol = 0
		} else {
			i := 0
			var values [maxEntryValue]int
			for !entryCompleted(reader) {
				if val, derr := decodeVQL(reader); derr != nil {
					err = derr
					return
				} else {
					values[i] = val
					i++
				}
			}

			entry, eerr := newEntry(&state, values, i)
			if eerr != nil {
				err = eerr
				return
			}

			line = append(line, entry)
			consume(reader, entrySeparator)
		}
	}

	return
}

func consume(r *strings.Reader, wanted byte) bool {
	if r.Len() > 0 {
		b, _ := r.ReadByte()
		if b == wanted {
			return true
		}
		r.UnreadByte()
	}
	return false
}

func entryCompleted(r *strings.Reader) bool {
	if r.Len() > 0 {
		b, _ := r.ReadByte()
		r.UnreadByte()
		return b == lineSeparator || b == entrySeparator
	}
	return true
}

func newEntry(s *unmarshalState, values [maxEntryValue]int,
	numValues int) (e Entry, err error) {
	e = Entry{-1, -1, -1, -1, -1}

	switch numValues {
	case 1:
		// Unmapped section of the generated file.
		e.GeneratedColumn = values[0] + s.gencol
		s.gencol = e.GeneratedColumn
	case 4:
		// Mapped section of the generated file.
		e.GeneratedColumn = values[0] + s.gencol
		e.SourceFileId = values[1] + s.source
		e.SourceLine = values[2] + s.line
		e.SourceColumn = values[3] + s.column
		s.gencol = e.GeneratedColumn
		s.source = e.SourceFileId
		s.line = e.SourceLine
		s.column = e.SourceColumn
	case 5:
		// Mapped section of the generated file with an associated name.
		e.GeneratedColumn = values[0] + s.gencol
		e.SourceFileId = values[1] + s.source
		e.SourceLine = values[2] + s.line
		e.SourceColumn = values[3] + s.column
		e.NameId = values[4] + s.name
		s.gencol = e.GeneratedColumn
		s.source = e.SourceFileId
		s.line = e.SourceLine
		s.column = e.SourceColumn
		s.name = e.NameId
	default:
		err = fmt.Errorf("unexpected number of values in entry: %v", numValues)
	}

	return
}

// Reads a source map.
func Read(reader io.Reader) (s SourceMap, err error) {
	var jsonMap jsonSourceMap
	dec := json.NewDecoder(reader)
	if err = dec.Decode(&jsonMap); err != nil {
		return
	}

	if jsonMap.Version != 3 {
		err = fmt.Errorf("unsupported version: %v", s.Version)
	}

	lines, err := parseMappings(jsonMap.Mappings)
	if err != nil {
		return
	}

	s.Version = jsonMap.Version
	s.File = jsonMap.File
	s.SourceRoot = jsonMap.SourceRoot
	s.Sources = jsonMap.Sources
	s.SourcesContent = jsonMap.SourcesContent
	s.Names = jsonMap.Names
	s.Mappings = lines

	return
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"mime"
	"os"
	"path/filepath"
	"strings"
)

var (
	PrintBase bool
	PrintFull bool
	Paths     []string
)

func init() {
	if helpNeeded() {
		help(1)
	} else if helpWanted() {
		help(0)
	}
	flags()
}

func helpNeeded() bool {
	if noArgs := (len(os.Args) == 1); noArgs {
		return true
	}
	return false
}

func helpWanted() bool {
	switch os.Args[1] {
	case "-h", "h", "help", "--help", "-H", "H", "HELP", "--HELP", "-help", "--h", "--H":
		return true
	}
	return false
}

// Print help and exit with a status code.
func help(status int) {
	defer os.Exit(status)
	fmt.Printf(
		"%s\n\n  %s\n\n  %s\n%s\n\n  %s\n%s\n%s\n%s\n%s\n\n  %s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
		"rmext",
		"Usage: rmext file...",
		"Description:",
		"    Print the basename of files WITHOUT their extension.",
		"Options:",
		"   -b         Print the basename of files without their path",
		"   -f         Print the full path of files",
		"   (default)  Print the path of files exactly as they were entered",
		"                (minus any file extensions)",
		"Notes:",
		"    This program relies on the system's list of known mimetypes.",
		"	 On Linux, usually the file '/etc/mime.types' stores all",
		"      MIME types known by the system.",
		"	 On Windows, the registry mess stores them.",
		"    In rare cases, the system may not have a mime entry for an",
		"      uncommon file type, and this program will not remove the",
		"      extension associated with that file type.",
		"    An example is '.go' files; Linux distributions usually do not",
		"      include a mime type for '.go' files by default (yet).",
	)
}

func flags() {
	flag.BoolVar(&PrintBase, "b", false, "")
	flag.BoolVar(&PrintFull, "f", false, "")
	flag.Parse()

	// Modify global variables based on commandline arguments.
	Paths = os.Args[1:]
	if PrintBase && PrintFull {
		help(1)
	}
	if !PrintBase && !PrintFull {
		return
	}
	bools := []string{"-b", "-f"}
	Paths = filter(Paths, bools...)
	if len(Paths) == 0 {
		help(1)
	}
	return
}

// Remove elements in a slice (if they exist).
// Only remove EXACT matches.
func filter(slc []string, args ...string) (filtered []string) {
	for _, s := range slc {
		if slcHas(slc, s) {
			continue
		}
		filtered = append(filtered, s)
	}
	return
}

// Check whether a slice contains a string.
// Only return true if an element in the slice EXACTLY matches the string.
// If testing for more than one string,
//   return true if ANY of them match an element in the slice.
func slcHas(slc []string, args ...string) bool {
	for _, s := range slc {
		for _, a := range args {
			if s == a {
				return true
			}
		}
	}
	return false
}

func main() {
	defer os.Exit(0)
	var err error
	for _, t := range Paths {
		switch {
		case PrintBase:
			t = filepath.Base(t)
		case PrintFull:
			t, err = filepath.Abs(t)
			chkerr(err)
		}
		base, _ := splitExt(t)
		fmt.Println(base)
	}
}

// Exit with status 1 if an error occurs.
func chkerr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Split the extension off a filename.
// Return the basename and the extension.
func splitExt(filename string) (base, ext string) {
	base = filepath.Clean(filename)
	for {
		testext := filepath.Ext(base)
		if testext == "" || mime.TypeByExtension(testext) == "" {
			return
		}
		ext = concat(testext, ext)
		base = strings.TrimSuffix(base, testext)
	}
}

// Concatenate strings.
func concat(slc ...string) string {
	b := bytes.NewBuffer(nil)
	defer b.Reset()
	for _, s := range slc {
		b.WriteString(s)
	}
	return b.String()
}
<commit_msg>More cleanup<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"mime"
	"os"
	"path/filepath"
	"strings"
)

var (
	PrintBase bool
	PrintFull bool
	Paths     []string
)

func init() {

	if helpNeeded() {
		help(1)
	} else if helpWanted() {
		help(0)
	}

	flags()

	if !validArgs() {
		help(1)
	}
}

func helpNeeded() bool {
	if noArgs := (len(os.Args) == 1); noArgs {
		return true
	}
	return false
}

func helpWanted() bool {
	switch os.Args[1] {
	case "-h", "h", "help", "--help", "-H", "H", "HELP", "--HELP", "-help", "--h", "--H":
		return true
	}
	return false
}

// Print help and exit with a status code.
func help(status int) {
	defer os.Exit(status)
	fmt.Printf(
		"%s\n\n  %s\n\n  %s\n%s\n\n  %s\n%s\n%s\n%s\n%s\n\n  %s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
		"rmext",
		"Usage: rmext file...",
		"Description:",
		"    Print the basename of files WITHOUT their extension.",
		"Options:",
		"   -b         Print the basename of files without their path",
		"   -f         Print the full path of files",
		"   (default)  Print the path of files exactly as they were entered",
		"                (minus any file extensions)",
		"Notes:",
		"    This program relies on the system's list of known mimetypes.",
		"	 On Linux, usually the file '/etc/mime.types' stores all",
		"      MIME types known by the system.",
		"	 On Windows, the registry mess stores them.",
		"    In rare cases, the system may not have a mime entry for an",
		"      uncommon file type, and this program will not remove the",
		"      extension associated with that file type.",
		"    An example is '.go' files; Linux distributions usually do not",
		"      include a mime type for '.go' files by default (yet).",
	)
}

func flags() {

	bools := []string{"-b", "-f"}

	flag.BoolVar(&PrintBase, "b", false, "")
	flag.BoolVar(&PrintFull, "f", false, "")
	flag.Parse()

	Paths = os.Args[1:]
	Paths = filter(Paths, bools...)
}

func validArgs() bool {

	if PrintBase && PrintFull {
		return false
	}

	if len(Paths) == 0 {
		return false
	}

	return true
}

// Remove elements in a slice (if they exist).
// Only remove EXACT matches.
func filter(slc []string, args ...string) (filtered []string) {
	for _, s := range slc {
		if slcHas(slc, s) {
			continue
		}
		filtered = append(filtered, s)
	}
	return
}

// Check whether a slice contains a string.
// Only return true if an element in the slice EXACTLY matches the string.
// If testing for more than one string,
//   return true if ANY of them match an element in the slice.
func slcHas(slc []string, args ...string) bool {
	for _, s := range slc {
		for _, a := range args {
			if s == a {
				return true
			}
		}
	}
	return false
}

func main() {
	defer os.Exit(0)
	var err error
	for _, t := range Paths {
		switch {
		case PrintBase:
			t = filepath.Base(t)
		case PrintFull:
			t, err = filepath.Abs(t)
			chkerr(err)
		}
		base, _ := splitExt(t)
		fmt.Println(base)
	}
}

// Exit with status 1 if an error occurs.
func chkerr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Split the extension off a filename.
// Return the basename and the extension.
func splitExt(filename string) (base, ext string) {
	base = filepath.Clean(filename)
	for {
		testext := filepath.Ext(base)
		if testext == "" || mime.TypeByExtension(testext) == "" {
			return
		}
		ext = concat(testext, ext)
		base = strings.TrimSuffix(base, testext)
	}
}

// Concatenate strings.
func concat(slc ...string) string {
	b := bytes.NewBuffer(nil)
	defer b.Reset()
	for _, s := range slc {
		b.WriteString(s)
	}
	return b.String()
}
<|endoftext|>


<commit_before>package gobot

import (
	"fmt"
	"math/rand"
	"reflect"
	"time"
)

type Robot struct {
	Connections   []interface{}
	Devices       []interface{}
	Name          string
	Commands      map[string]interface{} `json:"-"`
	RobotCommands []string               `json:"Commands"`
	Work          func()                 `json:"-"`
	connections   []*Connection          `json:"-"`
	devices       []*Device              `json:"-"`
}

func (r *Robot) Start() {
	r.initName()
	r.initCommands()
	r.initConnections()
	r.initDevices()
	r.startConnections()
	r.startDevices()
	r.Work()
	select {}
}

func (r *Robot) initName() {
	if r.Name == "" {
		rand.Seed(time.Now().UTC().UnixNano())
		i := rand.Int()
		r.Name = fmt.Sprintf("Robot %v", i)
	}
}

func (r *Robot) initCommands() {
	for k, _ := range r.Commands {
		r.RobotCommands = append(r.RobotCommands, k)
	}
}

func (r *Robot) initConnections() {
	r.connections = make([]*Connection, len(r.Connections))
	fmt.Println("Initializing connections...")
	for i := range r.Connections {
		fmt.Println("Initializing connection " + reflect.ValueOf(r.Connections[i]).Elem().FieldByName("Name").String() + "...")
		r.connections[i] = NewConnection(r.Connections[i], r)
	}
}

func (r *Robot) initDevices() {
	r.devices = make([]*Device, len(r.Devices))
	fmt.Println("Initializing devices...")
	for i := range r.Devices {
		fmt.Println("Initializing device " + reflect.ValueOf(r.Devices[i]).Elem().FieldByName("Name").String() + "...")
		r.devices[i] = NewDevice(r.Devices[i], r)
	}
}

func (r *Robot) startConnections() {
	fmt.Println("Starting connections...")
	for i := range r.connections {
		fmt.Println("Starting connection " + r.connections[i].Name + "...")
		r.connections[i].Connect()
	}
}

func (r *Robot) startDevices() {
	fmt.Println("Starting devices...")
	for i := range r.devices {
		fmt.Println("Starting device " + r.devices[i].Name + "...")
		r.devices[i].Start()
	}
}

func (r *Robot) GetDevices() []*Device {
	return r.devices
}

func (r *Robot) GetDevice(name string) *Device {
	for i := range r.devices {
		if r.devices[i].Name == name {
			return r.devices[i]
		}
	}
	return nil
}
<commit_msg>Work is optional<commit_after>package gobot

import (
	"fmt"
	"math/rand"
	"reflect"
	"time"
)

type Robot struct {
	Connections   []interface{}
	Devices       []interface{}
	Name          string
	Commands      map[string]interface{} `json:"-"`
	RobotCommands []string               `json:"Commands"`
	Work          func()                 `json:"-"`
	connections   []*Connection          `json:"-"`
	devices       []*Device              `json:"-"`
}

func (r *Robot) Start() {
	r.initName()
	r.initCommands()
	r.initConnections()
	r.initDevices()
	r.startConnections()
	r.startDevices()
	if r.Work != nil {
		r.Work()
	}
	select {}
}

func (r *Robot) initName() {
	if r.Name == "" {
		rand.Seed(time.Now().UTC().UnixNano())
		i := rand.Int()
		r.Name = fmt.Sprintf("Robot %v", i)
	}
}

func (r *Robot) initCommands() {
	for k, _ := range r.Commands {
		r.RobotCommands = append(r.RobotCommands, k)
	}
}

func (r *Robot) initConnections() {
	r.connections = make([]*Connection, len(r.Connections))
	fmt.Println("Initializing connections...")
	for i := range r.Connections {
		fmt.Println("Initializing connection " + reflect.ValueOf(r.Connections[i]).Elem().FieldByName("Name").String() + "...")
		r.connections[i] = NewConnection(r.Connections[i], r)
	}
}

func (r *Robot) initDevices() {
	r.devices = make([]*Device, len(r.Devices))
	fmt.Println("Initializing devices...")
	for i := range r.Devices {
		fmt.Println("Initializing device " + reflect.ValueOf(r.Devices[i]).Elem().FieldByName("Name").String() + "...")
		r.devices[i] = NewDevice(r.Devices[i], r)
	}
}

func (r *Robot) startConnections() {
	fmt.Println("Starting connections...")
	for i := range r.connections {
		fmt.Println("Starting connection " + r.connections[i].Name + "...")
		r.connections[i].Connect()
	}
}

func (r *Robot) startDevices() {
	fmt.Println("Starting devices...")
	for i := range r.devices {
		fmt.Println("Starting device " + r.devices[i].Name + "...")
		r.devices[i].Start()
	}
}

func (r *Robot) GetDevices() []*Device {
	return r.devices
}

func (r *Robot) GetDevice(name string) *Device {
	for i := range r.devices {
		if r.devices[i].Name == name {
			return r.devices[i]
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package gobot

import (
	"fmt"
	"log"
	"os"
	"os/signal"

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

// JSONRobot a JSON representation of a Robot.
type JSONRobot struct {
	Name        string            `json:"name"`
	Commands    []string          `json:"commands"`
	Connections []*JSONConnection `json:"connections"`
	Devices     []*JSONDevice     `json:"devices"`
}

// NewJSONRobot returns a JSONRobot given a Robot.
func NewJSONRobot(robot *Robot) *JSONRobot {
	jsonRobot := &JSONRobot{
		Name:        robot.Name,
		Commands:    []string{},
		Connections: []*JSONConnection{},
		Devices:     []*JSONDevice{},
	}

	for command := range robot.Commands() {
		jsonRobot.Commands = append(jsonRobot.Commands, command)
	}

	robot.Devices().Each(func(device Device) {
		jsonDevice := NewJSONDevice(device)
		jsonRobot.Connections = append(jsonRobot.Connections, NewJSONConnection(robot.Connection(jsonDevice.Connection)))
		jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice)
	})
	return jsonRobot
}

// Robot is a named entity that manages a collection of connections and devices.
// It contains its own work routine and a collection of
// custom commands to control a robot remotely via the Gobot api.
type Robot struct {
	Name        string
	Work        func()
	connections *Connections
	devices     *Devices
	trap        func(chan os.Signal)
	AutoRun     bool
	done        chan bool
	Commander
	Eventer
}

// Robots is a collection of Robot
type Robots []*Robot

// Len returns the amount of Robots in the collection.
func (r *Robots) Len() int {
	return len(*r)
}

// Start calls the Start method of each Robot in the collection
func (r *Robots) Start(args ...interface{}) (err error) {
	autoRun := true
	if args[0] != nil {
		autoRun = args[0].(bool)
	}
	for _, robot := range *r {
		if rerr := robot.Start(autoRun); rerr != nil {
			err = multierror.Append(err, rerr)
			return
		}
	}
	return
}

// Stop calls the Stop method of each Robot in the collection
func (r *Robots) Stop() (err error) {
	for _, robot := range *r {
		if rerr := robot.Stop(); rerr != nil {
			err = multierror.Append(err, rerr)
			return
		}
	}
	return
}

// Each enumerates through the Robots and calls specified callback function.
func (r *Robots) Each(f func(*Robot)) {
	for _, robot := range *r {
		f(robot)
	}
}

// NewRobot returns a new Robot given optional accepts:
//
// 	[]Connection: Connections which are automatically started and stopped with the robot
//	[]Device: Devices which are automatically started and stopped with the robot
//	func(): The work routine the robot will execute once all devices and connections have been initialized and started
// A name will be automaically generated if no name is supplied.
func NewRobot(v ...interface{}) *Robot {
	r := &Robot{
		Name:        fmt.Sprintf("%X", Rand(int(^uint(0)>>1))),
		connections: &Connections{},
		devices:     &Devices{},
		done:        make(chan bool, 1),
		trap: func(c chan os.Signal) {
			signal.Notify(c, os.Interrupt)
		},
		AutoRun:   true,
		Work:      nil,
		Eventer:   NewEventer(),
		Commander: NewCommander(),
	}

	for i := range v {
		switch v[i].(type) {
		case string:
			r.Name = v[i].(string)
		case []Connection:
			log.Println("Initializing connections...")
			for _, connection := range v[i].([]Connection) {
				c := r.AddConnection(connection)
				log.Println("Initializing connection", c.Name(), "...")
			}
		case []Device:
			log.Println("Initializing devices...")
			for _, device := range v[i].([]Device) {
				d := r.AddDevice(device)
				log.Println("Initializing device", d.Name(), "...")
			}
		case func():
			r.Work = v[i].(func())
		}
	}

	log.Println("Robot", r.Name, "initialized.")

	return r
}

// Start a Robot's Connections, Devices, and work.
func (r *Robot) Start(args ...interface{}) (err error) {
	if len(args) > 0 && args[0] != nil {
		r.AutoRun = args[0].(bool)
	}
	log.Println("Starting Robot", r.Name, "...")
	if cerr := r.Connections().Start(); cerr != nil {
		err = multierror.Append(err, cerr)
		return
	}
	if derr := r.Devices().Start(); derr != nil {
		err = multierror.Append(err, derr)
		return
	}
	if r.Work == nil {
		r.Work = func() {}
	}

	log.Println("Starting work...")
	go func() {
		r.Work()
		<-r.done
	}()

	if r.AutoRun {
		c := make(chan os.Signal, 1)
		r.trap(c)
		if err != nil {
			// there was an error during start, so we immediately pass the interrupt
			// in order to disconnect the initialized robots, connections and devices
			c <- os.Interrupt
		}

		// waiting for interrupt coming on the channel
		<-c

		// Stop calls the Stop method on itself, if we are "auto-running".
		r.Stop()
	}

	return
}

// Stop stops a Robot's connections and Devices
func (r *Robot) Stop() error {
	var result error
	log.Println("Stopping Robot", r.Name, "...")
	err := r.Devices().Halt()
	if err != nil {
		result = multierror.Append(result, err)
	}
	err = r.Connections().Finalize()
	if err != nil {
		result = multierror.Append(result, err)
	}

	r.done <- true
	return result
}

// Devices returns all devices associated with this Robot.
func (r *Robot) Devices() *Devices {
	return r.devices
}

// AddDevice adds a new Device to the robots collection of devices. Returns the
// added device.
func (r *Robot) AddDevice(d Device) Device {
	*r.devices = append(*r.Devices(), d)
	return d
}

// Device returns a device given a name. Returns nil if the Device does not exist.
func (r *Robot) Device(name string) Device {
	if r == nil {
		return nil
	}
	for _, device := range *r.devices {
		if device.Name() == name {
			return device
		}
	}
	return nil
}

// Connections returns all connections associated with this robot.
func (r *Robot) Connections() *Connections {
	return r.connections
}

// AddConnection adds a new connection to the robots collection of connections.
// Returns the added connection.
func (r *Robot) AddConnection(c Connection) Connection {
	*r.connections = append(*r.Connections(), c)
	return c
}

// Connection returns a connection given a name. Returns nil if the Connection
// does not exist.
func (r *Robot) Connection(name string) Connection {
	if r == nil {
		return nil
	}
	for _, connection := range *r.connections {
		if connection.Name() == name {
			return connection
		}
	}
	return nil
}
<commit_msg>docs: update params info for Robot<commit_after>package gobot

import (
	"fmt"
	"log"
	"os"
	"os/signal"

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

// JSONRobot a JSON representation of a Robot.
type JSONRobot struct {
	Name        string            `json:"name"`
	Commands    []string          `json:"commands"`
	Connections []*JSONConnection `json:"connections"`
	Devices     []*JSONDevice     `json:"devices"`
}

// NewJSONRobot returns a JSONRobot given a Robot.
func NewJSONRobot(robot *Robot) *JSONRobot {
	jsonRobot := &JSONRobot{
		Name:        robot.Name,
		Commands:    []string{},
		Connections: []*JSONConnection{},
		Devices:     []*JSONDevice{},
	}

	for command := range robot.Commands() {
		jsonRobot.Commands = append(jsonRobot.Commands, command)
	}

	robot.Devices().Each(func(device Device) {
		jsonDevice := NewJSONDevice(device)
		jsonRobot.Connections = append(jsonRobot.Connections, NewJSONConnection(robot.Connection(jsonDevice.Connection)))
		jsonRobot.Devices = append(jsonRobot.Devices, jsonDevice)
	})
	return jsonRobot
}

// Robot is a named entity that manages a collection of connections and devices.
// It contains its own work routine and a collection of
// custom commands to control a robot remotely via the Gobot api.
type Robot struct {
	Name        string
	Work        func()
	connections *Connections
	devices     *Devices
	trap        func(chan os.Signal)
	AutoRun     bool
	done        chan bool
	Commander
	Eventer
}

// Robots is a collection of Robot
type Robots []*Robot

// Len returns the amount of Robots in the collection.
func (r *Robots) Len() int {
	return len(*r)
}

// Start calls the Start method of each Robot in the collection
func (r *Robots) Start(args ...interface{}) (err error) {
	autoRun := true
	if args[0] != nil {
		autoRun = args[0].(bool)
	}
	for _, robot := range *r {
		if rerr := robot.Start(autoRun); rerr != nil {
			err = multierror.Append(err, rerr)
			return
		}
	}
	return
}

// Stop calls the Stop method of each Robot in the collection
func (r *Robots) Stop() (err error) {
	for _, robot := range *r {
		if rerr := robot.Stop(); rerr != nil {
			err = multierror.Append(err, rerr)
			return
		}
	}
	return
}

// Each enumerates through the Robots and calls specified callback function.
func (r *Robots) Each(f func(*Robot)) {
	for _, robot := range *r {
		f(robot)
	}
}

// NewRobot returns a new Robot. It supports the following optional params:
//
//		name:	string with the name of the Robot. A name will be automatically generated if no name is supplied.
// 	[]Connection: Connections which are automatically started and stopped with the robot
//		[]Device: Devices which are automatically started and stopped with the robot
//		func(): The work routine the robot will execute once all devices and connections have been initialized and started
//
func NewRobot(v ...interface{}) *Robot {
	r := &Robot{
		Name:        fmt.Sprintf("%X", Rand(int(^uint(0)>>1))),
		connections: &Connections{},
		devices:     &Devices{},
		done:        make(chan bool, 1),
		trap: func(c chan os.Signal) {
			signal.Notify(c, os.Interrupt)
		},
		AutoRun:   true,
		Work:      nil,
		Eventer:   NewEventer(),
		Commander: NewCommander(),
	}

	for i := range v {
		switch v[i].(type) {
		case string:
			r.Name = v[i].(string)
		case []Connection:
			log.Println("Initializing connections...")
			for _, connection := range v[i].([]Connection) {
				c := r.AddConnection(connection)
				log.Println("Initializing connection", c.Name(), "...")
			}
		case []Device:
			log.Println("Initializing devices...")
			for _, device := range v[i].([]Device) {
				d := r.AddDevice(device)
				log.Println("Initializing device", d.Name(), "...")
			}
		case func():
			r.Work = v[i].(func())
		}
	}

	log.Println("Robot", r.Name, "initialized.")

	return r
}

// Start a Robot's Connections, Devices, and work.
func (r *Robot) Start(args ...interface{}) (err error) {
	if len(args) > 0 && args[0] != nil {
		r.AutoRun = args[0].(bool)
	}
	log.Println("Starting Robot", r.Name, "...")
	if cerr := r.Connections().Start(); cerr != nil {
		err = multierror.Append(err, cerr)
		return
	}
	if derr := r.Devices().Start(); derr != nil {
		err = multierror.Append(err, derr)
		return
	}
	if r.Work == nil {
		r.Work = func() {}
	}

	log.Println("Starting work...")
	go func() {
		r.Work()
		<-r.done
	}()

	if r.AutoRun {
		c := make(chan os.Signal, 1)
		r.trap(c)
		if err != nil {
			// there was an error during start, so we immediately pass the interrupt
			// in order to disconnect the initialized robots, connections and devices
			c <- os.Interrupt
		}

		// waiting for interrupt coming on the channel
		<-c

		// Stop calls the Stop method on itself, if we are "auto-running".
		r.Stop()
	}

	return
}

// Stop stops a Robot's connections and Devices
func (r *Robot) Stop() error {
	var result error
	log.Println("Stopping Robot", r.Name, "...")
	err := r.Devices().Halt()
	if err != nil {
		result = multierror.Append(result, err)
	}
	err = r.Connections().Finalize()
	if err != nil {
		result = multierror.Append(result, err)
	}

	r.done <- true
	return result
}

// Devices returns all devices associated with this Robot.
func (r *Robot) Devices() *Devices {
	return r.devices
}

// AddDevice adds a new Device to the robots collection of devices. Returns the
// added device.
func (r *Robot) AddDevice(d Device) Device {
	*r.devices = append(*r.Devices(), d)
	return d
}

// Device returns a device given a name. Returns nil if the Device does not exist.
func (r *Robot) Device(name string) Device {
	if r == nil {
		return nil
	}
	for _, device := range *r.devices {
		if device.Name() == name {
			return device
		}
	}
	return nil
}

// Connections returns all connections associated with this robot.
func (r *Robot) Connections() *Connections {
	return r.connections
}

// AddConnection adds a new connection to the robots collection of connections.
// Returns the added connection.
func (r *Robot) AddConnection(c Connection) Connection {
	*r.connections = append(*r.Connections(), c)
	return c
}

// Connection returns a connection given a name. Returns nil if the Connection
// does not exist.
func (r *Robot) Connection(name string) Connection {
	if r == nil {
		return nil
	}
	for _, connection := range *r.connections {
		if connection.Name() == name {
			return connection
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package victor

import (
    "regexp"
    "log"
)

type RobotAdapter interface {
    Hear(string, func(*TextMessage))
    Respond(string, func(*TextMessage))
    Run()
}

type Robot struct {
    name      string
    options   map[string]string
    adapter   RobotAdapter
    listeners []*Listener
    users     []*User
}

func NewRobot(adapter string, options map[string]string) RobotAdapter {
    name := "robot"

    if _, exists := options["name"]; exists {
       name = options["name"]
    }

    robot := &Robot{
       name: name,
       options: options,
       listeners: make([]*Listener, 0, 1),
    }

    var aRobot RobotAdapter

    if adapter == "shell" {
        aRobot = &Shell{Robot: robot}
    } else if adapter == "campfire" {
        aRobot = &Campfire{Robot: robot}
    } else {
        panic("Unknown adapter.")
    }

    return aRobot
}

func (self *Robot) Hear(expStr string, callback func(*TextMessage)) {
    exp, _ := regexp.Compile(expStr)
    self.listeners = append(self.listeners, NewListener(exp, callback))
}

func (self *Robot) Respond(expStr string, callback func(*TextMessage)) {
    expWithNameStr := "(" + self.name + "[:,]?)\\s*(?:" + expStr + ")"
    exp, _         := regexp.Compile(expWithNameStr)

    self.listeners = append(self.listeners, NewListener(exp, callback))
}

func (self *Robot) Receive(msg *TextMessage) {
   for _, listener := range self.listeners {
     if listener.Test(msg) {
        log.Printf("Listener /%s/ triggered by '%s'", listener.Exp.String(), msg.Body)
        listener.Callback(msg)
     }
   }
}

func (self *Robot) RememberUser(user *User) {
    self.users = append(self.users, user)
}

func (self *Robot) UserForId(id int) *User {
    for _, user := range self.users {
        if user.Id == id {
            return user
        }
    }

    return nil
}

func (self *Robot) Shutdown() {
    log.Print("See ya!")
}
<commit_msg>Style<commit_after>package victor

import (
    "regexp"
    "log"
)

type RobotAdapter interface {
    Hear(string, func(*TextMessage))
    Respond(string, func(*TextMessage))
    Run()
}

type Robot struct {
    name      string
    options   map[string]string
    adapter   RobotAdapter
    listeners []*Listener
    users     []*User
}

func NewRobot(adapter string, options map[string]string) RobotAdapter {
    name := "robot"

    if _, exists := options["name"]; exists {
        name = options["name"]
    }

    robot := &Robot{
        name: name,
        options: options,
        listeners: make([]*Listener, 0, 1),
    }

    var aRobot RobotAdapter

    if adapter == "shell" {
        aRobot = &Shell{Robot: robot}
    } else if adapter == "campfire" {
        aRobot = &Campfire{Robot: robot}
    } else {
        panic("Unknown adapter.")
    }

    return aRobot
}

func (self *Robot) Hear(expStr string, callback func(*TextMessage)) {
    exp, _ := regexp.Compile(expStr)
    self.listeners = append(self.listeners, NewListener(exp, callback))
}

func (self *Robot) Respond(expStr string, callback func(*TextMessage)) {
    expWithNameStr := "(" + self.name + "[:,]?)\\s*(?:" + expStr + ")"
    exp, _         := regexp.Compile(expWithNameStr)

    self.listeners = append(self.listeners, NewListener(exp, callback))
}

func (self *Robot) Receive(msg *TextMessage) {
    for _, listener := range self.listeners {
            if listener.Test(msg) {
                log.Printf("Listener /%s/ triggered by '%s'", listener.Exp.String(), msg.Body)
                listener.Callback(msg)
            }
    }
}

func (self *Robot) RememberUser(user *User) {
    self.users = append(self.users, user)
}

func (self *Robot) UserForId(id int) *User {
    for _, user := range self.users {
        if user.Id == id {
            return user
        }
    }

    return nil
}

func (self *Robot) Shutdown() {
    log.Print("See ya!")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/iambc/xerrors"
)

type writermock struct {
}

func (db *writermock) getBoards(apiKey string) (currBoards []boards, err error) {
    if apiKey == `err` {
	return currBoards, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }

    currBoards = append(currBoards, boards{Id:1, Name:"Mock Board"})
    return currBoards, nil
}

func (db *writermock) getActiveThreadsForBoard(apiKey string, boardId int) (activeThreads []threads, err error) {
    if apiKey == `err` {
	return activeThreads, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    } else if apiKey == `empty` {
	return activeThreads, nil
    }
    activeThreads = append(activeThreads, threads{Id:1, Name:`Mock Thread`})
    return activeThreads, nil

}

func (db *writermock) getPostsForThread(apiKey string, threadId int) (currPosts []thread_posts, err error) {
    if apiKey == `err` {
	return currPosts, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    } else if apiKey == `empty` {
	return currPosts, nil
    }
    currPosts = append(currPosts, thread_posts{})
    return currPosts, nil
}

func (db *writermock) addPostToThread(threadId int, threadBodyPost string, attachmentUrl *string, clientRemoteAddr string) (err error) {
    if threadId == 1 {
	return xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
    return nil
}

func (db *writermock) addThread(boardId int, threadName string) (threads, error) {
    if boardId == 1 {
	return threads{}, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
    return threads{Id: 1, BoardId: boardId, Name: threadName}, nil
}

func (db *writermock) isThreadLimitReached(boardId int) (bool, error) {
    if boardId == 2 {
	return true, nil
    } else if boardId == 3 {
	return false, nil
    } else {
	return false, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
}

func (db *writermock) isPostLimitReached(threadId int) (bool, threads, error) {
    if threadId == 2 {
	return true, threads{Id: threadId, Name: `Mock Thread`}, nil
    } else if threadId == 3 {
	return false, threads{Id: threadId, Name: `Mock Thread`, MinPostLength: 2, MaxPostLength: 4}, nil
    } else {
	return false, threads{Id: threadId, Name: `Mock Thread`}, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
}
<commit_msg>feat: implementes writer interface (again)<commit_after>package main

import (
	"github.com/iambc/xerrors"
)

type writermock struct {
}

func (db *writermock) getBoards(apiKey string) (currBoards []boards, err error) {
    if apiKey == `err` {
	return currBoards, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }

    currBoards = append(currBoards, boards{Id:1, Name:"Mock Board"})
    return currBoards, nil
}

func (db *writermock) getActiveThreadsForBoard(apiKey string, boardId int) (activeThreads []threads, err error) {
    if apiKey == `err` {
	return activeThreads, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    } else if apiKey == `empty` {
	return activeThreads, nil
    }
    activeThreads = append(activeThreads, threads{Id:1, Name:`Mock Thread`})
    return activeThreads, nil

}

func (db *writermock) getPostsForThread(apiKey string, threadId int) (currPosts []thread_posts, err error) {
    if apiKey == `err` {
	return currPosts, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    } else if apiKey == `empty` {
	return currPosts, nil
    }
    currPosts = append(currPosts, thread_posts{})
    return currPosts, nil
}

func (db *writermock) addPostToThread(threadId int, threadBodyPost string, attachmentUrl *string, clientRemoteAddr string) (err error) {
    if threadId == 1 {
	return xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
    return nil
}

func (db *writermock) addThread(boardId int, threadName string) (threads, error) {
    if boardId == 1 {
	return threads{}, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
    return threads{Id: 1, BoardId: boardId, Name: threadName}, nil
}

func (db *writermock) isThreadLimitReached(boardId int) (bool, error) {
    if boardId == 2 {
	return true, nil
    } else if boardId == 3 {
	return false, nil
    } else {
	return false, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
}

func (db *writermock) isPostLimitReached(threadId int) (bool, threads, error) {
    if threadId == 2 {
	return true, threads{Id: threadId, Name: `Mock Thread`}, nil
    } else if threadId == 3 {
	return false, threads{Id: threadId, Name: `Mock Thread`, MinPostLength: 2, MaxPostLength: 4}, nil
    } else {
	return false, threads{Id: threadId, Name: `Mock Thread`}, xerrors.NewUIErr(`test err`, `test err`, `002`, true)
    }
}

func (db *writermock) archiveThread(threadId int){}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"time"

	"github.com/armon/go-metrics"
	"github.com/newrelic-forks/memberlist"
	"github.com/newrelic/bosun/catalog"
	"github.com/newrelic/bosun/service"
	"sync"
)

type servicesDelegate struct {
	state             *catalog.ServicesState
	pendingBroadcasts [][]byte
	notifications     chan []byte
	inProcess         bool
	Metadata          NodeMetadata
	sync.Mutex
}

type NodeMetadata struct {
	ClusterName string
	State       string
}

func NewServicesDelegate(state *catalog.ServicesState) *servicesDelegate {
	delegate := servicesDelegate{
		state:             state,
		pendingBroadcasts: make([][]byte, 0),
		notifications:     make(chan []byte, 25),
		inProcess:         false,
		Metadata:          NodeMetadata{ClusterName: "default"},
	}

	return &delegate
}

func (d *servicesDelegate) NodeMeta(limit int) []byte {
	log.Printf("NodeMeta(): %d\n", limit)
	data, err := json.Marshal(d.Metadata)
	if err != nil {
		log.Println("Error encoding Node metadata!")
		data = []byte("{}")
	}
	return data
}

func (d *servicesDelegate) NotifyMsg(message []byte) {
	defer metrics.MeasureSince([]string{"delegate", "NotifyMsg"}, time.Now())

	if len(message) < 1 {
		log.Println("NotifyMsg(): empty")
		return
	}

	log.Printf("NotifyMsg(): %s\n", string(message))

	// TODO don't just send container structs, send message structs
	d.notifications <- message

	// Lazily kick off goroutine
	d.Lock()
	defer d.Unlock()

	if !d.inProcess {
		go func() {
			for message := range d.notifications {
				entry := service.Decode(message)
				if entry == nil {
					log.Printf("NotifyMsg(): error decoding!\n")
					continue
				}
				d.state.AddServiceEntry(*entry)
			}
		}()
		d.inProcess = true
	}
}

func (d *servicesDelegate) GetBroadcasts(overhead, limit int) [][]byte {
	defer metrics.MeasureSince([]string{"delegate", "GetBroadcasts"}, time.Now())

	log.Printf("GetBroadcasts(): %d %d\n", overhead, limit)

	broadcast := make([][]byte, 0, 1)

	select {
	case broadcast = <-d.state.Broadcasts:
	default:
		if len(d.pendingBroadcasts) < 1 {
			return nil
		}
	}

	// Prefer newest messages (TODO what about tombstones?)
	broadcast = append(broadcast, d.pendingBroadcasts...)
	d.pendingBroadcasts = make([][]byte, 0, 1)

	broadcast, leftover := packPacket(broadcast, limit, overhead)
	if len(leftover) > 0 {
		d.pendingBroadcasts = leftover
	}

	if broadcast == nil || len(broadcast) < 1 {
		log.Println("Note: Not enough space to fit any messages or message was nil")
		return nil
	}

	log.Printf("Sending broadcast %d msgs %d 1st length\n",
		len(broadcast), len(broadcast[0]),
	)
	if len(leftover) > 0 {
		log.Printf("Leaving %d messages unsent\n", len(leftover))
	}

	return broadcast
}

func (d *servicesDelegate) LocalState(join bool) []byte {
	log.Printf("LocalState(): %b\n", join)
	return d.state.Encode()
}

func (d *servicesDelegate) MergeRemoteState(buf []byte, join bool) {
	defer metrics.MeasureSince([]string{"delegate", "MergeRemoteState"}, time.Now())

	log.Printf("MergeRemoteState(): %s %b\n", string(buf), join)

	otherState, err := catalog.Decode(buf)
	if err != nil {
		log.Printf("Failed to MergeRemoteState(): %s", err.Error())
		return
	}

	log.Printf("Merging state: %s", otherState.Format(nil))

	d.state.Merge(otherState)
}

func (d *servicesDelegate) NotifyJoin(node *memberlist.Node) {
	log.Printf("NotifyJoin(): %s %s\n", node.Name, string(node.Meta))
}

func (d *servicesDelegate) NotifyLeave(node *memberlist.Node) {
	log.Printf("NotifyLeave(): %s\n", node.Name)
	go d.state.ExpireServer(node.Name)
}

func (d *servicesDelegate) NotifyUpdate(node *memberlist.Node) {
	log.Printf("NotifyUpdate(): %s\n", node.Name)
}

func packPacket(broadcasts [][]byte, limit int, overhead int) (packet [][]byte, leftover [][]byte) {
	total := 0
	leftover = make([][]byte, 0) // So we don't return unallocated buffer
	for _, message := range broadcasts {
		if total+len(message)+overhead < limit {
			packet = append(packet, message)
			total += len(message) + overhead
		} else {
			leftover = append(leftover, message)
		}
	}

	return packet, leftover
}
<commit_msg>Measure the length of pendingBroadcasts.<commit_after>package main

import (
	"encoding/json"
	"log"
	"time"

	"github.com/armon/go-metrics"
	"github.com/newrelic-forks/memberlist"
	"github.com/newrelic/bosun/catalog"
	"github.com/newrelic/bosun/service"
	"sync"
)

type servicesDelegate struct {
	state             *catalog.ServicesState
	pendingBroadcasts [][]byte
	notifications     chan []byte
	inProcess         bool
	Metadata          NodeMetadata
	sync.Mutex
}

type NodeMetadata struct {
	ClusterName string
	State       string
}

func NewServicesDelegate(state *catalog.ServicesState) *servicesDelegate {
	delegate := servicesDelegate{
		state:             state,
		pendingBroadcasts: make([][]byte, 0),
		notifications:     make(chan []byte, 25),
		inProcess:         false,
		Metadata:          NodeMetadata{ClusterName: "default"},
	}

	return &delegate
}

func (d *servicesDelegate) NodeMeta(limit int) []byte {
	log.Printf("NodeMeta(): %d\n", limit)
	data, err := json.Marshal(d.Metadata)
	if err != nil {
		log.Println("Error encoding Node metadata!")
		data = []byte("{}")
	}
	return data
}

func (d *servicesDelegate) NotifyMsg(message []byte) {
	defer metrics.MeasureSince([]string{"delegate", "NotifyMsg"}, time.Now())

	if len(message) < 1 {
		log.Println("NotifyMsg(): empty")
		return
	}

	log.Printf("NotifyMsg(): %s\n", string(message))

	// TODO don't just send container structs, send message structs
	d.notifications <- message

	// Lazily kick off goroutine
	d.Lock()
	defer d.Unlock()

	if !d.inProcess {
		go func() {
			for message := range d.notifications {
				entry := service.Decode(message)
				if entry == nil {
					log.Printf("NotifyMsg(): error decoding!\n")
					continue
				}
				d.state.AddServiceEntry(*entry)
			}
		}()
		d.inProcess = true
	}
}

func (d *servicesDelegate) GetBroadcasts(overhead, limit int) [][]byte {
	defer metrics.MeasureSince([]string{"delegate", "GetBroadcasts"}, time.Now())
	metrics.SetGauge([]string{"delegate", "pendingBroadcasts"}, float32(len(d.pendingBroadcasts)))

	log.Printf("GetBroadcasts(): %d %d\n", overhead, limit)

	broadcast := make([][]byte, 0, 1)

	select {
	case broadcast = <-d.state.Broadcasts:
	default:
		if len(d.pendingBroadcasts) < 1 {
			return nil
		}
	}

	// Prefer newest messages (TODO what about tombstones?)
	broadcast = append(broadcast, d.pendingBroadcasts...)
	d.pendingBroadcasts = make([][]byte, 0, 1)

	broadcast, leftover := packPacket(broadcast, limit, overhead)
	if len(leftover) > 0 {
		d.pendingBroadcasts = leftover
	}

	if broadcast == nil || len(broadcast) < 1 {
		log.Println("Note: Not enough space to fit any messages or message was nil")
		return nil
	}

	log.Printf("Sending broadcast %d msgs %d 1st length\n",
		len(broadcast), len(broadcast[0]),
	)
	if len(leftover) > 0 {
		log.Printf("Leaving %d messages unsent\n", len(leftover))
	}

	return broadcast
}

func (d *servicesDelegate) LocalState(join bool) []byte {
	log.Printf("LocalState(): %b\n", join)
	return d.state.Encode()
}

func (d *servicesDelegate) MergeRemoteState(buf []byte, join bool) {
	defer metrics.MeasureSince([]string{"delegate", "MergeRemoteState"}, time.Now())

	log.Printf("MergeRemoteState(): %s %b\n", string(buf), join)

	otherState, err := catalog.Decode(buf)
	if err != nil {
		log.Printf("Failed to MergeRemoteState(): %s", err.Error())
		return
	}

	log.Printf("Merging state: %s", otherState.Format(nil))

	d.state.Merge(otherState)
}

func (d *servicesDelegate) NotifyJoin(node *memberlist.Node) {
	log.Printf("NotifyJoin(): %s %s\n", node.Name, string(node.Meta))
}

func (d *servicesDelegate) NotifyLeave(node *memberlist.Node) {
	log.Printf("NotifyLeave(): %s\n", node.Name)
	go d.state.ExpireServer(node.Name)
}

func (d *servicesDelegate) NotifyUpdate(node *memberlist.Node) {
	log.Printf("NotifyUpdate(): %s\n", node.Name)
}

func packPacket(broadcasts [][]byte, limit int, overhead int) (packet [][]byte, leftover [][]byte) {
	total := 0
	leftover = make([][]byte, 0) // So we don't return unallocated buffer
	for _, message := range broadcasts {
		if total+len(message)+overhead < limit {
			packet = append(packet, message)
			total += len(message) + overhead
		} else {
			leftover = append(leftover, message)
		}
	}

	return packet, leftover
}
<|endoftext|>


<commit_before>package shells

import (
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"strings"
)

type PowerShell struct {
	AbstractShell
}

type PsWriter struct {
	bytes.Buffer
}

func psQuote(text string) string {
	// taken from: http://www.robvanderwoude.com/escapechars.php
	text = strings.Replace(text, "`", "``", -1)
	// text = strings.Replace(text, "\0", "`0", -1)
	text = strings.Replace(text, "\a", "`a", -1)
	text = strings.Replace(text, "\b", "`b", -1)
	text = strings.Replace(text, "\f", "^f", -1)
	text = strings.Replace(text, "\r", "`r", -1)
	text = strings.Replace(text, "\n", "`n", -1)
	text = strings.Replace(text, "\t", "^t", -1)
	text = strings.Replace(text, "\v", "^v", -1)
	text = strings.Replace(text, "#", "`#", -1)
	text = strings.Replace(text, "'", "`'", -1)
	text = strings.Replace(text, "\"", "`\"", -1)
	return "\"" + text + "\""
}

func psQuoteVariable(text string) string {
	text = strings.Replace(text, "$", "`$", -1)
	text = psQuote(text)
	return text
}

func (b *PsWriter) Line(text string) {
	b.WriteString(text + "\r\n")
}

func (b *PsWriter) checkErrorLevel() {
	b.Line("if (!$?) { Exit $LASTEXITCODE }")
}

func (b *PsWriter) Command(command string, arguments ...string) {
	list := []string{
		psQuote(command),
	}

	for _, argument := range arguments {
		list = append(list, psQuote(argument))
	}

	b.Line(strings.Join(list, " "))
	b.checkErrorLevel()
}

func (b *PsWriter) Variable(variable common.BuildVariable) {
	b.Line("$env:" + variable.Key + "=" + psQuoteVariable(variable.Value))
}

func (b *PsWriter) IfDirectory(path string) {
	b.Line("if(Test-Path " + psQuote(helpers.ToBackslash(path)) + " -PathType Container) {")
}

func (b *PsWriter) IfFile(path string) {
	b.Line("if(Test-Path " + psQuote(helpers.ToBackslash(path)) + " -PathType Leaf) {")
}

func (b *PsWriter) Else() {
	b.Line("} else {")
}

func (b *PsWriter) EndIf() {
	b.Line("}")
}

func (b *PsWriter) Cd(path string) {
	b.Line("cd " + psQuote(helpers.ToBackslash(path)))
	b.checkErrorLevel()
}

func (b *PsWriter) RmDir(path string) {
	path = psQuote(helpers.ToBackslash(path))
	b.Line("if( (Get-Command -Name Remove-Item2 -Module NTFSSecurity -ErrorAction SilentlyContinue) -and (Test-Path " + path + " -PathType Container) ) {")
	b.Line("Remove-Item2 -Force -Recurse " + path)
	b.Line("} elseif(Test-Path " + path + ") {")
	b.Line("Remove-Item -Force -Recurse " + path)
	b.Line("}")
}

func (b *PsWriter) RmFile(path string) {
	path = psQuote(helpers.ToBackslash(path))
	b.Line("if( (Get-Command -Name Remove-Item2 -Module NTFSSecurity -ErrorAction SilentlyContinue) -and (Test-Path " + path + " -PathType Leaf) ) {")
	b.Line("Remove-Item2 -Force " + path)
	b.Line("} elseif(Test-Path " + path + ") {")
	b.Line("Remove-Item -Force " + path)
	b.Line("}")
}

func (b *PsWriter) Print(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Notice(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Warning(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Error(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) EmptyLine() {
	b.Line("echo \"\"")
}

func (b *PowerShell) GetName() string {
	return "powershell"
}

func (b *PowerShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	w := &PsWriter{}
	w.Line("$ErrorActionPreference = \"Stop\"")
	w.EmptyLine()

	if len(info.Build.Hostname) != 0 {
		w.Line("echo \"Running on $env:computername via " + psQuoteVariable(info.Build.Hostname) + "...\"")
	} else {
		w.Line("echo \"Running on $env:computername...\"")
	}

	w.Line("& {")
	b.GeneratePreBuild(w, info)
	w.Line("}")
	w.checkErrorLevel()

	w.Line("& {")
	b.GenerateCommands(w, info)
	w.Line("}")
	w.checkErrorLevel()

	w.Line("& {")
	b.GeneratePostBuild(w, info)
	w.Line("}")
	w.checkErrorLevel()

	script := common.ShellScript{
		BuildScript: w.String(),
		Command:     "powershell",
		Arguments:   []string{"-noprofile", "-noninteractive", "-executionpolicy", "Bypass", "-command"},
		PassFile:    true,
		Extension:   "ps1",
	}
	return &script, nil
}

func (b *PowerShell) IsDefault() bool {
	return false
}

func init() {
	common.RegisterShell(&PowerShell{})
}
<commit_msg>Fix PowerShell command execution<commit_after>package shells

import (
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"strings"
)

type PowerShell struct {
	AbstractShell
}

type PsWriter struct {
	bytes.Buffer
}

func psQuote(text string) string {
	// taken from: http://www.robvanderwoude.com/escapechars.php
	text = strings.Replace(text, "`", "``", -1)
	// text = strings.Replace(text, "\0", "`0", -1)
	text = strings.Replace(text, "\a", "`a", -1)
	text = strings.Replace(text, "\b", "`b", -1)
	text = strings.Replace(text, "\f", "^f", -1)
	text = strings.Replace(text, "\r", "`r", -1)
	text = strings.Replace(text, "\n", "`n", -1)
	text = strings.Replace(text, "\t", "^t", -1)
	text = strings.Replace(text, "\v", "^v", -1)
	text = strings.Replace(text, "#", "`#", -1)
	text = strings.Replace(text, "'", "`'", -1)
	text = strings.Replace(text, "\"", "`\"", -1)
	return "\"" + text + "\""
}

func psQuoteVariable(text string) string {
	text = strings.Replace(text, "$", "`$", -1)
	text = psQuote(text)
	return text
}

func (b *PsWriter) Line(text string) {
	b.WriteString(text + "\r\n")
}

func (b *PsWriter) checkErrorLevel() {
	b.Line("if (!$?) { Exit $LASTEXITCODE }")
}

func (b *PsWriter) Command(command string, arguments ...string) {
	list := []string{
		psQuote(command),
	}

	for _, argument := range arguments {
		list = append(list, psQuote(argument))
	}

	b.Line("& " + strings.Join(list, " "))
	b.checkErrorLevel()
}

func (b *PsWriter) Variable(variable common.BuildVariable) {
	b.Line("$env:" + variable.Key + "=" + psQuoteVariable(variable.Value))
}

func (b *PsWriter) IfDirectory(path string) {
	b.Line("if(Test-Path " + psQuote(helpers.ToBackslash(path)) + " -PathType Container) {")
}

func (b *PsWriter) IfFile(path string) {
	b.Line("if(Test-Path " + psQuote(helpers.ToBackslash(path)) + " -PathType Leaf) {")
}

func (b *PsWriter) Else() {
	b.Line("} else {")
}

func (b *PsWriter) EndIf() {
	b.Line("}")
}

func (b *PsWriter) Cd(path string) {
	b.Line("cd " + psQuote(helpers.ToBackslash(path)))
	b.checkErrorLevel()
}

func (b *PsWriter) RmDir(path string) {
	path = psQuote(helpers.ToBackslash(path))
	b.Line("if( (Get-Command -Name Remove-Item2 -Module NTFSSecurity -ErrorAction SilentlyContinue) -and (Test-Path " + path + " -PathType Container) ) {")
	b.Line("Remove-Item2 -Force -Recurse " + path)
	b.Line("} elseif(Test-Path " + path + ") {")
	b.Line("Remove-Item -Force -Recurse " + path)
	b.Line("}")
}

func (b *PsWriter) RmFile(path string) {
	path = psQuote(helpers.ToBackslash(path))
	b.Line("if( (Get-Command -Name Remove-Item2 -Module NTFSSecurity -ErrorAction SilentlyContinue) -and (Test-Path " + path + " -PathType Leaf) ) {")
	b.Line("Remove-Item2 -Force " + path)
	b.Line("} elseif(Test-Path " + path + ") {")
	b.Line("Remove-Item -Force " + path)
	b.Line("}")
}

func (b *PsWriter) Print(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Notice(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Warning(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) Error(format string, arguments ...interface{}) {
	coloredText := fmt.Sprintf(format, arguments...)
	b.Line("echo " + psQuoteVariable(coloredText))
}

func (b *PsWriter) EmptyLine() {
	b.Line("echo \"\"")
}

func (b *PowerShell) GetName() string {
	return "powershell"
}

func (b *PowerShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	w := &PsWriter{}
	w.Line("$ErrorActionPreference = \"Stop\"")
	w.EmptyLine()

	if len(info.Build.Hostname) != 0 {
		w.Line("echo \"Running on $env:computername via " + psQuoteVariable(info.Build.Hostname) + "...\"")
	} else {
		w.Line("echo \"Running on $env:computername...\"")
	}

	w.Line("& {")
	b.GeneratePreBuild(w, info)
	w.Line("}")
	w.checkErrorLevel()

	w.Line("& {")
	b.GenerateCommands(w, info)
	w.Line("}")
	w.checkErrorLevel()

	w.Line("& {")
	b.GeneratePostBuild(w, info)
	w.Line("}")
	w.checkErrorLevel()

	script := common.ShellScript{
		BuildScript: w.String(),
		Command:     "powershell",
		Arguments:   []string{"-noprofile", "-noninteractive", "-executionpolicy", "Bypass", "-command"},
		PassFile:    true,
		Extension:   "ps1",
	}
	return &script, nil
}

func (b *PowerShell) IsDefault() bool {
	return false
}

func init() {
	common.RegisterShell(&PowerShell{})
}
<|endoftext|>


<commit_before>package shells

import (
	"bufio"
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"io"
	"strings"
)

type PowerShell struct {
	AbstractShell
}

func (b *PowerShell) GetName() string {
	return "powershell"
}

func (b *PowerShell) writeCommand(w io.Writer, format string, args ...interface{}) {
	io.WriteString(w, fmt.Sprintf(format, args...)+"\r\n")
}

func (b *PowerShell) writeCommandChecked(w io.Writer, format string, args ...interface{}) {
	b.writeCommand(w, format, args...)
	b.writeCommand(w, "%s", "if (!$?) { Exit $LASTEXITCODE }")
}

func (b *PowerShell) writeCloneCmd(w io.Writer, build *common.Build, dir string) {
	b.writeCommand(w, "echo \"Cloning repository...\"")
	b.writeCommand(w, "$NTFSSecurityRemoveItem2 = Get-Command Remove-Item2 -ErrorAction SilentlyContinue")
	b.writeCommand(w, "$HasNTFSSecurityRemoveItem2 = ($NTFSSecurityRemoveItem2 -ne $null) -and ($NTFSSecurityRemoveItem2.ModuleName -eq \"NTFSSecurity\")")
	b.writeCommand(w, "if($HasNTFSSecurityRemoveItem2 -and Test-Path \"%s\") {", dir)
	b.writeCommandChecked(w, "Remove-Item2 -Force -Recurse \"%s\"", dir)
	b.writeCommand(w, "} elseif(Test-Path \"%s\") {")
	b.writeCommandChecked(w, "Remove-Item -Force -Recurse \"%s\"", dir)
	b.writeCommand(w, "}")
	b.writeCommandChecked(w, "(Test-Path \"%s\") -or (New-Item \"%s\" -ItemType \"directory\" )", dir, dir)
	b.writeCommandChecked(w, "git clone \"%s\" \"%s\"", build.RepoURL, dir)
	b.writeCommandChecked(w, "cd \"%s\"", dir)
}

func (b *PowerShell) writeFetchCmd(w io.Writer, build *common.Build, dir string) {
	b.writeCommand(w, "if(Test-Path \"%s\\.git\") {", dir)
	b.writeCommand(w, "echo \"Fetching changes...\"")
	b.writeCommandChecked(w, "cd \"%s\"", dir)
	b.writeCommandChecked(w, "git clean -ffdx")
	b.writeCommandChecked(w, "git reset --hard > $null")
	b.writeCommandChecked(w, "git remote set-url origin \"%s\"", build.RepoURL)
	b.writeCommandChecked(w, "git fetch origin --tags -p")
	b.writeCommand(w, "} else {")
	b.writeCloneCmd(w, build, dir)
	b.writeCommand(w, "}")
}

func (b *PowerShell) writeCheckoutCmd(w io.Writer, build *common.Build) {
	b.writeCommand(w, "echo \"Checking out %s as %s...\"", build.Sha[0:8], build.RefName)
	b.writeCommandChecked(w, "git checkout -qf \"%s\"", build.Sha)
}

func (b *PowerShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	build := info.Build
	projectDir := build.FullProjectDir()
	projectDir = helpers.ToBackslash(projectDir)

	b.writeCommand(w, "$ErrorActionPreference = \"Stop\"")

	if len(build.Hostname) != 0 {
		b.writeCommand(w, "echo \"Running on $env:computername via %s...\"", helpers.ShellEscape(build.Hostname))
	} else {
		b.writeCommand(w, "echo \"Running on $env:computername...\"")
	}
	b.writeCommand(w, "")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)
	b.writeCommand(w, "")

	for _, command := range strings.Split(build.Commands, "\n") {
		command = strings.TrimRight(command, " \t\r\n")
		if strings.TrimSpace(command) == "" {
			b.writeCommand(w, "echo \"\"")
			continue
		}

		if !helpers.BoolOrDefault(build.Runner.DisableVerbose, false) {
			b.writeCommand(w, "echo \"%s\"", command)
		}
		b.writeCommandChecked(w, "%s", command)
	}

	w.Flush()

	script := common.ShellScript{
		Environment: b.GetVariables(build, projectDir, info.Environment),
		Script:      buffer.String(),
		Command:     "powershell",
		Arguments:   []string{"-noprofile", "-noninteractive", "-executionpolicy", "Bypass", "-command"},
		PassFile:    true,
		Extension:   "ps1",
	}
	return &script, nil
}

func (b *PowerShell) IsDefault() bool {
	return false
}

func init() {
	common.RegisterShell(&PowerShell{})
}
<commit_msg>fix: %!s(missing) in generated Powershell script<commit_after>package shells

import (
	"bufio"
	"bytes"
	"fmt"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"io"
	"strings"
)

type PowerShell struct {
	AbstractShell
}

func (b *PowerShell) GetName() string {
	return "powershell"
}

func (b *PowerShell) writeCommand(w io.Writer, format string, args ...interface{}) {
	io.WriteString(w, fmt.Sprintf(format, args...)+"\r\n")
}

func (b *PowerShell) writeCommandChecked(w io.Writer, format string, args ...interface{}) {
	b.writeCommand(w, format, args...)
	b.writeCommand(w, "%s", "if (!$?) { Exit $LASTEXITCODE }")
}

func (b *PowerShell) writeCloneCmd(w io.Writer, build *common.Build, dir string) {
	b.writeCommand(w, "echo \"Cloning repository...\"")
	b.writeCommand(w, "$NTFSSecurityRemoveItem2 = Get-Command Remove-Item2 -ErrorAction SilentlyContinue")
	b.writeCommand(w, "$HasNTFSSecurityRemoveItem2 = ($NTFSSecurityRemoveItem2 -ne $null) -and ($NTFSSecurityRemoveItem2.ModuleName -eq \"NTFSSecurity\")")
	b.writeCommand(w, "if($HasNTFSSecurityRemoveItem2 -and Test-Path \"%s\") {", dir)
	b.writeCommandChecked(w, "Remove-Item2 -Force -Recurse \"%s\"", dir)
	b.writeCommand(w, "} elseif(Test-Path \"%s\") {", dir)
	b.writeCommandChecked(w, "Remove-Item -Force -Recurse \"%s\"", dir)
	b.writeCommand(w, "}")
	b.writeCommandChecked(w, "(Test-Path \"%s\") -or (New-Item \"%s\" -ItemType \"directory\" )", dir, dir)
	b.writeCommandChecked(w, "git clone \"%s\" \"%s\"", build.RepoURL, dir)
	b.writeCommandChecked(w, "cd \"%s\"", dir)
}

func (b *PowerShell) writeFetchCmd(w io.Writer, build *common.Build, dir string) {
	b.writeCommand(w, "if(Test-Path \"%s\\.git\") {", dir)
	b.writeCommand(w, "echo \"Fetching changes...\"")
	b.writeCommandChecked(w, "cd \"%s\"", dir)
	b.writeCommandChecked(w, "git clean -ffdx")
	b.writeCommandChecked(w, "git reset --hard > $null")
	b.writeCommandChecked(w, "git remote set-url origin \"%s\"", build.RepoURL)
	b.writeCommandChecked(w, "git fetch origin --tags -p")
	b.writeCommand(w, "} else {")
	b.writeCloneCmd(w, build, dir)
	b.writeCommand(w, "}")
}

func (b *PowerShell) writeCheckoutCmd(w io.Writer, build *common.Build) {
	b.writeCommand(w, "echo \"Checking out %s as %s...\"", build.Sha[0:8], build.RefName)
	b.writeCommandChecked(w, "git checkout -qf \"%s\"", build.Sha)
}

func (b *PowerShell) GenerateScript(info common.ShellScriptInfo) (*common.ShellScript, error) {
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)

	build := info.Build
	projectDir := build.FullProjectDir()
	projectDir = helpers.ToBackslash(projectDir)

	b.writeCommand(w, "$ErrorActionPreference = \"Stop\"")

	if len(build.Hostname) != 0 {
		b.writeCommand(w, "echo \"Running on $env:computername via %s...\"", helpers.ShellEscape(build.Hostname))
	} else {
		b.writeCommand(w, "echo \"Running on $env:computername...\"")
	}
	b.writeCommand(w, "")

	if build.AllowGitFetch {
		b.writeFetchCmd(w, build, projectDir)
	} else {
		b.writeCloneCmd(w, build, projectDir)
	}

	b.writeCheckoutCmd(w, build)
	b.writeCommand(w, "")

	for _, command := range strings.Split(build.Commands, "\n") {
		command = strings.TrimRight(command, " \t\r\n")
		if strings.TrimSpace(command) == "" {
			b.writeCommand(w, "echo \"\"")
			continue
		}

		if !helpers.BoolOrDefault(build.Runner.DisableVerbose, false) {
			b.writeCommand(w, "echo \"%s\"", command)
		}
		b.writeCommandChecked(w, "%s", command)
	}

	w.Flush()

	script := common.ShellScript{
		Environment: b.GetVariables(build, projectDir, info.Environment),
		Script:      buffer.String(),
		Command:     "powershell",
		Arguments:   []string{"-noprofile", "-noninteractive", "-executionpolicy", "Bypass", "-command"},
		PassFile:    true,
		Extension:   "ps1",
	}
	return &script, nil
}

func (b *PowerShell) IsDefault() bool {
	return false
}

func init() {
	common.RegisterShell(&PowerShell{})
}
<|endoftext|>


<commit_before>package sqlc

import (
	"reflect"
	"runtime"
	"strings"
	"testing"
)

func TestBasicComposition(t *testing.T) {
	s := Statement{}
	// These statements are deliberately out of order
	s = s.Group("role").Order("id").Limit("30")
	s = s.Where("name = 'Marge'")
	s = s.Select("*").From("Employees")

	sql, args := s.ToSQL()
	expect(t, args, make([]interface{}, 0))
	expect(t, sql, strings.TrimSpace(`
SELECT *
FROM Employees
WHERE (name = 'Marge')
GROUP BY role
ORDER BY id
LIMIT 30
  `))
}

func TestArgumentComposition(t *testing.T) {
	s := Statement{}
	s = s.Where("name = ?", "Marge").Where("role = ?", "Comptroller")
	sql, args := s.ToSQL()
	expect(t, args, []interface{}{"Marge", "Comptroller"})
	expect(t, sql, strings.TrimSpace("WHERE (name = ?) AND (role = ?)"))

	// PostgreSQL argument composition
	s.PostgreSQL = true
	sql, _ = s.ToSQL()
	expect(t, sql, strings.TrimSpace("WHERE (name = $1) AND (role = $2)"))
}

/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
	if !reflect.DeepEqual(a, b) {
		_, _, line, _ := runtime.Caller(1)
		t.Errorf("line %d: Got %#v, expected %#v", line, a, b)
	}
}
<commit_msg>Test immutability.<commit_after>package sqlc

import (
	"reflect"
	"runtime"
	"strings"
	"testing"
)

func TestBasicComposition(t *testing.T) {
	s := Statement{}
	// These statements are deliberately out of order
	s = s.Group("role").Order("id").Limit("30")
	s = s.Where("name = 'Marge'")
	s = s.Select("*").From("Employees")

	sql, args := s.ToSQL()
	expect(t, args, make([]interface{}, 0))
	expect(t, sql, strings.TrimSpace(`
SELECT *
FROM Employees
WHERE (name = 'Marge')
GROUP BY role
ORDER BY id
LIMIT 30
  `))
}

func TestArgumentComposition(t *testing.T) {
	s := Statement{}
	s = s.Where("name = ?", "Marge").Where("role = ?", "Comptroller")
	sql, args := s.ToSQL()
	expect(t, args, []interface{}{"Marge", "Comptroller"})
	expect(t, sql, strings.TrimSpace("WHERE (name = ?) AND (role = ?)"))

	// PostgreSQL argument composition
	s.PostgreSQL = true
	sql, _ = s.ToSQL()
	expect(t, sql, strings.TrimSpace("WHERE (name = $1) AND (role = $2)"))
}

func TestImmutability(t *testing.T) {
	orig := Statement{}
	orig = orig.Select("apples")
	sql, _ := orig.ToSQL()
	expect(t, sql, strings.TrimSpace("SELECT apples"))

	modified := orig.Select("oranges")
	sql, _ = modified.ToSQL()
	expect(t, sql, strings.TrimSpace("SELECT apples, oranges"))

	sql, _ = orig.ToSQL()
	expect(t, sql, strings.TrimSpace("SELECT apples"))
}

/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
	if !reflect.DeepEqual(a, b) {
		_, _, line, _ := runtime.Caller(1)
		t.Errorf("line %d: Got %#v, expected %#v", line, a, b)
	}
}
<|endoftext|>


<commit_before>// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// 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.

//go:build !wasm
// +build !wasm

package fulltext

import (
	"strings"

	"github.com/blevesearch/bleve/v2"
	"github.com/blevesearch/bleve/v2/mapping"
	"github.com/matrix-org/gomatrixserverlib"

	"github.com/matrix-org/dendrite/setup/config"
)

// Search contains all existing bleve.Index
type Search struct {
	FulltextIndex bleve.Index
}

// IndexElement describes the layout of an element to index
type IndexElement struct {
	EventID        string
	RoomID         string
	Content        string
	ContentType    string
	StreamPosition int64
}

// SetContentType sets i.ContentType given an identifier
func (i *IndexElement) SetContentType(v string) {
	switch v {
	case "m.room.message":
		i.ContentType = "content.body"
	case gomatrixserverlib.MRoomName:
		i.ContentType = "content.name"
	case gomatrixserverlib.MRoomTopic:
		i.ContentType = "content.topic"
	}
}

// New opens a new/existing fulltext index
func New(cfg config.Fulltext) (fts *Search, err error) {
	fts = &Search{}
	fts.FulltextIndex, err = openIndex(cfg)
	if err != nil {
		return nil, err
	}
	return fts, nil
}

// Close closes the fulltext index
func (f *Search) Close() error {
	return f.FulltextIndex.Close()
}

// Index indexes the given elements
func (f *Search) Index(elements ...IndexElement) error {
	batch := f.FulltextIndex.NewBatch()

	for _, element := range elements {
		err := batch.Index(element.EventID, element)
		if err != nil {
			return err
		}
	}
	return f.FulltextIndex.Batch(batch)
}

// Delete deletes an indexed element by the eventID
func (f *Search) Delete(eventID string) error {
	return f.FulltextIndex.Delete(eventID)
}

// Search searches the index given a search term, roomIDs and keys.
func (f *Search) Search(term string, roomIDs, keys []string, limit, from int, orderByStreamPos bool) (*bleve.SearchResult, error) {
	qry := bleve.NewConjunctionQuery()
	termQuery := bleve.NewBooleanQuery()

	terms := strings.Split(term, " ")
	for _, term := range terms {
		matchQuery := bleve.NewMatchQuery(term)
		matchQuery.SetField("Content")
		termQuery.AddMust(matchQuery)
	}
	qry.AddQuery(termQuery)

	roomQuery := bleve.NewBooleanQuery()
	for _, roomID := range roomIDs {
		roomSearch := bleve.NewMatchQuery(roomID)
		roomSearch.SetField("RoomID")
		roomQuery.AddShould(roomSearch)
	}
	if len(roomIDs) > 0 {
		qry.AddQuery(roomQuery)
	}
	keyQuery := bleve.NewBooleanQuery()
	for _, key := range keys {
		keySearch := bleve.NewMatchQuery(key)
		keySearch.SetField("ContentType")
		keyQuery.AddShould(keySearch)
	}
	if len(keys) > 0 {
		qry.AddQuery(keyQuery)
	}

	s := bleve.NewSearchRequestOptions(qry, limit, from, false)
	s.Fields = []string{"*"}
	s.SortBy([]string{"_score"})
	if orderByStreamPos {
		s.SortBy([]string{"-StreamPosition"})
	}

	return f.FulltextIndex.Search(s)
}

func openIndex(cfg config.Fulltext) (bleve.Index, error) {
	m := getMapping(cfg)
	if cfg.InMemory {
		return bleve.NewMemOnly(m)
	}
	if index, err := bleve.Open(string(cfg.IndexPath)); err == nil {
		return index, nil
	}

	index, err := bleve.New(string(cfg.IndexPath), m)
	if err != nil {
		return nil, err
	}
	return index, nil
}

func getMapping(cfg config.Fulltext) *mapping.IndexMappingImpl {
	enFieldMapping := bleve.NewTextFieldMapping()
	enFieldMapping.Analyzer = cfg.Language

	eventMapping := bleve.NewDocumentMapping()
	eventMapping.AddFieldMappingsAt("Content", enFieldMapping)
	eventMapping.AddFieldMappingsAt("StreamPosition", bleve.NewNumericFieldMapping())

	// Index entries as is
	idFieldMapping := bleve.NewKeywordFieldMapping()
	eventMapping.AddFieldMappingsAt("ContentType", idFieldMapping)
	eventMapping.AddFieldMappingsAt("RoomID", idFieldMapping)
	eventMapping.AddFieldMappingsAt("EventID", idFieldMapping)

	indexMapping := bleve.NewIndexMapping()
	indexMapping.AddDocumentMapping("Event", eventMapping)
	indexMapping.DefaultType = "Event"
	return indexMapping
}
<commit_msg>Side effect import bleve analyzer languages (#2763)<commit_after>// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// 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.

//go:build !wasm
// +build !wasm

package fulltext

import (
	"strings"

	"github.com/blevesearch/bleve/v2"

	// side effect imports to allow all possible languages
	_ "github.com/blevesearch/bleve/v2/analysis/lang/ar"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/cjk"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/ckb"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/da"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/de"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/en"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/es"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/fa"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/fi"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/fr"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/hi"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/hr"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/hu"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/it"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/nl"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/no"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/pt"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/ro"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/ru"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/sv"
	_ "github.com/blevesearch/bleve/v2/analysis/lang/tr"
	"github.com/blevesearch/bleve/v2/mapping"
	"github.com/matrix-org/gomatrixserverlib"

	"github.com/matrix-org/dendrite/setup/config"
)

// Search contains all existing bleve.Index
type Search struct {
	FulltextIndex bleve.Index
}

// IndexElement describes the layout of an element to index
type IndexElement struct {
	EventID        string
	RoomID         string
	Content        string
	ContentType    string
	StreamPosition int64
}

// SetContentType sets i.ContentType given an identifier
func (i *IndexElement) SetContentType(v string) {
	switch v {
	case "m.room.message":
		i.ContentType = "content.body"
	case gomatrixserverlib.MRoomName:
		i.ContentType = "content.name"
	case gomatrixserverlib.MRoomTopic:
		i.ContentType = "content.topic"
	}
}

// New opens a new/existing fulltext index
func New(cfg config.Fulltext) (fts *Search, err error) {
	fts = &Search{}
	fts.FulltextIndex, err = openIndex(cfg)
	if err != nil {
		return nil, err
	}
	return fts, nil
}

// Close closes the fulltext index
func (f *Search) Close() error {
	return f.FulltextIndex.Close()
}

// Index indexes the given elements
func (f *Search) Index(elements ...IndexElement) error {
	batch := f.FulltextIndex.NewBatch()

	for _, element := range elements {
		err := batch.Index(element.EventID, element)
		if err != nil {
			return err
		}
	}
	return f.FulltextIndex.Batch(batch)
}

// Delete deletes an indexed element by the eventID
func (f *Search) Delete(eventID string) error {
	return f.FulltextIndex.Delete(eventID)
}

// Search searches the index given a search term, roomIDs and keys.
func (f *Search) Search(term string, roomIDs, keys []string, limit, from int, orderByStreamPos bool) (*bleve.SearchResult, error) {
	qry := bleve.NewConjunctionQuery()
	termQuery := bleve.NewBooleanQuery()

	terms := strings.Split(term, " ")
	for _, term := range terms {
		matchQuery := bleve.NewMatchQuery(term)
		matchQuery.SetField("Content")
		termQuery.AddMust(matchQuery)
	}
	qry.AddQuery(termQuery)

	roomQuery := bleve.NewBooleanQuery()
	for _, roomID := range roomIDs {
		roomSearch := bleve.NewMatchQuery(roomID)
		roomSearch.SetField("RoomID")
		roomQuery.AddShould(roomSearch)
	}
	if len(roomIDs) > 0 {
		qry.AddQuery(roomQuery)
	}
	keyQuery := bleve.NewBooleanQuery()
	for _, key := range keys {
		keySearch := bleve.NewMatchQuery(key)
		keySearch.SetField("ContentType")
		keyQuery.AddShould(keySearch)
	}
	if len(keys) > 0 {
		qry.AddQuery(keyQuery)
	}

	s := bleve.NewSearchRequestOptions(qry, limit, from, false)
	s.Fields = []string{"*"}
	s.SortBy([]string{"_score"})
	if orderByStreamPos {
		s.SortBy([]string{"-StreamPosition"})
	}

	return f.FulltextIndex.Search(s)
}

func openIndex(cfg config.Fulltext) (bleve.Index, error) {
	m := getMapping(cfg)
	if cfg.InMemory {
		return bleve.NewMemOnly(m)
	}
	if index, err := bleve.Open(string(cfg.IndexPath)); err == nil {
		return index, nil
	}

	index, err := bleve.New(string(cfg.IndexPath), m)
	if err != nil {
		return nil, err
	}
	return index, nil
}

func getMapping(cfg config.Fulltext) *mapping.IndexMappingImpl {
	enFieldMapping := bleve.NewTextFieldMapping()
	enFieldMapping.Analyzer = cfg.Language

	eventMapping := bleve.NewDocumentMapping()
	eventMapping.AddFieldMappingsAt("Content", enFieldMapping)
	eventMapping.AddFieldMappingsAt("StreamPosition", bleve.NewNumericFieldMapping())

	// Index entries as is
	idFieldMapping := bleve.NewKeywordFieldMapping()
	eventMapping.AddFieldMappingsAt("ContentType", idFieldMapping)
	eventMapping.AddFieldMappingsAt("RoomID", idFieldMapping)
	eventMapping.AddFieldMappingsAt("EventID", idFieldMapping)

	indexMapping := bleve.NewIndexMapping()
	indexMapping.AddDocumentMapping("Event", eventMapping)
	indexMapping.DefaultType = "Event"
	return indexMapping
}
<|endoftext|>