<commit_before>package commands

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"unicode"

	"github.com/ipfs/go-ipfs/core/commands/e"

	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	mhash "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
	cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
	verifcid "gx/ipfs/QmVkMRSkXrpjqrroEXWuYBvDBnXCdMMY6gsKicBGVGUqKT/go-verifcid"
	cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
	mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
)

var CidCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Convert and discover properties of CIDs",
	},
	Subcommands: map[string]*cmds.Command{
		"format": cidFmtCmd,
		"base32": base32Cmd,
		"bases":  basesCmd,
		"codecs": codecsCmd,
		"hashes": hashesCmd,
	},
}

var cidFmtCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Format and convert a CID in various useful ways.",
		LongDescription: `
Format and converts <cid>'s in various useful ways.

The optional format string is a printf style format string:
` + cidutil.FormatRef,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("cid", true, true, "Cids to format.").EnableStdin(),
	},
	Options: []cmdkit.Option{
		cmdkit.StringOption("f", "Printf style format string.").WithDefault("%s"),
		cmdkit.StringOption("v", "CID version to convert to."),
		cmdkit.StringOption("b", "Multibase to display CID in."),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		fmtStr, _ := req.Options["f"].(string)
		verStr, _ := req.Options["v"].(string)
		baseStr, _ := req.Options["b"].(string)

		opts := cidFormatOpts{}

		if strings.IndexByte(fmtStr, '%') == -1 {
			return fmt.Errorf("invalid format string: %s", fmtStr)
		}
		opts.fmtStr = fmtStr

		switch verStr {
		case "":
			// noop
		case "0":
			opts.verConv = toCidV0
		case "1":
			opts.verConv = toCidV1
		default:
			return fmt.Errorf("invalid cid version: %s", verStr)
		}

		if baseStr != "" {
			encoder, err := mbase.EncoderByName(baseStr)
			if err != nil {
				return err
			}
			opts.newBase = encoder.Encoding()
		} else {
			opts.newBase = mbase.Encoding(-1)
		}

		return emitCids(req, resp, opts)
	},
	PostRun: cmds.PostRunMap{
		cmds.CLI: streamResults(func(v interface{}, out io.Writer) nonFatalError {
			r := v.(*CidFormatRes)
			if r.ErrorMsg != "" {
				return nonFatalError(fmt.Sprintf("%s: %s", r.CidStr, r.ErrorMsg))
			}
			fmt.Fprintf(out, "%s\n", r.Formatted)
			return ""
		}),
	},
	Type: CidFormatRes{},
}

type CidFormatRes struct {
	CidStr    string // Original Cid String passed in
	Formatted string // Formated Result
	ErrorMsg  string // Error
}

var base32Cmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Convert CIDs to Base32 CID version 1.",
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("cid", true, true, "Cids to convert.").EnableStdin(),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		opts := cidFormatOpts{
			fmtStr:  "%s",
			newBase: mbase.Encoding(mbase.Base32),
			verConv: toCidV1,
		}
		return emitCids(req, resp, opts)
	},
	PostRun: cidFmtCmd.PostRun,
	Type:    cidFmtCmd.Type,
}

type cidFormatOpts struct {
	fmtStr  string
	newBase mbase.Encoding
	verConv func(cid cid.Cid) (cid.Cid, error)
}

type argumentIterator struct {
	args []string
	body cmds.StdinArguments
}

func (i *argumentIterator) next() (string, bool) {
	if len(i.args) > 0 {
		arg := i.args[0]
		i.args = i.args[1:]
		return arg, true
	}
	if i.body == nil || !i.body.Scan() {
		return "", false
	}
	return strings.TrimSpace(i.body.Argument()), true
}

func (i *argumentIterator) err() error {
	if i.body == nil {
		return nil
	}
	return i.body.Err()
}

func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts) error {
	itr := argumentIterator{req.Arguments, req.BodyArgs()}
	for {
		cidStr, ok := itr.next()
		if !ok {
			break
		}
		emit := func(fmtd string, err error) {
			res := &CidFormatRes{CidStr: cidStr, Formatted: fmtd}
			if err != nil {
				res.ErrorMsg = err.Error()
			}
			resp.Emit(res)
		}
		c, err := cid.Decode(cidStr)
		if err != nil {
			emit("", err)
			continue
		}
		base := opts.newBase
		if base == -1 {
			base, _ = cid.ExtractEncoding(cidStr)
		}
		if opts.verConv != nil {
			c, err = opts.verConv(c)
			if err != nil {
				emit("", err)
				continue
			}
		}
		str, err := cidutil.Format(opts.fmtStr, base, c)
		if _, ok := err.(cidutil.FormatStringError); ok {
			// no point in continuing if there is a problem with the format string
			return err
		}
		emit(str, err)
	}
	err := itr.err()
	if err != nil {
		return err
	}
	return nil
}

func toCidV0(c cid.Cid) (cid.Cid, error) {
	if c.Type() != cid.DagProtobuf {
		return cid.Cid{}, fmt.Errorf("can't convert non-protobuf nodes to cidv0")
	}
	return cid.NewCidV0(c.Hash()), nil
}

func toCidV1(c cid.Cid) (cid.Cid, error) {
	return cid.NewCidV1(c.Type(), c.Hash()), nil
}

type CodeAndName struct {
	Code int
	Name string
}

var basesCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available multibase encodings.",
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("prefix", "also include the single leter prefixes in addition to the code"),
		cmdkit.BoolOption("numeric", "also include numeric codes"),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use EncodingToStr in case at some point there are multiple names for a given code
		for code, name := range mbase.EncodingToStr {
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
			prefixes, _ := req.Options["prefix"].(bool)
			numeric, _ := req.Options["numeric"].(bool)
			val, ok := val0.([]CodeAndName)
			if !ok {
				return e.TypeErr(val, val0)
			}
			sort.Sort(multibaseSorter{val})
			for _, v := range val {
				code := v.Code
				if code < 32 || code >= 127 {
					// don't display non-printable prefixes
					code = ' '
				}
				switch {
				case prefixes && numeric:
					fmt.Fprintf(w, "%c %5d  %s\n", code, v.Code, v.Name)
				case prefixes:
					fmt.Fprintf(w, "%c  %s\n", code, v.Name)
				case numeric:
					fmt.Fprintf(w, "%5d  %s\n", v.Code, v.Name)
				default:
					fmt.Fprintf(w, "%s\n", v.Name)
				}
			}
			return nil
		}),
	},
	Type: []CodeAndName{},
}

var codecsCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available CID codecs.",
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("numeric", "also include numeric codes"),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use CodecToStr as there are multiple names for a given code
		for code, name := range cid.CodecToStr {
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
			numeric, _ := req.Options["numeric"].(bool)
			val, ok := val0.([]CodeAndName)
			if !ok {
				return e.TypeErr(val, val0)
			}
			sort.Sort(codeAndNameSorter{val})
			for _, v := range val {
				if numeric {
					fmt.Fprintf(w, "%5d  %s\n", v.Code, v.Name)
				} else {
					fmt.Fprintf(w, "%s\n", v.Name)
				}
			}
			return nil
		}),
	},
	Type: []CodeAndName{},
}

var hashesCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available multihashes.",
	},
	Options: codecsCmd.Options,
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use mhash.Codes in case at some point there are multiple names for a given code
		for code, name := range mhash.Codes {
			if !verifcid.IsGoodHash(code) {
				continue
			}
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: codecsCmd.Encoders,
	Type:     codecsCmd.Type,
}

type multibaseSorter struct {
	data []CodeAndName
}

func (s multibaseSorter) Len() int      { return len(s.data) }
func (s multibaseSorter) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }

func (s multibaseSorter) Less(i, j int) bool {
	a := unicode.ToLower(rune(s.data[i].Code))
	b := unicode.ToLower(rune(s.data[j].Code))
	if a != b {
		return a < b
	}
	// lowecase letters should come before uppercase
	return s.data[i].Code > s.data[j].Code
}

type codeAndNameSorter struct {
	data []CodeAndName
}

func (s codeAndNameSorter) Len() int           { return len(s.data) }
func (s codeAndNameSorter) Swap(i, j int)      { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (s codeAndNameSorter) Less(i, j int) bool { return s.data[i].Code < s.data[j].Code }
<commit_msg>Eliminate `emit` closure, so something with errors on call to emit.<commit_after>package commands

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"unicode"

	"github.com/ipfs/go-ipfs/core/commands/e"

	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	mhash "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
	cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
	verifcid "gx/ipfs/QmVkMRSkXrpjqrroEXWuYBvDBnXCdMMY6gsKicBGVGUqKT/go-verifcid"
	cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
	mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
)

var CidCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Convert and discover properties of CIDs",
	},
	Subcommands: map[string]*cmds.Command{
		"format": cidFmtCmd,
		"base32": base32Cmd,
		"bases":  basesCmd,
		"codecs": codecsCmd,
		"hashes": hashesCmd,
	},
}

var cidFmtCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Format and convert a CID in various useful ways.",
		LongDescription: `
Format and converts <cid>'s in various useful ways.

The optional format string is a printf style format string:
` + cidutil.FormatRef,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("cid", true, true, "Cids to format.").EnableStdin(),
	},
	Options: []cmdkit.Option{
		cmdkit.StringOption("f", "Printf style format string.").WithDefault("%s"),
		cmdkit.StringOption("v", "CID version to convert to."),
		cmdkit.StringOption("b", "Multibase to display CID in."),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		fmtStr, _ := req.Options["f"].(string)
		verStr, _ := req.Options["v"].(string)
		baseStr, _ := req.Options["b"].(string)

		opts := cidFormatOpts{}

		if strings.IndexByte(fmtStr, '%') == -1 {
			return fmt.Errorf("invalid format string: %s", fmtStr)
		}
		opts.fmtStr = fmtStr

		switch verStr {
		case "":
			// noop
		case "0":
			opts.verConv = toCidV0
		case "1":
			opts.verConv = toCidV1
		default:
			return fmt.Errorf("invalid cid version: %s", verStr)
		}

		if baseStr != "" {
			encoder, err := mbase.EncoderByName(baseStr)
			if err != nil {
				return err
			}
			opts.newBase = encoder.Encoding()
		} else {
			opts.newBase = mbase.Encoding(-1)
		}

		return emitCids(req, resp, opts)
	},
	PostRun: cmds.PostRunMap{
		cmds.CLI: streamResults(func(v interface{}, out io.Writer) nonFatalError {
			r := v.(*CidFormatRes)
			if r.ErrorMsg != "" {
				return nonFatalError(fmt.Sprintf("%s: %s", r.CidStr, r.ErrorMsg))
			}
			fmt.Fprintf(out, "%s\n", r.Formatted)
			return ""
		}),
	},
	Type: CidFormatRes{},
}

type CidFormatRes struct {
	CidStr    string // Original Cid String passed in
	Formatted string // Formated Result
	ErrorMsg  string // Error
}

var base32Cmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Convert CIDs to Base32 CID version 1.",
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("cid", true, true, "Cids to convert.").EnableStdin(),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		opts := cidFormatOpts{
			fmtStr:  "%s",
			newBase: mbase.Encoding(mbase.Base32),
			verConv: toCidV1,
		}
		return emitCids(req, resp, opts)
	},
	PostRun: cidFmtCmd.PostRun,
	Type:    cidFmtCmd.Type,
}

type cidFormatOpts struct {
	fmtStr  string
	newBase mbase.Encoding
	verConv func(cid cid.Cid) (cid.Cid, error)
}

type argumentIterator struct {
	args []string
	body cmds.StdinArguments
}

func (i *argumentIterator) next() (string, bool) {
	if len(i.args) > 0 {
		arg := i.args[0]
		i.args = i.args[1:]
		return arg, true
	}
	if i.body == nil || !i.body.Scan() {
		return "", false
	}
	return strings.TrimSpace(i.body.Argument()), true
}

func (i *argumentIterator) err() error {
	if i.body == nil {
		return nil
	}
	return i.body.Err()
}

func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts) error {
	itr := argumentIterator{req.Arguments, req.BodyArgs()}
	var emitErr error
	for emitErr == nil {
		cidStr, ok := itr.next()
		if !ok {
			break
		}
		res := &CidFormatRes{CidStr: cidStr}
		c, err := cid.Decode(cidStr)
		if err != nil {
			res.ErrorMsg = err.Error()
			emitErr = resp.Emit(res)
			continue
		}
		base := opts.newBase
		if base == -1 {
			base, _ = cid.ExtractEncoding(cidStr)
		}
		if opts.verConv != nil {
			c, err = opts.verConv(c)
			if err != nil {
				res.ErrorMsg = err.Error()
				emitErr = resp.Emit(res)
				continue
			}
		}
		str, err := cidutil.Format(opts.fmtStr, base, c)
		if _, ok := err.(cidutil.FormatStringError); ok {
			// no point in continuing if there is a problem with the format string
			return err
		}
		if err != nil {
			res.ErrorMsg = err.Error()
		} else {
			res.Formatted = str
		}
		emitErr = resp.Emit(res)
	}
	if emitErr != nil {
		return emitErr
	}
	err := itr.err()
	if err != nil {
		return err
	}
	return nil
}

func toCidV0(c cid.Cid) (cid.Cid, error) {
	if c.Type() != cid.DagProtobuf {
		return cid.Cid{}, fmt.Errorf("can't convert non-protobuf nodes to cidv0")
	}
	return cid.NewCidV0(c.Hash()), nil
}

func toCidV1(c cid.Cid) (cid.Cid, error) {
	return cid.NewCidV1(c.Type(), c.Hash()), nil
}

type CodeAndName struct {
	Code int
	Name string
}

var basesCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available multibase encodings.",
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("prefix", "also include the single leter prefixes in addition to the code"),
		cmdkit.BoolOption("numeric", "also include numeric codes"),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use EncodingToStr in case at some point there are multiple names for a given code
		for code, name := range mbase.EncodingToStr {
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
			prefixes, _ := req.Options["prefix"].(bool)
			numeric, _ := req.Options["numeric"].(bool)
			val, ok := val0.([]CodeAndName)
			if !ok {
				return e.TypeErr(val, val0)
			}
			sort.Sort(multibaseSorter{val})
			for _, v := range val {
				code := v.Code
				if code < 32 || code >= 127 {
					// don't display non-printable prefixes
					code = ' '
				}
				switch {
				case prefixes && numeric:
					fmt.Fprintf(w, "%c %5d  %s\n", code, v.Code, v.Name)
				case prefixes:
					fmt.Fprintf(w, "%c  %s\n", code, v.Name)
				case numeric:
					fmt.Fprintf(w, "%5d  %s\n", v.Code, v.Name)
				default:
					fmt.Fprintf(w, "%s\n", v.Name)
				}
			}
			return nil
		}),
	},
	Type: []CodeAndName{},
}

var codecsCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available CID codecs.",
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("numeric", "also include numeric codes"),
	},
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use CodecToStr as there are multiple names for a given code
		for code, name := range cid.CodecToStr {
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
			numeric, _ := req.Options["numeric"].(bool)
			val, ok := val0.([]CodeAndName)
			if !ok {
				return e.TypeErr(val, val0)
			}
			sort.Sort(codeAndNameSorter{val})
			for _, v := range val {
				if numeric {
					fmt.Fprintf(w, "%5d  %s\n", v.Code, v.Name)
				} else {
					fmt.Fprintf(w, "%s\n", v.Name)
				}
			}
			return nil
		}),
	},
	Type: []CodeAndName{},
}

var hashesCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List available multihashes.",
	},
	Options: codecsCmd.Options,
	Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
		var res []CodeAndName
		// use mhash.Codes in case at some point there are multiple names for a given code
		for code, name := range mhash.Codes {
			if !verifcid.IsGoodHash(code) {
				continue
			}
			res = append(res, CodeAndName{int(code), name})
		}
		cmds.EmitOnce(resp, res)
		return nil
	},
	Encoders: codecsCmd.Encoders,
	Type:     codecsCmd.Type,
}

type multibaseSorter struct {
	data []CodeAndName
}

func (s multibaseSorter) Len() int      { return len(s.data) }
func (s multibaseSorter) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }

func (s multibaseSorter) Less(i, j int) bool {
	a := unicode.ToLower(rune(s.data[i].Code))
	b := unicode.ToLower(rune(s.data[j].Code))
	if a != b {
		return a < b
	}
	// lowecase letters should come before uppercase
	return s.data[i].Code > s.data[j].Code
}

type codeAndNameSorter struct {
	data []CodeAndName
}

func (s codeAndNameSorter) Len() int           { return len(s.data) }
func (s codeAndNameSorter) Swap(i, j int)      { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (s codeAndNameSorter) Less(i, j int) bool { return s.data[i].Code < s.data[j].Code }
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/nikhan/go-fetch"
	"github.com/nytlabs/st-core/core"
	"github.com/thejerf/suture"
)

type Position struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

type ProtoBlock struct {
	Label    string   `json:"label"`
	Parent   int      `json:"group"`
	Type     string   `json:"type"`
	Position Position `json:"position"`
}

type BlockLedger struct {
	Label       string              `json:"label"`
	Type        string              `json:"type"`
	Id          int                 `json:"id"`
	Block       *core.Block         `json:"-"`
	Parent      *Group              `json:"-"`
	Token       suture.ServiceToken `json:"-"`
	Composition int                 `json:"composition,omitempty"`
	Inputs      []BlockLedgerInput  `json:"inputs"`
	Outputs     []core.Output       `json:"outputs"`
	Position    Position            `json:"position"`
}

func (bl *BlockLedger) GetID() int {
	return bl.Id
}

func (bl *BlockLedger) GetParent() *Group {
	return bl.Parent
}

func (bl *BlockLedger) SetParent(group *Group) {
	bl.Parent = group
}

type BlockLedgerInput struct {
	Name  string            `json:"name,omitempty"`
	Type  string            `json:"type"`
	Value interface{}       `json:"value"`
	C     chan core.Message `json:"-"`
}

func (s *Server) ListBlocks() []BlockLedger {
	blocks := []BlockLedger{}
	for _, b := range s.blocks {
		blocks = append(blocks, *b)
	}
	return blocks
}

func (s *Server) BlockIndexHandler(w http.ResponseWriter, r *http.Request) {
	s.Lock()
	defer s.Unlock()

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(s.ListBlocks()); err != nil {
		panic(err)
	}
}

func (s *Server) BlockHandler(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) BlockModifyPositionHandler(w http.ResponseWriter, r *http.Request) {
}

func (s *Server) CreateBlock(p ProtoBlock) (*BlockLedger, error) {
	blockSpec, ok := s.library[p.Type]
	if !ok {
		return nil, errors.New("spec not found")
	}

	block := core.NewBlock(blockSpec)

	m := &BlockLedger{
		Label:    p.Label,
		Position: p.Position,
		Type:     p.Type,
		Block:    block,
		Id:       s.GetNextID(),
	}

	is := m.Block.GetInputs()

	// may want to move this into actual block someday
	inputs := make([]BlockLedgerInput, len(is), len(is))
	for i, v := range is {
		if q, ok := v.Value.(*fetch.Query); ok {
			inputs[i] = BlockLedgerInput{
				Name:  v.Name,
				Type:  "fetch",
				Value: q.String(),
				C:     v.C,
			}
		} else {
			inputs[i] = BlockLedgerInput{
				Name:  v.Name,
				Type:  "const",
				Value: v.Value,
				C:     v.C,
			}
		}
	}

	if _, ok := s.groups[p.Parent]; !ok {
		return nil, errors.New("invalid group, could not create block")
	}

	m.Token = s.supervisor.Add(block)
	m.Inputs = inputs
	m.Outputs = block.GetOutputs()
	s.blocks[m.Id] = m

	s.websocketBroadcast(Update{Action: CREATE, Type: BLOCK, Data: m})

	err := s.AddChildToGroup(p.Parent, m)
	if err != nil {
		return nil, err

	}

	return m, nil
}

// CreateBlockHandler responds to a POST request to instantiate a new block and add it to the Server.
func (s *Server) BlockCreateHandler(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	var m ProtoBlock
	err = json.Unmarshal(body, &m)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	s.Lock()
	defer s.Unlock()

	b, err := s.CreateBlock(m)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusOK)
	writeJSON(w, b)
}

func (s *Server) BlockModifyRouteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	routes, ok := vars["index"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no route index supplied"})
		return
	}

	route, err := strconv.Atoi(routes)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	var v BlockLedgerInput
	err = json.Unmarshal(body, &v)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not unmarshal value"})
		return
	}

	s.Lock()
	defer s.Unlock()

	err = s.ModifyBlockRoute(id, route, v)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) ModifyBlockRoute(id int, route int, v BlockLedgerInput) error {
	b, ok := s.blocks[id]
	if !ok {
		return errors.New("could not find block")
	}

	// again maybe this type should be native to block under core.
	var m interface{}
	switch v.Type {
	case "fetch":
		queryString, ok := v.Value.(string)
		if !ok {
			return errors.New("fetch is not string")
		}

		fo, err := fetch.Parse(queryString)
		if err != nil {
			return err
		}

		m = fo
	case "const":
		m = v.Value
	default:
		return errors.New("no value or query specified")
	}

	err := b.Block.SetInput(core.RouteIndex(route), m)
	if err != nil {
		return err
	}

	s.blocks[id].Inputs[route].Type = v.Type
	s.blocks[id].Inputs[route].Value = m

	update := struct {
		BlockLedgerInput
		Id    int `json:"id"`
		input int `json:"input"`
	}{
		v, id, route,
	}

	s.websocketBroadcast(Update{Action: UPDATE, Type: BLOCK, Data: update})
	return nil
}

func (s *Server) BlockModifyNameHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	s.Lock()
	defer s.Unlock()

	_, ok = s.blocks[id]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"block not found"})
		return
	}

	var label string
	err = json.Unmarshal(body, &label)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not unmarshal value"})
		return
	}

	s.blocks[id].Label = label

	update := struct {
		Id    int    `json:"id"`
		Label string `json:"label"`
	}{
		id, label,
	}

	s.websocketBroadcast(Update{Action: UPDATE, Type: BLOCK, Data: update})
	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) DeleteBlock(id int) error {
	b, ok := s.blocks[id]
	if !ok {
		return errors.New("block not found")
	}

	deleteSet := make(map[int]struct{})

	// build a set of connections that we may need to delete
	// we need to panic here because if any error is thrown we are in huge trouble
	// any panic indicates that our server connection ledger is no longer true
	for _, c := range s.connections {
		if c.Target.Id == id || c.Source.Id == id {
			deleteSet[c.Id] = struct{}{}
		}
	}

	// delete the connections that involve this block
	for k, _ := range deleteSet {
		s.DeleteConnection(k)
	}

	// remove from group
	s.DetachChild(b)

	// stop and delete the block
	s.supervisor.Remove(b.Token)
	s.websocketBroadcast(Update{Action: DELETE, Type: BLOCK, Data: s.blocks[id]})
	delete(s.blocks, id)
	return nil
}

func (s *Server) BlockDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	s.Lock()
	defer s.Unlock()

	err = s.DeleteBlock(id)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusNoContent)

}
<commit_msg>adding position to block<commit_after>package server

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/nikhan/go-fetch"
	"github.com/nytlabs/st-core/core"
	"github.com/thejerf/suture"
)

type Position struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

type ProtoBlock struct {
	Label    string   `json:"label"`
	Parent   int      `json:"group"`
	Type     string   `json:"type"`
	Position Position `json:"position"`
}

type BlockLedger struct {
	Label       string              `json:"label"`
	Type        string              `json:"type"`
	Id          int                 `json:"id"`
	Block       *core.Block         `json:"-"`
	Parent      *Group              `json:"-"`
	Token       suture.ServiceToken `json:"-"`
	Composition int                 `json:"composition,omitempty"`
	Inputs      []BlockLedgerInput  `json:"inputs"`
	Outputs     []core.Output       `json:"outputs"`
	Position    Position            `json:"position"`
}

func (bl *BlockLedger) GetID() int {
	return bl.Id
}

func (bl *BlockLedger) GetParent() *Group {
	return bl.Parent
}

func (bl *BlockLedger) SetParent(group *Group) {
	bl.Parent = group
}

type BlockLedgerInput struct {
	Name  string            `json:"name,omitempty"`
	Type  string            `json:"type"`
	Value interface{}       `json:"value"`
	C     chan core.Message `json:"-"`
}

func (s *Server) ListBlocks() []BlockLedger {
	blocks := []BlockLedger{}
	for _, b := range s.blocks {
		blocks = append(blocks, *b)
	}
	return blocks
}

func (s *Server) BlockIndexHandler(w http.ResponseWriter, r *http.Request) {
	s.Lock()
	defer s.Unlock()

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(s.ListBlocks()); err != nil {
		panic(err)
	}
}

func (s *Server) BlockHandler(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) BlockModifyPositionHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	var p Position
	err = json.Unmarshal(body, &p)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read JSON"})
		return
	}

	s.Lock()
	defer s.Unlock()

	b, ok := s.blocks[id]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not find block"})
		return
	}

	b.Position = p

	update := struct {
		Position
		Id int
	}{
		p,
		id,
	}

	s.websocketBroadcast(Update{Action: UPDATE, Type: BLOCK, Data: update})
	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) CreateBlock(p ProtoBlock) (*BlockLedger, error) {
	blockSpec, ok := s.library[p.Type]
	if !ok {
		return nil, errors.New("spec not found")
	}

	block := core.NewBlock(blockSpec)

	m := &BlockLedger{
		Label:    p.Label,
		Position: p.Position,
		Type:     p.Type,
		Block:    block,
		Id:       s.GetNextID(),
	}

	is := m.Block.GetInputs()

	// may want to move this into actual block someday
	inputs := make([]BlockLedgerInput, len(is), len(is))
	for i, v := range is {
		if q, ok := v.Value.(*fetch.Query); ok {
			inputs[i] = BlockLedgerInput{
				Name:  v.Name,
				Type:  "fetch",
				Value: q.String(),
				C:     v.C,
			}
		} else {
			inputs[i] = BlockLedgerInput{
				Name:  v.Name,
				Type:  "const",
				Value: v.Value,
				C:     v.C,
			}
		}
	}

	if _, ok := s.groups[p.Parent]; !ok {
		return nil, errors.New("invalid group, could not create block")
	}

	m.Token = s.supervisor.Add(block)
	m.Inputs = inputs
	m.Outputs = block.GetOutputs()
	s.blocks[m.Id] = m

	s.websocketBroadcast(Update{Action: CREATE, Type: BLOCK, Data: m})

	err := s.AddChildToGroup(p.Parent, m)
	if err != nil {
		return nil, err

	}

	return m, nil
}

// CreateBlockHandler responds to a POST request to instantiate a new block and add it to the Server.
func (s *Server) BlockCreateHandler(w http.ResponseWriter, r *http.Request) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	var m ProtoBlock
	err = json.Unmarshal(body, &m)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	s.Lock()
	defer s.Unlock()

	b, err := s.CreateBlock(m)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusOK)
	writeJSON(w, b)
}

func (s *Server) BlockModifyRouteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	routes, ok := vars["index"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no route index supplied"})
		return
	}

	route, err := strconv.Atoi(routes)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	var v BlockLedgerInput
	err = json.Unmarshal(body, &v)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not unmarshal value"})
		return
	}

	s.Lock()
	defer s.Unlock()

	err = s.ModifyBlockRoute(id, route, v)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) ModifyBlockRoute(id int, route int, v BlockLedgerInput) error {
	b, ok := s.blocks[id]
	if !ok {
		return errors.New("could not find block")
	}

	// again maybe this type should be native to block under core.
	var m interface{}
	switch v.Type {
	case "fetch":
		queryString, ok := v.Value.(string)
		if !ok {
			return errors.New("fetch is not string")
		}

		fo, err := fetch.Parse(queryString)
		if err != nil {
			return err
		}

		m = fo
	case "const":
		m = v.Value
	default:
		return errors.New("no value or query specified")
	}

	err := b.Block.SetInput(core.RouteIndex(route), m)
	if err != nil {
		return err
	}

	s.blocks[id].Inputs[route].Type = v.Type
	s.blocks[id].Inputs[route].Value = m

	update := struct {
		BlockLedgerInput
		Id    int `json:"id"`
		input int `json:"input"`
	}{
		v, id, route,
	}

	s.websocketBroadcast(Update{Action: UPDATE, Type: BLOCK, Data: update})
	return nil
}

func (s *Server) BlockModifyNameHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not read request body"})
		return
	}

	s.Lock()
	defer s.Unlock()

	_, ok = s.blocks[id]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"block not found"})
		return
	}

	var label string
	err = json.Unmarshal(body, &label)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"could not unmarshal value"})
		return
	}

	s.blocks[id].Label = label

	update := struct {
		Id    int    `json:"id"`
		Label string `json:"label"`
	}{
		id, label,
	}

	s.websocketBroadcast(Update{Action: UPDATE, Type: BLOCK, Data: update})
	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) DeleteBlock(id int) error {
	b, ok := s.blocks[id]
	if !ok {
		return errors.New("block not found")
	}

	deleteSet := make(map[int]struct{})

	// build a set of connections that we may need to delete
	// we need to panic here because if any error is thrown we are in huge trouble
	// any panic indicates that our server connection ledger is no longer true
	for _, c := range s.connections {
		if c.Target.Id == id || c.Source.Id == id {
			deleteSet[c.Id] = struct{}{}
		}
	}

	// delete the connections that involve this block
	for k, _ := range deleteSet {
		s.DeleteConnection(k)
	}

	// remove from group
	s.DetachChild(b)

	// stop and delete the block
	s.supervisor.Remove(b.Token)
	s.websocketBroadcast(Update{Action: DELETE, Type: BLOCK, Data: s.blocks[id]})
	delete(s.blocks, id)
	return nil
}

func (s *Server) BlockDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	ids, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{"no ID supplied"})
		return
	}

	id, err := strconv.Atoi(ids)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	s.Lock()
	defer s.Unlock()

	err = s.DeleteBlock(id)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		writeJSON(w, Error{err.Error()})
		return
	}

	w.WriteHeader(http.StatusNoContent)

}
<|endoftext|>


<commit_before>package platform

// Largely based on
// https://github.com/moby/moby/blob/bc846d2e8fe5538220e0c31e9d0e8446f6fbc022/distribution/cpuinfo_unix.go
// Copyright 2012-2017 Docker, Inc.
//
// https://github.com/containerd/containerd/blob/726dcaea50883e51b2ec6db13caff0e7936b711d/platforms/cpuinfo.go
//    Copyright The containerd Authors.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//        http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"strings"

	"github.com/containers/image/v5/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
	if runtime.GOOS != "linux" {
		return "", fmt.Errorf("getCPUInfo for OS %s not implemented", runtime.GOOS)
	}

	cpuinfo, err := os.Open("/proc/cpuinfo")
	if err != nil {
		return "", err
	}
	defer cpuinfo.Close()

	// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
	// the first core is enough.
	scanner := bufio.NewScanner(cpuinfo)
	for scanner.Scan() {
		newline := scanner.Text()
		list := strings.Split(newline, ":")

		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
			return strings.TrimSpace(list[1]), nil
		}
	}

	// Check whether the scanner encountered errors
	err = scanner.Err()
	if err != nil {
		return "", err
	}

	return "", fmt.Errorf("getCPUInfo for pattern: %s not found", pattern)
}

func getCPUVariantWindows(arch string) string {
	// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
	// runtime.GOARCH to determine the variants
	var variant string
	switch arch {
	case "arm64":
		variant = "v8"
	case "arm":
		variant = "v7"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariantArm() string {
	variant, err := getCPUInfo("Cpu architecture")
	if err != nil {
		return ""
	}
	// TODO handle RPi Zero mismatch (https://github.com/moby/moby/pull/36121#issuecomment-398328286)

	switch strings.ToLower(variant) {
	case "8", "aarch64":
		variant = "v8"
	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
		variant = "v7"
	case "6", "6tej":
		variant = "v6"
	case "5", "5t", "5te", "5tej":
		variant = "v5"
	case "4", "4t":
		variant = "v4"
	case "3":
		variant = "v3"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariant(os string, arch string) string {
	if os == "windows" {
		return getCPUVariantWindows(arch)
	}
	if arch == "arm" || arch == "arm64" {
		return getCPUVariantArm()
	}
	return ""
}

var compatibility = map[string][]string{
	"arm":   {"v7", "v6", "v5"},
	"arm64": {"v8"},
}

// WantedPlatforms returns all compatible platforms with the platform specifics possibly overriden by user,
// the most compatible platform is first.
// If some option (arch, os, variant) is not present, a value from current platform is detected.
func WantedPlatforms(ctx *types.SystemContext) ([]imgspecv1.Platform, error) {
	wantedArch := runtime.GOARCH
	wantedVariant := ""
	if ctx != nil && ctx.ArchitectureChoice != "" {
		wantedArch = ctx.ArchitectureChoice
	} else {
		// Only auto-detect the variant if we are using the default architecture.
		// If the user has specified the ArchitectureChoice, don't autodetect, even if
		// ctx.ArchitectureChoice == runtime.GOARCH, because we have no idea whether the runtime.GOARCH
		// value is relevant to the use case, and if we do autodetect a variant,
		// ctx.VariantChoice can't be used to override it back to "".
		wantedVariant = getCPUVariant(runtime.GOOS, runtime.GOARCH)
	}
	if ctx != nil && ctx.VariantChoice != "" {
		wantedVariant = ctx.VariantChoice
	}

	wantedOS := runtime.GOOS
	if ctx != nil && ctx.OSChoice != "" {
		wantedOS = ctx.OSChoice
	}

	var variants []string = nil
	if wantedVariant != "" && compatibility[wantedArch] != nil {
		variantOrder := compatibility[wantedArch]
		variants = make([]string, 0, len(variantOrder))
		wantedIndex := -1
		for i, v := range variantOrder {
			if wantedVariant == v {
				wantedIndex = i
				break
			}
		}
		// user wants a variant which we know nothing about - not even compatibility
		if wantedIndex == -1 {
			variants = []string{wantedVariant}
		} else {
			for i := wantedIndex; i < len(variantOrder); i++ {
				variants = append(variants, variantOrder[i])
			}
		}
	} else {
		variants = []string{wantedVariant}
	}

	res := make([]imgspecv1.Platform, 0, len(variants))
	for _, v := range variants {
		res = append(res, imgspecv1.Platform{
			OS:           wantedOS,
			Architecture: wantedArch,
			Variant:      v,
		})
	}
	return res, nil
}

func MatchesPlatform(image imgspecv1.Platform, wanted imgspecv1.Platform) bool {
	if image.Architecture != wanted.Architecture {
		return false
	}
	if image.OS != wanted.OS {
		return false
	}

	if wanted.Variant == "" || image.Variant == wanted.Variant {
		return true
	}

	return false
}
<commit_msg>Simplify variant list preparation.<commit_after>package platform

// Largely based on
// https://github.com/moby/moby/blob/bc846d2e8fe5538220e0c31e9d0e8446f6fbc022/distribution/cpuinfo_unix.go
// Copyright 2012-2017 Docker, Inc.
//
// https://github.com/containerd/containerd/blob/726dcaea50883e51b2ec6db13caff0e7936b711d/platforms/cpuinfo.go
//    Copyright The containerd Authors.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//        http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"strings"

	"github.com/containers/image/v5/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
	if runtime.GOOS != "linux" {
		return "", fmt.Errorf("getCPUInfo for OS %s not implemented", runtime.GOOS)
	}

	cpuinfo, err := os.Open("/proc/cpuinfo")
	if err != nil {
		return "", err
	}
	defer cpuinfo.Close()

	// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
	// the first core is enough.
	scanner := bufio.NewScanner(cpuinfo)
	for scanner.Scan() {
		newline := scanner.Text()
		list := strings.Split(newline, ":")

		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
			return strings.TrimSpace(list[1]), nil
		}
	}

	// Check whether the scanner encountered errors
	err = scanner.Err()
	if err != nil {
		return "", err
	}

	return "", fmt.Errorf("getCPUInfo for pattern: %s not found", pattern)
}

func getCPUVariantWindows(arch string) string {
	// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
	// runtime.GOARCH to determine the variants
	var variant string
	switch arch {
	case "arm64":
		variant = "v8"
	case "arm":
		variant = "v7"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariantArm() string {
	variant, err := getCPUInfo("Cpu architecture")
	if err != nil {
		return ""
	}
	// TODO handle RPi Zero mismatch (https://github.com/moby/moby/pull/36121#issuecomment-398328286)

	switch strings.ToLower(variant) {
	case "8", "aarch64":
		variant = "v8"
	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
		variant = "v7"
	case "6", "6tej":
		variant = "v6"
	case "5", "5t", "5te", "5tej":
		variant = "v5"
	case "4", "4t":
		variant = "v4"
	case "3":
		variant = "v3"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariant(os string, arch string) string {
	if os == "windows" {
		return getCPUVariantWindows(arch)
	}
	if arch == "arm" || arch == "arm64" {
		return getCPUVariantArm()
	}
	return ""
}

var compatibility = map[string][]string{
	"arm":   {"v7", "v6", "v5"},
	"arm64": {"v8"},
}

// WantedPlatforms returns all compatible platforms with the platform specifics possibly overriden by user,
// the most compatible platform is first.
// If some option (arch, os, variant) is not present, a value from current platform is detected.
func WantedPlatforms(ctx *types.SystemContext) ([]imgspecv1.Platform, error) {
	wantedArch := runtime.GOARCH
	wantedVariant := ""
	if ctx != nil && ctx.ArchitectureChoice != "" {
		wantedArch = ctx.ArchitectureChoice
	} else {
		// Only auto-detect the variant if we are using the default architecture.
		// If the user has specified the ArchitectureChoice, don't autodetect, even if
		// ctx.ArchitectureChoice == runtime.GOARCH, because we have no idea whether the runtime.GOARCH
		// value is relevant to the use case, and if we do autodetect a variant,
		// ctx.VariantChoice can't be used to override it back to "".
		wantedVariant = getCPUVariant(runtime.GOOS, runtime.GOARCH)
	}
	if ctx != nil && ctx.VariantChoice != "" {
		wantedVariant = ctx.VariantChoice
	}

	wantedOS := runtime.GOOS
	if ctx != nil && ctx.OSChoice != "" {
		wantedOS = ctx.OSChoice
	}

	var variants []string = nil
	if wantedVariant != "" && compatibility[wantedArch] != nil {
		variantOrder := compatibility[wantedArch]
		for i, v := range variantOrder {
			if wantedVariant == v {
				variants = variantOrder[i:]
				break
			}
		}
		// user wants a variant which we know nothing about - not even compatibility
		if variants == nil {
			variants = []string{wantedVariant}
		}
	} else {
		variants = []string{wantedVariant}
	}

	res := make([]imgspecv1.Platform, 0, len(variants))
	for _, v := range variants {
		res = append(res, imgspecv1.Platform{
			OS:           wantedOS,
			Architecture: wantedArch,
			Variant:      v,
		})
	}
	return res, nil
}

func MatchesPlatform(image imgspecv1.Platform, wanted imgspecv1.Platform) bool {
	if image.Architecture != wanted.Architecture {
		return false
	}
	if image.OS != wanted.OS {
		return false
	}

	if wanted.Variant == "" || image.Variant == wanted.Variant {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package generator

import (
	"bytes"
	"text/template"

	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
)

var (
	unaryTemplate        *template.Template
	serverStreamTemplate *template.Template
	clientStreamTemplate *template.Template
	bidirStreamTemplate  *template.Template
)

const (
	unary = `
func (s *{{.GetServiceImplName}}) {{.GetMethod}}(ctx context.Context, req *{{.GetInputType}}) (*{{.GetOutputType}}, error) {
	var (
		{{range $key, $value := .GetSafeResponseFields}}
		{{$key}} {{$value}} {{end}}
	)
	err := s.db.QueryRow(
		"{{.GetQuery}}",{{range $qParam := .GetQueryParams}}
		ToSafeType(req.{{$qParam}}),
		{{end}}).
		Scan({{range $key, $value := .GetSafeResponseFields}} &{{$key}},
		{{end}})

	if err != nil {
		return nil, ConvertError(err, req)
	}
	result := &{{.GetOutputType}}{}
	{{ range $local, $go := .GetResponseFieldsMap}}
	AssingTo(&result.{{$go}}, {{$local}})
	{{end}}

	return result, nil
}
`
	server = ``
	client = ``
	bidir  = ``
)

func init() {
	var err error
	unaryTemplate, err = template.New("unaryTemplate").Parse(unary)
	if err != nil {
		logrus.Fatal("Error parsing unary template!")
	}
	serverStreamTemplate, err = template.New("serverTemplate").Parse(server)
	if err != nil {
		logrus.Fatal("Error parsing server stream template!")
	}

	clientStreamTemplate, err = template.New("clientTemplate").Parse(client)
	if err != nil {
		logrus.Fatal("Error parsing client stream template!")
	}

	bidirStreamTemplate, err = template.New("bidirTemplate").Parse(bidir)
	if err != nil {
		logrus.Fatal("Error parsing bidirectional stream template!")
	}

}

type Service struct {
	Desc *descriptor.ServiceDescriptorProto
}

type Method struct {
	Desc *descriptor.MethodDescriptorProto
}

func (m *Method) GetServiceImplName() string {
	return "TestServiceImpl"
}

func (m *Method) GetMethod() string {
	return "TestMethod"
}

func (m *Method) GetInputType() string {
	return "InputType"
}

func (m *Method) GetOutputType() string {
	return "OutputType"
}

func (m *Method) GetSafeResponseFields() map[string]string {
	var ret map[string]string
	ret = make(map[string]string)
	ret["id"] = "int32"
	ret["val"] = "string"
	return ret
}

func (m *Method) GetResponseFieldsMap() map[string]string {
	var ret map[string]string
	ret = make(map[string]string)
	ret["id"] = "Id"
	ret["val"] = "Val"
	return ret
}

func (m *Method) GetQuery() string {
	return strings.Replace(strings.Replace("SQL \"test\"", "\\", "\\\\", -1), "\"", "\\\"", -1)
}

func (m *Method) GetQueryParams() []string {
	return []string{"id"}
}

func (m *Method) Generate() string {
	var tpl bytes.Buffer
	if err := unaryTemplate.Execute(&tpl, m); err != nil {
		logrus.Fatal("Error processing value function temaplate")
	}
	return tpl.String()
}
<commit_msg>finished other query types<commit_after>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package generator

import (
	"fmt"
	"bytes"
	"text/template"
	"os"

	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
)

var (
	unaryTemplate        *template.Template
	serverStreamTemplate *template.Template
	clientStreamTemplate *template.Template
	bidirStreamTemplate  *template.Template
)

const (
	unary = `
func (s *{{.GetServiceImplName}}) {{.GetMethod}}(ctx context.Context, req *{{.GetInputType}}) (*{{.GetOutputType}}, error) {
	var (
		{{range $key, $value := .GetSafeResponseFields}}
		{{$key}} {{$value}} {{end}}
	)
	err := s.db.QueryRow(
		"{{.GetQuery}}",{{range $qParam := .GetQueryParams}}
		ToSafeType(req.{{$qParam}}),
		{{end}}).
		Scan({{range $key, $value := .GetSafeResponseFields}} &{{$key}},
		{{end}})

	if err != nil {
		return nil, ConvertError(err, req)
	}
	result := &{{.GetOutputType}}{}
	{{range $local, $go := .GetResponseFieldsMap}}
	AssignTo(&result.{{$go}}, {{$local}}) {{end}}

	return result, nil
}
`
	server = `
func (s *{{.GetServiceImplName}}) {{.GetMethod}}(req *{{.GetInputType}}, stream {{.GetStreamType}}), error {
	rows, err := s.db.Query("{{.GetQuery}}", {{range $qParam := .GetQueryParams}}
		ToSafeType(req.{{$qParam}}),
	{{end}})
	if err != nil {
		return ConvertError(err, req)
	}

	defer rows.Close()

	for rows.Next() {
		err = rows.Err()
		if err != nil {
			return ConvertError(err, req)
		}

		var (
			{{range $key, $value := .GetSafeResponseFields}}
			{{$key}} {{$value}} {{end}}
		)

		err := rows.Scan({{range $key, $value := .GetSafeResponseFields}}
			&{{$key}},{{end}}
		)
		if err != nil {
			return ConvertError(err, req)
		}

		result := &{{.GetOutputType}}{}
		{{ range $local, $go := .GetResponseFieldsMap}}
		AssignTo(&result.{{$go}}, {{$local}}) {{end}}
	}
	return result, nil
}
`
	client = `
func (s *{{.GetServiceImplName}}) {{.GetMethod}}(stream {{.GetStreamType}}), error {
	stmt, err := s.db.Prepare("{{.GetQuery}}")
	if err != nil {
		return ConvertError(err, nil)
	}
	tx, err := s.db.Begin()
	if err != nil {
		return ConvertError(err, nil)
	}
	totalAffected := int64(0)

	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			tx.Rollback()
			return ConvertError(err, req)
		}

		affected, err := tx.Stmt(stmt).Exec({{range $local := .GetQueryParams}}
		ToSafeType(req.{{$local}}),
		{{end}})
		if err != nil {
			tx.Rollback()
			return ConvertError(err, req)
		}
		num, err := affected.RowsAffected()
		if err != nil {
			tx.Rollback()
			return ConvertError(err, req)
		}
		totalAffected += num
	}
	err = tx.Commit()
	if err != nil {
		fmt.Errorf("Commiting transaction failed, rolling back...")
		return ConvertError(err, nil)
	}
	stream.SendAndClose(&{{.GetNumRowsMessageName}} { {{.GetNumRowsFieldName}}: totalAffected })
	return nil
}
`
	bidir  = `
func (s *{{.GetServiceImplName}}) {{.GetMethod}}(stream {{.GetStreamType}}), error {
	stmt, err := s.db.Prepare("{{.GetQuery}}")
	if err != nil {
		return ConvertError(err, nil)
	}

	defer stmt.Close()

	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return ConvertError(err, nil)
		}
		var( {{range $key,$type := .GetSafeResponseFields}}
			{{$key}} {{$type}} {{end}}
		)

		err = stmt.QueryRow({{range $local := .GetQueryParams}}
			ToSafeType(req.{{$local}}),
		{{end}}).
		Scan({{range $key := .GetQueryParams}}
			&{{$key}},
		{{end}})

		result := &{{.GetOutputType}}{}

		{{range $local, $go := .GetResponseFieldsMap}}
		AssignTo(result.{{$go}}, {{$local}}){{end}}

		if err := stream.Send(result); err != nil {
			return ConvertError(err, req)
		}
	}
	return nil
}
`
)

func init() {
	var err error
	unaryTemplate, err = template.New("unaryTemplate").Parse(unary)
	if err != nil {
		logrus.WithError(err).Fatal("Error parsing unary template!")
	}
	serverStreamTemplate, err = template.New("serverTemplate").Parse(server)
	if err != nil {
		logrus.WithError(err).Fatal("Error parsing server stream template!")
	}

	clientStreamTemplate, err = template.New("clientTemplate").Parse(client)
	if err != nil {
		logrus.WithError(err).Fatal("Error parsing client stream template!")
	}

	bidirStreamTemplate, err = template.New("bidirTemplate").Parse(bidir)
	if err != nil {
		logrus.WithError(err).Fatal("Error parsing bidirectional stream template!")
	}
	//printTemplates()
}

func printTemplates() {
	logrus.Info("UNARY")
	unaryTemplate.Execute(os.Stdout, &Method{})
	fmt.Printf("\n")
	logrus.Info("SERVER")
	serverStreamTemplate.Execute(os.Stdout, &Method{})
	fmt.Printf("\n")
	logrus.Info("CLIENT")
	clientStreamTemplate.Execute(os.Stdout, &Method{})
	fmt.Printf("\n")
	logrus.Info("BIDI")
	bidirStreamTemplate.Execute(os.Stdout, &Method{})
	fmt.Printf("\n")
	logrus.Info("////////////////////////")
}

type Service struct {
	Desc *descriptor.ServiceDescriptorProto
}

type Method struct {
	Desc *descriptor.MethodDescriptorProto
}

func (m *Method) GetServiceImplName() string {
	return "TestServiceImpl"
}

func (m *Method) GetMethod() string {
	return "TestMethod"
}

func (m *Method) GetInputType() string {
	return "InputType"
}

func (m *Method) GetStreamType() string {
	return "Service_TestMethodServer"
}

func (m *Method) GetNumRowsMessageName() string {
	return "NumRows"
}

func (m *Method) GetNumRowsFieldName() string {
	return "Count"
}

func (m *Method) GetOutputType() string {
	return "OutputType"
}

func (m *Method) GetSafeResponseFields() map[string]string {
	var ret map[string]string
	ret = make(map[string]string)
	ret["id"] = "int32"
	ret["val"] = "string"
	return ret
}

func (m *Method) GetResponseFieldsMap() map[string]string {
	var ret map[string]string
	ret = make(map[string]string)
	ret["id"] = "Id"
	ret["val"] = "Val"
	return ret
}

func (m *Method) GetQuery() string {
	return strings.Replace(strings.Replace("SQL \"test\"", "\\", "\\\\", -1), "\"", "\\\"", -1)
}

func (m *Method) GetQueryParams() []string {
	return []string{"id"}
}

func (m *Method) Generate() string {
	var tpl bytes.Buffer
	if err := unaryTemplate.Execute(&tpl, m); err != nil {
		logrus.Fatal("Error processing value function temaplate")
	}
	return tpl.String()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/chrisseto/sux/pane"
	"github.com/nsf/termbox-go"
	"strings"
)

var (
	quitChan      chan bool
	selectChan    chan *pane.Pane
	selectedIndex = 0
	SelectedPane  *pane.Pane
	RunningPanes  []*pane.Pane
)

func RunPanes() error {
	quitChan = make(chan bool)
	selectChan = make(chan *pane.Pane)
	width, height := termbox.Size()
	uwidth, uheight := uint16(width), uint16(height-1)
	cmds := strings.Split(strings.Join(flag.Args(), " "), ",")

	RunningPanes = make([]*pane.Pane, len(cmds))

	for i, cmd := range cmds {
		cmdsp := strings.Split(strings.Trim(cmd, " "), " ")
		RunningPanes[i] = pane.CreatePane(uwidth, uheight, cmdsp[0], cmdsp[1:]...)
		err := RunningPanes[i].Start()

		if err != nil {
			return err
		}
	}

	SelectedPane = RunningPanes[selectedIndex]
	selectChan <- SelectedPane
	return nil
}

func Redraw() {
	select {
	case redraw <- struct{}{}:
	default: //Failed to send, a redraw is already happening
	}
}

func OutputLoop() {
	selected := <-selectChan
	selected.Redraw()
	WriteStatusBar(selected)
	termbox.Flush()
	for {
		select {
		case <-selected.ShouldRedraw:
			selected.Redraw()
			WriteStatusBar(selected)
			termbox.Flush()
		case <-redraw:
			selected.Redraw()
			WriteStatusBar(selected)
			termbox.Flush()
		case selected = <-selectChan:
		case <-quitChan:
			return
		}
	}
}

func setPane(index int) {
	SelectedPane = RunningPanes[index]
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	SelectedPane.Redraw()
	WriteStatusBar(SelectedPane)
	termbox.Flush()
	selectChan <- SelectedPane
}

func NextPane() {
	selectedIndex++
	if selectedIndex >= len(RunningPanes) {
		selectedIndex = 0
	}
	setPane(selectedIndex)
}

func PrevPane() {
	selectedIndex--
	if selectedIndex < 0 {
		selectedIndex = len(RunningPanes) - 1
	}
	setPane(selectedIndex)
}

func EndPanes() {
	quitChan <- true
	for _, cmd := range RunningPanes {
		cmd.Close()
	}
}

func WriteStatusBar(pane *pane.Pane) {
	width, height := termbox.Size()
	statusString := fmt.Sprintf("Pane #%d Command %s Args %v %s Mode", selectedIndex, pane.Prog, pane.Args, CurrentMode.Name)
	i := 0
	for _, char := range statusString {
		termbox.SetCell(i, height-1, char, termbox.ColorBlack, termbox.ColorGreen)
		i++
		if i > width {
			return
		}
	}
	for ; i < width; i++ {
		termbox.SetCell(i, height-1, ' ', termbox.ColorBlack, termbox.ColorGreen)
	}
}
<commit_msg>width and height are no longer uints<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/chrisseto/sux/pane"
	"github.com/nsf/termbox-go"
	"strings"
)

var (
	quitChan      chan bool
	selectChan    chan *pane.Pane
	selectedIndex = 0
	SelectedPane  *pane.Pane
	RunningPanes  []*pane.Pane
)

func RunPanes() error {
	quitChan = make(chan bool)
	selectChan = make(chan *pane.Pane)
	width, height := termbox.Size()
	cmds := strings.Split(strings.Join(flag.Args(), " "), ",")

	RunningPanes = make([]*pane.Pane, len(cmds))

	for i, cmd := range cmds {
		cmdsp := strings.Split(strings.Trim(cmd, " "), " ")
		RunningPanes[i] = pane.CreatePane(width, height-1, cmdsp[0], cmdsp[1:]...)
		err := RunningPanes[i].Start()

		if err != nil {
			return err
		}
	}

	SelectedPane = RunningPanes[selectedIndex]
	selectChan <- SelectedPane
	return nil
}

func Redraw() {
	select {
	case redraw <- struct{}{}:
	default: //Failed to send, a redraw is already happening
	}
}

func OutputLoop() {
	selected := <-selectChan
	selected.Redraw()
	WriteStatusBar(selected)
	termbox.Flush()
	for {
		select {
		case <-selected.ShouldRedraw:
			selected.Redraw()
			WriteStatusBar(selected)
			termbox.Flush()
		case <-redraw:
			selected.Redraw()
			WriteStatusBar(selected)
			termbox.Flush()
		case selected = <-selectChan:
		case <-quitChan:
			return
		}
	}
}

func setPane(index int) {
	SelectedPane = RunningPanes[index]
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	SelectedPane.Redraw()
	WriteStatusBar(SelectedPane)
	termbox.Flush()
	selectChan <- SelectedPane
}

func NextPane() {
	selectedIndex++
	if selectedIndex >= len(RunningPanes) {
		selectedIndex = 0
	}
	setPane(selectedIndex)
}

func PrevPane() {
	selectedIndex--
	if selectedIndex < 0 {
		selectedIndex = len(RunningPanes) - 1
	}
	setPane(selectedIndex)
}

func EndPanes() {
	quitChan <- true
	for _, cmd := range RunningPanes {
		cmd.Close()
	}
}

func WriteStatusBar(pane *pane.Pane) {
	width, height := termbox.Size()
	statusString := fmt.Sprintf("Pane #%d Command %s Args %v %s Mode", selectedIndex, pane.Prog, pane.Args, CurrentMode.Name)
	i := 0
	for _, char := range statusString {
		termbox.SetCell(i, height-1, char, termbox.ColorBlack, termbox.ColorGreen)
		i++
		if i > width {
			return
		}
	}
	for ; i < width; i++ {
		termbox.SetCell(i, height-1, ' ', termbox.ColorBlack, termbox.ColorGreen)
	}
}
<|endoftext|>


<commit_before>package kiwi

/*
Copyright (c) 2016, Alexander I.Grafov aka Axel
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of kvlog nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"io"
	"strconv"
	"sync"
	"time"
)

var outputs []*Output

type (
	// Output used for filtering incoming log records from all logger instances
	// and decides how to write them. Each Output wraps its own io.Writer.
	// Output methods are safe for concurrent usage.
	Output struct {
		sync.RWMutex
		//		In              chan map[string]value // TODO список вместо мапы
		In              chan *[]pair
		w               io.Writer
		format          format
		paused          bool
		closed          bool
		positiveFilters map[string]filter
		negativeFilters map[string]filter
		hiddenKeys      map[string]bool
	}
	format uint8
)

// const (
// 	mustPresentMask int8 = 0x01
// 	checkValueMask  int8 = 0x02
// )

const (
	Logfmt format = iota
	JSON
)

// UseOutput creates a new output for an arbitrary number of loggers.
// There are any number of outputs may be created for saving incoming log
// records to different places.
func UseOutput(w io.Writer, logFormat format) *Output {
	for _, out := range outputs {
		if out.w == w {
			return out
		}
	}
	out := &Output{
		In:              make(chan *[]pair, 16),
		w:               w,
		positiveFilters: make(map[string]filter),
		negativeFilters: make(map[string]filter),
		format:          logFormat}
	outputs = append(outputs, out)
	go processOutput(out)
	return out
}

// With sets restriction for records output.
// Only the records WITH any of the keys will be passed to output.
func (out *Output) With(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			delete(out.negativeFilters, tag)
			out.positiveFilters[tag] = &keyFilter{Key: tag}
		}
	}
	out.Unlock()
	return out
}

// Without sets restriction for records output.
// Only the records WITHOUT any of the keys will be passed to output.
func (out *Output) Without(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			out.negativeFilters[tag] = &keyFilter{Key: tag}
			delete(out.positiveFilters, tag)
		}
	}
	out.Unlock()
	return out
}

// WithValues sets restriction for records output.
// A record passed to output if the key equal one of any of the listed values.
func (out *Output) WithValues(key string, vals ...string) *Output {
	if len(vals) == 0 {
		return out.With(key)
	}
	out.Lock()
	if !out.closed {
		delete(out.negativeFilters, key)
		out.positiveFilters[key] = &valsFilter{Key: key, Vals: vals}
	}
	out.Unlock()
	return out
}

// WithoutValues sets restriction for records output.
func (out *Output) WithoutValues(key string, vals ...string) *Output {
	if len(vals) == 0 {
		return out.Without(key)
	}
	out.Lock()
	if !out.closed {
		delete(out.positiveFilters, key)
		out.negativeFilters[key] = &valsFilter{Key: key, Vals: vals}
	}
	out.Unlock()
	return out
}

// WithRangeInt64 sets restriction for records output.
func (out *Output) WithRangeInt64(key string, from, to int64) *Output {
	out.Lock()
	if !out.closed {
		delete(out.negativeFilters, key)
		out.positiveFilters[key] = &rangeInt64Filter{Key: key, From: from, To: to}
	}
	out.Unlock()
	return out
}

// WithRangeFloat64 sets restriction for records output.
func (out *Output) WithoutRangeInt64(key string, from, to int64) *Output {
	return out
}

// WithRangeFloat64 sets restriction for records output.
func (out *Output) WithRangeFloat64(key string, from, to float64) *Output {
	out.Lock()
	delete(out.negativeFilters, key)
	out.positiveFilters[key] = &rangeFloat64Filter{Key: key, From: from, To: to}
	out.Unlock()
	return out
}

// WithoutRangeFloat64  sets restriction for records output.
func (out *Output) WithoutRangeFloat64(key string, from, to float64) *Output {
	// XXX
	return out
}

// Reset all filters for the keys for the output.
func (out *Output) Reset(keys ...string) *Output {
	out.Lock()
	for _, tag := range keys {
		delete(out.positiveFilters, tag)
		delete(out.negativeFilters, tag)
	}
	out.Unlock()
	return out
}

// Hide keys from the output. Other keys in record will be displayed
// but not hidden keys.
func (out *Output) Hide(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			out.hiddenKeys[tag] = true
		}
	}
	out.Unlock()
	return out
}

// Unhide previously hidden keys. They will be displayed in the output again.
func (out *Output) Unhide(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			delete(out.hiddenKeys, tag)
		}
	}
	out.Unlock()
	return out
}

// Pause stops writing to the output.
func (out *Output) Pause() {
	out.paused = true
}

// Contiunue writing to the output.
func (out *Output) Continue() {
	out.paused = false
}

func (out *Output) Close() {
	out.Lock()
	out.closed = true
	out.Unlock()
	close(out.In)
}

func (out *Output) Flush() {
	out.In <- nil
	time.Sleep(5 * time.Millisecond)
}

// A new record passed to all outputs. Each output routine decides n
func passRecordToOutput(record []pair) {
	for _, out := range outputs {
		if !out.closed && !out.paused {
			out.In <- &record
		}
	}
}

func processOutput(out *Output) {
	for {
		record, ok := <-out.In
		if !ok {
			out.positiveFilters = nil
			out.negativeFilters = nil
			out.hiddenKeys = nil
			return
		}
		if out.closed || out.paused {
			continue
		}
		if record == nil {
			// Flush!
			time.Sleep(5 * time.Millisecond) // XXX make real flush
			continue
		}
		out.RLock()
		for _, pair := range *record {
			if filter, ok := out.negativeFilters[pair.Key]; ok {
				if filter.Check(pair.Key, pair.Val.Strv) {
					goto skipRecord
				}
			}
			if filter, ok := out.positiveFilters[pair.Key]; ok {
				if !filter.Check(pair.Key, pair.Val.Strv) {
					goto skipRecord
				}
			}
		}
		out.RUnlock()
		out.write(record)
		continue
	skipRecord:
		out.RUnlock()
	}
}

// it yet ignores output format
func (out *Output) write(record *[]pair) {
	var logLine bytes.Buffer
	switch out.format {
	case JSON:
		logLine.WriteRune('{')
		out.RLock()
		for _, pair := range *record {
			if ok := out.hiddenKeys[pair.Key]; ok {
				continue
			}
			logLine.WriteRune('"')
			logLine.WriteString(pair.Key)
			logLine.WriteString("\":")
			var curVal string
			if pair.Val.Func != nil {
				// Evaluate lazy value here
				// TODO exaluation should be made in logger not output!
				// XXX refactor it!
				tmp := toRecordValue(toFunc(pair.Val.Func))
				curVal = tmp.Strv
			} else {
				curVal = pair.Val.Strv
			}
			if pair.Val.Quoted {
				logLine.WriteString(strconv.Quote(curVal))
			} else {
				logLine.WriteString(curVal)
			}
			logLine.WriteString(", ")
		}
		logLine.WriteRune('}')
	case Logfmt:
		out.RLock()
		for _, pair := range *record {
			if ok := out.hiddenKeys[pair.Key]; ok {
				continue
			}
			logLine.WriteString(pair.Key)
			logLine.WriteRune('=')
			var curVal string
			if pair.Val.Func != nil {
				// Evaluate lazy value here
				// TODO exaluation should be made in logger not output!
				// XXX refactor it!
				tmp := toRecordValue(toFunc(pair.Val.Func))
				curVal = tmp.Strv
			} else {
				curVal = pair.Val.Strv
			}
			if pair.Val.Quoted {
				logLine.WriteString(strconv.Quote(curVal))
			} else {
				logLine.WriteString(curVal)
			}
			logLine.WriteRune(' ')
		}
	}
	out.RUnlock()
	logLine.WriteRune('\n')
	logLine.WriteTo(out.w)
}
<commit_msg>Refactor.<commit_after>package kiwi

/*
Copyright (c) 2016, Alexander I.Grafov aka Axel
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of kvlog nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"io"
	"strconv"
	"sync"
	"time"
)

var outputs []*Output

type (
	// Output used for filtering incoming log records from all logger instances
	// and decides how to write them. Each Output wraps its own io.Writer.
	// Output methods are safe for concurrent usage.
	Output struct {
		sync.RWMutex
		In              chan *[]pair
		w               io.Writer
		format          format
		paused          bool
		closed          bool
		positiveFilters map[string]filter
		negativeFilters map[string]filter
		hiddenKeys      map[string]bool
	}
	format uint8
)

// current output formats
const (
	Logfmt format = iota
	JSON
)

// UseOutput creates a new output for an arbitrary number of loggers.
// There are any number of outputs may be created for saving incoming log
// records to different places.
func UseOutput(w io.Writer, logFormat format) *Output {
	for _, out := range outputs {
		if out.w == w {
			return out
		}
	}
	out := &Output{
		In:              make(chan *[]pair, 16),
		w:               w,
		positiveFilters: make(map[string]filter),
		negativeFilters: make(map[string]filter),
		format:          logFormat}
	outputs = append(outputs, out)
	go processOutput(out)
	return out
}

// With sets restriction for records output.
// Only the records WITH any of the keys will be passed to output.
func (out *Output) With(keys ...string) *Output {
	if !out.closed {
		out.Lock()
		for _, tag := range keys {
			delete(out.negativeFilters, tag)
			out.positiveFilters[tag] = &keyFilter{Key: tag}
		}
		out.Unlock()
	}
	return out
}

// Without sets restriction for records output.
// Only the records WITHOUT any of the keys will be passed to output.
func (out *Output) Without(keys ...string) *Output {
	if !out.closed {
		out.Lock()
		for _, tag := range keys {
			out.negativeFilters[tag] = &keyFilter{Key: tag}
			delete(out.positiveFilters, tag)
		}
		out.Unlock()
	}
	return out
}

// WithValues sets restriction for records output.
// A record passed to output if the key equal one of any of the listed values.
func (out *Output) WithValues(key string, vals ...string) *Output {
	if len(vals) == 0 {
		return out.With(key)
	}
	if !out.closed {
		out.Lock()
		delete(out.negativeFilters, key)
		out.positiveFilters[key] = &valsFilter{Key: key, Vals: vals}
		out.Unlock()
	}
	return out
}

// WithoutValues sets restriction for records output.
func (out *Output) WithoutValues(key string, vals ...string) *Output {
	if len(vals) == 0 {
		return out.Without(key)
	}
	if !out.closed {
		out.Lock()
		delete(out.positiveFilters, key)
		out.negativeFilters[key] = &valsFilter{Key: key, Vals: vals}
		out.Unlock()
	}
	return out
}

// WithRangeInt64 sets restriction for records output.
func (out *Output) WithRangeInt64(key string, from, to int64) *Output {
	if !out.closed {
		out.Lock()

		delete(out.negativeFilters, key)
		out.positiveFilters[key] = &rangeInt64Filter{Key: key, From: from, To: to}
		out.Unlock()
	}
	return out
}

// WithRangeFloat64 sets restriction for records output.
func (out *Output) WithoutRangeInt64(key string, from, to int64) *Output {
	out.Lock()
	if !out.closed {
		delete(out.positiveFilters, key)
		out.negativeFilters[key] = &rangeInt64Filter{Key: key, From: from, To: to}
	}
	out.Unlock()
	return out
}

// WithRangeFloat64 sets restriction for records output.
func (out *Output) WithRangeFloat64(key string, from, to float64) *Output {
	out.Lock()
	delete(out.negativeFilters, key)
	out.positiveFilters[key] = &rangeFloat64Filter{Key: key, From: from, To: to}
	out.Unlock()
	return out
}

// WithoutRangeFloat64  sets restriction for records output.
func (out *Output) WithoutRangeFloat64(key string, from, to float64) *Output {
	if !out.closed {
		out.Lock()
		delete(out.positiveFilters, key)
		out.negativeFilters[key] = &rangeFloat64Filter{Key: key, From: from, To: to}
		out.Unlock()
	}
	return out
}

// Reset all filters for the keys for the output.
func (out *Output) Reset(keys ...string) *Output {
	out.Lock()
	for _, tag := range keys {
		delete(out.positiveFilters, tag)
		delete(out.negativeFilters, tag)
	}
	out.Unlock()
	return out
}

// Hide keys from the output. Other keys in record will be displayed
// but not hidden keys.
func (out *Output) Hide(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			out.hiddenKeys[tag] = true
		}
	}
	out.Unlock()
	return out
}

// Unhide previously hidden keys. They will be displayed in the output again.
func (out *Output) Unhide(keys ...string) *Output {
	out.Lock()
	if !out.closed {
		for _, tag := range keys {
			delete(out.hiddenKeys, tag)
		}
	}
	out.Unlock()
	return out
}

// Pause stops writing to the output.
func (out *Output) Pause() {
	out.paused = true
}

// Contiunue writing to the output.
func (out *Output) Continue() {
	out.paused = false
}

func (out *Output) Close() {
	out.Lock()
	out.closed = true
	out.Unlock()
	close(out.In)
}

func (out *Output) Flush() {
	out.In <- nil
	time.Sleep(5 * time.Millisecond)
}

// A new record passed to all outputs. Each output routine decides n
func passRecordToOutput(record []pair) {
	for _, out := range outputs {
		if !out.closed && !out.paused {
			out.In <- &record
		}
	}
}

func processOutput(out *Output) {
	for {
		record, ok := <-out.In
		if !ok {
			out.positiveFilters = nil
			out.negativeFilters = nil
			out.hiddenKeys = nil
			return
		}
		if out.closed || out.paused {
			continue
		}
		if record == nil {
			// Flush!
			time.Sleep(5 * time.Millisecond) // XXX make real flush
			continue
		}
		out.RLock()
		for _, pair := range *record {
			if filter, ok := out.negativeFilters[pair.Key]; ok {
				if filter.Check(pair.Key, pair.Val.Strv) {
					goto skipRecord
				}
			}
			if filter, ok := out.positiveFilters[pair.Key]; ok {
				if !filter.Check(pair.Key, pair.Val.Strv) {
					goto skipRecord
				}
			}
		}
		out.RUnlock()
		out.write(record)
		continue
	skipRecord:
		out.RUnlock()
	}
}

// it yet ignores output format
func (out *Output) write(record *[]pair) {
	var logLine bytes.Buffer
	switch out.format {
	case JSON:
		logLine.WriteRune('{')
		out.RLock()
		for _, pair := range *record {
			if ok := out.hiddenKeys[pair.Key]; ok {
				continue
			}
			logLine.WriteRune('"')
			logLine.WriteString(pair.Key)
			logLine.WriteString("\":")
			var curVal string
			if pair.Val.Func != nil {
				// Evaluate lazy value here
				// TODO exaluation should be made in logger not output!
				// XXX refactor it!
				tmp := toRecordValue(toFunc(pair.Val.Func))
				curVal = tmp.Strv
			} else {
				curVal = pair.Val.Strv
			}
			if pair.Val.Quoted {
				logLine.WriteString(strconv.Quote(curVal))
			} else {
				logLine.WriteString(curVal)
			}
			logLine.WriteString(", ")
		}
		logLine.WriteRune('}')
	case Logfmt:
		out.RLock()
		for _, pair := range *record {
			if ok := out.hiddenKeys[pair.Key]; ok {
				continue
			}
			logLine.WriteString(pair.Key)
			logLine.WriteRune('=')
			var curVal string
			if pair.Val.Func != nil {
				// Evaluate lazy value here
				// TODO exaluation should be made in logger not output!
				// XXX refactor it!
				tmp := toRecordValue(toFunc(pair.Val.Func))
				curVal = tmp.Strv
			} else {
				curVal = pair.Val.Strv
			}
			if pair.Val.Quoted {
				logLine.WriteString(strconv.Quote(curVal))
			} else {
				logLine.WriteString(curVal)
			}
			logLine.WriteRune(' ')
		}
	}
	out.RUnlock()
	logLine.WriteRune('\n')
	logLine.WriteTo(out.w)
}
<|endoftext|>


<commit_before>package main

/*
 *
 * Colored text output
 *
 * Only supports a few selected colors
 *
 */

import (
	"fmt"
	"os"
)

type Output struct {
	color   bool
	enabled bool
}

func NewOutput(color bool, enabled bool) *Output {
	var o *Output = new(Output)
	o.color = color
	o.enabled = enabled
	return o
}

func (o *Output) Err(msg string) {
	if o.enabled {
		fmt.Fprintf(os.Stderr, o.DarkRed(msg)+"\n")
	}
}

// Print the message as red text and exit with errorlevel 1
func (o *Output) Exit(msg string) {
	o.Err(msg)
	os.Exit(1)
}

func (o *Output) Println(msg string) {
	if o.enabled {
		fmt.Println(msg)
	}
}

func (o *Output) IsEnabled() bool {
	return o.enabled
}

func (o *Output) colorOn(num1 int, num2 int) string {
	if o.color {
		return fmt.Sprintf("\033[%d;%dm", num1, num2)
	}
	return ""
}

func (o *Output) colorOff() string {
	if o.color {
		return "\033[0m"
	}
	return ""
}

// TODO: Consider generating the following functions as closures instead

func (o *Output) DarkRed(s string) string {
	return o.colorOn(0, 31) + s + o.colorOff()
}

func (o *Output) LightGreen(s string) string {
	return o.colorOn(1, 32) + s + o.colorOff()
}

func (o *Output) DarkGreen(s string) string {
	return o.colorOn(0, 32) + s + o.colorOff()
}

func (o *Output) LightYellow(s string) string {
	return o.colorOn(1, 33) + s + o.colorOff()
}

func (o *Output) DarkYellow(s string) string {
	return o.colorOn(0, 33) + s + o.colorOff()
}

func (o *Output) LightBlue(s string) string {
	return o.colorOn(1, 34) + s + o.colorOff()
}

func (o *Output) DarkBlue(s string) string {
	return o.colorOn(0, 34) + s + o.colorOff()
}

func (o *Output) LightCyan(s string) string {
	return o.colorOn(1, 36) + s + o.colorOff()
}

func (o *Output) LightPurple(s string) string {
	return o.colorOn(1, 35) + s + o.colorOff()
}

func (o *Output) DarkPurple(s string) string {
	return o.colorOn(0, 35) + s + o.colorOff()
}

func (o *Output) DarkGray(s string) string {
	return o.colorOn(1, 30) + s + o.colorOff()
}
<commit_msg>Refactoring<commit_after>package main

/*
 *
 * Colored text output
 *
 * Only supports a few selected colors
 *
 */

import (
	"fmt"
	"os"
)

type Output struct {
	color   bool
	enabled bool
}

func NewOutput(color bool, enabled bool) *Output {
	return &Output{color, enabled}
}

func (o *Output) Err(msg string) {
	if o.enabled {
		fmt.Fprintf(os.Stderr, o.DarkRed(msg)+"\n")
	}
}

// Print the message as red text and exit with errorlevel 1
func (o *Output) Exit(msg string) {
	o.Err(msg)
	os.Exit(1)
}

func (o *Output) Println(msg string) {
	if o.enabled {
		fmt.Println(msg)
	}
}

func (o *Output) IsEnabled() bool {
	return o.enabled
}

func (o *Output) colorOn(num1 int, num2 int) string {
	if o.color {
		return fmt.Sprintf("\033[%d;%dm", num1, num2)
	}
	return ""
}

func (o *Output) colorOff() string {
	if o.color {
		return "\033[0m"
	}
	return ""
}

// TODO: Consider generating the following functions as closures instead

func (o *Output) DarkRed(s string) string {
	return o.colorOn(0, 31) + s + o.colorOff()
}

func (o *Output) LightGreen(s string) string {
	return o.colorOn(1, 32) + s + o.colorOff()
}

func (o *Output) DarkGreen(s string) string {
	return o.colorOn(0, 32) + s + o.colorOff()
}

func (o *Output) LightYellow(s string) string {
	return o.colorOn(1, 33) + s + o.colorOff()
}

func (o *Output) DarkYellow(s string) string {
	return o.colorOn(0, 33) + s + o.colorOff()
}

func (o *Output) LightBlue(s string) string {
	return o.colorOn(1, 34) + s + o.colorOff()
}

func (o *Output) DarkBlue(s string) string {
	return o.colorOn(0, 34) + s + o.colorOff()
}

func (o *Output) LightCyan(s string) string {
	return o.colorOn(1, 36) + s + o.colorOff()
}

func (o *Output) LightPurple(s string) string {
	return o.colorOn(1, 35) + s + o.colorOff()
}

func (o *Output) DarkPurple(s string) string {
	return o.colorOn(0, 35) + s + o.colorOff()
}

func (o *Output) DarkGray(s string) string {
	return o.colorOn(1, 30) + s + o.colorOff()
}
<|endoftext|>


<commit_before>package css

import (
	"fmt"
	"github.com/gorilla/css/scanner"
	"strings"
)

/*
	stylesheet  : [ CDO | CDC | S | statement ]*;
	statement   : ruleset | at-rule;
	at-rule     : ATKEYWORD S* any* [ block | ';' S* ];
	block       : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*;
	ruleset     : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
	selector    : any+;
	declaration : property S* ':' S* value;
	property    : IDENT;
	value       : [ any | block | ATKEYWORD S* ]+;
	any         : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
	              | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
	              | DASHMATCH | ':' | FUNCTION S* [any|unused]* ')'
	              | '(' S* [any|unused]* ')' | '[' S* [any|unused]* ']'
	              ] S*;
	unused      : block | ATKEYWORD S* | ';' S* | CDO S* | CDC S*;
*/

type State int

const (
	STATE_NONE State = iota
	STATE_SELECTOR
	STATE_DECLARE_BLOCK
	STATE_PROPERTY
	STATE_VALUE
)

type parserContext struct {
	State            State
	NowSelectorText  string
	NowRuleType      RuleType
	CurrentRule      *CSSRule
	CurrentMediaRule *CSSRule
}

func Parse(csstext string) *CSSStyleSheet {
	context := &parserContext{
		State:            STATE_NONE,
		NowSelectorText:  "",
		NowRuleType:      STYLE_RULE,
		CurrentMediaRule: nil,
	}

	css := &CSSStyleSheet{}
	css.CssRuleList = make([]*CSSRule, 0)
	s := scanner.New(csstext)

	for {
		token := s.Next()

		fmt.Printf("Parse(%d): %s:'%s'\n", context.State, token.Type.String(), token.Value)

		if token.Type == scanner.TokenEOF || token.Type == scanner.TokenError {
			break
		}

		switch token.Type {
		case scanner.TokenAtKeyword:
			context.State = STATE_SELECTOR
			switch token.Value {
			case "@media":
				context.NowRuleType = MEDIA_RULE
			}

		case scanner.TokenString:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}
		case scanner.TokenIdent:

			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

		case scanner.TokenDimension:
			fallthrough
		case scanner.TokenS:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}

		case scanner.TokenChar:
			if context.State == STATE_NONE {
				if token.Value == "}" && context.CurrentMediaRule != nil {
					// close media rule
					css.CssRuleList = append(css.CssRuleList, context.CurrentMediaRule)
					context.CurrentMediaRule = nil
					break
				}
				if token.Value != "{" {
					context.State = STATE_SELECTOR
					context.NowSelectorText += token.Value
					break
				}
			}
			if context.State == STATE_SELECTOR {
				if "{" == token.Value {
					if context.NowRuleType == MEDIA_RULE {
						context.CurrentMediaRule = NewRule(context.NowRuleType)
						context.CurrentMediaRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
						// reset
						context.NowSelectorText = ""
						context.NowRuleType = STYLE_RULE
						context.State = STATE_NONE
						break
					} else {
						context.CurrentRule = NewRule(context.NowRuleType)
						context.CurrentRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
						context.CurrentRule.Style.Styles = parseBlock(s)
						if context.CurrentMediaRule != nil {
							context.CurrentMediaRule.Rules = append(context.CurrentMediaRule.Rules, context.CurrentRule)
						} else {
							css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
						}
						context.CurrentRule = nil
						context.NowSelectorText = ""
						context.NowRuleType = STYLE_RULE
						context.State = STATE_NONE
						break
					}
				} else {
					context.NowSelectorText += token.Value
				}
				break
			}
		case scanner.TokenPercentage:
			fallthrough
		case scanner.TokenHash:
			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			fallthrough
		case scanner.TokenNumber:
			fallthrough
		case scanner.TokenFunction:
			fallthrough
		case scanner.TokenIncludes:
			fallthrough
		case scanner.TokenDashMatch:
			fallthrough
		case scanner.TokenPrefixMatch:
			fallthrough
		case scanner.TokenSuffixMatch:
			fallthrough
		case scanner.TokenSubstringMatch:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}

		// Unhandle token
		case scanner.TokenURI:
			fallthrough
		case scanner.TokenUnicodeRange:
			fallthrough
		case scanner.TokenCDO:
			fallthrough
		case scanner.TokenCDC:
			fallthrough
		case scanner.TokenComment:
			fallthrough
		default:
			fmt.Printf("Unhandled, %s:'%s'\n", token.Type.String(), token.Value)
		}
	}
	return css
}
<commit_msg>STATE_DECLARE_BLOCK is no longer needed<commit_after>package css

import (
	"fmt"
	"github.com/gorilla/css/scanner"
	"strings"
)

/*
	stylesheet  : [ CDO | CDC | S | statement ]*;
	statement   : ruleset | at-rule;
	at-rule     : ATKEYWORD S* any* [ block | ';' S* ];
	block       : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*;
	ruleset     : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
	selector    : any+;
	declaration : property S* ':' S* value;
	property    : IDENT;
	value       : [ any | block | ATKEYWORD S* ]+;
	any         : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
	              | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
	              | DASHMATCH | ':' | FUNCTION S* [any|unused]* ')'
	              | '(' S* [any|unused]* ')' | '[' S* [any|unused]* ']'
	              ] S*;
	unused      : block | ATKEYWORD S* | ';' S* | CDO S* | CDC S*;
*/

type State int

const (
	STATE_NONE State = iota
	STATE_SELECTOR
	STATE_PROPERTY
	STATE_VALUE
)

type parserContext struct {
	State            State
	NowSelectorText  string
	NowRuleType      RuleType
	CurrentRule      *CSSRule
	CurrentMediaRule *CSSRule
}

func Parse(csstext string) *CSSStyleSheet {
	context := &parserContext{
		State:            STATE_NONE,
		NowSelectorText:  "",
		NowRuleType:      STYLE_RULE,
		CurrentMediaRule: nil,
	}

	css := &CSSStyleSheet{}
	css.CssRuleList = make([]*CSSRule, 0)
	s := scanner.New(csstext)

	for {
		token := s.Next()

		fmt.Printf("Parse(%d): %s:'%s'\n", context.State, token.Type.String(), token.Value)

		if token.Type == scanner.TokenEOF || token.Type == scanner.TokenError {
			break
		}

		switch token.Type {
		case scanner.TokenAtKeyword:
			context.State = STATE_SELECTOR
			switch token.Value {
			case "@media":
				context.NowRuleType = MEDIA_RULE
			}

		case scanner.TokenString:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}
		case scanner.TokenIdent:

			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

		case scanner.TokenDimension:
			fallthrough
		case scanner.TokenS:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}

		case scanner.TokenChar:
			if context.State == STATE_NONE {
				if token.Value == "}" && context.CurrentMediaRule != nil {
					// close media rule
					css.CssRuleList = append(css.CssRuleList, context.CurrentMediaRule)
					context.CurrentMediaRule = nil
					break
				}
				if token.Value != "{" {
					context.State = STATE_SELECTOR
					context.NowSelectorText += token.Value
					break
				}
			}
			if context.State == STATE_SELECTOR {
				if "{" == token.Value {
					if context.NowRuleType == MEDIA_RULE {
						context.CurrentMediaRule = NewRule(context.NowRuleType)
						context.CurrentMediaRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
						// reset
						context.NowSelectorText = ""
						context.NowRuleType = STYLE_RULE
						context.State = STATE_NONE
						break
					} else {
						context.CurrentRule = NewRule(context.NowRuleType)
						context.CurrentRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
						context.CurrentRule.Style.Styles = parseBlock(s)
						if context.CurrentMediaRule != nil {
							context.CurrentMediaRule.Rules = append(context.CurrentMediaRule.Rules, context.CurrentRule)
						} else {
							css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
						}
						context.CurrentRule = nil
						context.NowSelectorText = ""
						context.NowRuleType = STYLE_RULE
						context.State = STATE_NONE
						break
					}
				} else {
					context.NowSelectorText += token.Value
				}
				break
			}
		case scanner.TokenPercentage:
			fallthrough
		case scanner.TokenHash:
			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			fallthrough
		case scanner.TokenNumber:
			fallthrough
		case scanner.TokenFunction:
			fallthrough
		case scanner.TokenIncludes:
			fallthrough
		case scanner.TokenDashMatch:
			fallthrough
		case scanner.TokenPrefixMatch:
			fallthrough
		case scanner.TokenSuffixMatch:
			fallthrough
		case scanner.TokenSubstringMatch:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
				break
			}

		// Unhandle token
		case scanner.TokenURI:
			fallthrough
		case scanner.TokenUnicodeRange:
			fallthrough
		case scanner.TokenCDO:
			fallthrough
		case scanner.TokenCDC:
			fallthrough
		case scanner.TokenComment:
			fallthrough
		default:
			fmt.Printf("Unhandled, %s:'%s'\n", token.Type.String(), token.Value)
		}
	}
	return css
}
<|endoftext|>