<commit_before>package mark

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// type position
type Pos int

// itemType identifies the type of lex items.
type itemType int

// Item represent a token or text string returned from the scanner
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

const eof = -1 // Zero value so closed channel delivers EOF

const (
	itemError itemType = iota // Error occurred; value is text of error
	// Intersting things
	itemNewLine
	itemHTML
	// Block Elements
	itemText
	itemLineBreak
	itemHeading
	itemLHeading // Setext-style headers
	itemBlockQuote
	itemList
	itemCodeBlock
	itemGfmCodeBlock
	itemHr
	itemTable
	// Span Elements
	itemLink
	itemAutoLink
	itemGfmLink
	itemStrong
	itemItalic
	itemStrike
	itemCode
	itemImage
	itemBr
	// Indentation
	itemIndent
)

var (
	reEmphasise = `^_{%[1]d}([\s\S]+?)_{%[1]d}|^\*{%[1]d}([\s\S]+?)\*{%[1]d}`
	reGfmCode   = `^%s{3,} *(\S+)? *\n([\s\S]+?)\s*%s{3,}$*(?:\n+|$)`
	reLinkText  = `(?:\[[^\]]*\]|[^\[\]]|\])*`
	reLinkHref  = `\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*`
)

// Block Grammer
var block = map[itemType]*regexp.Regexp{
	itemHeading:   regexp.MustCompile("^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)"),
	itemLHeading:  regexp.MustCompile("^([^\n]+)\n *(=|-){2,} *(?:\n+|$)"),
	itemHr:        regexp.MustCompile("^( *[-*_]){3,} *(?:\n+|$)"),
	itemCodeBlock: regexp.MustCompile("^(( {4}|\t)[^\n]+\n*)+"),
	// Backreferences is unavailable
	itemGfmCodeBlock: regexp.MustCompile(fmt.Sprintf(reGfmCode, "`", "`") + "|" + fmt.Sprintf(reGfmCode, "~", "~")),
	itemList:         regexp.MustCompile("(?:[*+-]|\\d+\\.)"),
}

// Inline Grammer
var span = map[itemType]*regexp.Regexp{
	itemText:   regexp.MustCompile("^([\\s\\S]+?)([!<\\[_*`~]| {2,}\n|\n|$)"),
	itemItalic: regexp.MustCompile(fmt.Sprintf(reEmphasise, 1)),
	itemStrong: regexp.MustCompile(fmt.Sprintf(reEmphasise, 2)),
	itemStrike: regexp.MustCompile("^~{2}([\\s\\S]+?)~{2}"),
	// itemMixed(e.g: ***str***, ~~*str*~~) will be part of the parser
	// or we'll lex recuresively
	itemCode: regexp.MustCompile("^`{1,2}\\s*([\\s\\S]*?[^`])\\s*`{1,2}"),
	itemBr:   regexp.MustCompile(`^ {2,}\n`),
	// Links
	itemLink:     regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
	itemAutoLink: regexp.MustCompile(`^<([^ >]+(@|:\/)[^ >]+)>`),
	itemGfmLink:  regexp.MustCompile(`^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])`),
	// Image
	// TODO(Ariel): DRY
	itemImage: regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name       string    // the name of the input; used only for error reports
	input      string    // the string being scanned
	state      stateFn   // the next lexing function to enter
	pos        Pos       // current position in the input
	start      Pos       // start position of this item
	width      Pos       // width of last rune read from input
	lastPos    Pos       // position of most recent item returned by nextItem
	items      chan item // channel of scanned items
	parenDepth int       // nesting depth of ( ) exprs
}

// lex creates a new lexer for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexAny; l.state != nil; {
		l.state = l.state(l)
	}
	close(l.items)
}

// next return the next rune in the input
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// lexAny scans non-space items.
func lexAny(l *lexer) stateFn {
	switch r := l.next(); {
	case r == eof:
		return nil
	case r == '*' || r == '-' || r == '_':
		p := l.peek()
		if p == '*' || p == '-' || p == '_' {
			l.backup()
			return lexHr
		} else {
			l.backup()
			return lexList
		}
	case '0' <= r && r <= '9':
		l.backup()
		return lexList
	case r == '>':
		l.emit(itemBlockQuote)
		return lexText
	case r == '#':
		l.backup()
		return lexHeading
	case r == ' ', r == '\t':
		// Should be here ?
		// TODO(Ariel): test that it's a codeBlock and not list for sure
		if block[itemCodeBlock].MatchString(l.input[l.pos-1:]) {
			l.backup()
			return lexCode
		}
		// Keep moving forward until we get all the
		// indentation size
		for ; r == l.peek(); r = l.next() {
		}
		l.emit(itemIndent)
		return lexAny
	case r == '`' || r == '~':
		// if it's gfm-code
		c := l.input[l.pos : l.pos+2]
		if c == "``" || c == "~~" {
			l.backup()
			return lexGfmCode
		}
		fallthrough
	default:
		l.backup()
		return lexText
	}
}

// lexHeading scans heading items.
func lexHeading(l *lexer) stateFn {
	if m := block[itemHeading].FindString(l.input[l.pos:]); m != "" {
		// Emit without the newline(\n)
		l.pos += Pos(len(m))
		// TODO(Ariel): hack, fix regexp
		if strings.HasSuffix(m, "\n") {
			l.pos--
		}
		l.emit(itemHeading)
		return lexAny
	}
	return lexText
}

// lexHr scans horizontal rules items.
func lexHr(l *lexer) stateFn {
	if block[itemHr].MatchString(l.input[l.pos:]) {
		match := block[itemHr].FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemHr)
		return lexAny
	}
	return lexText
}

// lexGfmCode scans GFM code block.
func lexGfmCode(l *lexer) stateFn {
	re := block[itemGfmCodeBlock]
	if re.MatchString(l.input[l.pos:]) {
		match := re.FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemGfmCodeBlock)
		return lexAny
	}
	return lexText
}

// lexCode scans code block.
func lexCode(l *lexer) stateFn {
	match := block[itemCodeBlock].FindString(l.input[l.pos:])
	l.pos += Pos(len(match))
	l.emit(itemCodeBlock)
	return lexAny
}

// lexList scans ordered and unordered lists.
func lexList(l *lexer) stateFn {
	if m := block[itemList].FindString(l.input[l.pos:]); m != "" {
		l.pos += Pos(len(m))
		l.emit(itemList)
	}
	return lexText
}

// lexText scans until eol(\n)
func lexText(l *lexer) stateFn {
Loop:
	for {
		switch r := l.next(); {
		case r == eof:
			break Loop
		case r == '\n':
			l.emit(itemNewLine)
			break Loop
		case r == ' ':
			l.backup()
			if m := span[itemBr].FindString(l.input[l.pos:]); m != "" {
				// length of new-line
				l.pos += Pos(len(m))
				l.emit(itemBr)
				break Loop
			} else {
				// ~backup()
				l.pos += l.width
				// Yeah, space it's also text.
				l.emit(itemText)
			}
		// if it's start as an emphasis
		case r == '_', r == '*', r == '~', r == '`':
			l.backup()
			input := l.input[l.pos:]
			// Strong
			if m := span[itemStrong].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemStrong)
				break
			}
			// Italic
			if m := span[itemItalic].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemItalic)
				break
			}
			// Strike
			if m := span[itemStrike].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemStrike)
				break
			}
			// InlineCode
			if m := span[itemCode].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemCode)
				break
			}
			// ~backup()
			l.pos += l.width
			fallthrough
		// itemLink, itemAutoLink, itemImage
		case r == '[', r == '<', r == '!':
			l.backup()
			input := l.input[l.pos:]
			if m := span[itemLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				if r == '[' {
					l.emit(itemLink)
				} else {
					l.emit(itemImage)
				}
				break
			}
			if m := span[itemAutoLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemAutoLink)
				break
			}
			// ~backup()
			l.pos += l.width
			fallthrough
		default:
			l.backup()
			input := l.input[l.pos:]
			// Test for Setext-style headers
			if m := block[itemLHeading].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemLHeading)
				break Loop
			}
			// GfmLink
			if m := span[itemGfmLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemGfmLink)
				break
			}
			// Simple text
			subMatch := span[itemText].FindStringSubmatch(input)
			if len(subMatch) >= 1 {
				l.pos += Pos(len(subMatch[1]))
			}
			l.emit(itemText)
		}
	}
	return lexAny
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// lexItem return the next item token, clled by the parser.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = l.pos
	return item
}
<commit_msg>fix(lexer): list as codeBlock example<commit_after>package mark

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// type position
type Pos int

// itemType identifies the type of lex items.
type itemType int

// Item represent a token or text string returned from the scanner
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

const eof = -1 // Zero value so closed channel delivers EOF

const (
	itemError itemType = iota // Error occurred; value is text of error
	// Intersting things
	itemNewLine
	itemHTML
	// Block Elements
	itemText
	itemLineBreak
	itemHeading
	itemLHeading // Setext-style headers
	itemBlockQuote
	itemList
	itemCodeBlock
	itemGfmCodeBlock
	itemHr
	itemTable
	// Span Elements
	itemLink
	itemAutoLink
	itemGfmLink
	itemStrong
	itemItalic
	itemStrike
	itemCode
	itemImage
	itemBr
	// Indentation
	itemIndent
)

var (
	reEmphasise = `^_{%[1]d}([\s\S]+?)_{%[1]d}|^\*{%[1]d}([\s\S]+?)\*{%[1]d}`
	reGfmCode   = `^%s{3,} *(\S+)? *\n([\s\S]+?)\s*%s{3,}$*(?:\n+|$)`
	reLinkText  = `(?:\[[^\]]*\]|[^\[\]]|\])*`
	reLinkHref  = `\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*`
)

// Block Grammer
var block = map[itemType]*regexp.Regexp{
	itemHeading:   regexp.MustCompile("^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)"),
	itemLHeading:  regexp.MustCompile("^([^\n]+)\n *(=|-){2,} *(?:\n+|$)"),
	itemHr:        regexp.MustCompile("^( *[-*_]){3,} *(?:\n+|$)"),
	itemCodeBlock: regexp.MustCompile(`^(( {4}|\t)[^-+*(\d\.)\n]+\n*)+`),
	// Backreferences is unavailable
	itemGfmCodeBlock: regexp.MustCompile(fmt.Sprintf(reGfmCode, "`", "`") + "|" + fmt.Sprintf(reGfmCode, "~", "~")),
	itemList:         regexp.MustCompile("(?:[*+-]|\\d+\\.)"),
}

// Inline Grammer
var span = map[itemType]*regexp.Regexp{
	itemText:   regexp.MustCompile("^([\\s\\S]+?)([!<\\[_*`~]| {2,}\n|\n|$)"),
	itemItalic: regexp.MustCompile(fmt.Sprintf(reEmphasise, 1)),
	itemStrong: regexp.MustCompile(fmt.Sprintf(reEmphasise, 2)),
	itemStrike: regexp.MustCompile("^~{2}([\\s\\S]+?)~{2}"),
	// itemMixed(e.g: ***str***, ~~*str*~~) will be part of the parser
	// or we'll lex recuresively
	itemCode: regexp.MustCompile("^`{1,2}\\s*([\\s\\S]*?[^`])\\s*`{1,2}"),
	itemBr:   regexp.MustCompile(`^ {2,}\n`),
	// Links
	itemLink:     regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
	itemAutoLink: regexp.MustCompile(`^<([^ >]+(@|:\/)[^ >]+)>`),
	itemGfmLink:  regexp.MustCompile(`^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])`),
	// Image
	// TODO(Ariel): DRY
	itemImage: regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name       string    // the name of the input; used only for error reports
	input      string    // the string being scanned
	state      stateFn   // the next lexing function to enter
	pos        Pos       // current position in the input
	start      Pos       // start position of this item
	width      Pos       // width of last rune read from input
	lastPos    Pos       // position of most recent item returned by nextItem
	items      chan item // channel of scanned items
	parenDepth int       // nesting depth of ( ) exprs
}

// lex creates a new lexer for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexAny; l.state != nil; {
		l.state = l.state(l)
	}
	close(l.items)
}

// next return the next rune in the input
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// lexAny scans non-space items.
func lexAny(l *lexer) stateFn {
	switch r := l.next(); {
	case r == eof:
		return nil
	case r == '*' || r == '-' || r == '_':
		p := l.peek()
		if p == '*' || p == '-' || p == '_' {
			l.backup()
			return lexHr
		} else {
			l.backup()
			return lexList
		}
	case '0' <= r && r <= '9':
		l.backup()
		return lexList
	case r == '>':
		l.emit(itemBlockQuote)
		return lexText
	case r == '#':
		l.backup()
		return lexHeading
	case r == ' ', r == '\t':
		// Should be here ?
		// TODO(Ariel): test that it's a codeBlock and not list for sure
		if block[itemCodeBlock].MatchString(l.input[l.pos-1:]) {
			l.backup()
			return lexCode
		}
		// Keep moving forward until we get all the
		// indentation size
		for ; r == l.peek(); r = l.next() {
		}
		l.emit(itemIndent)
		return lexAny
	case r == '`' || r == '~':
		// if it's gfm-code
		c := l.input[l.pos : l.pos+2]
		if c == "``" || c == "~~" {
			l.backup()
			return lexGfmCode
		}
		fallthrough
	default:
		l.backup()
		return lexText
	}
}

// lexHeading scans heading items.
func lexHeading(l *lexer) stateFn {
	if m := block[itemHeading].FindString(l.input[l.pos:]); m != "" {
		// Emit without the newline(\n)
		l.pos += Pos(len(m))
		// TODO(Ariel): hack, fix regexp
		if strings.HasSuffix(m, "\n") {
			l.pos--
		}
		l.emit(itemHeading)
		return lexAny
	}
	return lexText
}

// lexHr scans horizontal rules items.
func lexHr(l *lexer) stateFn {
	if block[itemHr].MatchString(l.input[l.pos:]) {
		match := block[itemHr].FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemHr)
		return lexAny
	}
	return lexText
}

// lexGfmCode scans GFM code block.
func lexGfmCode(l *lexer) stateFn {
	re := block[itemGfmCodeBlock]
	if re.MatchString(l.input[l.pos:]) {
		match := re.FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemGfmCodeBlock)
		return lexAny
	}
	return lexText
}

// lexCode scans code block.
func lexCode(l *lexer) stateFn {
	match := block[itemCodeBlock].FindString(l.input[l.pos:])
	l.pos += Pos(len(match))
	l.emit(itemCodeBlock)
	return lexAny
}

// lexList scans ordered and unordered lists.
func lexList(l *lexer) stateFn {
	if m := block[itemList].FindString(l.input[l.pos:]); m != "" {
		l.pos += Pos(len(m))
		l.emit(itemList)
	}
	return lexText
}

// lexText scans until eol(\n)
func lexText(l *lexer) stateFn {
Loop:
	for {
		switch r := l.next(); {
		case r == eof:
			break Loop
		case r == '\n':
			l.emit(itemNewLine)
			break Loop
		case r == ' ':
			l.backup()
			if m := span[itemBr].FindString(l.input[l.pos:]); m != "" {
				// length of new-line
				l.pos += Pos(len(m))
				l.emit(itemBr)
				break Loop
			} else {
				// ~backup()
				l.pos += l.width
				// Yeah, space it's also text.
				l.emit(itemText)
			}
		// if it's start as an emphasis
		case r == '_', r == '*', r == '~', r == '`':
			l.backup()
			input := l.input[l.pos:]
			// Strong
			if m := span[itemStrong].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemStrong)
				break
			}
			// Italic
			if m := span[itemItalic].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemItalic)
				break
			}
			// Strike
			if m := span[itemStrike].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemStrike)
				break
			}
			// InlineCode
			if m := span[itemCode].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemCode)
				break
			}
			// ~backup()
			l.pos += l.width
			fallthrough
		// itemLink, itemAutoLink, itemImage
		case r == '[', r == '<', r == '!':
			l.backup()
			input := l.input[l.pos:]
			if m := span[itemLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				if r == '[' {
					l.emit(itemLink)
				} else {
					l.emit(itemImage)
				}
				break
			}
			if m := span[itemAutoLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemAutoLink)
				break
			}
			// ~backup()
			l.pos += l.width
			fallthrough
		default:
			l.backup()
			input := l.input[l.pos:]
			// Test for Setext-style headers
			if m := block[itemLHeading].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemLHeading)
				break Loop
			}
			// GfmLink
			if m := span[itemGfmLink].FindString(input); m != "" {
				l.pos += Pos(len(m))
				l.emit(itemGfmLink)
				break
			}
			// Simple text
			subMatch := span[itemText].FindStringSubmatch(input)
			if len(subMatch) >= 1 {
				l.pos += Pos(len(subMatch[1]))
			}
			l.emit(itemText)
		}
	}
	return lexAny
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// lexItem return the next item token, clled by the parser.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = l.pos
	return item
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

package repoctl

import (
	"compress/gzip"
	"io"
	"net/http"
	"os"

	"github.com/goulash/errs"
	"github.com/goulash/osutil"
	"github.com/goulash/pacman/aur"
	"github.com/goulash/pacman/graph"
	"github.com/juju/utils/tar"
)

// DependencyGraph returns a dependency graph of the given package names.
func (r *Repo) DependencyGraph(h errs.Handler, pkgnames ...string) (*graph.Graph, error) {
	errs.Init(&h)

	aurpkgs, err := r.ReadAUR(h, pkgnames...)
	if err != nil {
		return nil, err
	}

	// Get dependencies
	f, err := graph.NewFactory()
	if err != nil {
		return nil, err
	}

	f.SetSkipInstalled(true)
	f.SetTruncate(true)
	return f.NewGraph(uniqueBases(aurpkgs))
}

// Download downloads and extracts the given package tarballs.
func (r *Repo) Download(h errs.Handler, destdir string, extract bool, clobber bool, pkgnames ...string) error {
	errs.Init(&h)
	if len(pkgnames) == 0 {
		return nil
	}

	// If a package cannot be found, we want to report it.
	aurpkgs, err := r.ReadAUR(h, pkgnames...)
	if err != nil {
		return err
	}
	return r.DownloadPackages(h, uniqueBases(aurpkgs), destdir, extract, clobber)
}

// DownloadPackages downloads the given AUR packages, printing messages for each one.
func (r *Repo) DownloadPackages(h errs.Handler, pkgs aur.Packages, destdir string, extract bool, clobber bool) error {
	errs.Init(&h)
	for _, p := range pkgs {
		r.printf("downloading: %s\n", p.Name)
		download := DownloadTarballAUR
		if extract {
			download = DownloadExtractAUR
		}
		err := h(download(p, destdir, clobber))
		if err != nil {
			return err
		}
	}
	return nil
}

// DownloadExtractAUR is a helper for Download and DownloadUpgrades.
func DownloadExtractAUR(ap *aur.Package, destdir string, clobber bool) error {
	var err error
	if destdir == "" {
		destdir, err = os.Getwd()
		if err != nil {
			return err
		}
	}

	// Make sure we don't clobber anything.
	if !clobber {
		ex, err := osutil.DirExists(ap.Name)
		if err != nil {
			return err
		}
		if ex {
			return ErrPkgDirExists
		}
	}

	response, err := http.Get(ap.DownloadURL())
	if err != nil {
		return err
	}
	defer response.Body.Close()

	gr, err := gzip.NewReader(response.Body)
	if err != nil {
		return err
	}

	return tar.UntarFiles(gr, destdir)
}

// DownloadTarballAUR downloads the given package from AUR.
func DownloadTarballAUR(ap *aur.Package, destdir string, clobber bool) error {
	var err error
	if destdir == "" {
		destdir, err = os.Getwd()
		if err != nil {
			return err
		}
	}

	url := ap.DownloadURL()
	of := ap.Name + ".tar.gz"

	// Make sure we don't clobber anything.
	if !clobber {
		ex, err := osutil.FileExists(of)
		if err != nil {
			return err
		}
		if ex {
			return ErrPkgFileExists
		}
	}

	response, err := http.Get(url)
	if err != nil {
		return err
	}
	defer response.Body.Close()

	file, err := os.Create(of)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(file, response.Body)
	if err != nil {
		// Should I delete?
		return err
	}
	return nil
}

// uniqueBases returns a subset of the given aurpkgs where the package bases
// are the same.
func uniqueBases(aurpkgs aur.Packages) aur.Packages {
	bases := make(aur.Packages, 0, len(aurpkgs))
	mp := make(map[string]bool)
	for _, p := range aurpkgs {
		if mp[p.PackageBase] {
			continue
		}
		mp[p.PackageBase] = true
		bases = append(bases, p)
	}
	return bases
}

func upgradesToPackages(us Upgrades) aur.Packages {
	pkgs := make(aur.Packages, len(us))
	for i, p := range us {
		pkgs[i] = p.New
	}
	return pkgs
}
<commit_msg>Do not abort download when some packages cannot be found in AUR<commit_after>// Copyright (c) 2015, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

package repoctl

import (
	"compress/gzip"
	"io"
	"net/http"
	"os"

	"github.com/goulash/errs"
	"github.com/goulash/osutil"
	"github.com/goulash/pacman/aur"
	"github.com/goulash/pacman/graph"
	"github.com/juju/utils/tar"
)

// DependencyGraph returns a dependency graph of the given package names.
func (r *Repo) DependencyGraph(h errs.Handler, pkgnames ...string) (*graph.Graph, error) {
	errs.Init(&h)

	aurpkgs, err := r.ReadAUR(h, pkgnames...)
	if err != nil {
		return nil, err
	}

	// Get dependencies
	f, err := graph.NewFactory()
	if err != nil {
		return nil, err
	}

	f.SetSkipInstalled(true)
	f.SetTruncate(true)
	return f.NewGraph(uniqueBases(aurpkgs))
}

// Download downloads and extracts the given package tarballs.
func (r *Repo) Download(h errs.Handler, destdir string, extract bool, clobber bool, pkgnames ...string) error {
	errs.Init(&h)
	if len(pkgnames) == 0 {
		return nil
	}

	// If a package cannot be found, we want to report it.
	aurpkgs, err := r.ReadAUR(h, pkgnames...)
	if err != nil {
		err = h(err)
		if err != nil {
			return err
		}
	}
	return r.DownloadPackages(h, uniqueBases(aurpkgs), destdir, extract, clobber)
}

// DownloadPackages downloads the given AUR packages, printing messages for each one.
func (r *Repo) DownloadPackages(h errs.Handler, pkgs aur.Packages, destdir string, extract bool, clobber bool) error {
	errs.Init(&h)
	for _, p := range pkgs {
		r.printf("downloading: %s\n", p.Name)
		download := DownloadTarballAUR
		if extract {
			download = DownloadExtractAUR
		}
		err := h(download(p, destdir, clobber))
		if err != nil {
			return err
		}
	}
	return nil
}

// DownloadExtractAUR is a helper for Download and DownloadUpgrades.
func DownloadExtractAUR(ap *aur.Package, destdir string, clobber bool) error {
	var err error
	if destdir == "" {
		destdir, err = os.Getwd()
		if err != nil {
			return err
		}
	}

	// Make sure we don't clobber anything.
	if !clobber {
		ex, err := osutil.DirExists(ap.Name)
		if err != nil {
			return err
		}
		if ex {
			return ErrPkgDirExists
		}
	}

	response, err := http.Get(ap.DownloadURL())
	if err != nil {
		return err
	}
	defer response.Body.Close()

	gr, err := gzip.NewReader(response.Body)
	if err != nil {
		return err
	}

	return tar.UntarFiles(gr, destdir)
}

// DownloadTarballAUR downloads the given package from AUR.
func DownloadTarballAUR(ap *aur.Package, destdir string, clobber bool) error {
	var err error
	if destdir == "" {
		destdir, err = os.Getwd()
		if err != nil {
			return err
		}
	}

	url := ap.DownloadURL()
	of := ap.Name + ".tar.gz"

	// Make sure we don't clobber anything.
	if !clobber {
		ex, err := osutil.FileExists(of)
		if err != nil {
			return err
		}
		if ex {
			return ErrPkgFileExists
		}
	}

	response, err := http.Get(url)
	if err != nil {
		return err
	}
	defer response.Body.Close()

	file, err := os.Create(of)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(file, response.Body)
	if err != nil {
		// Should I delete?
		return err
	}
	return nil
}

// uniqueBases returns a subset of the given aurpkgs where the package bases
// are the same.
func uniqueBases(aurpkgs aur.Packages) aur.Packages {
	bases := make(aur.Packages, 0, len(aurpkgs))
	mp := make(map[string]bool)
	for _, p := range aurpkgs {
		if mp[p.PackageBase] {
			continue
		}
		mp[p.PackageBase] = true
		bases = append(bases, p)
	}
	return bases
}

func upgradesToPackages(us Upgrades) aur.Packages {
	pkgs := make(aur.Packages, len(us))
	for i, p := range us {
		pkgs[i] = p.New
	}
	return pkgs
}
<|endoftext|>


<commit_before>package goini

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"regexp"
	"strings"
)

func Dump(i interface{}) (string, error) {
	s := new(bytes.Buffer)
	err := write(s, i)
	if err != nil {
		return "", err
	}
	return s.String(), nil
}

func write(w io.Writer, i interface{}) error {
	v := reflect.ValueOf(i)
	return writeValue(w, v, 0)
}

func writeValue(w io.Writer, v reflect.Value, deep int) error {
	if deep > 2 {
		return fmt.Errorf("not support nested map or struct more than 2 level")
	}
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		if err := encodeMap(w, v, deep+1); err != nil {
			return err
		}
	case reflect.Struct:
		if err := encodeStruct(w, v, deep+1); err != nil {
			return err
		}
	default:
		return fmt.Errorf("dump only support map and struct")
	}
	return nil
}

func isBaseKind(k reflect.Kind, includeBool bool) bool {
	switch k {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64,
		reflect.String:
		return true
	case reflect.Bool:
		return includeBool
	}
	return false
}

func parseTag(tag string) (string, []string) {
	splitter := regexp.MustCompile(`\s*,\s*`)
	commentSplitter := regexp.MustCompile(`\s*;\s*`)
	parts := splitter.Split(tag, 2)
	if len(parts) == 1 {
		return parts[0], nil
	}
	comments := commentSplitter.Split(parts[1], -1)
	return parts[0], comments
}

func writeSection(w io.Writer, name string, addLine bool) {
	if addLine {
		fmt.Fprintln(w, "")
	}
	fmt.Fprintf(w, "[%s]", name)
	fmt.Fprintln(w, "")
}

func writeComment(w io.Writer, comments []string) {
	if comments != nil {
		for _, c := range comments {
			fmt.Fprintln(w, ";", c)
		}
	}
}

func writeItem(w io.Writer, name string, comments []string, v reflect.Value, dumpSimpleType bool, deep int, addLine bool) (dumped bool, err error) {
	k := v.Type().Kind()
	if isBaseKind(k, true) {
		if dumpSimpleType {
			writeComment(w, comments)
			_, err = fmt.Fprintln(w, name, "=", v.Interface())
			dumped = true
		}
	} else if k == reflect.Slice {
		if dumpSimpleType {
			writeComment(w, comments)
			err = encodeSlice(w, name, v.Type().Elem().Kind(), v)
			dumped = true
		}
	} else if !dumpSimpleType {
		writeComment(w, comments)
		writeSection(w, name, addLine)
		err = writeValue(w, v, deep+1)
		dumped = true
	}
	return
}

func encodeMap(w io.Writer, v reflect.Value, deep int) (err error) {
	addLine, dumped := false, false
	for _, dumpType := range [2]bool{true, false} {
		for _, i := range v.MapKeys() {
			vv := v.MapIndex(i)
			if vv.Type().Kind() == reflect.Interface {
				vv = vv.Elem()
			}
			dumped, err = writeItem(w, i.String(), nil, vv, dumpType, deep, addLine)
			if err != nil {
				return
			}
			addLine = addLine || dumped
		}
	}
	return
}

func encodeSlice(w io.Writer, name string, k reflect.Kind, v reflect.Value) error {
	if !isBaseKind(k, false) {
		return fmt.Errorf("not support %s", v.Type())
	}
	fmt.Fprintf(w, "%s = ", name)
	for i := 0; i < v.Len(); i++ {
		if i > 0 {
			fmt.Fprint(w, ", ", v.Index(i).Interface())
		} else {
			fmt.Fprint(w, v.Index(i).Interface())
		}
	}
	fmt.Fprintln(w, "")
	return nil
}

func encodeStruct(w io.Writer, v reflect.Value, deep int) error {
	t := v.Type()
	addLine, dumped := false, false
	var err error
	for _, dumpType := range [2]bool{true, false} {
		for i := 0; i < t.NumField(); i++ {
			s := t.Field(i)
			name, comments := parseTag(s.Tag.Get("ini"))
			if name == "" {
				name = s.Name
			}
			if name == "-" || strings.ToLower(s.Name[:1]) == s.Name[:1] {
				continue
			}
			dumped, err = writeItem(w, name, comments, v.Field(i), dumpType, deep, addLine)
			if err != nil {
				return err
			}
			addLine = addLine || dumped
		}
	}
	return nil
}
<commit_msg>使用pkgpath判断是不是私有属性<commit_after>package goini

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"regexp"
)

func Dump(i interface{}) (string, error) {
	s := new(bytes.Buffer)
	err := write(s, i)
	if err != nil {
		return "", err
	}
	return s.String(), nil
}

func write(w io.Writer, i interface{}) error {
	v := reflect.ValueOf(i)
	return writeValue(w, v, 0)
}

func writeValue(w io.Writer, v reflect.Value, deep int) error {
	if deep > 2 {
		return fmt.Errorf("not support nested map or struct more than 2 level")
	}
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		if err := encodeMap(w, v, deep+1); err != nil {
			return err
		}
	case reflect.Struct:
		if err := encodeStruct(w, v, deep+1); err != nil {
			return err
		}
	default:
		return fmt.Errorf("dump only support map and struct")
	}
	return nil
}

func isBaseKind(k reflect.Kind, includeBool bool) bool {
	switch k {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64,
		reflect.String:
		return true
	case reflect.Bool:
		return includeBool
	}
	return false
}

func parseTag(tag string) (string, []string) {
	splitter := regexp.MustCompile(`\s*,\s*`)
	commentSplitter := regexp.MustCompile(`\s*;\s*`)
	parts := splitter.Split(tag, 2)
	if len(parts) == 1 {
		return parts[0], nil
	}
	comments := commentSplitter.Split(parts[1], -1)
	return parts[0], comments
}

func writeSection(w io.Writer, name string, addLine bool) {
	if addLine {
		fmt.Fprintln(w, "")
	}
	fmt.Fprintf(w, "[%s]", name)
	fmt.Fprintln(w, "")
}

func writeComment(w io.Writer, comments []string) {
	if comments != nil {
		for _, c := range comments {
			fmt.Fprintln(w, ";", c)
		}
	}
}

func writeItem(w io.Writer, name string, comments []string, v reflect.Value, dumpSimpleType bool, deep int, addLine bool) (dumped bool, err error) {
	k := v.Type().Kind()
	if isBaseKind(k, true) {
		if dumpSimpleType {
			writeComment(w, comments)
			_, err = fmt.Fprintln(w, name, "=", v.Interface())
			dumped = true
		}
	} else if k == reflect.Slice {
		if dumpSimpleType {
			writeComment(w, comments)
			err = encodeSlice(w, name, v.Type().Elem().Kind(), v)
			dumped = true
		}
	} else if !dumpSimpleType {
		writeComment(w, comments)
		writeSection(w, name, addLine)
		err = writeValue(w, v, deep+1)
		dumped = true
	}
	return
}

func encodeMap(w io.Writer, v reflect.Value, deep int) (err error) {
	addLine, dumped := false, false
	for _, dumpType := range [2]bool{true, false} {
		for _, i := range v.MapKeys() {
			vv := v.MapIndex(i)
			if vv.Type().Kind() == reflect.Interface {
				vv = vv.Elem()
			}
			dumped, err = writeItem(w, i.String(), nil, vv, dumpType, deep, addLine)
			if err != nil {
				return
			}
			addLine = addLine || dumped
		}
	}
	return
}

func encodeSlice(w io.Writer, name string, k reflect.Kind, v reflect.Value) error {
	if !isBaseKind(k, false) {
		return fmt.Errorf("not support %s", v.Type())
	}
	fmt.Fprintf(w, "%s = ", name)
	for i := 0; i < v.Len(); i++ {
		if i > 0 {
			fmt.Fprint(w, ", ", v.Index(i).Interface())
		} else {
			fmt.Fprint(w, v.Index(i).Interface())
		}
	}
	fmt.Fprintln(w, "")
	return nil
}

func encodeStruct(w io.Writer, v reflect.Value, deep int) error {
	t := v.Type()
	addLine, dumped := false, false
	var err error
	for _, dumpType := range [2]bool{true, false} {
		for i := 0; i < t.NumField(); i++ {
			s := t.Field(i)
			name, comments := parseTag(s.Tag.Get("ini"))
			if name == "" {
				name = s.Name
			}
			if name == "-" || s.PkgPath != "" {
				continue
			}
			dumped, err = writeItem(w, name, comments, v.Field(i), dumpType, deep, addLine)
			if err != nil {
				return err
			}
			addLine = addLine || dumped
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/toqueteos/webbrowser"
)

func tryOpenN(links []string, arg int) {
	if len(os.Args) != arg+1 {
		fmt.Println(usage)
		return
	}

	i, err := strconv.Atoi(os.Args[arg])
	if err != nil {
		fmt.Println("Argument was not a number")
		fmt.Println(usage)
		os.Exit(1)
	}

	if i < 1 || i > len(links) {
		fmt.Printf("Invalid number. Acceptable range: %d-%d\n", 1, len(links))
		printLinks(links)
		os.Exit(1)
	}

	tryOpen(links[i-1])
}

func tryOpen(link string) {
	err := webbrowser.Open(link)
	if err != nil {
		fmt.Println(link)
	}
}

func tryRemove(links []string, number string) ([]string, error) {
	i, err := strconv.Atoi(number)

	if err != nil {
		return links, fmt.Errorf("invalid number for rm: %s", os.Args[2])
	}

	if len(links) < i {
		return links, fmt.Errorf("invalid number, longer than list: %d", i)
	}

	if i < 1 {
		return links, fmt.Errorf("invalid link number less than zero")
	}

	links = append(links[0:i-1], links[i:]...)

	return links, nil
}

func printLinks(links []string) {
	if len(links) < 1 {
		fmt.Println("No items in reading list.")
	}
	for i := range links {
		fmt.Printf("%d.\t%s\n", i+1, links[i])
	}
}
<commit_msg>Add ranging to default open command<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/toqueteos/webbrowser"
)

const rangeSplit = ".."

func tryOpenN(links []string, arg int) {
	if len(os.Args) != arg+1 {
		fmt.Println(usage)
		return
	}

	from, to := os.Args[arg], os.Args[arg]

	if strings.Contains(from, rangeSplit) {
		rng := strings.Split(from, rangeSplit)

		if len(rng) < 2 {
			fmt.Println("illegal range given; format is <number>..<number>")
			os.Exit(1)
		}

		from, to = rng[0], rng[1]
	}

	fromI, err := strconv.Atoi(from)
	if err != nil {
		fmt.Println("Argument was not a number")
		fmt.Println(usage)
		os.Exit(1)
	}

	toI, err := strconv.Atoi(to)
	if err != nil {
		fmt.Println("Argument was not a number")
		fmt.Println(usage)
		os.Exit(1)
	}

	if fromI > toI {
		fromI, toI = toI, fromI
	}

	if toI < 1 || fromI > len(links) {
		fmt.Printf("Invalid number. Acceptable range: %d-%d\n", 1, len(links))
		printLinks(links)
		os.Exit(1)
	}

	for i := fromI; i <= toI && i < len(links) && i > 0; i++ {

		tryOpen(links[i-1])
	}
}

func tryOpen(link string) {
	err := webbrowser.Open(link)
	if err != nil {
		fmt.Println(link)
	}
}

func tryRemove(links []string, number string) ([]string, error) {
	i, err := strconv.Atoi(number)

	if err != nil {
		return links, fmt.Errorf("invalid number for rm: %s", os.Args[2])
	}

	if len(links) < i {
		return links, fmt.Errorf("invalid number, longer than list: %d", i)
	}

	if i < 1 {
		return links, fmt.Errorf("invalid link number less than zero")
	}

	links = append(links[0:i-1], links[i:]...)

	return links, nil
}

func printLinks(links []string) {
	if len(links) < 1 {
		fmt.Println("No items in reading list.")
	}
	for i := range links {
		fmt.Printf("%d.\t%s\n", i+1, links[i])
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"strings"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage    string            // The user's pipeline/job image
	labels       map[string]string // k8s labels attached to the RC and workers
	parallelism  int32             // Number of replicas the RC maintains
	workerEnv    []api.EnvVar      // Environment vars set in the user container
	volumes      []api.Volume      // Volumes that we expose to the user container
	volumeMounts []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
}

// PipelineRcName generates the name of the k8s replication controller that
// manages a pipeline's workers
func PipelineRcName(name string, version uint64) string {
	// k8s won't allow RC names that contain upper-case letters
	// TODO: deal with name collision
	return fmt.Sprintf("pipeline-%s-v%d", strings.ToLower(name), version)
}

// JobRcName generates the name of the k8s replication controller that manages
// an orphan job's workers
func JobRcName(id string) string {
	// k8s won't allow RC names that contain upper-case letters
	// TODO: deal with name collision
	return fmt.Sprintf("job-%s", strings.ToLower(id))
}

func (a *apiServer) workerPodSpec(options *workerOptions) api.PodSpec {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	return api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           a.workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    "user",
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		RestartPolicy:    "Always",
		Volumes:          options.volumes,
		ImagePullSecrets: options.imagePullSecrets,
	}
}

func (a *apiServer) getWorkerOptions(rcName string, parallelism int32, transform *pps.Transform) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		volumes = append(volumes, api.Volume{
			Name: secret.Name,
			VolumeSource: api.VolumeSource{
				Secret: &api.SecretVolumeSource{
					SecretName: secret.Name,
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      secret.Name,
			MountPath: secret.MountPath,
		})
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		parallelism:      int32(parallelism),
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:   options.rcName,
					Labels: options.labels,
				},
				Spec: a.workerPodSpec(options),
			},
		},
	}
	_, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc)
	fmt.Println("Error from a.kubeClient.ReplicationControllers(a.namespace).Create(rc): ", err)
	return err
}
<commit_msg>Remove unnecessary print statement<commit_after>package server

import (
	"fmt"
	"strings"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage    string            // The user's pipeline/job image
	labels       map[string]string // k8s labels attached to the RC and workers
	parallelism  int32             // Number of replicas the RC maintains
	workerEnv    []api.EnvVar      // Environment vars set in the user container
	volumes      []api.Volume      // Volumes that we expose to the user container
	volumeMounts []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
}

// PipelineRcName generates the name of the k8s replication controller that
// manages a pipeline's workers
func PipelineRcName(name string, version uint64) string {
	// k8s won't allow RC names that contain upper-case letters
	// TODO: deal with name collision
	return fmt.Sprintf("pipeline-%s-v%d", strings.ToLower(name), version)
}

// JobRcName generates the name of the k8s replication controller that manages
// an orphan job's workers
func JobRcName(id string) string {
	// k8s won't allow RC names that contain upper-case letters
	// TODO: deal with name collision
	return fmt.Sprintf("job-%s", strings.ToLower(id))
}

func (a *apiServer) workerPodSpec(options *workerOptions) api.PodSpec {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	return api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           a.workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    "user",
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		RestartPolicy:    "Always",
		Volumes:          options.volumes,
		ImagePullSecrets: options.imagePullSecrets,
	}
}

func (a *apiServer) getWorkerOptions(rcName string, parallelism int32, transform *pps.Transform) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		volumes = append(volumes, api.Volume{
			Name: secret.Name,
			VolumeSource: api.VolumeSource{
				Secret: &api.SecretVolumeSource{
					SecretName: secret.Name,
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      secret.Name,
			MountPath: secret.MountPath,
		})
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		parallelism:      int32(parallelism),
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:   options.rcName,
					Labels: options.labels,
				},
				Spec: a.workerPodSpec(options),
			},
		},
	}
	_, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc)
	return err
}
<|endoftext|>


<commit_before>package engine

import (
	"errors"
	"fmt"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/kex2"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
)

// XLoginProvision is an engine that will provision the current
// device.
type XLoginProvision struct {
	libkb.Contextified
	arg        *XLoginProvisionArg
	lks        *libkb.LKSec
	signingKey libkb.GenericKey
}

type XLoginProvisionArg struct {
	DeviceType string // desktop or mobile
	Username   string // optional
}

// NewXLoginProvision creates a XLoginProvision engine.  username
// is optional.
func NewXLoginProvision(g *libkb.GlobalContext, arg *XLoginProvisionArg) *XLoginProvision {
	return &XLoginProvision{
		Contextified: libkb.NewContextified(g),
		arg:          arg,
	}
}

// Name is the unique engine name.
func (e *XLoginProvision) Name() string {
	return "XLoginProvision"
}

// GetPrereqs returns the engine prereqs.
func (e *XLoginProvision) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *XLoginProvision) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.ProvisionUIKind,
		libkb.LoginUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *XLoginProvision) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&DeviceWrap{},
		&PaperKeyPrimary{},
	}
}

// Run starts the engine.
func (e *XLoginProvision) Run(ctx *Context) error {
	// check we have a good device type:
	if e.arg.DeviceType != libkb.DeviceTypeDesktop && e.arg.DeviceType != libkb.DeviceTypeMobile {
		return fmt.Errorf("device type must be %q or %q, not %q", libkb.DeviceTypeDesktop, libkb.DeviceTypeMobile, e.arg.DeviceType)
	}

	availableGPGPrivateKeyUsers, err := e.searchGPG(ctx)
	if err != nil {
		return err
	}
	e.G().Log.Debug("available private gpg key users: %v", availableGPGPrivateKeyUsers)

	arg := keybase1.ChooseProvisioningMethodArg{
		GpgUsers: availableGPGPrivateKeyUsers,
	}
	method, err := ctx.ProvisionUI.ChooseProvisioningMethod(context.TODO(), arg)
	if err != nil {
		return err
	}

	switch method {
	case keybase1.ProvisionMethod_DEVICE:
		return e.device(ctx)
	case keybase1.ProvisionMethod_GPG:
		return e.gpg(ctx)
	case keybase1.ProvisionMethod_PAPER_KEY:
		return e.paper(ctx)
	case keybase1.ProvisionMethod_PASSPHRASE:
		return e.passphrase(ctx)
	}

	return fmt.Errorf("unhandled provisioning method: %v", method)
}

// searchGPG looks in local gpg keyring for any private keys
// associated with keybase users.
//
// TODO: implement this
//
func (e *XLoginProvision) searchGPG(ctx *Context) ([]string, error) {
	return nil, nil
}

// device provisions this device with an existing device using the
// kex2 protocol.
func (e *XLoginProvision) device(ctx *Context) error {
	provisionerType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), 0)
	if err != nil {
		return err
	}
	e.G().Log.Debug("provisioner device type: %v", provisionerType)

	// make a new secret:
	secret, err := libkb.NewKex2Secret()
	if err != nil {
		return err
	}
	e.G().Log.Debug("secret phrase: %s", secret.Phrase())

	// make a new device:
	deviceID, err := libkb.NewDeviceID()
	if err != nil {
		return err
	}
	device := &libkb.Device{
		ID:   deviceID,
		Type: e.arg.DeviceType,
	}

	// create provisionee engine
	provisionee := NewKex2Provisionee(e.G(), device, secret.Secret())

	var canceler func()

	// display secret and prompt for secret from X in a goroutine:
	go func() {
		sb := secret.Secret()
		arg := keybase1.DisplayAndPromptSecretArg{
			Secret:          sb[:],
			Phrase:          secret.Phrase(),
			OtherDeviceType: provisionerType,
		}
		var contxt context.Context
		contxt, canceler = context.WithCancel(context.Background())
		receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg)
		if err != nil {
			// XXX ???
			e.G().Log.Warning("DisplayAndPromptSecret error: %s", err)
		} else if receivedSecret != nil {
			var ks kex2.Secret
			copy(ks[:], receivedSecret)
			provisionee.AddSecret(ks)
		}
	}()

	defer func() {
		if canceler != nil {
			e.G().Log.Debug("canceling DisplayAndPromptSecret call")
			canceler()
		}
	}()

	// run provisionee
	if err := RunEngine(provisionee, ctx); err != nil {
		return err
	}

	return nil
}

func (e *XLoginProvision) gpg(ctx *Context) error {
	panic("gpg provision not yet implemented")
}

func (e *XLoginProvision) paper(ctx *Context) error {
	// prompt for the username (if not provided) and load the user:
	// check if they have any paper keys
	// if they do, can call findPaperKeys
	// if that succeeds, then need to get ppstream (for lks).
	// addDeviceKeyWithSigner
	panic("paper provision not yet implemented")
}

func (e *XLoginProvision) passphrase(ctx *Context) error {
	// prompt for the username (if not provided) and load the user:
	user, err := e.loadUser(ctx)
	if err != nil {
		return err
	}

	// check if they have any devices, pgp keys
	hasSinglePGP := false
	ckf := user.GetComputedKeyFamily()
	if ckf != nil {
		devices := ckf.GetAllDevices()
		for _, dev := range devices {
			if *dev.Status == libkb.DeviceStatusActive {
				return libkb.PassphraseProvisionImpossibleError{}
			}
		}
		hasSinglePGP = len(ckf.GetActivePGPKeys(false)) == 1
	}

	// if they have a single pgp key in their family, there's a chance it is a synced
	// pgp key, so try provisioning with it.
	if hasSinglePGP {
		e.G().Log.Debug("user %q has a single pgp key, trying to provision with it", user.GetName())
		if err := e.pgpProvision(ctx, user); err != nil {
			return err
		}
	} else {
		e.G().Log.Debug("user %q has no devices, no pgp keys", user.GetName())
		if err := e.addEldestDeviceKey(ctx, user); err != nil {
			return err
		}
	}

	// and finally, a paper key
	if err := e.paperKey(ctx, user); err != nil {
		return err
	}

	return nil
}

func (e *XLoginProvision) pgpProvision(ctx *Context, user *libkb.User) error {
	e.G().Log.Debug("pgp provision")

	// need a session to try to get synced private key
	if err := e.G().LoginState().LoginWithPrompt(user.GetName(), ctx.LoginUI, ctx.SecretUI, nil); err != nil {
		return err
	}

	// this could go in afterFn of LoginWithPrompt?

	key, err := user.SyncedSecretKey(nil)
	if err != nil {
		return err
	}
	if key == nil {
		return errors.New("failed to get synced secret key")
	}

	e.G().Log.Debug("got synced secret key")

	// unlock it
	unlocked, err := key.PromptAndUnlock(nil, "sign new device", "keybase", nil, ctx.SecretUI, nil, user)
	if err != nil {
		return err
	}

	e.G().Log.Debug("unlocked secret key")

	eldest := user.GetEldestKID()

	devname, err := e.deviceName(ctx)
	if err != nil {
		return err
	}
	pps, err := e.ppStream(ctx)
	if err != nil {
		return err
	}
	if e.lks == nil {
		e.lks = libkb.NewLKSec(pps, user.GetUID(), e.G())
	}
	args := &DeviceWrapArgs{
		Me:         user,
		DeviceName: devname,
		Lks:        e.lks,
		IsEldest:   false,
		Signer:     unlocked,
		EldestKID:  eldest,
	}
	eng := NewDeviceWrap(args, e.G())
	if err := RunEngine(eng, ctx); err != nil {
		return err
	}

	e.signingKey = eng.SigningKey()
	return nil
}

// prompt for username (if not provided) and load the user.
func (e *XLoginProvision) loadUser(ctx *Context) (*libkb.User, error) {
	if len(e.arg.Username) == 0 {
		username, err := ctx.LoginUI.GetEmailOrUsername(context.TODO(), 0)
		if err != nil {
			return nil, err
		}
		e.arg.Username = username
	}
	arg := libkb.NewLoadUserByNameArg(e.G(), e.arg.Username)
	arg.PublicKeyOptional = true
	return libkb.LoadUser(arg)
}

func (e *XLoginProvision) addEldestDeviceKey(ctx *Context, user *libkb.User) error {
	devname, err := e.deviceName(ctx)
	if err != nil {
		return err
	}
	pps, err := e.ppStream(ctx)
	if err != nil {
		return err
	}
	if e.lks == nil {
		e.lks = libkb.NewLKSec(pps, user.GetUID(), e.G())
	}
	args := &DeviceWrapArgs{
		Me:         user,
		DeviceName: devname,
		Lks:        e.lks,
		IsEldest:   true,
	}
	eng := NewDeviceWrap(args, e.G())
	if err := RunEngine(eng, ctx); err != nil {
		return err
	}

	e.signingKey = eng.SigningKey()
	return nil
}

func (e *XLoginProvision) paperKey(ctx *Context, user *libkb.User) error {
	args := &PaperKeyPrimaryArgs{
		SigningKey: e.signingKey,
		Me:         user,
	}
	eng := NewPaperKeyPrimary(e.G(), args)
	return RunEngine(eng, ctx)
}

func (e *XLoginProvision) deviceName(ctx *Context) (string, error) {
	// TODO: get existing device names
	arg := keybase1.PromptNewDeviceNameArg{}
	return ctx.ProvisionUI.PromptNewDeviceName(context.TODO(), arg)
}

func (e *XLoginProvision) ppStream(ctx *Context) (*libkb.PassphraseStream, error) {
	return e.G().LoginState().GetPassphraseStream(ctx.SecretUI)
}
<commit_msg>Refactor common code<commit_after>package engine

import (
	"errors"
	"fmt"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/kex2"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
)

// XLoginProvision is an engine that will provision the current
// device.
type XLoginProvision struct {
	libkb.Contextified
	arg        *XLoginProvisionArg
	user       *libkb.User
	lks        *libkb.LKSec
	signingKey libkb.GenericKey
}

type XLoginProvisionArg struct {
	DeviceType string // desktop or mobile
	Username   string // optional
}

// NewXLoginProvision creates a XLoginProvision engine.  username
// is optional.
func NewXLoginProvision(g *libkb.GlobalContext, arg *XLoginProvisionArg) *XLoginProvision {
	return &XLoginProvision{
		Contextified: libkb.NewContextified(g),
		arg:          arg,
	}
}

// Name is the unique engine name.
func (e *XLoginProvision) Name() string {
	return "XLoginProvision"
}

// GetPrereqs returns the engine prereqs.
func (e *XLoginProvision) Prereqs() Prereqs {
	return Prereqs{}
}

// RequiredUIs returns the required UIs.
func (e *XLoginProvision) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.ProvisionUIKind,
		libkb.LoginUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *XLoginProvision) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&DeviceWrap{},
		&PaperKeyPrimary{},
	}
}

// Run starts the engine.
func (e *XLoginProvision) Run(ctx *Context) error {
	// check we have a good device type:
	if e.arg.DeviceType != libkb.DeviceTypeDesktop && e.arg.DeviceType != libkb.DeviceTypeMobile {
		return fmt.Errorf("device type must be %q or %q, not %q", libkb.DeviceTypeDesktop, libkb.DeviceTypeMobile, e.arg.DeviceType)
	}

	availableGPGPrivateKeyUsers, err := e.searchGPG(ctx)
	if err != nil {
		return err
	}
	e.G().Log.Debug("available private gpg key users: %v", availableGPGPrivateKeyUsers)

	arg := keybase1.ChooseProvisioningMethodArg{
		GpgUsers: availableGPGPrivateKeyUsers,
	}
	method, err := ctx.ProvisionUI.ChooseProvisioningMethod(context.TODO(), arg)
	if err != nil {
		return err
	}

	switch method {
	case keybase1.ProvisionMethod_DEVICE:
		return e.device(ctx)
	case keybase1.ProvisionMethod_GPG:
		return e.gpg(ctx)
	case keybase1.ProvisionMethod_PAPER_KEY:
		return e.paper(ctx)
	case keybase1.ProvisionMethod_PASSPHRASE:
		return e.passphrase(ctx)
	}

	return fmt.Errorf("unhandled provisioning method: %v", method)
}

// searchGPG looks in local gpg keyring for any private keys
// associated with keybase users.
//
// TODO: implement this
//
func (e *XLoginProvision) searchGPG(ctx *Context) ([]string, error) {
	return nil, nil
}

// device provisions this device with an existing device using the
// kex2 protocol.
func (e *XLoginProvision) device(ctx *Context) error {
	provisionerType, err := ctx.ProvisionUI.ChooseDeviceType(context.TODO(), 0)
	if err != nil {
		return err
	}
	e.G().Log.Debug("provisioner device type: %v", provisionerType)

	// make a new secret:
	secret, err := libkb.NewKex2Secret()
	if err != nil {
		return err
	}
	e.G().Log.Debug("secret phrase: %s", secret.Phrase())

	// make a new device:
	deviceID, err := libkb.NewDeviceID()
	if err != nil {
		return err
	}
	device := &libkb.Device{
		ID:   deviceID,
		Type: e.arg.DeviceType,
	}

	// create provisionee engine
	provisionee := NewKex2Provisionee(e.G(), device, secret.Secret())

	var canceler func()

	// display secret and prompt for secret from X in a goroutine:
	go func() {
		sb := secret.Secret()
		arg := keybase1.DisplayAndPromptSecretArg{
			Secret:          sb[:],
			Phrase:          secret.Phrase(),
			OtherDeviceType: provisionerType,
		}
		var contxt context.Context
		contxt, canceler = context.WithCancel(context.Background())
		receivedSecret, err := ctx.ProvisionUI.DisplayAndPromptSecret(contxt, arg)
		if err != nil {
			// XXX ???
			e.G().Log.Warning("DisplayAndPromptSecret error: %s", err)
		} else if receivedSecret != nil {
			var ks kex2.Secret
			copy(ks[:], receivedSecret)
			provisionee.AddSecret(ks)
		}
	}()

	defer func() {
		if canceler != nil {
			e.G().Log.Debug("canceling DisplayAndPromptSecret call")
			canceler()
		}
	}()

	// run provisionee
	if err := RunEngine(provisionee, ctx); err != nil {
		return err
	}

	return nil
}

func (e *XLoginProvision) gpg(ctx *Context) error {
	panic("gpg provision not yet implemented")
}

func (e *XLoginProvision) paper(ctx *Context) error {
	// prompt for the username (if not provided) and load the user:
	// check if they have any paper keys
	// if they do, can call findPaperKeys
	// if that succeeds, then need to get ppstream (for lks).
	// addDeviceKeyWithSigner
	panic("paper provision not yet implemented")
}

func (e *XLoginProvision) passphrase(ctx *Context) error {
	// prompt for the username (if not provided) and load the user:
	var err error
	e.user, err = e.loadUser(ctx)
	if err != nil {
		return err
	}

	// check if they have any devices, pgp keys
	hasSinglePGP := false
	ckf := e.user.GetComputedKeyFamily()
	if ckf != nil {
		devices := ckf.GetAllDevices()
		for _, dev := range devices {
			if *dev.Status == libkb.DeviceStatusActive {
				return libkb.PassphraseProvisionImpossibleError{}
			}
		}
		hasSinglePGP = len(ckf.GetActivePGPKeys(false)) == 1
	}

	// if they have a single pgp key in their family, there's a chance it is a synced
	// pgp key, so try provisioning with it.
	if hasSinglePGP {
		e.G().Log.Debug("user %q has a single pgp key, trying to provision with it", e.user.GetName())
		if err := e.pgpProvision(ctx); err != nil {
			return err
		}
	} else {
		e.G().Log.Debug("user %q has no devices, no pgp keys", e.user.GetName())
		if err := e.addEldestDeviceKey(ctx); err != nil {
			return err
		}
	}

	// and finally, a paper key
	if err := e.paperKey(ctx); err != nil {
		return err
	}

	return nil
}

func (e *XLoginProvision) pgpProvision(ctx *Context) error {
	e.G().Log.Debug("pgp provision")

	// need a session to try to get synced private key
	if err := e.G().LoginState().LoginWithPrompt(e.user.GetName(), ctx.LoginUI, ctx.SecretUI, nil); err != nil {
		return err
	}

	// this could go in afterFn of LoginWithPrompt?

	unlocked, err := e.syncedPGPKey(ctx)
	if err != nil {
		return err
	}

	args, err := e.makeDeviceWrapArgs(ctx)
	if err != nil {
		return err
	}
	args.Signer = unlocked
	args.IsEldest = false
	args.EldestKID = e.user.GetEldestKID()

	return e.makeDeviceKeys(ctx, args)
}

func (e *XLoginProvision) addEldestDeviceKey(ctx *Context) error {
	args, err := e.makeDeviceWrapArgs(ctx)
	if err != nil {
		return err
	}
	args.IsEldest = true

	return e.makeDeviceKeys(ctx, args)
}

func (e *XLoginProvision) paperKey(ctx *Context) error {
	args := &PaperKeyPrimaryArgs{
		SigningKey: e.signingKey,
		Me:         e.user,
	}
	eng := NewPaperKeyPrimary(e.G(), args)
	return RunEngine(eng, ctx)
}

func (e *XLoginProvision) deviceName(ctx *Context) (string, error) {
	// TODO: get existing device names
	arg := keybase1.PromptNewDeviceNameArg{}
	return ctx.ProvisionUI.PromptNewDeviceName(context.TODO(), arg)
}

func (e *XLoginProvision) ppStream(ctx *Context) (*libkb.PassphraseStream, error) {
	return e.G().LoginState().GetPassphraseStream(ctx.SecretUI)
}

// ensure we have LKSec for saving device keys.
func (e *XLoginProvision) ensureLKSec(ctx *Context) error {
	if e.lks != nil {
		return nil
	}

	pps, err := e.ppStream(ctx)
	if err != nil {
		return err
	}

	e.lks = libkb.NewLKSec(pps, e.user.GetUID(), e.G())
	return nil
}

func (e *XLoginProvision) makeDeviceWrapArgs(ctx *Context) (*DeviceWrapArgs, error) {
	if err := e.ensureLKSec(ctx); err != nil {
		return nil, err
	}

	devname, err := e.deviceName(ctx)
	if err != nil {
		return nil, err
	}

	return &DeviceWrapArgs{
		Me:         e.user,
		DeviceName: devname,
		Lks:        e.lks,
	}, nil
}

func (e *XLoginProvision) makeDeviceKeys(ctx *Context, args *DeviceWrapArgs) error {
	eng := NewDeviceWrap(args, e.G())
	if err := RunEngine(eng, ctx); err != nil {
		return err
	}

	e.signingKey = eng.SigningKey()
	return nil
}

// prompt for username (if not provided) and load the user.
func (e *XLoginProvision) loadUser(ctx *Context) (*libkb.User, error) {
	if len(e.arg.Username) == 0 {
		username, err := ctx.LoginUI.GetEmailOrUsername(context.TODO(), 0)
		if err != nil {
			return nil, err
		}
		e.arg.Username = username
	}
	arg := libkb.NewLoadUserByNameArg(e.G(), e.arg.Username)
	arg.PublicKeyOptional = true
	return libkb.LoadUser(arg)
}

func (e *XLoginProvision) syncedPGPKey(ctx *Context) (libkb.GenericKey, error) {
	key, err := e.user.SyncedSecretKey(nil)
	if err != nil {
		return nil, err
	}
	if key == nil {
		return nil, errors.New("failed to get synced secret key")
	}

	e.G().Log.Debug("got synced secret key")

	// unlock it
	unlocked, err := key.PromptAndUnlock(nil, "sign new device", "keybase", nil, ctx.SecretUI, nil, e.user)
	if err != nil {
		return nil, err
	}

	e.G().Log.Debug("unlocked secret key")
	return unlocked, nil
}
<|endoftext|>


<commit_before>package tree

import (
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"testing"
)

func ExampleTree() {
	file, err := ioutil.ReadFile("files.txt")
	if err != nil {
		log.Fatal(err)
	}

	g := New("/")
	lines := strings.Split(string(file), "\n")

	g.EatLines(lines)

	fmt.Print(g.Format())
	// Output:
	// .
	// ├── 1
	// │   ├── 2
	// │   │   └── 3
	// │   │       ├── 4
	// │   │       │   ├── 5
	// │   │       │   └── fisk2.txt
	// │   │       └── fisk2.txt
	// │   ├── 3
	// │   │   ├── 4
	// │   │   │   ├── 5
	// │   │   │   └── fisk2.txt
	// │   │   └── fisk2.txt
	// │   ├── 5
	// │   │   ├── 4
	// │   │   │   ├── 3
	// │   │   │   │   ├── 2
	// │   │   │   │   └── fisk.txt
	// │   │   │   └── fisk.txt
	// │   │   ├── fisk.txt
	// │   │   └── fisk2.txt
	// │   └── fisk.txt
	// └── fisk.txt
	//
}

func TestShallowTree(t *testing.T) {
	lines := []string{
		"one",
		"other",
		"this",
	}

	expected := `.
├── one
├── other
└── this
`
	tr := New("/")
	tr.EatLines(lines)

	output := tr.Format()

	errorFormat := `Expected
===
%s===

Got
===
%s===`

	if output != expected {
		t.Error("fisk...")
		t.Errorf(
			errorFormat,
			expected,
			output,
		)
	}
}

func TestNodeFormat(t *testing.T) {
	lines := []string{
		"one",
		"other$retho",
		"this",
	}

	expected := `.
├── ✓ one ⚡
├── ✓ other ⚡
│   └── ✓ retho ⚡
└── ✓ this ⚡
`
	tr := New("$")
	tr.NodeFormat = "✓ %s ⚡"
	tr.EatLines(lines)

	output := tr.Format()

	errorFormat := `Expected
===
%s===

Got
===
%s===`

	if output != expected {
		t.Error("fisk...")
		t.Errorf(
			errorFormat,
			expected,
			output,
		)
	}
}

func BenchmarkTreeFormat(b *testing.B) {
	file, err := ioutil.ReadFile("files.txt")
	lines := strings.Split(string(file), "\n")
	if nil != err {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		t := New("/")
		t.EatLines(lines)
		t.Format()
	}
}

func BenchmarkHeavyTreeFormat(b *testing.B) {
	file, err := ioutil.ReadFile("data.csv")
	lines := strings.Split(string(file), "\n")
	if nil != err {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		t := New(",")
		t.EatLines(lines)
		t.Format()
	}
}
<commit_msg>Simplify tests<commit_after>package tree

import (
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"testing"
)

func ExampleTree() {
	file, err := ioutil.ReadFile("files.txt")
	if err != nil {
		log.Fatal(err)
	}

	g := New("/")
	lines := strings.Split(string(file), "\n")

	g.EatLines(lines)

	fmt.Print(g.Format())
	// Output:
	// .
	// ├── 1
	// │   ├── 2
	// │   │   └── 3
	// │   │       ├── 4
	// │   │       │   ├── 5
	// │   │       │   └── fisk2.txt
	// │   │       └── fisk2.txt
	// │   ├── 3
	// │   │   ├── 4
	// │   │   │   ├── 5
	// │   │   │   └── fisk2.txt
	// │   │   └── fisk2.txt
	// │   ├── 5
	// │   │   ├── 4
	// │   │   │   ├── 3
	// │   │   │   │   ├── 2
	// │   │   │   │   └── fisk.txt
	// │   │   │   └── fisk.txt
	// │   │   ├── fisk.txt
	// │   │   └── fisk2.txt
	// │   └── fisk.txt
	// └── fisk.txt
	//
}

func TestShallowTree(t *testing.T) {
	lines := []string{
		"one",
		"other",
		"this",
	}

	expected := `.
├── one
├── other
└── this
`

	setup := func() *tree {
		return New("/")
	}
	RunFormatTestCase(lines, expected, setup, t)
}

func RunFormatTestCase(inputLines []string, expected string, setup func() *tree, t *testing.T) {
	tr := setup()

	tr.EatLines(inputLines)

	output := tr.Format()

	errorFormat := `Expected
===
%s===

Got
===
%s===`

	if output != expected {
		t.Errorf(
			errorFormat,
			expected,
			output,
		)
	}
}

func TestNodeFormat(t *testing.T) {
	lines := []string{
		"one",
		"other$retho",
		"this",
	}

	expected := `.
├── ✓ one ⚡
├── ✓ other ⚡
│   └── ✓ retho ⚡
└── ✓ this ⚡
`
	setup := func() *tree {
		tr := New("$")
		tr.NodeFormat = "✓ %s ⚡"
		return tr
	}

	RunFormatTestCase(lines, expected, setup, t)
}

func BenchmarkTreeFormat(b *testing.B) {
	file, err := ioutil.ReadFile("files.txt")
	lines := strings.Split(string(file), "\n")
	if nil != err {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		t := New("/")
		t.EatLines(lines)
		t.Format()
	}
}

func BenchmarkHeavyTreeFormat(b *testing.B) {
	file, err := ioutil.ReadFile("data.csv")
	lines := strings.Split(string(file), "\n")
	if nil != err {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		t := New(",")
		t.EatLines(lines)
		t.Format()
	}
}
<|endoftext|>


<commit_before>package http

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/openark/golib/log"

	"github.com/github/orchestrator/go/config"
	"github.com/github/orchestrator/go/raft"
	"github.com/go-martini/martini"
)

var counter = 5

var reverseProxy = func(w http.ResponseWriter, r *http.Request, c martini.Context) {
	log.Infof("........... HERE!! %d", counter)
	if !orcraft.IsRaftEnabled() {
		return
	}
	if orcraft.IsLeader() {
		// nothing to do
		// return
	}
	if counter == 0 {
		log.Infof("........... done proxy")
		counter = 3
		return
	}
	leader := orcraft.GetLeader()
	hostPort := strings.Split(leader, ":")
	leaderHost := hostPort[0]

	hostPort = strings.Split(config.Config.ListenAddress, ":")
	port := hostPort[1]
	leaderURI := fmt.Sprintf("http://%s:%s", leaderHost, port)
	url, err := url.Parse(leaderURI)
	if err != nil {
		log.Errore(err)
		return
	}
	proxy := httputil.NewSingleHostReverseProxy(url)
	counter--
	log.Debugf("................reverse proxy to %s", leaderURI)
	proxy.ServeHTTP(w, r)
}

// All returns a Handler that adds gzip compression to all requests
func RaftReverseProxy() martini.Handler {
	return func(w http.ResponseWriter, r *http.Request, c martini.Context) {
		reverseProxy(w, r, c)
	}
}
<commit_msg>aborting if no leader<commit_after>package http

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/openark/golib/log"

	"github.com/github/orchestrator/go/config"
	"github.com/github/orchestrator/go/raft"
	"github.com/go-martini/martini"
)

var counter = 5

var reverseProxy = func(w http.ResponseWriter, r *http.Request, c martini.Context) {
	log.Infof("........... HERE!! %d", counter)
	if !orcraft.IsRaftEnabled() {
		return
	}
	if orcraft.IsLeader() {
		// nothing to do
		// return
	}
	if counter == 0 {
		log.Infof("........... done proxy")
		counter = 3
		return
	}
	leader := orcraft.GetLeader()
	if leader == "" {
		log.Errorf("raft reverse-proxy: leader is unknown")
		return
	}
	hostPort := strings.Split(leader, ":")
	leaderHost := hostPort[0]

	hostPort = strings.Split(config.Config.ListenAddress, ":")
	port := hostPort[1]
	leaderURI := fmt.Sprintf("http://%s:%s", leaderHost, port)
	url, err := url.Parse(leaderURI)
	if err != nil {
		log.Errore(err)
		return
	}
	proxy := httputil.NewSingleHostReverseProxy(url)
	counter--
	log.Debugf("................reverse proxy to %s", leaderURI)
	proxy.ServeHTTP(w, r)
}

// All returns a Handler that adds gzip compression to all requests
func RaftReverseProxy() martini.Handler {
	return func(w http.ResponseWriter, r *http.Request, c martini.Context) {
		reverseProxy(w, r, c)
	}
}
<|endoftext|>


<commit_before>package stringext

import (
	"bytes"
	"fmt"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

var (
	camelcase = regexp.MustCompile(`(?m)[-.$/:_{}\s]`)
	acronyms  = regexp.MustCompile(`(Url|Http|Id|Io|Uuid|Api|Uri|Ssl|Cname|Oauth|Otp)$`)
)

func ToLowerFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToLower(r)) + ident[n:]
}

func ToUpperFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToUpper(r)) + ident[n:]
}

func JSONTag(n string, required bool) string {
	tags := []string{ToLowerFirst(n)}
	if !required {
		tags = append(tags, "omitempty")
	}

	return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ","))
}

func AsComment(c string) string {
	var buf bytes.Buffer
	const maxLen = 70
	removeNewlines := func(s string) string {
		return strings.Replace(s, "\n", "\n// ", -1)
	}
	for len(c) > 0 {
		line := c
		if len(line) < maxLen {
			fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
			break
		}
		line = line[:maxLen]
		si := strings.LastIndex(line, " ")
		if si != -1 {
			line = line[:si]
		}
		fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
		c = c[len(line):]
		if si != -1 {
			c = c[1:]
		}
	}

	return buf.String()
}

func Contains(n string, r []string) bool {
	for _, r := range r {
		if r == n {
			return true
		}
	}

	return false
}

func DepunctWithInitialUpper(ident string) string {
	return Depunct(ident, true)
}

func DepunctWithInitialLower(ident string) string {
	return Depunct(ident, false)
}

func Depunct(ident string, initialCap bool) string {
	matches := camelcase.Split(ident, -1)
	for i, m := range matches {
		if initialCap || i > 0 {
			m = ToUpperFirst(m)
		}
		matches[i] = acronyms.ReplaceAllStringFunc(m, func(c string) string {
			if len(c) > 4 {
				return strings.ToUpper(c[:2]) + c[2:]
			}
			return strings.ToUpper(c)
		})
	}
	return strings.Join(matches, "")
}
<commit_msg>Stringext: added new function for creating pointer referance variables<commit_after>package stringext

import (
	"bytes"
	"fmt"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

var (
	camelcase = regexp.MustCompile(`(?m)[-.$/:_{}\s]`)
	acronyms  = regexp.MustCompile(`(Url|Http|Id|Io|Uuid|Api|Uri|Ssl|Cname|Oauth|Otp)$`)
)

func ToLowerFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToLower(r)) + ident[n:]
}

func Pointerize(ident string) string {
	r, _ := utf8.DecodeRuneInString(ident)
	return string(unicode.ToLower(r))
}

func ToUpperFirst(ident string) string {
	r, n := utf8.DecodeRuneInString(ident)
	return string(unicode.ToUpper(r)) + ident[n:]
}

func JSONTag(n string, required bool) string {
	tags := []string{ToLowerFirst(n)}
	if !required {
		tags = append(tags, "omitempty")
	}

	return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ","))
}

func AsComment(c string) string {
	var buf bytes.Buffer
	const maxLen = 70
	removeNewlines := func(s string) string {
		return strings.Replace(s, "\n", "\n// ", -1)
	}
	for len(c) > 0 {
		line := c
		if len(line) < maxLen {
			fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
			break
		}
		line = line[:maxLen]
		si := strings.LastIndex(line, " ")
		if si != -1 {
			line = line[:si]
		}
		fmt.Fprintf(&buf, "// %s\n", removeNewlines(line))
		c = c[len(line):]
		if si != -1 {
			c = c[1:]
		}
	}

	return buf.String()
}

func Contains(n string, r []string) bool {
	for _, r := range r {
		if r == n {
			return true
		}
	}

	return false
}

func DepunctWithInitialUpper(ident string) string {
	return Depunct(ident, true)
}

func DepunctWithInitialLower(ident string) string {
	return Depunct(ident, false)
}

func Depunct(ident string, initialCap bool) string {
	matches := camelcase.Split(ident, -1)
	for i, m := range matches {
		if initialCap || i > 0 {
			m = ToUpperFirst(m)
		}
		matches[i] = acronyms.ReplaceAllStringFunc(m, func(c string) string {
			if len(c) > 4 {
				return strings.ToUpper(c[:2]) + c[2:]
			}
			return strings.ToUpper(c)
		})
	}
	return strings.Join(matches, "")
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"fmt"
	"net/http"
	"socialapi/models"
)

func CreatePost(channelId int64, token string) (*models.ChannelMessage, error) {
	return CreatePostWithBodyAndAuth(channelId, "create a message", token)
}

func CreatePostWithBodyAndAuth(channelId int64, body, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	cm := models.NewChannelMessage()
	cm.Body = body
	res, err := marshallAndSendRequestWithAuth("POST", url, cm, token)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil

}

func CreatePostWithBody(channelId, accountId int64, body string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = body
	cm.AccountId = accountId

	return createPostRequest(channelId, cm, http.Header{})
}

func CreatePostWithHeader(channelId, accountId int64, header http.Header, token string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = "Text1Text2"
	cm.AccountId = accountId

	return createPostRequestWithAuth(channelId, cm, header, token)
}

func GetPost(id int64, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/message/%d", id)
	cm := models.NewChannelMessage()
	cmI, err := sendModelWithAuth("GET", url, cm, token)
	if err != nil {
		return nil, err
	}
	return cmI.(*models.ChannelMessage), nil
}

func GetPostBySlug(slug string, accountId int64) (*models.ChannelMessageContainer, error) {
	url := fmt.Sprintf("/message/slug/%s?accountId=%d", slug, accountId)
	cmc := models.NewChannelMessageContainer()
	cmI, err := sendModel("GET", url, cmc)
	if err != nil {
		return nil, err
	}
	return cmI.(*models.ChannelMessageContainer), nil
}

func DeletePost(id int64, token string) error {
	url := fmt.Sprintf("/message/%d", id)
	_, err := sendRequestWithAuth("DELETE", url, nil, token)
	return err
}

func UpdatePost(cm *models.ChannelMessage, token string) (*models.ChannelMessage, error) {
	cm.Body = "after update"

	url := fmt.Sprintf("/message/%d", cm.Id)
	// cmI, err := sendModel("POST", url, cm)
	cmI, err := sendModelWithAuth("POST", url, cm, token)
	if err != nil {
		return nil, err
	}

	return cmI.(*models.ChannelMessage), nil
}

type PayloadRequest struct {
	Body      string                 `json:"body"`
	AccountId int64                  `json:"accountId,string"`
	Payload   map[string]interface{} `json:"payload"`
}

func CreatePostWithPayload(channelId, accountId int64, payload map[string]interface{}, token string) (*models.ChannelMessage, error) {
	pr := PayloadRequest{}
	pr.Body = "message with payload"
	pr.AccountId = accountId
	pr.Payload = payload

	return createPostRequestWithAuth(channelId, pr, http.Header{}, token)
}

func createPostRequest(channelId int64, model interface{}, h http.Header) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	res, err := marshallAndSendRequestWithHeader("POST", url, model, h)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil
}

func createPostRequestWithAuth(channelId int64, model interface{}, h http.Header, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	res, err := marshallAndSendRequestWithHeaderAndAuth("POST", url, model, h, token)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil
}
<commit_msg>socialapi: delete account parameter from post-rest<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"net/http"
	"socialapi/models"
)

func CreatePost(channelId int64, token string) (*models.ChannelMessage, error) {
	return CreatePostWithBodyAndAuth(channelId, "create a message", token)
}

func CreatePostWithBodyAndAuth(channelId int64, body, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	cm := models.NewChannelMessage()
	cm.Body = body
	res, err := marshallAndSendRequestWithAuth("POST", url, cm, token)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil

}

func CreatePostWithBody(channelId, accountId int64, body string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = body
	cm.AccountId = accountId

	return createPostRequest(channelId, cm, http.Header{})
}

func CreatePostWithHeader(channelId int64, header http.Header, token string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = "Text1Text2"

	return createPostRequestWithAuth(channelId, cm, header, token)
}

func GetPost(id int64, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/message/%d", id)
	cm := models.NewChannelMessage()
	cmI, err := sendModelWithAuth("GET", url, cm, token)
	if err != nil {
		return nil, err
	}
	return cmI.(*models.ChannelMessage), nil
}

func GetPostBySlug(slug string, accountId int64) (*models.ChannelMessageContainer, error) {
	url := fmt.Sprintf("/message/slug/%s?accountId=%d", slug, accountId)
	cmc := models.NewChannelMessageContainer()
	cmI, err := sendModel("GET", url, cmc)
	if err != nil {
		return nil, err
	}
	return cmI.(*models.ChannelMessageContainer), nil
}

func DeletePost(id int64, token string) error {
	url := fmt.Sprintf("/message/%d", id)
	_, err := sendRequestWithAuth("DELETE", url, nil, token)
	return err
}

func UpdatePost(cm *models.ChannelMessage, token string) (*models.ChannelMessage, error) {
	cm.Body = "after update"

	url := fmt.Sprintf("/message/%d", cm.Id)
	// cmI, err := sendModel("POST", url, cm)
	cmI, err := sendModelWithAuth("POST", url, cm, token)
	if err != nil {
		return nil, err
	}

	return cmI.(*models.ChannelMessage), nil
}

type PayloadRequest struct {
	Body      string                 `json:"body"`
	AccountId int64                  `json:"accountId,string"`
	Payload   map[string]interface{} `json:"payload"`
}

func CreatePostWithPayload(channelId int64, payload map[string]interface{}, token string) (*models.ChannelMessage, error) {
	pr := PayloadRequest{}
	pr.Body = "message with payload"
	pr.Payload = payload

	return createPostRequestWithAuth(channelId, pr, http.Header{}, token)
}

func createPostRequest(channelId int64, model interface{}, h http.Header) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	res, err := marshallAndSendRequestWithHeader("POST", url, model, h)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil
}

func createPostRequestWithAuth(channelId int64, model interface{}, h http.Header, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	res, err := marshallAndSendRequestWithHeaderAndAuth("POST", url, model, h, token)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil
}
<|endoftext|>


<commit_before>package omni

import (
	"encoding/json"
	"fmt"
	"path"
)

type ExecResult struct {
	Platform string
	Version  string
	Log      string
	ExitCode int
}

func (e ExecResult) String() string {
	return fmt.Sprint(e.Log)
}

type ExecOptions struct {
	Output string
	Format string
}

type ExecTask struct {
	Platform string
	Version  string
	Dir      string
	Command  string
	Args     []string
}

func Exec(basePath string, platform string, version string, command []string, opts ExecOptions) error {
	result, err := doExec(basePath, platform, version, command, opts)
	if err != nil {
		return err
	}
	return writeOutput([]ExecResult{result}, opts)
}

func ExecMultiple(basePath string, platform string, versions []string, command []string, opts ExecOptions) error {
	results := []ExecResult{}
	for _, version := range versions {
		result, err := doExec(basePath, platform, version, command, opts)
		if err != nil {
			return err
		}
		results = append(results, result)
	}
	return writeOutput(results, opts)
}

func doExec(basePath string, platform string, version string, command []string, opts ExecOptions) (ExecResult, error) {
	task := ExecTask{
		Platform: platform,
		Version:  version,
		Dir:      path.Join(basePath, platform, version),
		Command:  command[0],
	}
	if len(command) > 1 {
		task.Args = command[1:]
	}

	switch platform {
	case "puppet":
		return ExecRuby(&task), nil
	default:
		return ExecResult{}, ErrInvalidPlatform
	}
}

func writeOutput(results []ExecResult, opts ExecOptions) error {
	switch opts.Format {
	case "json":
		out, err := json.Marshal(results)
		if err != nil {
			return err
		}
		fmt.Println(string(out))
	case "text":
		for _, result := range results {
			fmt.Print(result)
		}
		return nil
	default:
		return ErrInvalidFormat
	}
	return nil
}
<commit_msg>Adding write output to file instead of stdout as option<commit_after>package omni

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path"
)

type ExecResult struct {
	Platform string
	Version  string
	Log      string
	ExitCode int
}

func (e ExecResult) String() string {
	return fmt.Sprint(e.Log)
}

type ExecOptions struct {
	Output string
	Format string
}

type ExecTask struct {
	Platform string
	Version  string
	Dir      string
	Command  string
	Args     []string
}

func Exec(basePath string, platform string, version string, command []string, opts ExecOptions) error {
	result, err := doExec(basePath, platform, version, command, opts)
	if err != nil {
		return err
	}
	return writeOutput([]ExecResult{result}, opts)
}

func ExecMultiple(basePath string, platform string, versions []string, command []string, opts ExecOptions) error {
	results := []ExecResult{}
	for _, version := range versions {
		result, err := doExec(basePath, platform, version, command, opts)
		if err != nil {
			return err
		}
		results = append(results, result)
	}
	return writeOutput(results, opts)
}

func doExec(basePath string, platform string, version string, command []string, opts ExecOptions) (ExecResult, error) {
	task := ExecTask{
		Platform: platform,
		Version:  version,
		Dir:      path.Join(basePath, platform, version),
		Command:  command[0],
	}
	if len(command) > 1 {
		task.Args = command[1:]
	}

	switch platform {
	case "puppet":
		return ExecRuby(&task), nil
	default:
		return ExecResult{}, ErrInvalidPlatform
	}
}

func writeOutput(results []ExecResult, opts ExecOptions) error {
	out := ""
	switch opts.Format {
	case "json":
		result, err := json.Marshal(results)
		if err != nil {
			return err
		}
		out = string(result)
	case "text":
		for _, result := range results {
			out += result.Log
		}
	default:
		return ErrInvalidFormat
	}

	switch opts.Output {
	case "":
		fmt.Print(out)
	default:
		if err := ioutil.WriteFile(opts.Output, []byte(out), 0755); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package ui

import (
	"github.com/google/gxui"
	"github.com/google/gxui/drivers/gl"
	"github.com/google/gxui/samples/flags"
    "github.com/google/gxui/math"
)

func Start() {
	gl.StartDriver(appMain)
}

// Create a PanelHolder with a 3 panels
func panelHolder(name string, theme gxui.Theme) gxui.PanelHolder {
	label := func(text string) gxui.Label {
		label := theme.CreateLabel()
		label.SetText(text)
		return label
	}

	holder := theme.CreatePanelHolder()
	holder.AddPanel(label(name+" 0 content"), name+" 0 panel")
	holder.AddPanel(label(name+" 1 content"), name+" 1 panel")
	holder.AddPanel(label(name+" 2 content"), name+" 2 panel")
	return holder
}

func appMain(driver gxui.Driver) {
	theme := flags.CreateTheme(driver)

	// ┌───────┐║┌───────┐
	// │       │║│       │
	// │   A   │║│   B   │
	// │       │║│       │
	// └───────┘║└───────┘
	// ═══════════════════
	// ┌───────┐║┌───────┐
	// │       │║│       │
	// │   C   │║│   D   │
	// │       │║│       │
	// └───────┘║└───────┘

	menu := theme.CreateLinearLayout()
	menu.SetDirection(gxui.LeftToRight)
	logo_label:=theme.CreateLabel()
	logo_label.SetColor(gxui.White)
	logo_label.SetText("Pan")
	logo_label.SetSize(math.Size{300,200})
	menu.AddChild(logo_label)

	splitterCD := theme.CreateSplitterLayout()
	splitterCD.SetOrientation(gxui.Horizontal)
	splitterCD.AddChild(panelHolder("C", theme))
	splitterCD.AddChild(panelHolder("D", theme))

	vSplitter := theme.CreateSplitterLayout()
	vSplitter.SetOrientation(gxui.Vertical)
	vSplitter.AddChild(menu)
	vSplitter.AddChild(splitterCD)

	window := theme.CreateWindow(800, 600, "Baidu Pan in Go")
	window.SetScale(flags.DefaultScaleFactor)
	window.AddChild(vSplitter)
	window.OnClose(driver.Terminate)
}<commit_msg>add font<commit_after>package ui

import (
	"github.com/google/gxui"
	"github.com/google/gxui/drivers/gl"
	"github.com/google/gxui/samples/flags"
    "github.com/google/gxui/math"
    "log"
    "io/ioutil"
)

func Start() {
	gl.StartDriver(appMain)
}

// Create a PanelHolder with a 3 panels
func panelHolder(name string, theme gxui.Theme) gxui.PanelHolder {
	label := func(text string) gxui.Label {
		label := theme.CreateLabel()
		label.SetText(text)
		return label
	}

	holder := theme.CreatePanelHolder()
	holder.AddPanel(label(name+" 0 content"), name+" 0 panel")
	holder.AddPanel(label(name+" 1 content"), name+" 1 panel")
	holder.AddPanel(label(name+" 2 content"), name+" 2 panel")
	return holder
}

func appMain(driver gxui.Driver) {
	theme := flags.CreateTheme(driver)

	// ┌───────┐║┌───────┐
	// │       │║│       │
	// │   A   │║│   B   │
	// │       │║│       │
	// └───────┘║└───────┘
	// ═══════════════════
	// ┌───────┐║┌───────┐
	// │       │║│       │
	// │   C   │║│   D   │
	// │       │║│       │
	// └───────┘║└───────┘

	ftData, err := ioutil.ReadFile("static/font/simsun.ttf")
	if err != nil {
		log.Println(err)
	}
	ft, err := driver.CreateFont(ftData, 20)
	if err != nil {
		log.Println(err)
	}
	menu := theme.CreateLinearLayout()
	menu.SetDirection(gxui.LeftToRight)
	logo_label:=theme.CreateLabel()
	logo_label.SetColor(gxui.White)
	logo_label.SetFont(ft)
	logo_label.SetText("百度")
	logo_label.SetSize(math.Size{300,200})
	menu.AddChild(logo_label)

	splitterCD := theme.CreateSplitterLayout()
	splitterCD.SetOrientation(gxui.Horizontal)
	splitterCD.AddChild(panelHolder("C", theme))
	splitterCD.AddChild(panelHolder("D", theme))

	vSplitter := theme.CreateSplitterLayout()
	vSplitter.SetOrientation(gxui.Vertical)
	vSplitter.AddChild(menu)
	vSplitter.AddChild(splitterCD)

	window := theme.CreateWindow(800, 600, "Baidu Pan in Go")
	window.SetScale(flags.DefaultScaleFactor)
	window.AddChild(vSplitter)
	window.OnClose(driver.Terminate)
}<|endoftext|>


<commit_before>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package hooks adds all the standard gopls implementations.
// This can be used in tests without needing to use the gopls main, and is
// also the place to edit for custom builds of gopls.
package hooks // import "golang.org/x/tools/gopls/internal/hooks"

import (
	"context"
	"regexp"

	"golang.org/x/tools/internal/lsp/source"
	"mvdan.cc/gofumpt/format"
	"mvdan.cc/xurls/v2"
)

func Options(options *source.Options) {
	options.LicensesText = licensesText
	if options.GoDiff {
		options.ComputeEdits = ComputeEdits
	}
	options.URLRegexp = urlRegexp()
	options.GofumptFormat = func(ctx context.Context, src []byte) ([]byte, error) {
		return format.Source(src, format.Options{})
	}
	updateAnalyzers(options)
}

func urlRegexp() *regexp.Regexp {
	// Ensure links are matched as full words, not anywhere.
	re := regexp.MustCompile(`\b(` + xurls.Relaxed().String() + `)\b`)
	re.Longest()
	return re
}
<commit_msg>gopls/internal/hooks: compile URL regexp once<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package hooks adds all the standard gopls implementations.
// This can be used in tests without needing to use the gopls main, and is
// also the place to edit for custom builds of gopls.
package hooks // import "golang.org/x/tools/gopls/internal/hooks"

import (
	"context"
	"regexp"

	"golang.org/x/tools/internal/lsp/source"
	"mvdan.cc/gofumpt/format"
	"mvdan.cc/xurls/v2"
)

func Options(options *source.Options) {
	options.LicensesText = licensesText
	if options.GoDiff {
		options.ComputeEdits = ComputeEdits
	}
	options.URLRegexp = relaxedFullWord
	options.GofumptFormat = func(ctx context.Context, src []byte) ([]byte, error) {
		return format.Source(src, format.Options{})
	}
	updateAnalyzers(options)
}

var relaxedFullWord *regexp.Regexp

// Ensure links are matched as full words, not anywhere.
func init() {
	relaxedFullWord = regexp.MustCompile(`\b(` + xurls.Relaxed().String() + `)\b`)
	relaxedFullWord.Longest()
}
<|endoftext|>