Prettier printing.
This commit is contained in:
parent
8a218f35c0
commit
467d1d3d44
5 changed files with 73 additions and 26 deletions
|
|
@ -196,14 +196,14 @@ func expandSigils(input string, vars map[string][]string) []string {
|
|||
func expandRecipeSigils(input string, vars map[string][]string) string {
|
||||
expanded := ""
|
||||
for i := 0; i < len(input); {
|
||||
j := strings.IndexAny(input[i:], "$\\")
|
||||
if j < 0 {
|
||||
off := strings.IndexAny(input[i:], "$\\")
|
||||
if off < 0 {
|
||||
expanded += input[i:]
|
||||
break
|
||||
}
|
||||
expanded += input[i : i+off]
|
||||
i += off
|
||||
|
||||
expanded += input[i:j]
|
||||
i = j
|
||||
c, w := utf8.DecodeRuneInString(input[i:])
|
||||
if c == '$' {
|
||||
i += w
|
||||
|
|
|
|||
8
lex.go
8
lex.go
|
|
@ -49,6 +49,7 @@ type token struct {
|
|||
typ tokenType // token type
|
||||
val string // token string
|
||||
line int // line where it was found
|
||||
col int // column on which the token began
|
||||
}
|
||||
|
||||
func (t *token) String() string {
|
||||
|
|
@ -65,6 +66,7 @@ type lexer struct {
|
|||
input string // input string to be lexed
|
||||
output chan token // channel on which tokens are sent
|
||||
start int // token beginning
|
||||
startcol int // column on which the token begins
|
||||
pos int // position within input
|
||||
line int // line within input
|
||||
col int // column within input
|
||||
|
|
@ -129,11 +131,13 @@ func (l *lexer) next() rune {
|
|||
func (l *lexer) skip() {
|
||||
l.next()
|
||||
l.start = l.pos
|
||||
l.startcol = l.col
|
||||
}
|
||||
|
||||
func (l *lexer) emit(typ tokenType) {
|
||||
l.output <- token{typ, l.input[l.start:l.pos], l.line}
|
||||
l.output <- token{typ, l.input[l.start:l.pos], l.line, l.startcol}
|
||||
l.start = l.pos
|
||||
l.startcol = 0
|
||||
}
|
||||
|
||||
// Consume the next run if it is in the given string.
|
||||
|
|
@ -189,7 +193,7 @@ func (l *lexer) skipUntil(invalid string) {
|
|||
|
||||
// Start a new lexer to lex the given input.
|
||||
func lex(input string) (*lexer, chan token) {
|
||||
l := &lexer{input: input, output: make(chan token), line: 1, indented: true}
|
||||
l := &lexer{input: input, output: make(chan token), line: 1, col: 0, indented: true}
|
||||
go l.run()
|
||||
return l, l.output
|
||||
}
|
||||
|
|
|
|||
30
mk.go
30
mk.go
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// True if messages should be printed without fancy colors.
|
||||
|
|
@ -13,6 +14,9 @@ var nocolor bool = false
|
|||
// True if we are no actualyl executing any recipes or updating any timestamps.
|
||||
var dryrun bool = false
|
||||
|
||||
// Lock on standard out, messages don't get interleaved too much.
|
||||
var mkMsgMutex sync.Mutex
|
||||
|
||||
// The maximum number of times an rule may be applied.
|
||||
const max_rule_cnt = 3
|
||||
|
||||
|
|
@ -29,7 +33,9 @@ const (
|
|||
|
||||
func mk(rs *ruleSet, target string, dryrun bool) {
|
||||
g := buildgraph(rs, target)
|
||||
//g.visualize(os.Stdout)
|
||||
if g.root.exists {
|
||||
return
|
||||
}
|
||||
mkNode(g, g.root)
|
||||
}
|
||||
|
||||
|
|
@ -129,13 +135,13 @@ func mkNode(g *graph, u *node) {
|
|||
|
||||
// execute the recipe, unless the prereqs failed
|
||||
if finalstatus != nodeStatusFailed {
|
||||
mkPrintMessage("mking " + u.name)
|
||||
//mkPrintMessage("mking " + u.name)
|
||||
if !dorecipe(u.name, u, e) {
|
||||
finalstatus = nodeStatusFailed
|
||||
}
|
||||
}
|
||||
|
||||
mkPrintSuccess("finished mking " + u.name)
|
||||
//mkPrintSuccess("finished mking " + u.name)
|
||||
}
|
||||
|
||||
func mkError(msg string) {
|
||||
|
|
@ -158,26 +164,34 @@ func mkPrintSuccess(msg string) {
|
|||
}
|
||||
|
||||
func mkPrintMessage(msg string) {
|
||||
mkMsgMutex.Lock()
|
||||
if nocolor {
|
||||
fmt.Println(msg)
|
||||
} else {
|
||||
fmt.Printf("%s%s%s\n", colorBlue, msg, colorDefault)
|
||||
}
|
||||
mkMsgMutex.Unlock()
|
||||
}
|
||||
|
||||
func mkPrintRecipe(msg string) {
|
||||
if !nocolor {
|
||||
os.Stdout.WriteString(colorYellow)
|
||||
func mkPrintRecipe(target string, recipe string) {
|
||||
mkMsgMutex.Lock()
|
||||
if nocolor {
|
||||
fmt.Printf("%s: ", target)
|
||||
} else {
|
||||
fmt.Printf("%s%s%s => %s", colorBlue, target, colorDefault, colorMagenta)
|
||||
}
|
||||
printIndented(os.Stdout, recipe, len(target)+4)
|
||||
if len(recipe) == 0 {
|
||||
os.Stdout.WriteString("\n")
|
||||
}
|
||||
printIndented(os.Stdout, msg)
|
||||
if !nocolor {
|
||||
os.Stdout.WriteString(colorDefault)
|
||||
}
|
||||
mkMsgMutex.Unlock()
|
||||
}
|
||||
|
||||
func main() {
|
||||
var mkfilepath string
|
||||
var dryrun bool
|
||||
flag.StringVar(&mkfilepath, "f", "mkfile", "use the given file as mkfile")
|
||||
flag.BoolVar(&dryrun, "n", false, "print commands without actually executing")
|
||||
flag.Parse()
|
||||
|
|
|
|||
4
parse.go
4
parse.go
|
|
@ -76,7 +76,7 @@ func parseInto(input string, name string, rules *ruleSet) {
|
|||
|
||||
// insert a dummy newline to allow parsing of any assignments or recipeless
|
||||
// rules to finish.
|
||||
state = state(p, token{tokenNewline, "\n", l.line})
|
||||
state = state(p, token{tokenNewline, "\n", l.line, l.col})
|
||||
|
||||
// TODO: Error when state != parseTopLevel
|
||||
}
|
||||
|
|
@ -339,7 +339,7 @@ func parseRecipe(p *parser, t token) parserStateFun {
|
|||
}
|
||||
|
||||
if t.typ == tokenRecipe {
|
||||
r.recipe = t.val
|
||||
r.recipe = stripIndentation(t.val, t.col)
|
||||
}
|
||||
|
||||
p.rules.add(r)
|
||||
|
|
|
|||
49
recipe.go
49
recipe.go
|
|
@ -10,28 +10,57 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Try to unindent a recipe, so that it begins an column 0. (This is mainly for
|
||||
// recipes in python, or other indentation-significant languages.)
|
||||
//func stripIndentation(s string) string {
|
||||
|
||||
//}
|
||||
|
||||
// Indent each line of a recipe.
|
||||
func printIndented(out io.Writer, s string) {
|
||||
func stripIndentation(s string, mincol int) string {
|
||||
// trim leading whitespace
|
||||
reader := bufio.NewReader(strings.NewReader(s))
|
||||
output := ""
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if len(line) > 0 {
|
||||
io.WriteString(out, " ")
|
||||
io.WriteString(out, line)
|
||||
col := 0
|
||||
i := 0
|
||||
for i < len(line) && col < mincol {
|
||||
c, w := utf8.DecodeRuneInString(line[i:])
|
||||
if strings.IndexRune(" \t\n", c) >= 0 {
|
||||
col += 1
|
||||
i += w
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
output += line[i:]
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// Indent each line of a recipe.
|
||||
func printIndented(out io.Writer, s string, ind int) {
|
||||
indentation := strings.Repeat(" ", ind)
|
||||
reader := bufio.NewReader(strings.NewReader(s))
|
||||
firstline := true
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if len(line) > 0 {
|
||||
if !firstline {
|
||||
io.WriteString(out, indentation)
|
||||
}
|
||||
io.WriteString(out, line)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
firstline = false
|
||||
}
|
||||
}
|
||||
|
||||
// Execute a recipe.
|
||||
|
|
@ -70,7 +99,7 @@ func dorecipe(target string, u *node, e *edge) bool {
|
|||
}
|
||||
|
||||
if !e.r.attributes.quiet {
|
||||
mkPrintRecipe(input)
|
||||
mkPrintRecipe(target, input)
|
||||
}
|
||||
|
||||
if dryrun {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue