<commit_before>package cask

import "github.com/pkg/errors"

// A Parser represents the parser that uses the emitted token provided by Lexer.
type Parser struct {
	// cask specifies the parsed Cask.
	cask *Cask

	// lexer specifies Lexer pointer.
	lexer *Lexer

	// currentToken specifies the current emitted Lexer token.
	currentToken Token

	// peekToken specifies the next Lexer token.
	peekToken Token

	// errors specify an array of errors.
	errors []error

	// currentCaskVariant specifies the temporary cask Variant that currently
	// being parsed.
	currentCaskVariant *Variant

	// currentIfVariant specifies the temporary cask Variant that holds data
	// extracted in if condition.
	currentIfVariant *Variant
}

// NewParser creates a new Parser instance and returns its pointer. Requires a
// Lexer and a Cask to be specified as arguments.
func NewParser(lexer *Lexer) *Parser {
	p := &Parser{
		lexer:  lexer,
		errors: []error{},
	}

	// read two tokens, so both currentToken and peekToken are set
	p.nextToken()
	p.nextToken()

	return p
}

// parseVersion parses the version if the Parser.peekToken matches the cask
// requirements. If the ":latest" symbol is found, the version will become the
// "latest" string.
func (p *Parser) parseVersion() (string, error) {
	if p.peekTokenIs(STRING) {
		p.accept(STRING)
		return p.currentToken.Literal, nil
	}

	if p.peekTokenIs(SYMBOL) && p.peekToken.Literal == "latest" {
		p.accept(SYMBOL)
		return "latest", nil
	}

	return "", errors.New("version not found")
}

// parseAppcast parses the appcast if the Parser.peekToken matches the cask
// requirements. Supports both with and without checkpoint.
func (p *Parser) parseAppcast() (*Appcast, error) {
	if p.peekTokenIs(STRING) {
		p.accept(STRING)

		url := p.currentToken.Literal
		checkpoint := ""

		if p.peekTokenIs(COMMA) {
			p.accept(COMMA)
		}

		if p.peekTokenIs(NEWLINE) {
			p.accept(NEWLINE)
		}

		if p.peekTokenIs(IDENT) && p.peekToken.Literal == "checkpoint" {
			p.accept(IDENT)
			p.accept(SYMBOL)

			if p.peekTokenIs(STRING) {
				p.accept(STRING)
				checkpoint = p.currentToken.Literal
			}
		}

		return NewAppcast(url, checkpoint), nil
	}

	return nil, errors.New("appcast not found")
}

//
func (p *Parser) parseArtifact() (*Artifact, error) {
	switch p.currentToken.Literal {
	case "app":
		return p.parseArtifactApp()
	case "pkg":
		return p.parseArtifactPkg()
	case "binary":
		return p.parseArtifactBinary()
	default:
		return nil, errors.New("artifact not found")
	}
}

func (p *Parser) parseArtifactApp() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "app" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactApp, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "target" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(STRING) {
					p.accept(STRING)
					a.Target = p.currentToken.Literal
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "app" artifact`)
}

func (p *Parser) parseArtifactPkg() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "pkg" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactApp, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "allow_untrusted" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(TRUE) {
					p.accept(TRUE)
					a.AllowUntrusted = true
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "pkg" artifact`)
}

func (p *Parser) parseArtifactBinary() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "binary" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactBinary, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "target" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(STRING) {
					p.accept(STRING)
					a.Target = p.currentToken.Literal
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "binary" artifact`)
}

// parseConditionMacOS parses the "MacOS.release" condition statement.
func (p *Parser) parseConditionMacOS() (min MacOS, max MacOS, err error) {
	var comparison TokenType
	var hasEqual bool
	var mac MacOS

	if p.currentTokenIs(CONST) && p.currentToken.Literal == "MacOS" {
		p.accept(DOT)

		// release
		if p.peekTokenIs(IDENT) && p.peekToken.Literal == "release" {
			p.accept(IDENT)

			// comparison
			if p.peekTokenOneOf(EQ, GT, LT) {
				p.acceptOneOf(EQ, GT, LT)
				comparison = p.currentToken.Type

				if p.peekTokenIs(ASSIGN) {
					p.accept(ASSIGN)
					hasEqual = true
				}
			}

			// macOS
			if p.peekTokenIs(SYMBOL) {
				p.accept(SYMBOL)
				switch p.currentToken.Literal {
				case "high_sierra":
					mac = MacOSHighSierra
				case "sierra":
					mac = MacOSSierra
				case "el_capitan":
					mac = MacOSElCapitan
				case "yosemite":
					mac = MacOSYosemite
				case "mavericks":
					mac = MacOSMavericks
				case "mountain_lion":
					mac = MacOSMountainLion
				case "lion":
					mac = MacOSLion
				case "snow_leopard":
					mac = MacOSSnowLeopard
				case "leopard":
					mac = MacOSLeopard
				case "tiger":
					mac = MacOSTiger
				default:
					return MacOSHighSierra, MacOSHighSierra, errors.New("MacOS condition is unknown")
				}
			}

			// comparison with macOS
			switch comparison {
			case EQ:
				return mac, mac, nil
			case GT:
				min = mac - 1
				max = MacOSHighSierra
				if hasEqual || min < 0 {
					min = mac
				}
				return min, max, nil
			case LT:
				min = MacOSTiger
				max = mac + 1
				if hasEqual || max > MacOSTiger {
					max = mac
				}
				return min, max, nil
			}
		}
	}

	// by default should return the latest
	return MacOSHighSierra, MacOSHighSierra, errors.New("MacOS condition not found")
}

// nextToken updates the Parser.currentToken and Parser.peekToken values to
// match the next Lexer token.
func (p *Parser) nextToken() {
	p.currentToken = p.peekToken
	if p.lexer.HasNext() {
		p.peekToken = p.lexer.NextToken()
	}
}

// currentTokenIs checks whether the current Token.Type matches the specified
// TokenType.
func (p *Parser) currentTokenIs(t TokenType) bool {
	return p.currentToken.Type == t
}

// currentTokenOneOf checks whether the current Token.Type is from valid
// TokenType set.
func (p *Parser) currentTokenOneOf(types ...TokenType) bool {
	for _, t := range types {
		if p.currentToken.Type == t {
			return true
		}
	}
	return false
}

// currentTokenLiteralIs checks whether the current Token.Literal matches the
// specified value.
func (p *Parser) currentTokenLiteralIs(l string) bool {
	return p.currentToken.Literal == l
}

// currentTokenLiteralOneOf checks whether the current Token.Literal is from
// valid values set.
func (p *Parser) currentTokenLiteralOneOf(literals ...string) bool {
	for _, l := range literals {
		if p.currentToken.Literal == l {
			return true
		}
	}
	return false
}

// peekTokenIs checks whether the next Token.Type matches the specified
// TokenType.
func (p *Parser) peekTokenIs(t TokenType) bool {
	return p.peekToken.Type == t
}

// peekTokenOneOf checks whether the next Token.Type is from valid TokenType
// set.
func (p *Parser) peekTokenOneOf(types ...TokenType) bool {
	for _, t := range types {
		if p.peekToken.Type == t {
			return true
		}
	}
	return false
}

// accept moves to the next Token if it's from the valid TokenType set.
func (p *Parser) accept(t TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	}

	p.peekError(t)
	return false
}

// acceptOneOf moves to the next Token if it's from the valid TokenType set.
func (p *Parser) acceptOneOf(t ...TokenType) bool {
	if p.peekTokenOneOf(t...) {
		p.nextToken()
		return true
	}

	p.peekError(t...)
	return false
}

// peekError adds a new unexpectedTokenError to Parser.errors.
func (p *Parser) peekError(t ...TokenType) {
	p.errors = append(p.errors, &unexpectedTokenError{
		expectedTokens: t,
		actualToken:    p.peekToken.Type,
	})
}

// Errors returns all errors which happened during the Parser.input parsing.
func (p *Parser) Errors() []error {
	return p.errors
}
<commit_msg>Add missing comments for Parser functions<commit_after>package cask

import "github.com/pkg/errors"

// A Parser represents the parser that uses the emitted token provided by Lexer.
type Parser struct {
	// cask specifies the parsed Cask.
	cask *Cask

	// lexer specifies Lexer pointer.
	lexer *Lexer

	// currentToken specifies the current emitted Lexer token.
	currentToken Token

	// peekToken specifies the next Lexer token.
	peekToken Token

	// errors specify an array of errors.
	errors []error

	// currentCaskVariant specifies the temporary cask Variant that currently
	// being parsed.
	currentCaskVariant *Variant

	// currentIfVariant specifies the temporary cask Variant that holds data
	// extracted in if condition.
	currentIfVariant *Variant
}

// NewParser creates a new Parser instance and returns its pointer. Requires a
// Lexer and a Cask to be specified as arguments.
func NewParser(lexer *Lexer) *Parser {
	p := &Parser{
		lexer:  lexer,
		errors: []error{},
	}

	// read two tokens, so both currentToken and peekToken are set
	p.nextToken()
	p.nextToken()

	return p
}

// parseVersion parses the version if the Parser.peekToken matches the cask
// requirements. If the ":latest" symbol is found, the version will become the
// "latest" string.
func (p *Parser) parseVersion() (string, error) {
	if p.peekTokenIs(STRING) {
		p.accept(STRING)
		return p.currentToken.Literal, nil
	}

	if p.peekTokenIs(SYMBOL) && p.peekToken.Literal == "latest" {
		p.accept(SYMBOL)
		return "latest", nil
	}

	return "", errors.New("version not found")
}

// parseAppcast parses the appcast if the Parser.peekToken matches the cask
// requirements. Supports both with and without checkpoint.
func (p *Parser) parseAppcast() (*Appcast, error) {
	if p.peekTokenIs(STRING) {
		p.accept(STRING)

		url := p.currentToken.Literal
		checkpoint := ""

		if p.peekTokenIs(COMMA) {
			p.accept(COMMA)
		}

		if p.peekTokenIs(NEWLINE) {
			p.accept(NEWLINE)
		}

		if p.peekTokenIs(IDENT) && p.peekToken.Literal == "checkpoint" {
			p.accept(IDENT)
			p.accept(SYMBOL)

			if p.peekTokenIs(STRING) {
				p.accept(STRING)
				checkpoint = p.currentToken.Literal
			}
		}

		return NewAppcast(url, checkpoint), nil
	}

	return nil, errors.New("appcast not found")
}

// parseArtifact parses the artifact if the Parser.currentToken matches one of
// the supported artifacts.
func (p *Parser) parseArtifact() (*Artifact, error) {
	switch p.currentToken.Literal {
	case "app":
		return p.parseArtifactApp()
	case "pkg":
		return p.parseArtifactPkg()
	case "binary":
		return p.parseArtifactBinary()
	default:
		return nil, errors.New("artifact not found")
	}
}

// parseArtifactApp parses the "app" artifact if the Parser.currentToken matches
// the requirements.
func (p *Parser) parseArtifactApp() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "app" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactApp, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "target" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(STRING) {
					p.accept(STRING)
					a.Target = p.currentToken.Literal
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "app" artifact`)
}

// parseArtifactPkg parses the "pkg" artifact if the Parser.currentToken matches
// the requirements.
func (p *Parser) parseArtifactPkg() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "pkg" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactApp, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "allow_untrusted" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(TRUE) {
					p.accept(TRUE)
					a.AllowUntrusted = true
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "pkg" artifact`)
}

// parseArtifactBinary parses the "binary" artifact if the Parser.currentToken
// matches the requirements.
func (p *Parser) parseArtifactBinary() (*Artifact, error) {
	if p.currentTokenIs(IDENT) && p.currentToken.Literal == "binary" {
		if p.peekTokenIs(STRING) {
			p.accept(STRING)

			a := NewArtifact(ArtifactBinary, p.currentToken.Literal)

			if p.peekTokenIs(COMMA) {
				p.accept(COMMA)
			}

			if p.peekTokenIs(NEWLINE) {
				p.accept(NEWLINE)
			}

			if p.peekTokenIs(IDENT) && p.peekToken.Literal == "target" {
				p.accept(IDENT)
				p.accept(SYMBOL)

				if p.peekTokenIs(STRING) {
					p.accept(STRING)
					a.Target = p.currentToken.Literal
				}
			}

			return a, nil
		}
	}

	return nil, errors.New(`error parsing "binary" artifact`)
}

// parseConditionMacOS parses the "MacOS.release" condition statement.
func (p *Parser) parseConditionMacOS() (min MacOS, max MacOS, err error) {
	var comparison TokenType
	var hasEqual bool
	var mac MacOS

	if p.currentTokenIs(CONST) && p.currentToken.Literal == "MacOS" {
		p.accept(DOT)

		// release
		if p.peekTokenIs(IDENT) && p.peekToken.Literal == "release" {
			p.accept(IDENT)

			// comparison
			if p.peekTokenOneOf(EQ, GT, LT) {
				p.acceptOneOf(EQ, GT, LT)
				comparison = p.currentToken.Type

				if p.peekTokenIs(ASSIGN) {
					p.accept(ASSIGN)
					hasEqual = true
				}
			}

			// macOS
			if p.peekTokenIs(SYMBOL) {
				p.accept(SYMBOL)
				switch p.currentToken.Literal {
				case "high_sierra":
					mac = MacOSHighSierra
				case "sierra":
					mac = MacOSSierra
				case "el_capitan":
					mac = MacOSElCapitan
				case "yosemite":
					mac = MacOSYosemite
				case "mavericks":
					mac = MacOSMavericks
				case "mountain_lion":
					mac = MacOSMountainLion
				case "lion":
					mac = MacOSLion
				case "snow_leopard":
					mac = MacOSSnowLeopard
				case "leopard":
					mac = MacOSLeopard
				case "tiger":
					mac = MacOSTiger
				default:
					return MacOSHighSierra, MacOSHighSierra, errors.New("MacOS condition is unknown")
				}
			}

			// comparison with macOS
			switch comparison {
			case EQ:
				return mac, mac, nil
			case GT:
				min = mac - 1
				max = MacOSHighSierra
				if hasEqual || min < 0 {
					min = mac
				}
				return min, max, nil
			case LT:
				min = MacOSTiger
				max = mac + 1
				if hasEqual || max > MacOSTiger {
					max = mac
				}
				return min, max, nil
			}
		}
	}

	// by default should return the latest
	return MacOSHighSierra, MacOSHighSierra, errors.New("MacOS condition not found")
}

// nextToken updates the Parser.currentToken and Parser.peekToken values to
// match the next Lexer token.
func (p *Parser) nextToken() {
	p.currentToken = p.peekToken
	if p.lexer.HasNext() {
		p.peekToken = p.lexer.NextToken()
	}
}

// currentTokenIs checks whether the current Token.Type matches the specified
// TokenType.
func (p *Parser) currentTokenIs(t TokenType) bool {
	return p.currentToken.Type == t
}

// currentTokenOneOf checks whether the current Token.Type is from valid
// TokenType set.
func (p *Parser) currentTokenOneOf(types ...TokenType) bool {
	for _, t := range types {
		if p.currentToken.Type == t {
			return true
		}
	}
	return false
}

// currentTokenLiteralIs checks whether the current Token.Literal matches the
// specified value.
func (p *Parser) currentTokenLiteralIs(l string) bool {
	return p.currentToken.Literal == l
}

// currentTokenLiteralOneOf checks whether the current Token.Literal is from
// valid values set.
func (p *Parser) currentTokenLiteralOneOf(literals ...string) bool {
	for _, l := range literals {
		if p.currentToken.Literal == l {
			return true
		}
	}
	return false
}

// peekTokenIs checks whether the next Token.Type matches the specified
// TokenType.
func (p *Parser) peekTokenIs(t TokenType) bool {
	return p.peekToken.Type == t
}

// peekTokenOneOf checks whether the next Token.Type is from valid TokenType
// set.
func (p *Parser) peekTokenOneOf(types ...TokenType) bool {
	for _, t := range types {
		if p.peekToken.Type == t {
			return true
		}
	}
	return false
}

// accept moves to the next Token if it's from the valid TokenType set.
func (p *Parser) accept(t TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	}

	p.peekError(t)
	return false
}

// acceptOneOf moves to the next Token if it's from the valid TokenType set.
func (p *Parser) acceptOneOf(t ...TokenType) bool {
	if p.peekTokenOneOf(t...) {
		p.nextToken()
		return true
	}

	p.peekError(t...)
	return false
}

// peekError adds a new unexpectedTokenError to Parser.errors.
func (p *Parser) peekError(t ...TokenType) {
	p.errors = append(p.errors, &unexpectedTokenError{
		expectedTokens: t,
		actualToken:    p.peekToken.Type,
	})
}

// Errors returns all errors which happened during the Parser.input parsing.
func (p *Parser) Errors() []error {
	return p.errors
}
<|endoftext|>


<commit_before>// mpstat collector
// this will :
//  - call mpstat
//  - gather CPU metrics
//  - feed the collector

package collector

import (
    "log"
    "os/exec"
    "regexp"
    "strconv"
    "strings"
    // Prometheus Go toolset
    "github.com/prometheus/client_golang/prometheus"
)

type gzCPUUsageExporter struct {
    gzCPUUsage      *prometheus.GaugeVec
}

func NewGZCPUUsageExporter() (*gzCPUUsageExporter, error) {
    return &gzCPUUsageExporter{
        gzCPUUsage: prometheus.NewGaugeVec(prometheus.GaugeOpts{
            Name: "smartos_cpu_usage_percents",
            Help: "CPU usage exposed in percent.",
        }, []string{"cpu","mode"}),
    }, nil
}

func (e *gzCPUUsageExporter) Describe(ch chan<- *prometheus.Desc) {
    e.gzCPUUsage.Describe(ch)
}

func (e *gzCPUUsageExporter) Collect(ch chan<- prometheus.Metric) {
    e.mpstat()
    e.gzCPUUsage.Collect(ch)
}

func (e *gzCPUUsageExporter) mpstat() {
    // XXX needs enhancement :
    // use of mpstat will wait 2 seconds in order to collect statistics
    out, eerr := exec.Command("mpstat", "1", "2").Output()
    if eerr != nil {
        log.Fatal(eerr)
    }
    perr := e.parseMpstatOutput(string(out))
    if perr != nil {
        log.Fatal(perr)
    }
}

func (e *gzCPUUsageExporter) parseMpstatOutput(out string) (error) {
    // this regexp will remove all lines containing header labels
    r,_ := regexp.Compile(`(?m)[\r\n]+^.*CPU.*$`)
    result:= r.ReplaceAllString(out,"")

    outlines := strings.Split(result, "\n")
    l := len(outlines)
    for _, line := range outlines[1:l-1] {
        parsedLine := strings.Fields(line)
        cpuId := parsedLine[0]
        cpuUsr, err := strconv.ParseFloat(parsedLine[12], 64)
        if err != nil {
            return err
        }
        cpuSys, err := strconv.ParseFloat(parsedLine[13], 64)
        if err != nil {
            return err
        }
        cpuIdl, err := strconv.ParseFloat(parsedLine[15], 64)
        if err != nil {
            return err
        }
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "type":"user"}).Set(cpuUsr)
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "type":"system"}).Set(cpuSys)
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "type":"idle"}).Set(cpuIdl)
        //fmt.Printf("cpuId : %d, cpuUsr : %d, cpuSys : %d \n", cpuId, cpuUsr, cpuSys)
    }
    return nil
}
<commit_msg>Fix labels in mpstat<commit_after>// mpstat collector
// this will :
//  - call mpstat
//  - gather CPU metrics
//  - feed the collector

package collector

import (
    "log"
    "os/exec"
    "regexp"
    "strconv"
    "strings"
    // Prometheus Go toolset
    "github.com/prometheus/client_golang/prometheus"
)

type gzCPUUsageExporter struct {
    gzCPUUsage      *prometheus.GaugeVec
}

func NewGZCPUUsageExporter() (*gzCPUUsageExporter, error) {
    return &gzCPUUsageExporter{
        gzCPUUsage: prometheus.NewGaugeVec(prometheus.GaugeOpts{
            Name: "smartos_cpu_usage_percents",
            Help: "CPU usage exposed in percent.",
        }, []string{"cpu","mode"}),
    }, nil
}

func (e *gzCPUUsageExporter) Describe(ch chan<- *prometheus.Desc) {
    e.gzCPUUsage.Describe(ch)
}

func (e *gzCPUUsageExporter) Collect(ch chan<- prometheus.Metric) {
    e.mpstat()
    e.gzCPUUsage.Collect(ch)
}

func (e *gzCPUUsageExporter) mpstat() {
    // XXX needs enhancement :
    // use of mpstat will wait 2 seconds in order to collect statistics
    out, eerr := exec.Command("mpstat", "1", "2").Output()
    if eerr != nil {
        log.Fatal(eerr)
    }
    perr := e.parseMpstatOutput(string(out))
    if perr != nil {
        log.Fatal(perr)
    }
}

func (e *gzCPUUsageExporter) parseMpstatOutput(out string) (error) {
    // this regexp will remove all lines containing header labels
    r,_ := regexp.Compile(`(?m)[\r\n]+^.*CPU.*$`)
    result:= r.ReplaceAllString(out,"")

    outlines := strings.Split(result, "\n")
    l := len(outlines)
    for _, line := range outlines[1:l-1] {
        parsedLine := strings.Fields(line)
        cpuId := parsedLine[0]
        cpuUsr, err := strconv.ParseFloat(parsedLine[12], 64)
        if err != nil {
            return err
        }
        cpuSys, err := strconv.ParseFloat(parsedLine[13], 64)
        if err != nil {
            return err
        }
        cpuIdl, err := strconv.ParseFloat(parsedLine[15], 64)
        if err != nil {
            return err
        }
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "mode":"user"}).Set(cpuUsr)
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "mode":"system"}).Set(cpuSys)
        e.gzCPUUsage.With(prometheus.Labels{"cpu": cpuId, "mode":"idle"}).Set(cpuIdl)
        //fmt.Printf("cpuId : %d, cpuUsr : %d, cpuSys : %d \n", cpuId, cpuUsr, cpuSys)
    }
    return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	ch "github.com/jnormington/clubhouse-go"
)

var outputFormat = "%-40s %-17s %s\n"

// ImportCardsIntoClubhouse takes *[]Card, *ClubhouseOptions and builds a clubhouse Story
// this story from both the card and clubhouse options and creates via the api.
func ImportCardsIntoClubhouse(cards *[]Card, opts *ClubhouseOptions, um *UserMap) {
	fmt.Println("Importing trello cards into Clubhouse...")
	fmt.Printf(outputFormat+"\n", "Trello Card Link", "Import Status", "Error/Story ID")

	for _, c := range *cards {
		//We could use bulk update but lets give the user some prompt feedback
		st, err := opts.ClubhouseEntry.CreateStory(*buildClubhouseStory(&c, opts, um))
		if err != nil {
			fmt.Printf(outputFormat, c.ShortURL, "Failed", err)
			continue
		}

		fmt.Printf(outputFormat, c.ShortURL, "Success", fmt.Sprintf("Story ID: %d", st.ID))
	}
}

func buildLinkFiles(card *Card, opts *ClubhouseOptions) []int64 {
	var ids []int64

	for k, v := range card.Attachments {
		lf := ch.CreateLinkedFile{
			Name:       k,
			Type:       "url",
			URL:        v,
			UploaderID: opts.ImportMember.ID,
		}

		r, err := opts.ClubhouseEntry.CreateLinkedFiles(lf)
		if err != nil {
			fmt.Println("Fail to create linked file card name:", card.Name, "Dropbox link:", v, "Err:", err)
		} else {
			ids = append(ids, r.ID)
		}
	}

	return ids
}

func buildClubhouseStory(card *Card, opts *ClubhouseOptions, um *UserMap) *ch.CreateStory {

	return &ch.CreateStory{
		ProjectID:       opts.Project.ID,
		WorkflowStateID: opts.State.ID,
		RequestedByID:   um.GetCreator(card.IDCreator),
		OwnerIds:        mapOwnersFromTrelloCard(card, um),
		StoryType:       opts.StoryType,

		Name:        card.Name,
		Description: card.Desc,
		Deadline:    card.DueDate,
		CreatedAt:   card.CreatedAt,

		Labels:   *buildLabels(card),
		Tasks:    *buildTasks(card),
		Comments: *buildComments(card, opts.AddCommentWithTrelloLink, um),

		LinkedFileIds: buildLinkFiles(card, opts),
	}
}

func mapOwnersFromTrelloCard(c *Card, um *UserMap) []string {
	var owners []string

	for _, o := range c.IDOwners {
		owners = append(owners, um.GetCreator(o))
	}

	return owners
}

func buildComments(card *Card, addCommentWithTrelloLink bool, um *UserMap) *[]ch.CreateComment {
	var comments []ch.CreateComment

	for _, cm := range card.Comments {
		com := ch.CreateComment{
			CreatedAt: *cm.CreatedAt,
			AuthorID:  um.GetCreator(cm.IDCreator),
			Text:      cm.Text,
		}

		comments = append(comments, com)
	}

	if addCommentWithTrelloLink {
		cc := ch.CreateComment{
			CreatedAt: time.Now(),
			Text:      fmt.Sprintf("Card imported from Trello: %s", card.ShortURL),
		}

		comments = append(comments, cc)
	}

	return &comments
}

func buildTasks(card *Card) *[]ch.CreateTask {
	var tasks []ch.CreateTask

	for _, t := range card.Tasks {
		ts := ch.CreateTask{
			Complete:    t.Completed,
			Description: t.Description,
		}

		tasks = append(tasks, ts)
	}

	return &tasks
}

func buildLabels(card *Card) *[]ch.CreateLabel {
	var labels []ch.CreateLabel

	for _, l := range card.Labels {
		labels = append(labels, ch.CreateLabel{Name: l})
	}

	return &labels
}
<commit_msg>Ensure all slices are initialized as the API requires an empty array<commit_after>package main

import (
	"fmt"
	"time"

	ch "github.com/jnormington/clubhouse-go"
)

var outputFormat = "%-40s %-17s %s\n"

// ImportCardsIntoClubhouse takes *[]Card, *ClubhouseOptions and builds a clubhouse Story
// this story from both the card and clubhouse options and creates via the api.
func ImportCardsIntoClubhouse(cards *[]Card, opts *ClubhouseOptions, um *UserMap) {
	fmt.Println("Importing trello cards into Clubhouse...")
	fmt.Printf(outputFormat+"\n", "Trello Card Link", "Import Status", "Error/Story ID")

	for _, c := range *cards {
		//We could use bulk update but lets give the user some prompt feedback
		st, err := opts.ClubhouseEntry.CreateStory(*buildClubhouseStory(&c, opts, um))
		if err != nil {
			fmt.Printf(outputFormat, c.ShortURL, "Failed", err)
			continue
		}

		fmt.Printf(outputFormat, c.ShortURL, "Success", fmt.Sprintf("Story ID: %d", st.ID))
	}
}

func buildLinkFiles(card *Card, opts *ClubhouseOptions) []int64 {
	ids := []int64{}

	for k, v := range card.Attachments {
		lf := ch.CreateLinkedFile{
			Name:       k,
			Type:       "url",
			URL:        v,
			UploaderID: opts.ImportMember.ID,
		}

		r, err := opts.ClubhouseEntry.CreateLinkedFiles(lf)
		if err != nil {
			fmt.Println("Fail to create linked file card name:", card.Name, "Dropbox link:", v, "Err:", err)
		} else {
			ids = append(ids, r.ID)
		}
	}

	return ids
}

func buildClubhouseStory(card *Card, opts *ClubhouseOptions, um *UserMap) *ch.CreateStory {

	return &ch.CreateStory{
		ProjectID:       opts.Project.ID,
		WorkflowStateID: opts.State.ID,
		RequestedByID:   um.GetCreator(card.IDCreator),
		OwnerIds:        mapOwnersFromTrelloCard(card, um),
		StoryType:       opts.StoryType,
		FollowerIds:     []string{},
		FileIds:         []int64{},

		Name:        card.Name,
		Description: card.Desc,
		Deadline:    card.DueDate,
		CreatedAt:   card.CreatedAt,

		Labels:   *buildLabels(card),
		Tasks:    *buildTasks(card),
		Comments: *buildComments(card, opts.AddCommentWithTrelloLink, um),

		LinkedFileIds: buildLinkFiles(card, opts),
	}
}

func mapOwnersFromTrelloCard(c *Card, um *UserMap) []string {
	owners := []string{}

	for _, o := range c.IDOwners {
		owners = append(owners, um.GetCreator(o))
	}

	return owners
}

func buildComments(card *Card, addCommentWithTrelloLink bool, um *UserMap) *[]ch.CreateComment {
	comments := []ch.CreateComment{}

	for _, cm := range card.Comments {
		com := ch.CreateComment{
			CreatedAt: *cm.CreatedAt,
			AuthorID:  um.GetCreator(cm.IDCreator),
			Text:      cm.Text,
		}

		comments = append(comments, com)
	}

	if addCommentWithTrelloLink {
		cc := ch.CreateComment{
			CreatedAt: time.Now(),
			Text:      fmt.Sprintf("Card imported from Trello: %s", card.ShortURL),
		}

		comments = append(comments, cc)
	}

	return &comments
}

func buildTasks(card *Card) *[]ch.CreateTask {
	tasks := []ch.CreateTask{}

	for _, t := range card.Tasks {
		ts := ch.CreateTask{
			Complete:    t.Completed,
			Description: t.Description,
		}

		tasks = append(tasks, ts)
	}

	return &tasks
}

func buildLabels(card *Card) *[]ch.CreateLabel {
	labels := []ch.CreateLabel{}

	for _, l := range card.Labels {
		labels = append(labels, ch.CreateLabel{Name: l})
	}

	return &labels
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/mitchellh/cli"
	"github.com/posener/complete"
)

var _ cli.Command = (*KVPatchCommand)(nil)
var _ cli.CommandAutocomplete = (*KVPatchCommand)(nil)

type KVPatchCommand struct {
	*BaseCommand

	testStdin io.Reader // for tests
}

func (c *KVPatchCommand) Synopsis() string {
	return "Sets or updates data in the KV store without overwriting"
}

func (c *KVPatchCommand) Help() string {
	helpText := `
Usage: vault kv patch [options] KEY [DATA]

  *NOTE*: This is only supported for KV v2 engine mounts.

  Writes the data to the given path in the key-value store. The data can be of
  any type.

      $ vault kv patch secret/foo bar=baz

  The data can also be consumed from a file on disk by prefixing with the "@"
  symbol. For example:

      $ vault kv patch secret/foo @data.json

  Or it can be read from stdin using the "-" symbol:

      $ echo "abcd1234" | vault kv patch secret/foo bar=-

  Additional flags and more advanced use cases are detailed below.

` + c.Flags().Help()
	return strings.TrimSpace(helpText)
}

func (c *KVPatchCommand) Flags() *FlagSets {
	set := c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat)

	return set
}

func (c *KVPatchCommand) AutocompleteArgs() complete.Predictor {
	return nil
}

func (c *KVPatchCommand) AutocompleteFlags() complete.Flags {
	return c.Flags().Completions()
}

func (c *KVPatchCommand) Run(args []string) int {
	f := c.Flags()

	if err := f.Parse(args); err != nil {
		c.UI.Error(err.Error())
		return 1
	}

	args = f.Args()
	// Pull our fake stdin if needed
	stdin := (io.Reader)(os.Stdin)
	if c.testStdin != nil {
		stdin = c.testStdin
	}

	switch {
	case len(args) < 1:
		c.UI.Error(fmt.Sprintf("Not enough arguments (expected >1, got %d)", len(args)))
		return 1
	case len(args) == 1:
		c.UI.Error("Must supply data")
		return 1
	}

	var err error
	path := sanitizePath(args[0])

	client, err := c.Client()
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	newData, err := parseArgsData(stdin, args[1:])
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err))
		return 1
	}

	mountPath, v2, err := isKVv2(path, client)
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	if !v2 {
		c.UI.Error(fmt.Sprintf("K/V engine mount must be version 2 for patch support"))
		return 2
	}

	path = addPrefixToVKVPath(path, mountPath, "data")
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	// First, do a read
	secret, err := kvReadRequest(client, path, nil)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error doing pre-read at %s: %s", path, err))
		return 2
	}

	// Make sure a value already exists
	if secret == nil || secret.Data == nil {
		c.UI.Error(fmt.Sprintf("No value found at %s", path))
		return 2
	}

	// Verify metadata found
	rawMeta, ok := secret.Data["metadata"]
	if !ok || rawMeta == nil {
		c.UI.Error(fmt.Sprintf("No metadata found at %s; patch only works on existing data", path))
		return 2
	}
	meta, ok := rawMeta.(map[string]interface{})
	if !ok {
		c.UI.Error(fmt.Sprintf("Metadata found at %s is not the expected type (JSON object)", path))
		return 2
	}
	if meta == nil {
		c.UI.Error(fmt.Sprintf("No metadata found at %s; patch only works on existing data", path))
		return 2
	}

	// Verify old data found
	rawData, ok := secret.Data["data"]
	if !ok || rawData == nil {
		c.UI.Error(fmt.Sprintf("No data found at %s; patch only works on existing data", path))
		return 2
	}
	data, ok := rawData.(map[string]interface{})
	if !ok {
		c.UI.Error(fmt.Sprintf("Data found at %s is not the expected type (JSON object)", path))
		return 2
	}
	if data == nil {
		c.UI.Error(fmt.Sprintf("No data found at %s; patch only works on existing data", path))
		return 2
	}

	// Copy new data over
	for k, v := range newData {
		data[k] = v
	}

	secret, err = client.Logical().Write(path, map[string]interface{}{
		"data": data,
		"options": map[string]interface{}{
			"cas": meta["version"],
		},
	})
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error writing data to %s: %s", path, err))
		return 2
	}
	if secret == nil {
		// Don't output anything unless using the "table" format
		if Format(c.UI) == "table" {
			c.UI.Info(fmt.Sprintf("Success! Data written to: %s", path))
		}
		return 0
	}

	if c.flagField != "" {
		return PrintRawField(c.UI, secret, c.flagField)
	}

	return OutputSecret(c.UI, secret)
}
<commit_msg>fix output-curl-string for 'vault kv patch' (#6848)<commit_after>package command

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/mitchellh/cli"
	"github.com/posener/complete"
)

var _ cli.Command = (*KVPatchCommand)(nil)
var _ cli.CommandAutocomplete = (*KVPatchCommand)(nil)

type KVPatchCommand struct {
	*BaseCommand

	testStdin io.Reader // for tests
}

func (c *KVPatchCommand) Synopsis() string {
	return "Sets or updates data in the KV store without overwriting"
}

func (c *KVPatchCommand) Help() string {
	helpText := `
Usage: vault kv patch [options] KEY [DATA]

  *NOTE*: This is only supported for KV v2 engine mounts.

  Writes the data to the given path in the key-value store. The data can be of
  any type.

      $ vault kv patch secret/foo bar=baz

  The data can also be consumed from a file on disk by prefixing with the "@"
  symbol. For example:

      $ vault kv patch secret/foo @data.json

  Or it can be read from stdin using the "-" symbol:

      $ echo "abcd1234" | vault kv patch secret/foo bar=-

  Additional flags and more advanced use cases are detailed below.

` + c.Flags().Help()
	return strings.TrimSpace(helpText)
}

func (c *KVPatchCommand) Flags() *FlagSets {
	set := c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat)

	return set
}

func (c *KVPatchCommand) AutocompleteArgs() complete.Predictor {
	return nil
}

func (c *KVPatchCommand) AutocompleteFlags() complete.Flags {
	return c.Flags().Completions()
}

func (c *KVPatchCommand) Run(args []string) int {
	f := c.Flags()

	if err := f.Parse(args); err != nil {
		c.UI.Error(err.Error())
		return 1
	}

	args = f.Args()
	// Pull our fake stdin if needed
	stdin := (io.Reader)(os.Stdin)
	if c.testStdin != nil {
		stdin = c.testStdin
	}

	switch {
	case len(args) < 1:
		c.UI.Error(fmt.Sprintf("Not enough arguments (expected >1, got %d)", len(args)))
		return 1
	case len(args) == 1:
		c.UI.Error("Must supply data")
		return 1
	}

	var err error
	path := sanitizePath(args[0])

	client, err := c.Client()
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	newData, err := parseArgsData(stdin, args[1:])
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err))
		return 1
	}

	mountPath, v2, err := isKVv2(path, client)
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	if !v2 {
		c.UI.Error(fmt.Sprintf("K/V engine mount must be version 2 for patch support"))
		return 2
	}

	path = addPrefixToVKVPath(path, mountPath, "data")
	if err != nil {
		c.UI.Error(err.Error())
		return 2
	}

	// First, do a read.
	// Note that we don't want to see curl output for the read request.
	curOutputCurl := client.OutputCurlString()
	client.SetOutputCurlString(false)
	secret, err := kvReadRequest(client, path, nil)
	client.SetOutputCurlString(curOutputCurl)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error doing pre-read at %s: %s", path, err))
		return 2
	}

	// Make sure a value already exists
	if secret == nil || secret.Data == nil {
		c.UI.Error(fmt.Sprintf("No value found at %s", path))
		return 2
	}

	// Verify metadata found
	rawMeta, ok := secret.Data["metadata"]
	if !ok || rawMeta == nil {
		c.UI.Error(fmt.Sprintf("No metadata found at %s; patch only works on existing data", path))
		return 2
	}
	meta, ok := rawMeta.(map[string]interface{})
	if !ok {
		c.UI.Error(fmt.Sprintf("Metadata found at %s is not the expected type (JSON object)", path))
		return 2
	}
	if meta == nil {
		c.UI.Error(fmt.Sprintf("No metadata found at %s; patch only works on existing data", path))
		return 2
	}

	// Verify old data found
	rawData, ok := secret.Data["data"]
	if !ok || rawData == nil {
		c.UI.Error(fmt.Sprintf("No data found at %s; patch only works on existing data", path))
		return 2
	}
	data, ok := rawData.(map[string]interface{})
	if !ok {
		c.UI.Error(fmt.Sprintf("Data found at %s is not the expected type (JSON object)", path))
		return 2
	}
	if data == nil {
		c.UI.Error(fmt.Sprintf("No data found at %s; patch only works on existing data", path))
		return 2
	}

	// Copy new data over
	for k, v := range newData {
		data[k] = v
	}

	secret, err = client.Logical().Write(path, map[string]interface{}{
		"data": data,
		"options": map[string]interface{}{
			"cas": meta["version"],
		},
	})
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error writing data to %s: %s", path, err))
		return 2
	}
	if secret == nil {
		// Don't output anything unless using the "table" format
		if Format(c.UI) == "table" {
			c.UI.Info(fmt.Sprintf("Success! Data written to: %s", path))
		}
		return 0
	}

	if c.flagField != "" {
		return PrintRawField(c.UI, secret, c.flagField)
	}

	return OutputSecret(c.UI, secret)
}
<|endoftext|>


<commit_before>// Package commands contains all functionality that is triggered by the user,
// either through keyboard bindings or the command-line interface. New commands
// such as 'sort', 'add', etc. must be implemented here.
package commands

import (
	"fmt"
	"sort"
	"strings"

	"github.com/ambientsound/pms/api"
	"github.com/ambientsound/pms/input/lexer"
	"github.com/ambientsound/pms/parser"
	"github.com/ambientsound/pms/song"
	"github.com/ambientsound/pms/utils"
)

// Verbs contain mappings from strings to Command constructors.
// Make sure to add commands here when implementing them.
var Verbs = map[string]func(api.API) Command{
	"add":       NewAdd,
	"bind":      NewBind,
	"copy":      NewYank,
	"cursor":    NewCursor,
	"cut":       NewCut,
	"inputmode": NewInputMode,
	"isolate":   NewIsolate,
	"list":      NewList,
	"next":      NewNext,
	"paste":     NewPaste,
	"pause":     NewPause,
	"play":      NewPlay,
	"prev":      NewPrevious,
	"previous":  NewPrevious,
	"print":     NewPrint,
	"q":         NewQuit,
	"quit":      NewQuit,
	"redraw":    NewRedraw,
	"se":        NewSet,
	"seek":      NewSeek,
	"select":    NewSelect,
	"set":       NewSet,
	"single":    NewSingle,
	"sort":      NewSort,
	"stop":      NewStop,
	"style":     NewStyle,
	"volume":    NewVolume,
	"yank":      NewYank,
}

// Command must be implemented by all commands.
type Command interface {
	// Execute parses the next input token.
	// FIXME: Execute is deprecated
	Execute(class int, s string) error

	// Exec executes the AST generated by the command.
	Exec() error

	// SetScanner assigns a scanner to the command.
	// FIXME: move to constructor?
	SetScanner(*lexer.Scanner)

	// Parse and make an abstract syntax tree. This function MUST NOT have any side effects.
	Parse() error

	// TabComplete returns a set of tokens that could possibly be used as the next
	// command parameter.
	TabComplete() []string

	// Scanned returns a slice of tokens that have been scanned using Parse().
	Scanned() []parser.Token
}

// command is a helper base class that all commands may use.
type command struct {
	cmdline string
}

// newcommand is an abolition which implements workarounds so that not
// everything in commands/ has to be refactored right away.
// FIXME
type newcommand struct {
	parser.Parser
	cmdline     string
	tabComplete []string
}

// New returns the Command associated with the given verb.
func New(verb string, a api.API) Command {
	ctor := Verbs[verb]
	if ctor == nil {
		return nil
	}
	return ctor(a)
}

// Keys returns a string slice with all verbs that can be invoked to run a command.
func Keys() []string {
	keys := make(sort.StringSlice, 0, len(Verbs))
	for verb := range Verbs {
		keys = append(keys, verb)
	}
	keys.Sort()
	return keys
}

// setTabComplete defines a string slice that will be used for tab completion
// at the current point in parsing.
func (c *newcommand) setTabComplete(filter string, s []string) {
	c.tabComplete = utils.TokenFilter(filter, s)
}

// setTabCompleteTag sets the tab complete list to a list of tag keys in a specific song.
func (c *newcommand) setTabCompleteTag(lit string, song *song.Song) {
	if song == nil {
		c.setTabCompleteEmpty()
		return
	}
	c.setTabComplete(lit, song.TagKeys())
}

// setTabCompleteEmpty removes all tab completions.
func (c *newcommand) setTabCompleteEmpty() {
	c.setTabComplete("", []string{})
}

// ParseTags parses a set of tags until the end of the line, and maintains the
// tab complete list according to a specified song.
func (c *newcommand) ParseTags(song *song.Song) ([]string, error) {
	c.setTabCompleteEmpty()
	tags := make([]string, 0)
	tag := ""

	for {
		tok, lit := c.Scan()

		switch tok {
		case lexer.TokenWhitespace:
			if len(tag) > 0 {
				tags = append(tags, strings.ToLower(tag))
			}
			tag = ""
		case lexer.TokenEnd, lexer.TokenComment:
			if len(tag) > 0 {
				tags = append(tags, strings.ToLower(tag))
			}
			if len(tags) == 0 {
				return nil, fmt.Errorf("Unexpected END, expected tag")
			}
			return tags, nil
		default:
			tag += lit
		}

		c.setTabCompleteTag(tag, song)
	}
}

//
// These functions belong to the old implementation.
// FIXME: remove everything below.
//

// Execute implements Command.Execute.
func (c *newcommand) Execute(class int, s string) error {
	return nil
}

// TabComplete implements Command.TabComplete.
func (c *newcommand) TabComplete() []string {
	if c.tabComplete == nil {
		// FIXME
		return make([]string, 0)
	}
	return c.tabComplete
}

// Parse implements Command.Parse.
func (c *command) SetScanner(s *lexer.Scanner) {
}

// Parse implements Command.Parse.
func (c *command) Parse() error {
	return nil
}

// Scanned implements Command.Scanned.
func (c *command) Scanned() []parser.Token {
	return make([]parser.Token, 0)
}

// TabComplete implements Command.TabComplete.
func (c *command) TabComplete() []string {
	return []string{}
}

// Exec implements Command.TabComplete.
func (c *command) Exec() error {
	return nil
}
<commit_msg>Formatting<commit_after>// Package commands contains all functionality that is triggered by the user,
// either through keyboard bindings or the command-line interface. New commands
// such as 'sort', 'add', etc. must be implemented here.
package commands

import (
	"fmt"
	"sort"
	"strings"

	"github.com/ambientsound/pms/api"
	"github.com/ambientsound/pms/input/lexer"
	"github.com/ambientsound/pms/parser"
	"github.com/ambientsound/pms/song"
	"github.com/ambientsound/pms/utils"
)

// Verbs contain mappings from strings to Command constructors.
// Make sure to add commands here when implementing them.
var Verbs = map[string]func(api.API) Command{
	"add":       NewAdd,
	"bind":      NewBind,
	"copy":      NewYank,
	"cursor":    NewCursor,
	"cut":       NewCut,
	"inputmode": NewInputMode,
	"isolate":   NewIsolate,
	"list":      NewList,
	"next":      NewNext,
	"paste":     NewPaste,
	"pause":     NewPause,
	"play":      NewPlay,
	"previous":  NewPrevious,
	"prev":      NewPrevious,
	"print":     NewPrint,
	"q":         NewQuit,
	"quit":      NewQuit,
	"redraw":    NewRedraw,
	"seek":      NewSeek,
	"select":    NewSelect,
	"se":        NewSet,
	"set":       NewSet,
	"single":    NewSingle,
	"sort":      NewSort,
	"stop":      NewStop,
	"style":     NewStyle,
	"volume":    NewVolume,
	"yank":      NewYank,
}

// Command must be implemented by all commands.
type Command interface {
	// Execute parses the next input token.
	// FIXME: Execute is deprecated
	Execute(class int, s string) error

	// Exec executes the AST generated by the command.
	Exec() error

	// SetScanner assigns a scanner to the command.
	// FIXME: move to constructor?
	SetScanner(*lexer.Scanner)

	// Parse and make an abstract syntax tree. This function MUST NOT have any side effects.
	Parse() error

	// TabComplete returns a set of tokens that could possibly be used as the next
	// command parameter.
	TabComplete() []string

	// Scanned returns a slice of tokens that have been scanned using Parse().
	Scanned() []parser.Token
}

// command is a helper base class that all commands may use.
type command struct {
	cmdline string
}

// newcommand is an abolition which implements workarounds so that not
// everything in commands/ has to be refactored right away.
// FIXME
type newcommand struct {
	parser.Parser
	cmdline     string
	tabComplete []string
}

// New returns the Command associated with the given verb.
func New(verb string, a api.API) Command {
	ctor := Verbs[verb]
	if ctor == nil {
		return nil
	}
	return ctor(a)
}

// Keys returns a string slice with all verbs that can be invoked to run a command.
func Keys() []string {
	keys := make(sort.StringSlice, 0, len(Verbs))
	for verb := range Verbs {
		keys = append(keys, verb)
	}
	keys.Sort()
	return keys
}

// setTabComplete defines a string slice that will be used for tab completion
// at the current point in parsing.
func (c *newcommand) setTabComplete(filter string, s []string) {
	c.tabComplete = utils.TokenFilter(filter, s)
}

// setTabCompleteTag sets the tab complete list to a list of tag keys in a specific song.
func (c *newcommand) setTabCompleteTag(lit string, song *song.Song) {
	if song == nil {
		c.setTabCompleteEmpty()
		return
	}
	c.setTabComplete(lit, song.TagKeys())
}

// setTabCompleteEmpty removes all tab completions.
func (c *newcommand) setTabCompleteEmpty() {
	c.setTabComplete("", []string{})
}

// ParseTags parses a set of tags until the end of the line, and maintains the
// tab complete list according to a specified song.
func (c *newcommand) ParseTags(song *song.Song) ([]string, error) {
	c.setTabCompleteEmpty()
	tags := make([]string, 0)
	tag := ""

	for {
		tok, lit := c.Scan()

		switch tok {
		case lexer.TokenWhitespace:
			if len(tag) > 0 {
				tags = append(tags, strings.ToLower(tag))
			}
			tag = ""
		case lexer.TokenEnd, lexer.TokenComment:
			if len(tag) > 0 {
				tags = append(tags, strings.ToLower(tag))
			}
			if len(tags) == 0 {
				return nil, fmt.Errorf("Unexpected END, expected tag")
			}
			return tags, nil
		default:
			tag += lit
		}

		c.setTabCompleteTag(tag, song)
	}
}

//
// These functions belong to the old implementation.
// FIXME: remove everything below.
//

// Execute implements Command.Execute.
func (c *newcommand) Execute(class int, s string) error {
	return nil
}

// TabComplete implements Command.TabComplete.
func (c *newcommand) TabComplete() []string {
	if c.tabComplete == nil {
		// FIXME
		return make([]string, 0)
	}
	return c.tabComplete
}

// Parse implements Command.Parse.
func (c *command) SetScanner(s *lexer.Scanner) {
}

// Parse implements Command.Parse.
func (c *command) Parse() error {
	return nil
}

// Scanned implements Command.Scanned.
func (c *command) Scanned() []parser.Token {
	return make([]parser.Token, 0)
}

// TabComplete implements Command.TabComplete.
func (c *command) TabComplete() []string {
	return []string{}
}

// Exec implements Command.TabComplete.
func (c *command) Exec() error {
	return nil
}
<|endoftext|>


<commit_before>package kaonashi

import (
	"log"
	"net/http"

	"github.com/go-zoo/bone"
	"github.com/rs/xhandler"
	"golang.org/x/net/context"
)

const (
	ctxKeyConfig = "config"
	ctxKeyDB     = "db"
)

// Init create tables
func Init(confPath string) {
	var appConfig *AppConfig
	var err error
	if confPath != "" {
		appConfig, err = NewAppConfig(confPath)
		if err != nil {
			log.Fatalf("failed to load config: %s", err)
		}
	} else {
		appConfig = NewDefaultConfig()
	}
	db, err := NewDB(appConfig)
	if err != nil {
		log.Fatalf("failed to open database: %s", err)
	}

	err = createTables(db)
	if err != nil {
		log.Fatalf("failed to create table: %s", err)
	}
}

// Run kaonashi
func Run(confPath string) {
	var appConfig *AppConfig
	var err error
	if confPath != "" {
		appConfig, err = NewAppConfig(confPath)
		if err != nil {
			log.Fatalf("failed to load config: %s", err)
		}
	} else {
		appConfig = NewDefaultConfig()
	}
	db, err := NewDB(appConfig)
	if err != nil {
		log.Fatalf("failed to open database: %s", err)
	}

	// set up root context
	rootCtx := context.Background()
	rootCtx = context.WithValue(rootCtx, ctxKeyConfig, appConfig)
	rootCtx = context.WithValue(rootCtx, ctxKeyDB, db)

	// middleware chaining
	c := xhandler.Chain{}
	c.Use(recoverMiddleware)
	c.Use(loggingMiddleware)
	c.UseC(xhandler.CloseHandler)

	// application routing
	mux := bone.New()
	mux.Get("/note", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(getNoteTitlesHandler)))
	mux.Get("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(getNoteHandler)))
	mux.Delete("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(deleteNoteHandler)))
	mux.Put("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(updateNoteHandler)))
	mux.Post("/note", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(createNoteHandler)))
	if err := http.ListenAndServe(":"+appConfig.ServerPort, mux); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add servre start log<commit_after>package kaonashi

import (
	"log"
	"net/http"

	"github.com/go-zoo/bone"
	"github.com/rs/xhandler"
	"golang.org/x/net/context"
)

const (
	ctxKeyConfig = "config"
	ctxKeyDB     = "db"
)

// Init create tables
func Init(confPath string) {
	var appConfig *AppConfig
	var err error
	if confPath != "" {
		appConfig, err = NewAppConfig(confPath)
		if err != nil {
			log.Fatalf("failed to load config: %s", err)
		}
	} else {
		appConfig = NewDefaultConfig()
	}
	db, err := NewDB(appConfig)
	if err != nil {
		log.Fatalf("failed to open database: %s", err)
	}

	err = createTables(db)
	if err != nil {
		log.Fatalf("failed to create table: %s", err)
	}
}

// Run kaonashi
func Run(confPath string) {
	var appConfig *AppConfig
	var err error
	if confPath != "" {
		appConfig, err = NewAppConfig(confPath)
		if err != nil {
			log.Fatalf("failed to load config: %s", err)
		}
	} else {
		appConfig = NewDefaultConfig()
	}
	db, err := NewDB(appConfig)
	if err != nil {
		log.Fatalf("failed to open database: %s", err)
	}

	// set up root context
	rootCtx := context.Background()
	rootCtx = context.WithValue(rootCtx, ctxKeyConfig, appConfig)
	rootCtx = context.WithValue(rootCtx, ctxKeyDB, db)

	// middleware chaining
	c := xhandler.Chain{}
	c.Use(recoverMiddleware)
	c.Use(loggingMiddleware)
	c.UseC(xhandler.CloseHandler)

	// application routing
	mux := bone.New()
	mux.Get("/note", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(getNoteTitlesHandler)))
	mux.Get("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(getNoteHandler)))
	mux.Delete("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(deleteNoteHandler)))
	mux.Put("/note/:id", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(updateNoteHandler)))
	mux.Post("/note", c.HandlerCtx(rootCtx, xhandler.HandlerFuncC(createNoteHandler)))
	if err := http.ListenAndServe(":"+appConfig.ServerPort, mux); err != nil {
		log.Fatal(err)
	}
	log.Println("starting kaonashi")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

const (
	HELP = `md2xml [-h] file.md
Transform a given Markdown file into XML.
-h        To print this help page.
-x        Print intermediate XHTML output.
file.md   The markdown file to convert.
Note: this program calls xsltproc that must have been installed.`
	STYLESHEET_ARTICLE = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="UTF-8"/>
  <xsl:param name="id">ID</xsl:param>
  <xsl:param name="date">DATE</xsl:param>
  <xsl:param name="title">TITLE</xsl:param>
  <xsl:param name="author">AUTHOR</xsl:param>
  <xsl:param name="email">EMAIL</xsl:param>

  <xsl:template match="/xhtml">
    <xsl:text disable-output-escaping="yes">
    <!DOCTYPE article PUBLIC "-//CAFEBABE//DTD blog 1.0//EN"
                             "../dtd/article.dtd">
    </xsl:text>

      <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
      <xsl:attribute name="date"><xsl:value-of select="$date"/></xsl:attribute>
      <xsl:attribute name="author"><xsl:value-of select="$author"/></xsl:attribute>
      <xsl:attribute name="email"><xsl:value-of select="$email"/></xsl:attribute>
      <title><xsl:value-of select="$title"/></title>
      <text>
       <xsl:apply-templates/>
      </text>

  </xsl:template>

  <xsl:template match="h1">
    <sect level="1"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h2">
    <sect level="2"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h3">
    <sect level="3"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h4">
    <sect level="4"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h5">
    <sect level="5"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h6">
    <sect level="6"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="p[count(text())=0 and count(code)=1]">
    <source><xsl:apply-templates select="code"/></source>
  </xsl:template>

  <xsl:template match="p[count(text())=1 and count(img)=1]">
    <xsl:apply-templates select="img"/>
  </xsl:template>

  <xsl:template match="img">

      <xsl:if test="@alt">
        <xsl:attribute name="title">
          <xsl:value-of select="{@alt}"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="@title">
        <xsl:attribute name="title2">
          <xsl:value-of select="{@title}"/>
        </xsl:attribute>
      </xsl:if>

  </xsl:template>

  <xsl:template match="p">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="ul">
    <list><xsl:apply-templates/></list>
  </xsl:template>

  <xsl:template match="ol">
    <enum><xsl:apply-templates/></enum>
  </xsl:template>

  <xsl:template match="li">
    <item><xsl:apply-templates/></item>
  </xsl:template>

  <xsl:template match="table">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="th">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="tr">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="td">
    <co><xsl:apply-templates/></co>
  </xsl:template>

  <xsl:template match="pre">
    <source><xsl:apply-templates/></source>
  </xsl:template>

  <xsl:template match="em">
    <term><xsl:apply-templates/></term>
  </xsl:template>

  <xsl:template match="strong">
    <imp><xsl:apply-templates/></imp>
  </xsl:template>

  <xsl:template match="a">
    <link url="{@href}"><xsl:apply-templates/></link>
  </xsl:template>

</xsl:stylesheet>`
	STYLESHEET_BLOG = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="UTF-8"/>
  <xsl:param name="id">ID</xsl:param>
  <xsl:param name="date">DATE</xsl:param>
  <xsl:param name="title">TITLE</xsl:param>

  <xsl:template match="/xhtml">
    <xsl:text disable-output-escaping="yes">
    <!DOCTYPE blog PUBLIC "-//CAFEBABE//DTD blog 1.0//EN"
                             "../dtd/blog.dtd">
    </xsl:text>
    <blog>
      <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
      <xsl:attribute name="date"><xsl:value-of select="$date"/></xsl:attribute>
      <title><xsl:value-of select="$title"/></title>
      <xsl:apply-templates/>
    </blog>
  </xsl:template>

  <xsl:template match="p[count(text())=0 and count(code)=1]">
    <source><xsl:apply-templates select="code"/></source>
  </xsl:template>

  <xsl:template match="p[count(text())=1 and count(img)=1]">
    <xsl:apply-templates select="img"/>
  </xsl:template>

  <xsl:template match="img">

  </xsl:template>

  <xsl:template match="p">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="ul">
    <list><xsl:apply-templates/></list>
  </xsl:template>

  <xsl:template match="ol">
    <enum><xsl:apply-templates/></enum>
  </xsl:template>

  <xsl:template match="li">
    <item><xsl:apply-templates/></item>
  </xsl:template>

  <xsl:template match="table">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="th">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="tr">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="td">
    <co><xsl:apply-templates/></co>
  </xsl:template>

  <xsl:template match="pre">
    <source><xsl:apply-templates/></source>
  </xsl:template>

  <xsl:template match="em">
    <term><xsl:apply-templates/></term>
  </xsl:template>

  <xsl:template match="strong">
    <imp><xsl:apply-templates/></imp>
  </xsl:template>

  <xsl:template match="a">
    <link url="{@href}"><xsl:apply-templates/></link>
  </xsl:template>

</xsl:stylesheet>`
	XHTML_HEADER = "<xhtml>\n"
	XHTML_FOOTER = "\n</xhtml>"
)

func processXsl(xmlFile string, data map[string]string, article bool) []byte {
	xslFile, err := ioutil.TempFile("/tmp", "md2xsl-")
	if err != nil {
		panic(err)
	}
	stylesheet := STYLESHEET_ARTICLE
	if !article {
		stylesheet = STYLESHEET_BLOG
	}
	err = ioutil.WriteFile(xslFile.Name(), []byte(stylesheet), 0755)
	if err != nil {
		panic(err)
	}
	defer os.Remove(xslFile.Name())
	params := make([]string, 0, 2+3*len(data))
	for name, value := range data {
		params = append(params, "--stringparam")
		params = append(params, name)
		params = append(params, value)
	}
	params = append(params, xslFile.Name())
	params = append(params, xmlFile)
	command := exec.Command("xsltproc", params...)
	result, err := command.CombinedOutput()
	if err != nil {
	 print(result)
		panic(err)
	}
	return result
}

func markdown2xhtml(markdown string) []byte {
	mdFile, err := ioutil.TempFile("/tmp", "md2xsl-")
	if err != nil {
		panic(err)
	}
	defer os.Remove(mdFile.Name())
	ioutil.WriteFile(mdFile.Name(), []byte(markdown), 0x755)
	command := exec.Command("pandoc", mdFile.Name(), "-f", "markdown", "-t", "html")
	result, err := command.CombinedOutput()
	if err != nil {
		panic(err)
	}
	return []byte(XHTML_HEADER + string(result) + XHTML_FOOTER)
}

func markdownData(text string) (map[string]string, string) {
	data := make(map[string]string)
	lines := strings.Split(text, "\n")
	var limit int
	for index, line := range lines {
		if strings.HasPrefix(line, "% ") && strings.Index(line, ":") >= 0 {
			name := strings.TrimSpace(line[2:strings.Index(line, ":")])
			value := strings.TrimSpace(line[strings.Index(line, ":")+1 : len(line)])
			data[name] = value
		} else {
			limit = index
			break
		}
	}
	return data, strings.Join(lines[limit:len(lines)], "\n")
}

func escapeXml(source string) string {
	source = strings.Replace(source, "&", "&", -1)
	source = strings.Replace(source, "<", "<", -1)
	return source
}

func processFile(filename string, printXhtml bool, article bool) string {
	source, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	data, markdown := markdownData(string(source))
	markdown = escapeXml(markdown)
	xhtml := markdown2xhtml(markdown)
	if printXhtml {
		return string(xhtml)
	}
	xmlFile, err := ioutil.TempFile("/tmp", "md2xml-")
	if err != nil {
		panic(err)
	}
	defer os.Remove(xmlFile.Name())
	ioutil.WriteFile(xmlFile.Name(), xhtml, 0755)
	result := processXsl(xmlFile.Name(), data, article)
	return string(result)
}

func main() {
	xhtml := false
	article := false
	if len(os.Args) < 2 {
		fmt.Println(HELP)
		os.Exit(1)
	}
	for _, arg := range os.Args[1:] {
		if arg == "-h" || os.Args[1] == "--help" {
			fmt.Println(HELP)
			os.Exit(0)
		} else if arg == "-x" || arg == "--xhtml" {
			xhtml = true
		} else if arg == "-a" || arg == "--article" {
			article = true
		} else {
			fmt.Println(processFile(arg, xhtml, article))
		}
	}
}<commit_msg>Fixed images<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

const (
	HELP = `md2xml [-h] file.md
Transform a given Markdown file into XML.
-h        To print this help page.
-x        Print intermediate XHTML output.
file.md   The markdown file to convert.
Note: this program calls xsltproc that must have been installed.`
	STYLESHEET_ARTICLE = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="UTF-8"/>
  <xsl:param name="id">ID</xsl:param>
  <xsl:param name="date">DATE</xsl:param>
  <xsl:param name="title">TITLE</xsl:param>
  <xsl:param name="author">AUTHOR</xsl:param>
  <xsl:param name="email">EMAIL</xsl:param>

  <xsl:template match="/xhtml">
    <xsl:text disable-output-escaping="yes">
    <!DOCTYPE article PUBLIC "-//CAFEBABE//DTD blog 1.0//EN"
                             "../dtd/article.dtd">
    </xsl:text>

      <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
      <xsl:attribute name="date"><xsl:value-of select="$date"/></xsl:attribute>
      <xsl:attribute name="author"><xsl:value-of select="$author"/></xsl:attribute>
      <xsl:attribute name="email"><xsl:value-of select="$email"/></xsl:attribute>
      <title><xsl:value-of select="$title"/></title>
      <text>
       <xsl:apply-templates/>
      </text>

  </xsl:template>

  <xsl:template match="h1">
    <sect level="1"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h2">
    <sect level="2"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h3">
    <sect level="3"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h4">
    <sect level="4"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h5">
    <sect level="5"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="h6">
    <sect level="6"><title><xsl:value-of select="."/></title></sect>
  </xsl:template>

  <xsl:template match="p[@class='caption']">
  </xsl:template>

  <xsl:template match="p[count(text())=0 and count(code)=1]">
    <source><xsl:apply-templates select="code"/></source>
  </xsl:template>

  <xsl:template match="p[count(text())=1 and count(img)=1]">
    <xsl:apply-templates select="img"/>
  </xsl:template>

  <xsl:template match="img">

      <xsl:if test="@alt">
        <xsl:attribute name="title">
          <xsl:value-of select="@alt"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="@title">
        <xsl:attribute name="title">
          <xsl:value-of select="@title"/>
        </xsl:attribute>
      </xsl:if>

  </xsl:template>

  <xsl:template match="p">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="ul">
    <list><xsl:apply-templates/></list>
  </xsl:template>

  <xsl:template match="ol">
    <enum><xsl:apply-templates/></enum>
  </xsl:template>

  <xsl:template match="li">
    <item><xsl:apply-templates/></item>
  </xsl:template>

  <xsl:template match="table">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="th">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="tr">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="td">
    <co><xsl:apply-templates/></co>
  </xsl:template>

  <xsl:template match="pre">
    <source><xsl:apply-templates/></source>
  </xsl:template>

  <xsl:template match="em">
    <term><xsl:apply-templates/></term>
  </xsl:template>

  <xsl:template match="strong">
    <imp><xsl:apply-templates/></imp>
  </xsl:template>

  <xsl:template match="a">
    <link url="{@href}"><xsl:apply-templates/></link>
  </xsl:template>

</xsl:stylesheet>`
	STYLESHEET_BLOG = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="UTF-8"/>
  <xsl:param name="id">ID</xsl:param>
  <xsl:param name="date">DATE</xsl:param>
  <xsl:param name="title">TITLE</xsl:param>

  <xsl:template match="/xhtml">
    <xsl:text disable-output-escaping="yes">
    <!DOCTYPE blog PUBLIC "-//CAFEBABE//DTD blog 1.0//EN"
                          "../dtd/blog.dtd">
    </xsl:text>
    <blog>
      <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
      <xsl:attribute name="date"><xsl:value-of select="$date"/></xsl:attribute>
      <title><xsl:value-of select="$title"/></title>
      <xsl:apply-templates/>
    </blog>
  </xsl:template>

  <xsl:template match="h1">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="h2">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="h3">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="h4">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="h5">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="h6">

<imp><xsl:value-of select="."/></imp>

  </xsl:template>

  <xsl:template match="p[@class='caption']">
  </xsl:template>

  <xsl:template match="p[count(text())=0 and count(code)=1]">
    <source><xsl:apply-templates select="code"/></source>
  </xsl:template>

  <xsl:template match="p[count(text())=1 and count(img)=1]">
    <xsl:apply-templates select="img"/>
  </xsl:template>

  <xsl:template match="img">

      <xsl:if test="@alt">
        <xsl:attribute name="title">
          <xsl:value-of select="@alt"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="@title">
        <xsl:attribute name="title">
          <xsl:value-of select="@title"/>
        </xsl:attribute>
      </xsl:if>

  </xsl:template>

  <xsl:template match="p">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="ul">
    <list><xsl:apply-templates/></list>
  </xsl:template>

  <xsl:template match="ol">
    <enum><xsl:apply-templates/></enum>
  </xsl:template>

  <xsl:template match="li">
    <item><xsl:apply-templates/></item>
  </xsl:template>

  <xsl:template match="table">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="th">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="tr">

<xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="td">
    <co><xsl:apply-templates/></co>
  </xsl:template>

  <xsl:template match="pre">
    <source><xsl:apply-templates/></source>
  </xsl:template>

  <xsl:template match="em">
    <term><xsl:apply-templates/></term>
  </xsl:template>

  <xsl:template match="strong">
    <imp><xsl:apply-templates/></imp>
  </xsl:template>

  <xsl:template match="a">
    <link url="{@href}"><xsl:apply-templates/></link>
  </xsl:template>

</xsl:stylesheet>`
	XHTML_HEADER = "<xhtml>\n"
	XHTML_FOOTER = "\n</xhtml>"
)

func processXsl(xmlFile string, data map[string]string, article bool) []byte {
	xslFile, err := ioutil.TempFile("/tmp", "md2xsl-")
	if err != nil {
		panic(err)
	}
	stylesheet := STYLESHEET_ARTICLE
	if !article {
		stylesheet = STYLESHEET_BLOG
	}
	err = ioutil.WriteFile(xslFile.Name(), []byte(stylesheet), 0755)
	if err != nil {
		panic(err)
	}
	defer os.Remove(xslFile.Name())
	params := make([]string, 0, 2+3*len(data))
	for name, value := range data {
		params = append(params, "--stringparam")
		params = append(params, name)
		params = append(params, value)
	}
	params = append(params, xslFile.Name())
	params = append(params, xmlFile)
	command := exec.Command("xsltproc", params...)
	result, err := command.CombinedOutput()
	if err != nil {
	 print(result)
		panic(err)
	}
	return result
}

func markdown2xhtml(markdown string) []byte {
	mdFile, err := ioutil.TempFile("/tmp", "md2xsl-")
	if err != nil {
		panic(err)
	}
	defer os.Remove(mdFile.Name())
	ioutil.WriteFile(mdFile.Name(), []byte(markdown), 0x755)
	command := exec.Command("pandoc", mdFile.Name(), "-f", "markdown", "-t", "html")
	result, err := command.CombinedOutput()
	if err != nil {
		panic(err)
	}
	return []byte(XHTML_HEADER + string(result) + XHTML_FOOTER)
}

func markdownData(text string) (map[string]string, string) {
	data := make(map[string]string)
	lines := strings.Split(text, "\n")
	var limit int
	for index, line := range lines {
		if strings.HasPrefix(line, "% ") && strings.Index(line, ":") >= 0 {
			name := strings.TrimSpace(line[2:strings.Index(line, ":")])
			value := strings.TrimSpace(line[strings.Index(line, ":")+1 : len(line)])
			data[name] = value
		} else {
			limit = index
			break
		}
	}
	return data, strings.Join(lines[limit:len(lines)], "\n")
}

func escapeXml(source string) string {
	source = strings.Replace(source, "&", "&", -1)
	source = strings.Replace(source, "<", "<", -1)
	return source
}

func processFile(filename string, printXhtml bool, article bool) string {
	source, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	data, markdown := markdownData(string(source))
	markdown = escapeXml(markdown)
	xhtml := markdown2xhtml(markdown)
	if printXhtml {
		return string(xhtml)
	}
	xmlFile, err := ioutil.TempFile("/tmp", "md2xml-")
	if err != nil {
		panic(err)
	}
	defer os.Remove(xmlFile.Name())
	ioutil.WriteFile(xmlFile.Name(), xhtml, 0755)
	result := processXsl(xmlFile.Name(), data, article)
	return string(result)
}

func main() {
	xhtml := false
	article := false
	if len(os.Args) < 2 {
		fmt.Println(HELP)
		os.Exit(1)
	}
	for _, arg := range os.Args[1:] {
		if arg == "-h" || os.Args[1] == "--help" {
			fmt.Println(HELP)
			os.Exit(0)
		} else if arg == "-x" || arg == "--xhtml" {
			xhtml = true
		} else if arg == "-a" || arg == "--article" {
			article = true
		} else {
			fmt.Println(processFile(arg, xhtml, article))
		}
	}
}
<|endoftext|>


<commit_before>package lbx

import (
	"github.com/lhcb-org/lbx/lbx/vcs"
)

// Repos is the database of known repositories
var Repos = RepoInfos{
	"gaudi": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/gaudi",
			Root: "/gaudi",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/gaudi",
			Root: "/gaudi",
		},
	},

	"lbsvn": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/lhcb",
			Root: "/lhcb",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/lhcb",
			Root: "/lhcb",
		},
	},

	"dirac": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/dirac",
			Root: "/dirac",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/dirac",
			Root: "/dirac",
		},
	},

	"lhcbint": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/lhcbint",
			Root: "/lhcbint",
		},
	},
}

type RepoInfo struct {
	Cmd  *vcs.Cmd
	Repo string
	Root string
}

type RepoInfos map[string][]RepoInfo

// Repositories returns a map of named-repositories
func Repositories(user, protocol string) RepoInfos {
	repos := make(RepoInfos, len(Repos))
	for k := range Repos {
		repos[k] = append([]RepoInfo{}, Repos[k]...)
	}
	if user != "" {

	}
	return repos
}

func (repo *RepoInfo) ListPackages(hat string) []string {
	pkgs := make([]string, 0)
	return pkgs
}
<commit_msg>repo: fixup Root of svn path<commit_after>package lbx

import (
	"github.com/lhcb-org/lbx/lbx/vcs"
)

// Repos is the database of known repositories
var Repos = RepoInfos{
	"gaudi": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/gaudi",
			Root: "/reps/gaudi",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/gaudi",
			Root: "/guest/gaudi",
		},
	},

	"lbsvn": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/lhcb",
			Root: "/reps/lhcb",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/lhcb",
			Root: "/guest/lhcb",
		},
	},

	"dirac": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/dirac",
			Root: "/reps/dirac",
		},
		{
			Cmd:  vcs.Svn,
			Repo: "http://svn.cern.ch/guest/dirac",
			Root: "/guest/dirac",
		},
	},

	"lhcbint": []RepoInfo{
		{
			Cmd:  vcs.Svn,
			Repo: "svn+ssh://svn.cern.ch/reps/lhcbint",
			Root: "/reps/lhcbint",
		},
	},
}

type RepoInfo struct {
	Cmd  *vcs.Cmd
	Repo string
	Root string
}

type RepoInfos map[string][]RepoInfo

// Repositories returns a map of named-repositories
func Repositories(user, protocol string) RepoInfos {
	repos := make(RepoInfos, len(Repos))
	for k := range Repos {
		repos[k] = append([]RepoInfo{}, Repos[k]...)
	}
	if user != "" {

	}
	return repos
}

func (repo *RepoInfo) ListPackages(hat string) []string {
	pkgs := make([]string, 0)
	return pkgs
}
<|endoftext|>


<commit_before>package lfs

import (
	"crypto/tls"
	"fmt"
	"github.com/rubyist/tracerx"
	"io"
	"net/http"
	"os"
	"strings"
)

func DoHTTP(c *Configuration, req *http.Request) (*http.Response, error) {
	var res *http.Response
	var err error

	if req.Body != nil {
		req.Body = newCountedRequest(req)
	}

	traceHttpRequest(c, req)

	switch req.Method {
	case "GET", "HEAD":
		res, err = c.RedirectingHttpClient().Do(req)
	default:
		res, err = c.HttpClient().Do(req)
	}

	traceHttpResponse(c, res)

	return res, err
}

func (c *Configuration) HttpClient() *http.Client {
	if c.httpClient == nil {
		c.httpClient = &http.Client{
			Transport: c.RedirectingHttpClient().Transport,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return RedirectError
			},
		}
	}
	return c.httpClient
}

func (c *Configuration) RedirectingHttpClient() *http.Client {
	if c.redirectingHttpClient == nil {
		tr := &http.Transport{}
		sslVerify, _ := c.GitConfig("http.sslverify")
		if sslVerify == "false" || len(os.Getenv("GIT_SSL_NO_VERIFY")) > 0 {
			tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
		}
		c.redirectingHttpClient = &http.Client{Transport: tr}
	}
	return c.redirectingHttpClient
}

var tracedTypes = []string{"json", "text", "xml", "html"}

func traceHttpRequest(c *Configuration, req *http.Request) {
	tracerx.Printf("HTTP: %s %s", req.Method, req.URL.String())

	if c.isTracingHttp == false {
		return
	}

	fmt.Fprintf(os.Stderr, "> %s %s %s\n", req.Method, req.URL.RequestURI(), req.Proto)
	for key, _ := range req.Header {
		fmt.Fprintf(os.Stderr, "> %s: %s\n", key, req.Header.Get(key))
	}
}

func traceHttpResponse(c *Configuration, res *http.Response) {
	tracerx.Printf("HTTP: %d", res.StatusCode)

	if c.isTracingHttp == false {
		return
	}

	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "< %s %s\n", res.Proto, res.Status)
	for key, _ := range res.Header {
		fmt.Fprintf(os.Stderr, "< %s: %s\n", key, res.Header.Get(key))
	}

	traceBody := false
	ctype := strings.ToLower(strings.SplitN(res.Header.Get("Content-Type"), ";", 2)[0])
	for _, tracedType := range tracedTypes {
		if strings.Contains(ctype, tracedType) {
			traceBody = true
		}
	}

	res.Body = newCountedResponse(res)
	if traceBody {
		res.Body = newTracedBody(res.Body)
	}

	fmt.Fprintf(os.Stderr, "\n")
}

const (
	countingUpload = iota
	countingDownload
)

type countingBody struct {
	Direction int
	Size      int64
	io.ReadCloser
}

func (r *countingBody) Read(p []byte) (int, error) {
	n, err := r.ReadCloser.Read(p)
	r.Size += int64(n)
	return n, err
}

func (r *countingBody) Close() error {
	if r.Direction == countingUpload {
		fmt.Fprintf(os.Stderr, "* uploaded %d bytes\n", r.Size)
	} else {
		fmt.Fprintf(os.Stderr, "* downloaded %d bytes\n", r.Size)
	}
	return r.ReadCloser.Close()
}

func newCountedResponse(res *http.Response) *countingBody {
	return &countingBody{countingDownload, 0, res.Body}
}

func newCountedRequest(req *http.Request) *countingBody {
	return &countingBody{countingUpload, 0, req.Body}
}

type tracedBody struct {
	io.ReadCloser
}

func (r *tracedBody) Read(p []byte) (int, error) {
	n, err := r.ReadCloser.Read(p)
	fmt.Fprintf(os.Stderr, "%s\n", string(p[0:n]))
	return n, err
}

func (r *tracedBody) Close() error {
	return r.ReadCloser.Close()
}

func newTracedBody(body io.ReadCloser) *tracedBody {
	return &tracedBody{body}
}
<commit_msg>dont show tracing messages without GIT_CURL_VERBOSE<commit_after>package lfs

import (
	"crypto/tls"
	"fmt"
	"github.com/rubyist/tracerx"
	"io"
	"net/http"
	"os"
	"strings"
)

func DoHTTP(c *Configuration, req *http.Request) (*http.Response, error) {
	var res *http.Response
	var err error

	traceHttpRequest(c, req)

	switch req.Method {
	case "GET", "HEAD":
		res, err = c.RedirectingHttpClient().Do(req)
	default:
		res, err = c.HttpClient().Do(req)
	}

	traceHttpResponse(c, res)

	return res, err
}

func (c *Configuration) HttpClient() *http.Client {
	if c.httpClient == nil {
		c.httpClient = &http.Client{
			Transport: c.RedirectingHttpClient().Transport,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return RedirectError
			},
		}
	}
	return c.httpClient
}

func (c *Configuration) RedirectingHttpClient() *http.Client {
	if c.redirectingHttpClient == nil {
		tr := &http.Transport{}
		sslVerify, _ := c.GitConfig("http.sslverify")
		if sslVerify == "false" || len(os.Getenv("GIT_SSL_NO_VERIFY")) > 0 {
			tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
		}
		c.redirectingHttpClient = &http.Client{Transport: tr}
	}
	return c.redirectingHttpClient
}

var tracedTypes = []string{"json", "text", "xml", "html"}

func traceHttpRequest(c *Configuration, req *http.Request) {
	tracerx.Printf("HTTP: %s %s", req.Method, req.URL.String())

	if c.isTracingHttp == false {
		return
	}

	if req.Body != nil {
		req.Body = newCountedRequest(req)
	}

	fmt.Fprintf(os.Stderr, "> %s %s %s\n", req.Method, req.URL.RequestURI(), req.Proto)
	for key, _ := range req.Header {
		fmt.Fprintf(os.Stderr, "> %s: %s\n", key, req.Header.Get(key))
	}
}

func traceHttpResponse(c *Configuration, res *http.Response) {
	tracerx.Printf("HTTP: %d", res.StatusCode)

	if c.isTracingHttp == false {
		return
	}

	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "< %s %s\n", res.Proto, res.Status)
	for key, _ := range res.Header {
		fmt.Fprintf(os.Stderr, "< %s: %s\n", key, res.Header.Get(key))
	}

	traceBody := false
	ctype := strings.ToLower(strings.SplitN(res.Header.Get("Content-Type"), ";", 2)[0])
	for _, tracedType := range tracedTypes {
		if strings.Contains(ctype, tracedType) {
			traceBody = true
		}
	}

	res.Body = newCountedResponse(res)
	if traceBody {
		res.Body = newTracedBody(res.Body)
	}

	fmt.Fprintf(os.Stderr, "\n")
}

const (
	countingUpload = iota
	countingDownload
)

type countingBody struct {
	Direction int
	Size      int64
	io.ReadCloser
}

func (r *countingBody) Read(p []byte) (int, error) {
	n, err := r.ReadCloser.Read(p)
	r.Size += int64(n)
	return n, err
}

func (r *countingBody) Close() error {
	if r.Direction == countingUpload {
		fmt.Fprintf(os.Stderr, "* uploaded %d bytes\n", r.Size)
	} else {
		fmt.Fprintf(os.Stderr, "* downloaded %d bytes\n", r.Size)
	}
	return r.ReadCloser.Close()
}

func newCountedResponse(res *http.Response) *countingBody {
	return &countingBody{countingDownload, 0, res.Body}
}

func newCountedRequest(req *http.Request) *countingBody {
	return &countingBody{countingUpload, 0, req.Body}
}

type tracedBody struct {
	io.ReadCloser
}

func (r *tracedBody) Read(p []byte) (int, error) {
	n, err := r.ReadCloser.Read(p)
	fmt.Fprintf(os.Stderr, "%s\n", string(p[0:n]))
	return n, err
}

func (r *tracedBody) Close() error {
	return r.ReadCloser.Close()
}

func newTracedBody(body io.ReadCloser) *tracedBody {
	return &tracedBody{body}
}
<|endoftext|>


<commit_before>package asp

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/thought-machine/please/src/core"
)

// valueToPyObject converts a field value to a pyObject
func valueToPyObject(value reflect.Value) pyObject {
	switch value.Kind() {
	case reflect.String:
		return pyString(value.String())
	case reflect.Bool:
		return newPyBool(value.Bool())
	case reflect.Slice:
		l := make(pyList, value.Len())
		for i := 0; i < value.Len(); i++ {
			l[i] = pyString(value.Index(i).String())
		}
		return l
	case reflect.Struct:
		return pyString(value.Interface().(fmt.Stringer).String())
	default:
		log.Fatalf("Unknown config field type for %s", tag)
	}
	return nil
}

// newConfig creates a new pyConfig object from the configuration.
// This is typically only created once at global scope, other scopes copy it with .Copy()
func newConfig(state *core.BuildState) *pyConfig {
	base := make(pyDict, 100)

	v := reflect.ValueOf(state.Config).Elem()
	for i := 0; i < v.NumField(); i++ {
		if field := v.Field(i); field.Kind() == reflect.Struct {
			for j := 0; j < field.NumField(); j++ {
				subfieldType := field.Type().Field(j)
				if varName := subfieldType.Tag.Get("var"); varName != "" {
					base[varName] = valueToPyObject(field.Field(j))
				}
			}
		}
	}

	// Arbitrary build config stuff
	for k, v := range state.Config.BuildConfig {
		// It's hard to know what the correct thing to do with build config when it comes to inheriting it from the
		// parent subrepo or not. Historically we wouldn't load from the subrepo at all, so we err on the side of
		// caution here: we only load in values that aren't already present as this is closer to how it used to work.
		key := strings.ReplaceAll(strings.ToUpper(k), "-", "_")
		if _, ok := base[key]; !ok {
			// TODO(jpoole): handle relative build labels
			base[key] = pyString(v)
		}
	}
	// Settings specific to package() which aren't in the config, but it's easier to
	// just put them in now.
	base["DEFAULT_VISIBILITY"] = None
	base["DEFAULT_TESTONLY"] = False
	base["DEFAULT_LICENCES"] = None
	// Bazel supports a 'features' flag to toggle things on and off.
	// We don't but at least let them call package() without blowing up.
	if state.Config.Bazel.Compatibility {
		base["FEATURES"] = pyList{}
	}

	arch := state.Arch

	base["OS"] = pyString(arch.OS)
	base["ARCH"] = pyString(arch.Arch)
	base["HOSTOS"] = pyString(arch.HostOS())
	base["HOSTARCH"] = pyString(arch.HostArch())
	base["TARGET_OS"] = pyString(state.TargetArch.OS)
	base["TARGET_ARCH"] = pyString(state.TargetArch.Arch)
	base["BUILD_CONFIG"] = pyString(state.Config.Build.Config)
	base["DEBUG_PORT"] = pyInt(state.DebugPort)

	if !state.Config.FeatureFlags.ExcludeGoRules {
		base["GOOS"] = pyString(arch.OS)
		base["GOARCH"] = pyString(arch.GoArch())
	}

	return &pyConfig{base: &pyConfigBase{dict: base}}
}

func resolvePluginValue(values []string, subrepo string) []string {
	ret := make([]string, len(values))
	for i, v := range values {
		if core.LooksLikeABuildLabel(v) {
			l, err := core.TryParseBuildLabel(v, "", subrepo)
			if err != nil {
				panic(err)
			}
			// Force the full build label including empty subrepo so this is portable
			v = fmt.Sprintf("///%v//%v:%v", l.Subrepo, l.PackageName, l.Name)
		}
		ret[i] = v
	}
	return ret
}

func getExtraVals(config *core.Configuration, pluginName string) map[string][]string {
	plugin := config.Plugin[pluginName]
	if plugin == nil {
		return map[string][]string{}
	}

	return plugin.ExtraValues
}

// pluginConfig loads the plugin's config into a pyDict. It will load con
func pluginConfig(pluginState *core.BuildState, pkgState *core.BuildState) pyDict {
	pluginName := strings.ToLower(pluginState.RepoConfig.PluginDefinition.Name)
	var extraVals map[string][]string
	var ret pyDict
	if pkgState.ParentState == nil {
		extraVals = getExtraVals(pkgState.RepoConfig, pluginName)
		ret = pyDict{}
	} else {
		extraVals = getExtraVals(pkgState.RepoConfig, pluginName)
		ret = pluginConfig(pluginState, pkgState.ParentState)
	}
	definedKeys := map[string]bool{}
	for key, definition := range pluginState.RepoConfig.PluginConfig {
		definedKeys[strings.ToLower(definition.ConfigKey)] = true
		key = strings.ToUpper(key)
		if _, ok := ret[key]; ok && definition.Inherit {
			// If the config key is already defined, and we should inherit it from the host repo, continue.
			continue
		}

		configKey := definition.ConfigKey
		if configKey == "" {
			configKey = strings.ReplaceAll(key, "_", "")
		}

		fullConfigKey := fmt.Sprintf("%v.%v", pluginName, configKey)
		value, ok := extraVals[strings.ToLower(configKey)]
		if !ok {
			// The default values are defined in the subrepo so should be parsed in that context
			value = resolvePluginValue(definition.DefaultValue, pluginState.CurrentSubrepo)
		} else {
			value = resolvePluginValue(value, pkgState.CurrentSubrepo)
		}

		if len(value) == 0 && !definition.Optional {
			if _, ok := ret[key]; ok {
				// Inherit config from the host repo if we don't override it
				continue
			}
			log.Fatalf("plugin config %s is not optional", fullConfigKey)
		}

		if !definition.Repeatable && len(value) > 1 {
			log.Fatalf("plugin config %v is not repeatable", fullConfigKey)
		}

		if definition.Repeatable {
			l := make(pyList, 0, len(value))
			for _, v := range value {
				l = append(l, toPyObject(fullConfigKey, v, definition.Type))
			}
			ret[key] = l
		} else {
			val := ""
			if len(value) == 1 {
				val = value[0]
			}
			ret[key] = toPyObject(fullConfigKey, val, definition.Type)
		}
	}

	// Validate against definedKeys
	for k := range extraVals {
		if _, ok := definedKeys[strings.ToLower(k)]; !ok {
			log.Warning("Unrecognised config key \"%v\" for plugin \"%v\"", k, pluginName)
		}
	}

	return ret
}

func (i *interpreter) loadPluginConfig(pluginState *core.BuildState, pkgState *core.BuildState, c *pyConfig) {
	pluginName := pluginState.Config.PluginDefinition.Name
	if pluginName == "" {
		// Subinclude is not a plugin. Stop here.
		return
	}

	var dict pyDict
	if !c.base.finalised {
		c.base.Lock()
		defer c.base.Unlock()

		dict = c.base.dict
	} else {
		if c.overlay == nil {
			c.overlay = pyDict{}
		}
		dict = c.overlay
	}

	key := strings.ToUpper(pluginName)
	if _, ok := dict[key]; ok {
		return
	}

	cfg := pluginConfig(pluginState, pkgState)
	dict[key] = cfg
}

func toPyObject(key, val, toType string) pyObject {
	if toType == "" || toType == "str" {
		return pyString(val)
	}

	if toType == "bool" {
		val = strings.ToLower(val)
		if val == "true" || val == "yes" || val == "on" {
			return pyBool(true)
		}
		if val == "false" || val == "no" || val == "off" || val == "" {
			return pyBool(false)
		}
		log.Fatalf("%s: Invalid boolean value %v", key, val)
	}

	if toType == "int" {
		if val == "" {
			return pyInt(0)
		}

		i, err := strconv.Atoi(val)
		if err != nil {
			log.Fatalf("%s: Invalid int value %v", key, val)
		}
		return pyInt(i)
	}

	log.Fatalf("%s: invalid config type %v", key, toType)
	return pyNone{}
}
<commit_msg>Fix config key default value and validation (#2382)<commit_after>package asp

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/thought-machine/please/src/core"
)

// valueToPyObject converts a field value to a pyObject
func valueToPyObject(value reflect.Value) pyObject {
	switch value.Kind() {
	case reflect.String:
		return pyString(value.String())
	case reflect.Bool:
		return newPyBool(value.Bool())
	case reflect.Slice:
		l := make(pyList, value.Len())
		for i := 0; i < value.Len(); i++ {
			l[i] = pyString(value.Index(i).String())
		}
		return l
	case reflect.Struct:
		return pyString(value.Interface().(fmt.Stringer).String())
	default:
		log.Fatalf("Unknown config field type for %s", tag)
	}
	return nil
}

// newConfig creates a new pyConfig object from the configuration.
// This is typically only created once at global scope, other scopes copy it with .Copy()
func newConfig(state *core.BuildState) *pyConfig {
	base := make(pyDict, 100)

	v := reflect.ValueOf(state.Config).Elem()
	for i := 0; i < v.NumField(); i++ {
		if field := v.Field(i); field.Kind() == reflect.Struct {
			for j := 0; j < field.NumField(); j++ {
				subfieldType := field.Type().Field(j)
				if varName := subfieldType.Tag.Get("var"); varName != "" {
					base[varName] = valueToPyObject(field.Field(j))
				}
			}
		}
	}

	// Arbitrary build config stuff
	for k, v := range state.Config.BuildConfig {
		// It's hard to know what the correct thing to do with build config when it comes to inheriting it from the
		// parent subrepo or not. Historically we wouldn't load from the subrepo at all, so we err on the side of
		// caution here: we only load in values that aren't already present as this is closer to how it used to work.
		key := strings.ReplaceAll(strings.ToUpper(k), "-", "_")
		if _, ok := base[key]; !ok {
			// TODO(jpoole): handle relative build labels
			base[key] = pyString(v)
		}
	}
	// Settings specific to package() which aren't in the config, but it's easier to
	// just put them in now.
	base["DEFAULT_VISIBILITY"] = None
	base["DEFAULT_TESTONLY"] = False
	base["DEFAULT_LICENCES"] = None
	// Bazel supports a 'features' flag to toggle things on and off.
	// We don't but at least let them call package() without blowing up.
	if state.Config.Bazel.Compatibility {
		base["FEATURES"] = pyList{}
	}

	arch := state.Arch

	base["OS"] = pyString(arch.OS)
	base["ARCH"] = pyString(arch.Arch)
	base["HOSTOS"] = pyString(arch.HostOS())
	base["HOSTARCH"] = pyString(arch.HostArch())
	base["TARGET_OS"] = pyString(state.TargetArch.OS)
	base["TARGET_ARCH"] = pyString(state.TargetArch.Arch)
	base["BUILD_CONFIG"] = pyString(state.Config.Build.Config)
	base["DEBUG_PORT"] = pyInt(state.DebugPort)

	if !state.Config.FeatureFlags.ExcludeGoRules {
		base["GOOS"] = pyString(arch.OS)
		base["GOARCH"] = pyString(arch.GoArch())
	}

	return &pyConfig{base: &pyConfigBase{dict: base}}
}

func resolvePluginValue(values []string, subrepo string) []string {
	ret := make([]string, len(values))
	for i, v := range values {
		if core.LooksLikeABuildLabel(v) {
			l, err := core.TryParseBuildLabel(v, "", subrepo)
			if err != nil {
				panic(err)
			}
			// Force the full build label including empty subrepo so this is portable
			v = fmt.Sprintf("///%v//%v:%v", l.Subrepo, l.PackageName, l.Name)
		}
		ret[i] = v
	}
	return ret
}

func getExtraVals(config *core.Configuration, pluginName string) map[string][]string {
	plugin := config.Plugin[pluginName]
	if plugin == nil {
		return map[string][]string{}
	}

	return plugin.ExtraValues
}

func getConfigKey(aspKey, configKey string) string {
	if configKey == "" {
		configKey = strings.ReplaceAll(aspKey, "_", "")
	}
	return strings.ToLower(configKey)
}

// pluginConfig loads the plugin's config into a pyDict. It will load con
func pluginConfig(pluginState *core.BuildState, pkgState *core.BuildState) pyDict {
	pluginName := strings.ToLower(pluginState.RepoConfig.PluginDefinition.Name)
	var extraVals map[string][]string
	var ret pyDict
	if pkgState.ParentState == nil {
		extraVals = getExtraVals(pkgState.RepoConfig, pluginName)
		ret = pyDict{}
	} else {
		extraVals = getExtraVals(pkgState.RepoConfig, pluginName)
		ret = pluginConfig(pluginState, pkgState.ParentState)
	}
	definedKeys := map[string]bool{}
	for key, definition := range pluginState.RepoConfig.PluginConfig {
		configKey := getConfigKey(key, definition.ConfigKey)
		definedKeys[configKey] = true

		key = strings.ToUpper(key)
		if _, ok := ret[key]; ok && definition.Inherit {
			// If the config key is already defined, and we should inherit it from the host repo, continue.
			continue
		}

		fullConfigKey := fmt.Sprintf("%v.%v", pluginName, configKey)
		value, ok := extraVals[strings.ToLower(configKey)]
		if !ok {
			// The default values are defined in the subrepo so should be parsed in that context
			value = resolvePluginValue(definition.DefaultValue, pluginState.CurrentSubrepo)
		} else {
			value = resolvePluginValue(value, pkgState.CurrentSubrepo)
		}

		if len(value) == 0 && !definition.Optional {
			if _, ok := ret[key]; ok {
				// Inherit config from the host repo if we don't override it
				continue
			}
			log.Fatalf("plugin config %s is not optional", fullConfigKey)
		}

		if !definition.Repeatable && len(value) > 1 {
			log.Fatalf("plugin config %v is not repeatable", fullConfigKey)
		}

		if definition.Repeatable {
			l := make(pyList, 0, len(value))
			for _, v := range value {
				l = append(l, toPyObject(fullConfigKey, v, definition.Type))
			}
			ret[key] = l
		} else {
			val := ""
			if len(value) == 1 {
				val = value[0]
			}
			ret[key] = toPyObject(fullConfigKey, val, definition.Type)
		}
	}

	// Validate against definedKeys
	for k := range extraVals {
		if _, ok := definedKeys[strings.ToLower(k)]; !ok {
			log.Warning("Unrecognised config key \"%v\" for plugin \"%v\"", k, pluginName)
		}
	}

	return ret
}

func (i *interpreter) loadPluginConfig(pluginState *core.BuildState, pkgState *core.BuildState, c *pyConfig) {
	pluginName := pluginState.Config.PluginDefinition.Name
	if pluginName == "" {
		// Subinclude is not a plugin. Stop here.
		return
	}

	var dict pyDict
	if !c.base.finalised {
		c.base.Lock()
		defer c.base.Unlock()

		dict = c.base.dict
	} else {
		if c.overlay == nil {
			c.overlay = pyDict{}
		}
		dict = c.overlay
	}

	key := strings.ToUpper(pluginName)
	if _, ok := dict[key]; ok {
		return
	}

	cfg := pluginConfig(pluginState, pkgState)
	dict[key] = cfg
}

func toPyObject(key, val, toType string) pyObject {
	if toType == "" || toType == "str" {
		return pyString(val)
	}

	if toType == "bool" {
		val = strings.ToLower(val)
		if val == "true" || val == "yes" || val == "on" {
			return pyBool(true)
		}
		if val == "false" || val == "no" || val == "off" || val == "" {
			return pyBool(false)
		}
		log.Fatalf("%s: Invalid boolean value %v", key, val)
	}

	if toType == "int" {
		if val == "" {
			return pyInt(0)
		}

		i, err := strconv.Atoi(val)
		if err != nil {
			log.Fatalf("%s: Invalid int value %v", key, val)
		}
		return pyInt(i)
	}

	log.Fatalf("%s: invalid config type %v", key, toType)
	return pyNone{}
}
<|endoftext|>