<commit_before>package conio

import "bufio"
import "bytes"
import "fmt"
import "os"
import "unicode"

import "github.com/mattn/go-runewidth"

var widthCache = make(map[rune]int)

func getCharWidth(n rune) int {
	width, ok := widthCache[n]
	if !ok {
		width = runewidth.RuneWidth(n)
		widthCache[n] = width
	}
	return width
	// if n > 0xFF {
	//	return 2;
	//}else{
	//	return 1;
	//}
}

var stdOut *bufio.Writer = bufio.NewWriter(os.Stdout)

func PutRep(ch rune, n int) {
	for i := 0; i < n; i++ {
		stdOut.WriteRune(ch)
	}
}

func Backspace(n int) {
	stdOut.Flush()
	x, y := GetLocate()
	Locate(x-n, y)
}

func shineCursor() {
	x, y := GetLocate()
	Locate(x, y)
}

type ReadLineBuffer struct {
	Buffer    []rune
	Length    int
	Cursor    int
	Unicode   rune
	Keycode   uint16
	ViewStart int
	ViewWidth int
}

func (this *ReadLineBuffer) Insert(pos int, c []rune) bool {
	n := len(c)
	for this.Length+n >= len(this.Buffer) {
		tmp := make([]rune, len(this.Buffer)*2)
		copy(tmp, this.Buffer)
		this.Buffer = tmp
	}
	for i := this.Length; i >= pos; i-- {
		this.Buffer[i+n] = this.Buffer[i]
	}
	for i := 0; i < n; i++ {
		this.Buffer[pos+i] = c[i]
	}
	this.Length += n
	return true
}

func (this *ReadLineBuffer) InsertString(pos int, s string) int {
	list := make([]rune, 0)
	for _, r := range s {
		list = append(list, r)
	}
	if this.Insert(pos, list) {
		return len(list)
	} else {
		return -1
	}
}

func (this *ReadLineBuffer) Delete(pos int, n int) int {
	if this.Length < pos+n {
		return 0
	}
	delw := 0
	for i := pos; i < pos+n; i++ {
		delw += getCharWidth(this.Buffer[i])
	}
	for i := pos; i < this.Length-n; i++ {
		this.Buffer[i] = this.Buffer[i+n]
	}
	this.Length -= n
	return delw
}

func (this *ReadLineBuffer) ReplaceAndRepaint(pos int, str string) {
	n := this.Cursor - pos
	this.Delete(pos, n)
	this.InsertString(pos, str)
	if pos < this.ViewStart {
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	} else {
		Backspace(this.GetWidthBetween(pos, this.Cursor))
	}
	this.Cursor = pos
	for _, ch := range str {
		if this.Cursor >= this.ViewStart {
			PutRep(ch, 1)
		}
		this.Cursor++
	}
	this.Repaint(this.Cursor, 0)
}

func (this *ReadLineBuffer) GetWidthBetween(from int, to int) int {
	width := 0
	for i := from; i < to; i++ {
		width += getCharWidth(this.Buffer[i])
	}
	return width
}

func (this *ReadLineBuffer) Repaint(pos int, del int) {
	bs := 0
	vp := this.GetWidthBetween(this.ViewStart, pos)

	for i := pos; i < this.Length; i++ {
		w1 := getCharWidth(this.Buffer[i])
		vp += w1
		if vp >= this.ViewWidth {
			break
		}
		PutRep(this.Buffer[i], 1)
		bs += w1
	}
	PutRep(' ', del)
	Backspace(bs + del)
}

func (this *ReadLineBuffer) RepaintAll(header string) {
	PutRep('\r', 1)
	for _, ch := range header {
		PutRep(ch, 1)
	}
	for i := this.ViewStart; i < this.Cursor; i++ {
		PutRep(this.Buffer[i], 1)
	}
	this.Repaint(this.Cursor, 0)
}

func (this ReadLineBuffer) String() string {
	var result bytes.Buffer
	for i := 0; i < this.Length; i++ {
		result.WriteRune(this.Buffer[i])
	}
	return result.String()
}

func (this *ReadLineBuffer) CurrentWordTop() (wordTop int) {
	wordTop = -1
	isQuoted := false
	for i := 0; i < this.Cursor; i++ {
		if this.Buffer[i] == '"' {
			isQuoted = !isQuoted
		}
		if unicode.IsSpace(this.Buffer[i]) && !isQuoted {
			wordTop = -1
		} else if wordTop < 0 {
			wordTop = i
		}
	}
	if wordTop < 0 {
		return this.Cursor
	} else {
		return wordTop
	}
}

func (this *ReadLineBuffer) CurrentWord() (string, int) {
	var buffer bytes.Buffer
	start := this.CurrentWordTop()
	for i := start; i < this.Cursor; i++ {
		if this.Buffer[i] != '"' {
			buffer.WriteRune(this.Buffer[i])
		}
	}
	return buffer.String(), start
}

type KeyFuncResult int

const (
	CONTINUE KeyFuncResult = iota
	ENTER    KeyFuncResult = iota
	ABORT    KeyFuncResult = iota
)

func KeyFuncPass(this *ReadLineBuffer) KeyFuncResult {
	return CONTINUE
}

func KeyFuncEnter(this *ReadLineBuffer) KeyFuncResult { // Ctrl-M
	return ENTER
}

func KeyFuncHead(this *ReadLineBuffer) KeyFuncResult { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *ReadLineBuffer) KeyFuncResult { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(getCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *ReadLineBuffer) KeyFuncResult { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRep(this.Buffer[this.Cursor], 1)
		}
	} else {
		PutRep('\a', 1)
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := getCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + getCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRep(this.Buffer[this.Cursor], 1)
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *ReadLineBuffer) KeyFuncResult { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRep(this.Buffer[this.Cursor], 1)
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if getCharWidth(this.Buffer[this.Cursor]) > getCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRep(this.Buffer[i], 1)
		}
		PutRep(' ', 1)
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *ReadLineBuffer) KeyFuncResult { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *ReadLineBuffer) KeyFuncResult { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *ReadLineBuffer) KeyFuncResult { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *ReadLineBuffer) KeyFuncResult {
	ch := this.Unicode
	if ch < 0x20 || !this.Insert(this.Cursor, []rune{ch}) {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := getCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if getCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRep(this.Buffer[i], 1)
		}
		PutRep(' ', 1)
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *ReadLineBuffer) KeyFuncResult {
	L := this.InsertString(this.Cursor, fmt.Sprintf("[%X]", this.Unicode))
	if L >= 0 {
		this.Repaint(this.Cursor, -L)
		this.Cursor += L
	}
	return CONTINUE
}

func KeyFuncClearAfter(this *ReadLineBuffer) KeyFuncResult {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0
	for i < this.Length && w < this.ViewWidth {
		w1 := getCharWidth(this.Buffer[i])
		PutRep(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *ReadLineBuffer) KeyFuncResult {
	KeyFuncClearAfter(this)
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRep(' ', width)
	Backspace(width)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncClearBefore(this *ReadLineBuffer) KeyFuncResult {
	keta := this.Delete( 0 , this.Cursor )
	Backspace(keta)
	this.Cursor = 0
	this.Repaint( 0 , keta )
	return CONTINUE
}

var KeyMap = map[rune]func(*ReadLineBuffer) KeyFuncResult{
	'\r':         KeyFuncEnter,
	'\x01':       KeyFuncHead,
	'\x02':       KeyFuncBackword,
	'\x05':       KeyFuncTail,
	'\x06':       KeyFuncForward,
	'\b':         KeyFuncBackSpace,
	'\x04':       KeyFuncDeleteOrAbort,
	'\x7F':       KeyFuncDelete,
	('K' & 0x1F): KeyFuncClearAfter,
	'\x1B':       KeyFuncClear,
	('U' & 0x1F): KeyFuncClearBefore,
}

// KeyCode from
// http://msdn.microsoft.com/ja-jp/library/windows/desktop/dd375731(v=vs.85).aspx
const (
	K_LEFT  = 0x25
	K_RIGHT = 0x27
	K_DEL   = 0x2E
	K_HOME  = 0x24
	K_END   = 0x23
	K_CTRL  = 0x11
	K_SHIFT = 0x10
	K_UP    = 0x26
	K_DOWN  = 0x28
)

var ZeroMap = map[uint16]func(*ReadLineBuffer) KeyFuncResult{
	K_LEFT:  KeyFuncBackword,
	K_RIGHT: KeyFuncForward,
	K_DEL:   KeyFuncDelete,
	K_HOME:  KeyFuncHead,
	K_END:   KeyFuncTail,
	K_CTRL:  KeyFuncPass,
	K_SHIFT: KeyFuncPass,
}

func ReadLine() (string, KeyFuncResult) {
	var this ReadLineBuffer
	this.Buffer = make([]rune, 20)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	this.ViewWidth = 60
	for {
		stdOut.Flush()
		shineCursor()
		this.Unicode, this.Keycode = GetKey()
		var f func(*ReadLineBuffer) KeyFuncResult
		var ok bool
		if this.Unicode != 0 {
			f, ok = KeyMap[this.Unicode]
			if !ok {
				//f = KeyFuncInsertReport
				f = KeyFuncInsertSelf
			}
		} else {
			f, ok = ZeroMap[this.Keycode]
			if !ok {
				f = KeyFuncPass
			}
		}
		rc := f(&this)
		if rc != CONTINUE {
			stdOut.WriteRune('\n')
			stdOut.Flush()
			return this.String(), rc
		}
	}
}
<commit_msg>go fmt for readline.go<commit_after>package conio

import "bufio"
import "bytes"
import "fmt"
import "os"
import "unicode"

import "github.com/mattn/go-runewidth"

var widthCache = make(map[rune]int)

func getCharWidth(n rune) int {
	width, ok := widthCache[n]
	if !ok {
		width = runewidth.RuneWidth(n)
		widthCache[n] = width
	}
	return width
	// if n > 0xFF {
	//	return 2;
	//}else{
	//	return 1;
	//}
}

var stdOut *bufio.Writer = bufio.NewWriter(os.Stdout)

func PutRep(ch rune, n int) {
	for i := 0; i < n; i++ {
		stdOut.WriteRune(ch)
	}
}

func Backspace(n int) {
	stdOut.Flush()
	x, y := GetLocate()
	Locate(x-n, y)
}

func shineCursor() {
	x, y := GetLocate()
	Locate(x, y)
}

type ReadLineBuffer struct {
	Buffer    []rune
	Length    int
	Cursor    int
	Unicode   rune
	Keycode   uint16
	ViewStart int
	ViewWidth int
}

func (this *ReadLineBuffer) Insert(pos int, c []rune) bool {
	n := len(c)
	for this.Length+n >= len(this.Buffer) {
		tmp := make([]rune, len(this.Buffer)*2)
		copy(tmp, this.Buffer)
		this.Buffer = tmp
	}
	for i := this.Length; i >= pos; i-- {
		this.Buffer[i+n] = this.Buffer[i]
	}
	for i := 0; i < n; i++ {
		this.Buffer[pos+i] = c[i]
	}
	this.Length += n
	return true
}

func (this *ReadLineBuffer) InsertString(pos int, s string) int {
	list := make([]rune, 0)
	for _, r := range s {
		list = append(list, r)
	}
	if this.Insert(pos, list) {
		return len(list)
	} else {
		return -1
	}
}

func (this *ReadLineBuffer) Delete(pos int, n int) int {
	if this.Length < pos+n {
		return 0
	}
	delw := 0
	for i := pos; i < pos+n; i++ {
		delw += getCharWidth(this.Buffer[i])
	}
	for i := pos; i < this.Length-n; i++ {
		this.Buffer[i] = this.Buffer[i+n]
	}
	this.Length -= n
	return delw
}

func (this *ReadLineBuffer) ReplaceAndRepaint(pos int, str string) {
	n := this.Cursor - pos
	this.Delete(pos, n)
	this.InsertString(pos, str)
	if pos < this.ViewStart {
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	} else {
		Backspace(this.GetWidthBetween(pos, this.Cursor))
	}
	this.Cursor = pos
	for _, ch := range str {
		if this.Cursor >= this.ViewStart {
			PutRep(ch, 1)
		}
		this.Cursor++
	}
	this.Repaint(this.Cursor, 0)
}

func (this *ReadLineBuffer) GetWidthBetween(from int, to int) int {
	width := 0
	for i := from; i < to; i++ {
		width += getCharWidth(this.Buffer[i])
	}
	return width
}

func (this *ReadLineBuffer) Repaint(pos int, del int) {
	bs := 0
	vp := this.GetWidthBetween(this.ViewStart, pos)

	for i := pos; i < this.Length; i++ {
		w1 := getCharWidth(this.Buffer[i])
		vp += w1
		if vp >= this.ViewWidth {
			break
		}
		PutRep(this.Buffer[i], 1)
		bs += w1
	}
	PutRep(' ', del)
	Backspace(bs + del)
}

func (this *ReadLineBuffer) RepaintAll(header string) {
	PutRep('\r', 1)
	for _, ch := range header {
		PutRep(ch, 1)
	}
	for i := this.ViewStart; i < this.Cursor; i++ {
		PutRep(this.Buffer[i], 1)
	}
	this.Repaint(this.Cursor, 0)
}

func (this ReadLineBuffer) String() string {
	var result bytes.Buffer
	for i := 0; i < this.Length; i++ {
		result.WriteRune(this.Buffer[i])
	}
	return result.String()
}

func (this *ReadLineBuffer) CurrentWordTop() (wordTop int) {
	wordTop = -1
	isQuoted := false
	for i := 0; i < this.Cursor; i++ {
		if this.Buffer[i] == '"' {
			isQuoted = !isQuoted
		}
		if unicode.IsSpace(this.Buffer[i]) && !isQuoted {
			wordTop = -1
		} else if wordTop < 0 {
			wordTop = i
		}
	}
	if wordTop < 0 {
		return this.Cursor
	} else {
		return wordTop
	}
}

func (this *ReadLineBuffer) CurrentWord() (string, int) {
	var buffer bytes.Buffer
	start := this.CurrentWordTop()
	for i := start; i < this.Cursor; i++ {
		if this.Buffer[i] != '"' {
			buffer.WriteRune(this.Buffer[i])
		}
	}
	return buffer.String(), start
}

type KeyFuncResult int

const (
	CONTINUE KeyFuncResult = iota
	ENTER    KeyFuncResult = iota
	ABORT    KeyFuncResult = iota
)

func KeyFuncPass(this *ReadLineBuffer) KeyFuncResult {
	return CONTINUE
}

func KeyFuncEnter(this *ReadLineBuffer) KeyFuncResult { // Ctrl-M
	return ENTER
}

func KeyFuncHead(this *ReadLineBuffer) KeyFuncResult { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *ReadLineBuffer) KeyFuncResult { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(getCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *ReadLineBuffer) KeyFuncResult { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRep(this.Buffer[this.Cursor], 1)
		}
	} else {
		PutRep('\a', 1)
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := getCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + getCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRep(this.Buffer[this.Cursor], 1)
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *ReadLineBuffer) KeyFuncResult { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRep(this.Buffer[this.Cursor], 1)
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if getCharWidth(this.Buffer[this.Cursor]) > getCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRep(this.Buffer[i], 1)
		}
		PutRep(' ', 1)
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *ReadLineBuffer) KeyFuncResult { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *ReadLineBuffer) KeyFuncResult { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *ReadLineBuffer) KeyFuncResult { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *ReadLineBuffer) KeyFuncResult {
	ch := this.Unicode
	if ch < 0x20 || !this.Insert(this.Cursor, []rune{ch}) {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := getCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if getCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRep(this.Buffer[i], 1)
		}
		PutRep(' ', 1)
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *ReadLineBuffer) KeyFuncResult {
	L := this.InsertString(this.Cursor, fmt.Sprintf("[%X]", this.Unicode))
	if L >= 0 {
		this.Repaint(this.Cursor, -L)
		this.Cursor += L
	}
	return CONTINUE
}

func KeyFuncClearAfter(this *ReadLineBuffer) KeyFuncResult {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0
	for i < this.Length && w < this.ViewWidth {
		w1 := getCharWidth(this.Buffer[i])
		PutRep(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *ReadLineBuffer) KeyFuncResult {
	KeyFuncClearAfter(this)
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRep(' ', width)
	Backspace(width)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncClearBefore(this *ReadLineBuffer) KeyFuncResult {
	keta := this.Delete(0, this.Cursor)
	Backspace(keta)
	this.Cursor = 0
	this.Repaint(0, keta)
	return CONTINUE
}

var KeyMap = map[rune]func(*ReadLineBuffer) KeyFuncResult{
	'\r':         KeyFuncEnter,
	'\x01':       KeyFuncHead,
	'\x02':       KeyFuncBackword,
	'\x05':       KeyFuncTail,
	'\x06':       KeyFuncForward,
	'\b':         KeyFuncBackSpace,
	'\x04':       KeyFuncDeleteOrAbort,
	'\x7F':       KeyFuncDelete,
	('K' & 0x1F): KeyFuncClearAfter,
	'\x1B':       KeyFuncClear,
	('U' & 0x1F): KeyFuncClearBefore,
}

// KeyCode from
// http://msdn.microsoft.com/ja-jp/library/windows/desktop/dd375731(v=vs.85).aspx
const (
	K_LEFT  = 0x25
	K_RIGHT = 0x27
	K_DEL   = 0x2E
	K_HOME  = 0x24
	K_END   = 0x23
	K_CTRL  = 0x11
	K_SHIFT = 0x10
	K_UP    = 0x26
	K_DOWN  = 0x28
)

var ZeroMap = map[uint16]func(*ReadLineBuffer) KeyFuncResult{
	K_LEFT:  KeyFuncBackword,
	K_RIGHT: KeyFuncForward,
	K_DEL:   KeyFuncDelete,
	K_HOME:  KeyFuncHead,
	K_END:   KeyFuncTail,
	K_CTRL:  KeyFuncPass,
	K_SHIFT: KeyFuncPass,
}

func ReadLine() (string, KeyFuncResult) {
	var this ReadLineBuffer
	this.Buffer = make([]rune, 20)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	this.ViewWidth = 60
	for {
		stdOut.Flush()
		shineCursor()
		this.Unicode, this.Keycode = GetKey()
		var f func(*ReadLineBuffer) KeyFuncResult
		var ok bool
		if this.Unicode != 0 {
			f, ok = KeyMap[this.Unicode]
			if !ok {
				//f = KeyFuncInsertReport
				f = KeyFuncInsertSelf
			}
		} else {
			f, ok = ZeroMap[this.Keycode]
			if !ok {
				f = KeyFuncPass
			}
		}
		rc := f(&this)
		if rc != CONTINUE {
			stdOut.WriteRune('\n')
			stdOut.Flush()
			return this.String(), rc
		}
	}
}
<|endoftext|>


<commit_before>package consistenthash

import (
	"hash/crc32"
	"sort"
	"strconv"
)

//Hash specified hash algorithm
type Hash func(data []byte) uint32

type Map struct {
	hash     Hash           //选择hash算法
	replicas int            //节点的副本数
	keys     []int          //需要排序
	hashMap  map[int]string //真实节点对应的虚拟节点
}

func New(replicas int, fn Hash) *Map {
	m := &Map{
		replicas: replicas,
		hash:     fn,
		hashMap:  make(map[int]string),
	}

	if m.hash == nil {
		m.hash = crc32.ChecksumIEEE
	}
	return m
}

//Returns true if there are no items available.
func (m *Map) IsEmpty() bool {
	return len(m.keys) == 0
}

//Adds some keys to the hash.
func (m *Map) Add(keys ...string) {
	for _, key := range keys {
		for i := 0; i < m.replicas; i++ {
			hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
			m.keys = append(m.keys, hash)
			m.hashMap[hash] = key
		}
	}
	sort.Ints(m.keys)
}

//Gets the closest item in the hash to the provided key
func (m *Map) Get(key string) string {
	if m.IsEmpty() {
		return ""
	}

	hash := int(m.hash([]byte(key)))

	// 顺时针“行走”，找到第一个大于哈希值的节点
	for _, v := range m.keys {
		if v >= hash {
			return m.hashMap[v] // 返回真实节点
		}
	}

	// hash值大于最大节点哈希值的情况
	return m.hashMap[m.keys[0]]
}
<commit_msg>modfiy keys get method<commit_after>package consistenthash

import (
	"hash/crc32"
	"sort"
	"strconv"
)

//Hash specified hash algorithm
type Hash func(data []byte) uint32

type Map struct {
	hash     Hash           //选择hash算法
	replicas int            //节点的副本数
	keys     []int          //需要排序
	hashMap  map[int]string //真实节点对应的虚拟节点
}

func New(replicas int, fn Hash) *Map {
	m := &Map{
		replicas: replicas,
		hash:     fn,
		hashMap:  make(map[int]string),
	}

	if m.hash == nil {
		m.hash = crc32.ChecksumIEEE
	}
	return m
}

//Returns true if there are no items available.
func (m *Map) IsEmpty() bool {
	return len(m.keys) == 0
}

//Adds some keys to the hash.
func (m *Map) Add(keys ...string) {
	for _, key := range keys {
		for i := 0; i < m.replicas; i++ {
			hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
			m.keys = append(m.keys, hash)
			m.hashMap[hash] = key
		}
	}
	sort.Ints(m.keys)
}

// Gets the closest item in the hash to the provided key.
func (m *Map) Get(key string) string {
	if m.IsEmpty() {
		return ""
	}

	hash := int(m.hash([]byte(key)))

	// Binary search for appropriate replica.
	idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })

	// Means we have cycled back to the first replica.
	if idx == len(m.keys) {
		idx = 0
	}

	return m.hashMap[m.keys[idx]]
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha512"
	"io"

	"github.com/amoghe/dedup/codec"
)

type SigMaker struct {
	segmenter Segmenter
	stats     *ParseStats
	writer    codec.SignatureWriter
}

func NewSigMaker(winsz, mask uint64, output io.WriteCloser) *SigMaker {
	sm := SigMaker{
		stats:     NewParseStats(sha512.New()),
		segmenter: Segmenter{WindowSize: *windowSize, Mask: mask},
		writer:    codec.NewGobWriter(output),
	}
	sm.segmenter.SegHandler = &sm
	return &sm
}

// Do generates the signatures
func (d *SigMaker) Do(f io.ReadCloser) error {
	err := d.segmenter.SegmentFile(f)
	return err
}

// Handle allows the Deduplicator to be a SegmentHandler (satisfies interface)
func (s *SigMaker) Handle(segment []byte) error {
	segHash := s.stats.UpdateStats(segment)
	return s.writer.WriteSignature(segHash)
}
<commit_msg>Fix linter style warning in diff.go<commit_after>package main

import (
	"crypto/sha512"
	"io"

	"github.com/amoghe/dedup/codec"
)

type SigMaker struct {
	segmenter Segmenter
	stats     *ParseStats
	writer    codec.SignatureWriter
}

func NewSigMaker(winsz, mask uint64, output io.WriteCloser) *SigMaker {
	sm := SigMaker{
		stats:     NewParseStats(sha512.New()),
		segmenter: Segmenter{WindowSize: *windowSize, Mask: mask},
		writer:    codec.NewGobWriter(output),
	}
	sm.segmenter.SegHandler = &sm
	return &sm
}

// Do generates the signatures
func (s *SigMaker) Do(f io.ReadCloser) error {
	err := s.segmenter.SegmentFile(f)
	return err
}

// Handle allows the Deduplicator to be a SegmentHandler (satisfies interface)
func (s *SigMaker) Handle(segment []byte) error {
	segHash := s.stats.UpdateStats(segment)
	return s.writer.WriteSignature(segHash)
}
<|endoftext|>


<commit_before>package dnsr

import (
	"fmt"
	"io"
	"strings"
	"sync"
	"time"

	lru "github.com/hashicorp/golang-lru"
	"github.com/miekg/dns"
)

//go:generate sh generate.sh

var (
	Root        *Resolver
	DebugLogger io.Writer
	Timeout     = 500 * time.Millisecond
)

func init() {
	Root = New(strings.Count(root, "\n"))
	for t := range dns.ParseZone(strings.NewReader(root), "", "") {
		if t.Error == nil {
			Root.saveDNSRR(t.RR)
		}
	}
}

// Resolver implements a primitive, non-recursive, caching DNS resolver.
type Resolver struct {
	cache  *lru.Cache
	client *dns.Client
}

// New initializes a Resolver with the specified cache size. Cache size defaults to 10,000 if size <= 0.
func New(size int) *Resolver {
	if size <= 0 {
		size = 10000
	}
	cache, _ := lru.New(size)
	r := &Resolver{
		client: &dns.Client{
			DialTimeout:  Timeout,
			ReadTimeout:  Timeout,
			WriteTimeout: Timeout,
		},
		cache: cache,
	}
	return r
}

// Resolve finds DNS records of type qtype for the domain qname. It returns a channel of *RR.
// The implementation guarantees that the output channel will close, so it is safe to range over.
// For nonexistent domains (where a DNS server will return NXDOMAIN), it will simply close the output channel.
// Specify an empty string in qtype to receive any DNS records found (currently A, AAAA, NS, CNAME, and TXT).
func (r *Resolver) Resolve(qname string, qtype string) <-chan *RR {
	return r.resolve(qname, qtype, 0)
}

func (r *Resolver) resolve(qname string, qtype string, depth int) <-chan *RR {
	c := make(chan *RR, 20)
	go func() {
		defer close(c)
		logResolveStart(qname, qtype, depth)
		defer logResolveEnd(qname, qtype, depth, time.Now())
		qname = toLowerFQDN(qname)
		if r.recall(c, qname, qtype) {
			return
		}
		r.resolveNS(c, qname, qtype, depth)
	}()
	return c
}

func (r *Resolver) recall(c chan<- *RR, qname string, qtype string) bool {
	if rrs := r.cacheGet(qname, qtype); rrs != nil {
		inject(c, rrs...)
		return true
	}
	return false
}

func (r *Resolver) resolveNS(c chan<- *RR, qname string, qtype string, depth int) {
	success := make(chan bool)
	for pname, ok := qname, true; ok; pname, ok = parent(pname) {
		if pname == qname && qtype == "NS" { // If we’re looking for [foo.com,NS], then skip to [com,NS]
			continue
		}

		// Query all DNS servers in parallel
		found := false
		for nrr := range r.resolve(pname, "NS", depth+1) {
			if qtype != "" && r.recall(c, qname, qtype) {
				return
			}
			if nrr.Type != "NS" {
				continue
			}

			go r.exchange(success, c, nrr.Value, qname, qtype, depth)
			found = true
		}

		// Wait for first response
		if found {
			select {
			case <-success:
				r.resolveCNAMEs(c, qname, qtype, depth)
				return
			case <-time.After(Timeout):
				continue
			}
		}
	}
}

func (r *Resolver) exchange(success chan<- bool, c chan<- *RR, host string, qname string, qtype string, depth int) {
	dtype := dns.StringToType[qtype]
	if dtype == 0 {
		dtype = dns.TypeA
	}
	qmsg := &dns.Msg{}
	qmsg.SetQuestion(qname, dtype)
	qmsg.MsgHdr.RecursionDesired = false

	// Find each A record for the DNS server
	for rr := range r.resolve(host, "A", depth+1) {
		if rr.Type != "A" { // FIXME: support AAAA records?
			continue
		}

		// Synchronously query this DNS server
		start := time.Now()
		rmsg, _, err := r.client.Exchange(qmsg, rr.Value+":53")
		logExchange(rr.Value, qmsg, depth, start, err)
		if err != nil {
			continue
		}

		// If successful, cache the results and return
		r.saveDNSRR(rmsg.Answer...)
		r.saveDNSRR(rmsg.Ns...)
		r.saveDNSRR(rmsg.Extra...)
		if rmsg.Rcode == dns.RcodeNameError {
			r.cacheAdd(qname, nil) // FIXME: cache NXDOMAIN responses responsibly
		}
		success <- true
		return
	}
}

func (r *Resolver) resolveCNAMEs(c chan<- *RR, qname string, qtype string, depth int) {
	rrs := r.cacheGet(qname, "")
	if rrs == nil || !inject(c, rrs...) {
		return
	}
	for _, crr := range rrs {
		if crr.Type != "CNAME" {
			continue
		}
		logCNAME(depth, crr.String())
		for rr := range r.resolve(crr.Value, qtype, depth+1) {
			r.cacheAdd(qname, rr)
			if !inject(c, rr) {
				return
			}
		}
	}
}

func inject(c chan<- *RR, rrs ...*RR) bool {
	for _, rr := range rrs {
		select {
		case c <- rr:
		default:
			// return false
		}
	}
	return true
}

func parent(name string) (string, bool) {
	labels := dns.SplitDomainName(name)
	if labels == nil {
		return "", false
	}
	return toLowerFQDN(strings.Join(labels[1:], ".")), true
}

func toLowerFQDN(name string) string {
	return dns.Fqdn(strings.ToLower(name))
}

func logResolveStart(qname string, qtype string, depth int) {
	if DebugLogger == nil {
		return
	}
	fmt.Fprintf(DebugLogger, "%s┌─── resolve(\"%s\", \"%s\", %d)\n",
		strings.Repeat("│   ", depth), qname, qtype, depth)
}

func logResolveEnd(qname string, qtype string, depth int, start time.Time) {
	if DebugLogger == nil {
		return
	}
	dur := time.Since(start)
	fmt.Fprintf(DebugLogger, "%s└─── %dms: resolve(\"%s\", \"%s\", %d)\n",
		strings.Repeat("│   ", depth), dur/time.Millisecond, qname, qtype, depth)
}

func logCNAME(depth int, cname string) {
	if DebugLogger == nil {
		return
	}
	fmt.Fprintf(DebugLogger, "%s│    CNAME: %s\n", strings.Repeat("│   ", depth), cname)
}

func logExchange(host string, qmsg *dns.Msg, depth int, start time.Time, err error) {
	if DebugLogger == nil {
		return
	}
	dur := time.Since(start)
	fmt.Fprintf(DebugLogger, "%s│    %dms: dig @%s %s %s\n",
		strings.Repeat("│   ", depth), dur/time.Millisecond, host, qmsg.Question[0].Name, dns.TypeToString[qmsg.Question[0].Qtype])
	if err != nil {
		fmt.Fprintf(DebugLogger, "%s│    %dms: ERROR: %s\n",
			strings.Repeat("│   ", depth), dur/time.Millisecond, err.Error())
	}
}

// RR represents a DNS resource record.
type RR struct {
	Name  string
	Type  string
	Value string
}

// String returns a string representation of an RR in zone-file format.
func (rr *RR) String() string {
	return rr.Name + "\t      3600\tIN\t" + rr.Type + "\t" + rr.Value
}

func convertRR(drr dns.RR) *RR {
	switch t := drr.(type) {
	case *dns.NS:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.Ns}
	case *dns.CNAME:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.Target}
	case *dns.A:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.A.String()}
	case *dns.AAAA:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.AAAA.String()}
	case *dns.TXT:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], strings.Join(t.Txt, "\t")}
	default:
		// fmt.Printf("%s\n", drr.String())
	}
	return nil
}

type key struct {
	Name string
	Type string
}

type entry struct {
	m   sync.RWMutex
	rrs map[RR]struct{}
}

// saveDNSRR saves 1 or more DNS records to the resolver cache.
func (r *Resolver) saveDNSRR(drrs ...dns.RR) {
	for _, drr := range drrs {
		if rr := convertRR(drr); rr != nil {
			r.cacheAdd(rr.Name, rr)
		}
	}
}

// cacheAdd adds 0 or more DNS records to the resolver cache for a specific
// domain name and record type. This ensures the cache entry exists, even
// if empty, for NXDOMAIN responses.
func (r *Resolver) cacheAdd(qname string, rr *RR) {
	qname = toLowerFQDN(qname)
	e := r.getEntry(qname)
	if e == nil {
		e = &entry{rrs: make(map[RR]struct{}, 0)}
		e.m.Lock()
		r.cache.Add(qname, e)
	} else {
		e.m.Lock()
	}
	defer e.m.Unlock()
	if rr != nil {
		e.rrs[*rr] = struct{}{}
	}
}

// cacheGet returns a randomly ordered slice of DNS records.
func (r *Resolver) cacheGet(qname string, qtype string) []*RR {
	e := r.getEntry(qname)
	if e == nil && r != Root {
		e = Root.getEntry(qname)
	}
	if e == nil {
		return nil
	}
	e.m.RLock()
	defer e.m.RUnlock()
	if len(e.rrs) == 0 {
		return []*RR{}
	}
	rrs := make([]*RR, 0, len(e.rrs))
	for rr, _ := range e.rrs {
		// fmt.Printf("%s\n", rr.String())
		if qtype == "" || rr.Type == qtype {
			rrs = append(rrs, &RR{rr.Name, rr.Type, rr.Value})
		}
	}
	if len(rrs) == 0 && (qtype != "" && qtype != "NS") {
		return nil
	}
	return rrs
}

// getEntry returns a single cache entry or nil if an entry does not exist in the cache.
func (r *Resolver) getEntry(qname string) *entry {
	c, ok := r.cache.Get(qname)
	if !ok {
		return nil
	}
	e, ok := c.(*entry)
	if !ok {
		return nil
	}
	return e
}
<commit_msg>whitespace<commit_after>package dnsr

import (
	"fmt"
	"io"
	"strings"
	"sync"
	"time"

	lru "github.com/hashicorp/golang-lru"
	"github.com/miekg/dns"
)

//go:generate sh generate.sh

var (
	Root        *Resolver
	DebugLogger io.Writer
	Timeout     = 500 * time.Millisecond
)

func init() {
	Root = New(strings.Count(root, "\n"))
	for t := range dns.ParseZone(strings.NewReader(root), "", "") {
		if t.Error == nil {
			Root.saveDNSRR(t.RR)
		}
	}
}

// Resolver implements a primitive, non-recursive, caching DNS resolver.
type Resolver struct {
	cache  *lru.Cache
	client *dns.Client
}

// New initializes a Resolver with the specified cache size. Cache size defaults to 10,000 if size <= 0.
func New(size int) *Resolver {
	if size <= 0 {
		size = 10000
	}
	cache, _ := lru.New(size)
	r := &Resolver{
		client: &dns.Client{
			DialTimeout:  Timeout,
			ReadTimeout:  Timeout,
			WriteTimeout: Timeout,
		},
		cache: cache,
	}
	return r
}

// Resolve finds DNS records of type qtype for the domain qname. It returns a channel of *RR.
// The implementation guarantees that the output channel will close, so it is safe to range over.
// For nonexistent domains (where a DNS server will return NXDOMAIN), it will simply close the output channel.
// Specify an empty string in qtype to receive any DNS records found (currently A, AAAA, NS, CNAME, and TXT).
func (r *Resolver) Resolve(qname string, qtype string) <-chan *RR {
	return r.resolve(qname, qtype, 0)
}

func (r *Resolver) resolve(qname string, qtype string, depth int) <-chan *RR {
	c := make(chan *RR, 20)
	go func() {
		defer close(c)
		logResolveStart(qname, qtype, depth)
		defer logResolveEnd(qname, qtype, depth, time.Now())
		qname = toLowerFQDN(qname)
		if r.recall(c, qname, qtype) {
			return
		}
		r.resolveNS(c, qname, qtype, depth)
	}()
	return c
}

func (r *Resolver) recall(c chan<- *RR, qname string, qtype string) bool {
	if rrs := r.cacheGet(qname, qtype); rrs != nil {
		inject(c, rrs...)
		return true
	}
	return false
}

func (r *Resolver) resolveNS(c chan<- *RR, qname string, qtype string, depth int) {
	success := make(chan bool)
	for pname, ok := qname, true; ok; pname, ok = parent(pname) {
		if pname == qname && qtype == "NS" { // If we’re looking for [foo.com,NS], then skip to [com,NS]
			continue
		}

		// Query all DNS servers in parallel
		found := false
		for nrr := range r.resolve(pname, "NS", depth+1) {
			if qtype != "" && r.recall(c, qname, qtype) {
				return
			}
			if nrr.Type != "NS" {
				continue
			}
			go r.exchange(success, c, nrr.Value, qname, qtype, depth)
			found = true
		}

		// Wait for first response
		if found {
			select {
			case <-success:
				r.resolveCNAMEs(c, qname, qtype, depth)
				return
			case <-time.After(Timeout):
				continue
			}
		}
	}
}

func (r *Resolver) exchange(success chan<- bool, c chan<- *RR, host string, qname string, qtype string, depth int) {
	dtype := dns.StringToType[qtype]
	if dtype == 0 {
		dtype = dns.TypeA
	}
	qmsg := &dns.Msg{}
	qmsg.SetQuestion(qname, dtype)
	qmsg.MsgHdr.RecursionDesired = false

	// Find each A record for the DNS server
	for rr := range r.resolve(host, "A", depth+1) {
		if rr.Type != "A" { // FIXME: support AAAA records?
			continue
		}

		// Synchronously query this DNS server
		start := time.Now()
		rmsg, _, err := r.client.Exchange(qmsg, rr.Value+":53")
		logExchange(rr.Value, qmsg, depth, start, err)
		if err != nil {
			continue
		}

		// If successful, cache the results and return
		r.saveDNSRR(rmsg.Answer...)
		r.saveDNSRR(rmsg.Ns...)
		r.saveDNSRR(rmsg.Extra...)
		if rmsg.Rcode == dns.RcodeNameError {
			r.cacheAdd(qname, nil) // FIXME: cache NXDOMAIN responses responsibly
		}
		success <- true
		return
	}
}

func (r *Resolver) resolveCNAMEs(c chan<- *RR, qname string, qtype string, depth int) {
	rrs := r.cacheGet(qname, "")
	if rrs == nil || !inject(c, rrs...) {
		return
	}
	for _, crr := range rrs {
		if crr.Type != "CNAME" {
			continue
		}
		logCNAME(depth, crr.String())
		for rr := range r.resolve(crr.Value, qtype, depth+1) {
			r.cacheAdd(qname, rr)
			if !inject(c, rr) {
				return
			}
		}
	}
}

func inject(c chan<- *RR, rrs ...*RR) bool {
	for _, rr := range rrs {
		select {
		case c <- rr:
		default:
			// return false
		}
	}
	return true
}

func parent(name string) (string, bool) {
	labels := dns.SplitDomainName(name)
	if labels == nil {
		return "", false
	}
	return toLowerFQDN(strings.Join(labels[1:], ".")), true
}

func toLowerFQDN(name string) string {
	return dns.Fqdn(strings.ToLower(name))
}

func logResolveStart(qname string, qtype string, depth int) {
	if DebugLogger == nil {
		return
	}
	fmt.Fprintf(DebugLogger, "%s┌─── resolve(\"%s\", \"%s\", %d)\n",
		strings.Repeat("│   ", depth), qname, qtype, depth)
}

func logResolveEnd(qname string, qtype string, depth int, start time.Time) {
	if DebugLogger == nil {
		return
	}
	dur := time.Since(start)
	fmt.Fprintf(DebugLogger, "%s└─── %dms: resolve(\"%s\", \"%s\", %d)\n",
		strings.Repeat("│   ", depth), dur/time.Millisecond, qname, qtype, depth)
}

func logCNAME(depth int, cname string) {
	if DebugLogger == nil {
		return
	}
	fmt.Fprintf(DebugLogger, "%s│    CNAME: %s\n", strings.Repeat("│   ", depth), cname)
}

func logExchange(host string, qmsg *dns.Msg, depth int, start time.Time, err error) {
	if DebugLogger == nil {
		return
	}
	dur := time.Since(start)
	fmt.Fprintf(DebugLogger, "%s│    %dms: dig @%s %s %s\n",
		strings.Repeat("│   ", depth), dur/time.Millisecond, host, qmsg.Question[0].Name, dns.TypeToString[qmsg.Question[0].Qtype])
	if err != nil {
		fmt.Fprintf(DebugLogger, "%s│    %dms: ERROR: %s\n",
			strings.Repeat("│   ", depth), dur/time.Millisecond, err.Error())
	}
}

// RR represents a DNS resource record.
type RR struct {
	Name  string
	Type  string
	Value string
}

// String returns a string representation of an RR in zone-file format.
func (rr *RR) String() string {
	return rr.Name + "\t      3600\tIN\t" + rr.Type + "\t" + rr.Value
}

func convertRR(drr dns.RR) *RR {
	switch t := drr.(type) {
	case *dns.NS:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.Ns}
	case *dns.CNAME:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.Target}
	case *dns.A:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.A.String()}
	case *dns.AAAA:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], t.AAAA.String()}
	case *dns.TXT:
		return &RR{t.Hdr.Name, dns.TypeToString[t.Hdr.Rrtype], strings.Join(t.Txt, "\t")}
	default:
		// fmt.Printf("%s\n", drr.String())
	}
	return nil
}

type key struct {
	Name string
	Type string
}

type entry struct {
	m   sync.RWMutex
	rrs map[RR]struct{}
}

// saveDNSRR saves 1 or more DNS records to the resolver cache.
func (r *Resolver) saveDNSRR(drrs ...dns.RR) {
	for _, drr := range drrs {
		if rr := convertRR(drr); rr != nil {
			r.cacheAdd(rr.Name, rr)
		}
	}
}

// cacheAdd adds 0 or more DNS records to the resolver cache for a specific
// domain name and record type. This ensures the cache entry exists, even
// if empty, for NXDOMAIN responses.
func (r *Resolver) cacheAdd(qname string, rr *RR) {
	qname = toLowerFQDN(qname)
	e := r.getEntry(qname)
	if e == nil {
		e = &entry{rrs: make(map[RR]struct{}, 0)}
		e.m.Lock()
		r.cache.Add(qname, e)
	} else {
		e.m.Lock()
	}
	defer e.m.Unlock()
	if rr != nil {
		e.rrs[*rr] = struct{}{}
	}
}

// cacheGet returns a randomly ordered slice of DNS records.
func (r *Resolver) cacheGet(qname string, qtype string) []*RR {
	e := r.getEntry(qname)
	if e == nil && r != Root {
		e = Root.getEntry(qname)
	}
	if e == nil {
		return nil
	}
	e.m.RLock()
	defer e.m.RUnlock()
	if len(e.rrs) == 0 {
		return []*RR{}
	}
	rrs := make([]*RR, 0, len(e.rrs))
	for rr, _ := range e.rrs {
		// fmt.Printf("%s\n", rr.String())
		if qtype == "" || rr.Type == qtype {
			rrs = append(rrs, &RR{rr.Name, rr.Type, rr.Value})
		}
	}
	if len(rrs) == 0 && (qtype != "" && qtype != "NS") {
		return nil
	}
	return rrs
}

// getEntry returns a single cache entry or nil if an entry does not exist in the cache.
func (r *Resolver) getEntry(qname string) *entry {
	c, ok := r.cache.Get(qname)
	if !ok {
		return nil
	}
	e, ok := c.(*entry)
	if !ok {
		return nil
	}
	return e
}
<|endoftext|>


<commit_before>package reporter

import (
	"fmt"

	"github.com/afeld/tangle/models"
)

func reportBrokenLink(link models.Link) {
	source := link.SourceURL.String()
	line := link.Node.LineNumber()
	dest, _ := link.DestURL()
	fmt.Printf("%s line %d has broken link to %s.\n", source, line, dest)
}

func ReportResults(resultByLink map[models.Link]bool) {
	fmt.Printf("Number of links found: %d\n", len(resultByLink))

	numBrokenLinks := 0
	for link, isValid := range resultByLink {
		if !isValid {
			numBrokenLinks++
			reportBrokenLink(link)
		}
	}

	fmt.Printf("Number of broken links: %d\n", numBrokenLinks)
}
<commit_msg>improve reporting of number of links<commit_after>package reporter

import (
	"fmt"

	"github.com/afeld/tangle/models"
)

func reportBrokenLink(link models.Link) {
	source := link.SourceURL.String()
	line := link.Node.LineNumber()
	dest, _ := link.DestURL()
	fmt.Printf("%s line %d has broken link to %s.\n", source, line, dest)
}

func ReportResults(resultByLink map[models.Link]bool) {
	numBrokenLinks := 0
	for link, isValid := range resultByLink {
		if !isValid {
			numBrokenLinks++
			reportBrokenLink(link)
		}
	}

	fmt.Printf("Number of broken links: %d/%d\n", numBrokenLinks, len(resultByLink))
}
<|endoftext|>


<commit_before>package libcontainer

import (
	"encoding/json"
	"os"
	"testing"
)

// Checks whether the expected capability is specified in the capabilities.
func contains(expected string, values []string) bool {
	for _, v := range values {
		if v == expected {
			return true
		}
	}
	return false
}

func TestContainerJsonFormat(t *testing.T) {
	f, err := os.Open("container.json")
	if err != nil {
		t.Fatal("Unable to open container.json")
	}
	defer f.Close()

	var container *Container
	if err := json.NewDecoder(f).Decode(&container); err != nil {
		t.Fatalf("failed to decode container config: %s", err)
	}
	if container.Hostname != "koye" {
		t.Log("hostname is not set")
		t.Fail()
	}

	if !container.Tty {
		t.Log("tty should be set to true")
		t.Fail()
	}

	if !container.Namespaces["NEWNET"] {
		t.Log("namespaces should contain NEWNET")
		t.Fail()
	}

	if container.Namespaces["NEWUSER"] {
		t.Log("namespaces should not contain NEWUSER")
		t.Fail()
	}

	if contains("SYS_ADMIN", container.Capabilities) {
		t.Log("SYS_ADMIN should not be enabled in capabilities mask")
		t.Fail()
	}

	if !contains("MKNOD", container.Capabilities) {
		t.Log("MKNOD should be enabled in capabilities mask")
		t.Fail()
	}

	if !contains("SYS_CHROOT", container.Capabilities) {
		t.Log("capabilities mask should contain SYS_CHROOT")
		t.Fail()
	}
}
<commit_msg>Fix unit test path Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@docker.com> (github: crosbymichael)<commit_after>package libcontainer

import (
	"encoding/json"
	"os"
	"testing"
)

// Checks whether the expected capability is specified in the capabilities.
func contains(expected string, values []string) bool {
	for _, v := range values {
		if v == expected {
			return true
		}
	}
	return false
}

func TestContainerJsonFormat(t *testing.T) {
	f, err := os.Open("sample_configs/attach_to_bridge.json")
	if err != nil {
		t.Fatal("Unable to open container.json")
	}
	defer f.Close()

	var container *Container
	if err := json.NewDecoder(f).Decode(&container); err != nil {
		t.Fatalf("failed to decode container config: %s", err)
	}
	if container.Hostname != "koye" {
		t.Log("hostname is not set")
		t.Fail()
	}

	if !container.Tty {
		t.Log("tty should be set to true")
		t.Fail()
	}

	if !container.Namespaces["NEWNET"] {
		t.Log("namespaces should contain NEWNET")
		t.Fail()
	}

	if container.Namespaces["NEWUSER"] {
		t.Log("namespaces should not contain NEWUSER")
		t.Fail()
	}

	if contains("SYS_ADMIN", container.Capabilities) {
		t.Log("SYS_ADMIN should not be enabled in capabilities mask")
		t.Fail()
	}

	if !contains("MKNOD", container.Capabilities) {
		t.Log("MKNOD should be enabled in capabilities mask")
		t.Fail()
	}

	if !contains("SYS_CHROOT", container.Capabilities) {
		t.Log("capabilities mask should contain SYS_CHROOT")
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package markdown

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/russross/blackfriday"
)

var renderFuncs []func(string) string = []func(string) string{
	// pre-transformations
	transformFigures,

	// main Markdown rendering
	renderMarkdown,

	// post-transformations
	transformCodeWithLanguagePrefix,
	transformFootnotes,
}

func Render(source string) string {
	for _, f := range renderFuncs {
		source = f(source)
	}
	return source
}

// Look for any whitespace between HTML tags.
var whitespaceRE *regexp.Regexp = regexp.MustCompile(`>\s+<`)

func collapseHTML(html string) string {
	html = strings.Replace(html, "\n", "", -1)
	html = whitespaceRE.ReplaceAllString(html, "><")
	return html
}

func renderMarkdown(source string) string {
	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_DASHES
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_USE_XHTML

	extensions := 0
	extensions |= blackfriday.EXTENSION_AUTO_HEADER_IDS
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_HEADER_IDS
	extensions |= blackfriday.EXTENSION_LAX_HTML_BLOCKS
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH

	renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")
	return string(blackfriday.Markdown([]byte(source), renderer, extensions))
}

var codeRE *regexp.Regexp = regexp.MustCompile(`<code class="(\w+)">`)

func transformCodeWithLanguagePrefix(source string) string {
	return codeRE.ReplaceAllString(source, `<code class="language-$1">`)
}

const figureHTML = `

%s

`

var figureRE *regexp.Regexp = regexp.MustCompile(`!fig src="(.*)" caption="(.*)"`)

func transformFigures(source string) string {
	return figureRE.ReplaceAllStringFunc(source, func(figure string) string {
		matches := figureRE.FindStringSubmatch(figure)
		return fmt.Sprintf(figureHTML, matches[1], matches[2])
	})
}

// A layer that we wrap the entire footer section in for styling purposes.
const footerWrapper = `

  %s

`

// HTML for a footnote within the document.
const footnoteAnchorHTML = `

  %s

`

// HTML for a reference to a footnote within the document.
const footnoteReferenceHTML = `

  %s

`

// Look for the section the section at the bottom of the page that looks like
//
[1] (the paragraph tag is there because Markdown will have already
// wrapped it by this point).
var footerRE *regexp.Regexp = regexp.MustCompile(`(?ms:^<p>\[\d+\].*)`)

var footnoteRE *regexp.Regexp = regexp.MustCompile(`\[(\d+)\](\s+.*)`)

// Note that this must be a post-transform filter. If it wasn't, our Markdown
// renderer would not render the Markdown inside the footnotes layer because it
// would already be wrapped in HTML.
func transformFootnotes(source string) string {
	footer := footerRE.FindString(source)

	if footer != "" {
		// remove the footer for now
		source = strings.Replace(source, footer, "", 1)

		footer = footnoteRE.ReplaceAllStringFunc(footer, func(footnote string) string {
			// first create a footnote with an anchor that links can target
			matches := footnoteRE.FindStringSubmatch(footnote)
			number := matches[1]
			anchor := fmt.Sprintf(footnoteAnchorHTML, number, number, number) + matches[2]

			// then replace all references in the body to this footnote
			referenceRE := regexp.MustCompile(fmt.Sprintf(`\[%s\]`, number))
			reference := fmt.Sprintf(footnoteReferenceHTML, number, number, number)
			source = referenceRE.ReplaceAllString(source, collapseHTML(reference))

			return collapseHTML(anchor)
		})

		// and wrap the whole footer section in a layer
		footer = fmt.Sprintf(footerWrapper, footer)
		source = source + footer
	}

	return source
}
<commit_msg>Some tweaks/comments<commit_after>package markdown

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/russross/blackfriday"
)

var renderFuncs []func(string) string = []func(string) string{
	// pre-transformations
	transformFigures,

	// main Markdown rendering
	renderMarkdown,

	// post-transformations
	transformCodeWithLanguagePrefix,
	transformFootnotes,
}

func Render(source string) string {
	for _, f := range renderFuncs {
		source = f(source)
	}
	return source
}

// Look for any whitespace between HTML tags.
var whitespaceRE *regexp.Regexp = regexp.MustCompile(`>\s+<`)

// Simply collapses certain HTML snippets by removing newlines and whitespace
// between tags. This is mainline used to make HTML snippets readable as
// constants, but then to make them fit a little more nicely into the rendered
// markup.
func collapseHTML(html string) string {
	html = strings.Replace(html, "\n", "", -1)
	html = whitespaceRE.ReplaceAllString(html, "><")
	return html
}

func renderMarkdown(source string) string {
	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_DASHES
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_USE_XHTML

	extensions := 0
	extensions |= blackfriday.EXTENSION_AUTO_HEADER_IDS
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_HEADER_IDS
	extensions |= blackfriday.EXTENSION_LAX_HTML_BLOCKS
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH

	renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")
	return string(blackfriday.Markdown([]byte(source), renderer, extensions))
}

var codeRE *regexp.Regexp = regexp.MustCompile(`<code class="(\w+)">`)

func transformCodeWithLanguagePrefix(source string) string {
	return codeRE.ReplaceAllString(source, `<code class="language-$1">`)
}

const figureHTML = `

%s

`

var figureRE *regexp.Regexp = regexp.MustCompile(`!fig src="(.*)" caption="(.*)"`)

func transformFigures(source string) string {
	return figureRE.ReplaceAllStringFunc(source, func(figure string) string {
		matches := figureRE.FindStringSubmatch(figure)
		return fmt.Sprintf(figureHTML, matches[1], matches[2])
	})
}

// A layer that we wrap the entire footer section in for styling purposes.
const footerWrapper = `

  %s

`

// HTML for a footnote within the document.
const footnoteAnchorHTML = `

  %s

`

// HTML for a reference to a footnote within the document.
const footnoteReferenceHTML = `

  %s

`

// Look for the section the section at the bottom of the page that looks like
//
[1] (the paragraph tag is there because Markdown will have already
// wrapped it by this point).
var footerRE *regexp.Regexp = regexp.MustCompile(`(?ms:^<p>\[\d+\].*)`)

// Look for a single footnote within the footer.
var footnoteRE *regexp.Regexp = regexp.MustCompile(`\[(\d+)\](\s+.*)`)

// Note that this must be a post-transform filter. If it wasn't, our Markdown
// renderer would not render the Markdown inside the footnotes layer because it
// would already be wrapped in HTML.
func transformFootnotes(source string) string {
	footer := footerRE.FindString(source)

	if footer != "" {
		// remove the footer for now
		source = strings.Replace(source, footer, "", 1)

		footer = footnoteRE.ReplaceAllStringFunc(footer, func(footnote string) string {
			// first create a footnote with an anchor that links can target
			matches := footnoteRE.FindStringSubmatch(footnote)
			number := matches[1]
			anchor := fmt.Sprintf(footnoteAnchorHTML, number, number, number) + matches[2]

			// then replace all references in the body to this footnote
			referenceRE := regexp.MustCompile(fmt.Sprintf(`\[%s\]`, number))
			reference := fmt.Sprintf(footnoteReferenceHTML, number, number, number)
			source = referenceRE.ReplaceAllString(source, collapseHTML(reference))

			return collapseHTML(anchor)
		})

		// and wrap the whole footer section in a layer for styling
		footer = fmt.Sprintf(footerWrapper, footer)
		source = source + footer
	}

	return source
}
<|endoftext|>


<commit_before>package containerimage

import (
	"context"
	"encoding/json"
	"runtime"
	"time"

	"github.com/moby/buildkit/cache"
	"github.com/moby/buildkit/util/progress"
	"github.com/moby/buildkit/util/system"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// const (
// 	emptyGZLayer = digest.Digest("sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1")
// )

func emptyImageConfig() ([]byte, error) {
	img := ocispec.Image{
		Architecture: runtime.GOARCH,
		OS:           runtime.GOOS,
	}
	img.RootFS.Type = "layers"
	img.Config.WorkingDir = "/"
	img.Config.Env = []string{"PATH=" + system.DefaultPathEnv}
	dt, err := json.Marshal(img)
	return dt, errors.Wrap(err, "failed to create empty image config")
}

func parseHistoryFromConfig(dt []byte) ([]ocispec.History, error) {
	var config struct {
		History []ocispec.History
	}
	if err := json.Unmarshal(dt, &config); err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal history from config")
	}
	return config.History, nil
}

func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache []byte) ([]byte, error) {
	m := map[string]json.RawMessage{}
	if err := json.Unmarshal(dt, &m); err != nil {
		return nil, errors.Wrap(err, "failed to parse image config for patch")
	}

	var rootFS ocispec.RootFS
	rootFS.Type = "layers"
	rootFS.DiffIDs = append(rootFS.DiffIDs, dps...)

	dt, err := json.Marshal(rootFS)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal rootfs")
	}
	m["rootfs"] = dt

	dt, err = json.Marshal(history)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal history")
	}
	m["history"] = dt

	if _, ok := m["created"]; !ok {
		var tm *time.Time
		for _, h := range history {
			if h.Created != nil {
				tm = h.Created
			}
		}
		dt, err = json.Marshal(&tm)
		if err != nil {
			return nil, errors.Wrap(err, "failed to marshal creation time")
		}
		m["created"] = dt
	}

	if cache != nil {
		dt, err := json.Marshal(cache)
		if err != nil {
			return nil, err
		}
		m["moby.buildkit.cache.v0"] = dt
	}

	dt, err = json.Marshal(m)
	return dt, errors.Wrap(err, "failed to marshal config after patch")
}

func normalizeLayersAndHistory(diffs []digest.Digest, history []ocispec.History, ref cache.ImmutableRef) ([]digest.Digest, []ocispec.History) {
	refMeta := getRefMetadata(ref, len(diffs))
	var historyLayers int
	for _, h := range history {
		if !h.EmptyLayer {
			historyLayers++
		}
	}
	if historyLayers > len(diffs) {
		// this case shouldn't happen but if it does force set history layers empty
		// from the bottom
		logrus.Warn("invalid image config with unaccounted layers")
		historyCopy := make([]ocispec.History, 0, len(history))
		var l int
		for _, h := range history {
			if l >= len(diffs) {
				h.EmptyLayer = true
			}
			if !h.EmptyLayer {
				l++
			}
			historyCopy = append(historyCopy, h)
		}
		history = historyCopy
	}

	if len(diffs) > historyLayers {
		// some history items are missing. add them based on the ref metadata
		for _, md := range refMeta[historyLayers:] {
			history = append(history, ocispec.History{
				Created:   &md.createdAt,
				CreatedBy: md.description,
				Comment:   "buildkit.exporter.image.v0",
			})
		}
	}

	var layerIndex int
	for i, h := range history {
		if !h.EmptyLayer {
			if h.Created == nil {
				h.Created = &refMeta[layerIndex].createdAt
			}
			layerIndex++
		}
		history[i] = h
	}

	// Find the first new layer time. Otherwise, the history item for a first
	// metadata command would be the creation time of a base image layer.
	// If there is no such then the last layer with timestamp.
	var created *time.Time
	var noCreatedTime bool
	for _, h := range history {
		if h.Created != nil {
			created = h.Created
			if noCreatedTime {
				break
			}
		} else {
			noCreatedTime = true
		}
	}

	// Fill in created times for all history items to be either the first new
	// layer time or the previous layer.
	noCreatedTime = false
	for i, h := range history {
		if h.Created != nil {
			if noCreatedTime {
				created = h.Created
			}
		} else {
			noCreatedTime = true
			h.Created = created
		}
		history[i] = h
	}

	return diffs, history
}

type refMetadata struct {
	description string
	createdAt   time.Time
}

func getRefMetadata(ref cache.ImmutableRef, limit int) []refMetadata {
	if limit <= 0 {
		return nil
	}
	meta := refMetadata{
		description: "created by buildkit", // shouldn't be shown but don't fail build
		createdAt:   time.Now(),
	}
	if ref == nil {
		return append(getRefMetadata(nil, limit-1), meta)
	}
	if descr := cache.GetDescription(ref.Metadata()); descr != "" {
		meta.description = descr
	}
	meta.createdAt = cache.GetCreatedAt(ref.Metadata())
	p := ref.Parent()
	if p != nil {
		defer p.Release(context.TODO())
	}
	return append(getRefMetadata(p, limit-1), meta)
}

func oneOffProgress(ctx context.Context, id string) func(err error) error {
	pw, _, _ := progress.FromContext(ctx)
	now := time.Now()
	st := progress.Status{
		Started: &now,
	}
	pw.Write(id, st)
	return func(err error) error {
		// TODO: set error on status
		now := time.Now()
		st.Completed = &now
		pw.Write(id, st)
		pw.Close()
		return err
	}
}
<commit_msg>builder-next/patchImageConfig: nitpicks<commit_after>package containerimage

import (
	"context"
	"encoding/json"
	"runtime"
	"time"

	"github.com/moby/buildkit/cache"
	"github.com/moby/buildkit/util/progress"
	"github.com/moby/buildkit/util/system"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// const (
// 	emptyGZLayer = digest.Digest("sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1")
// )

func emptyImageConfig() ([]byte, error) {
	img := ocispec.Image{
		Architecture: runtime.GOARCH,
		OS:           runtime.GOOS,
	}
	img.RootFS.Type = "layers"
	img.Config.WorkingDir = "/"
	img.Config.Env = []string{"PATH=" + system.DefaultPathEnv}
	dt, err := json.Marshal(img)
	return dt, errors.Wrap(err, "failed to create empty image config")
}

func parseHistoryFromConfig(dt []byte) ([]ocispec.History, error) {
	var config struct {
		History []ocispec.History
	}
	if err := json.Unmarshal(dt, &config); err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal history from config")
	}
	return config.History, nil
}

func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache []byte) ([]byte, error) {
	m := map[string]json.RawMessage{}
	if err := json.Unmarshal(dt, &m); err != nil {
		return nil, errors.Wrap(err, "failed to parse image config for patch")
	}

	var rootFS ocispec.RootFS
	rootFS.Type = "layers"
	rootFS.DiffIDs = append(rootFS.DiffIDs, dps...)

	dt, err := json.Marshal(rootFS)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal rootfs")
	}
	m["rootfs"] = dt

	dt, err = json.Marshal(history)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal history")
	}
	m["history"] = dt

	if _, ok := m["created"]; !ok {
		var tm *time.Time
		for _, h := range history {
			if h.Created != nil {
				tm = h.Created
			}
		}
		dt, err = json.Marshal(&tm)
		if err != nil {
			return nil, errors.Wrap(err, "failed to marshal creation time")
		}
		m["created"] = dt
	}

	if cache != nil {
		dt, err = json.Marshal(cache)
		if err != nil {
			return nil, errors.Wrap(err, "failed to marshal cache")
		}
		m["moby.buildkit.cache.v0"] = dt
	}

	dt, err = json.Marshal(m)
	return dt, errors.Wrap(err, "failed to marshal config after patch")
}

func normalizeLayersAndHistory(diffs []digest.Digest, history []ocispec.History, ref cache.ImmutableRef) ([]digest.Digest, []ocispec.History) {
	refMeta := getRefMetadata(ref, len(diffs))
	var historyLayers int
	for _, h := range history {
		if !h.EmptyLayer {
			historyLayers++
		}
	}
	if historyLayers > len(diffs) {
		// this case shouldn't happen but if it does force set history layers empty
		// from the bottom
		logrus.Warn("invalid image config with unaccounted layers")
		historyCopy := make([]ocispec.History, 0, len(history))
		var l int
		for _, h := range history {
			if l >= len(diffs) {
				h.EmptyLayer = true
			}
			if !h.EmptyLayer {
				l++
			}
			historyCopy = append(historyCopy, h)
		}
		history = historyCopy
	}

	if len(diffs) > historyLayers {
		// some history items are missing. add them based on the ref metadata
		for _, md := range refMeta[historyLayers:] {
			history = append(history, ocispec.History{
				Created:   &md.createdAt,
				CreatedBy: md.description,
				Comment:   "buildkit.exporter.image.v0",
			})
		}
	}

	var layerIndex int
	for i, h := range history {
		if !h.EmptyLayer {
			if h.Created == nil {
				h.Created = &refMeta[layerIndex].createdAt
			}
			layerIndex++
		}
		history[i] = h
	}

	// Find the first new layer time. Otherwise, the history item for a first
	// metadata command would be the creation time of a base image layer.
	// If there is no such then the last layer with timestamp.
	var created *time.Time
	var noCreatedTime bool
	for _, h := range history {
		if h.Created != nil {
			created = h.Created
			if noCreatedTime {
				break
			}
		} else {
			noCreatedTime = true
		}
	}

	// Fill in created times for all history items to be either the first new
	// layer time or the previous layer.
	noCreatedTime = false
	for i, h := range history {
		if h.Created != nil {
			if noCreatedTime {
				created = h.Created
			}
		} else {
			noCreatedTime = true
			h.Created = created
		}
		history[i] = h
	}

	return diffs, history
}

type refMetadata struct {
	description string
	createdAt   time.Time
}

func getRefMetadata(ref cache.ImmutableRef, limit int) []refMetadata {
	if limit <= 0 {
		return nil
	}
	meta := refMetadata{
		description: "created by buildkit", // shouldn't be shown but don't fail build
		createdAt:   time.Now(),
	}
	if ref == nil {
		return append(getRefMetadata(nil, limit-1), meta)
	}
	if descr := cache.GetDescription(ref.Metadata()); descr != "" {
		meta.description = descr
	}
	meta.createdAt = cache.GetCreatedAt(ref.Metadata())
	p := ref.Parent()
	if p != nil {
		defer p.Release(context.TODO())
	}
	return append(getRefMetadata(p, limit-1), meta)
}

func oneOffProgress(ctx context.Context, id string) func(err error) error {
	pw, _, _ := progress.FromContext(ctx)
	now := time.Now()
	st := progress.Status{
		Started: &now,
	}
	pw.Write(id, st)
	return func(err error) error {
		// TODO: set error on status
		now := time.Now()
		st.Completed = &now
		pw.Write(id, st)
		pw.Close()
		return err
	}
}
<|endoftext|>


<commit_before>package seq

import (
	"testing"
	"time"

	"github.com/facebookgo/ensure"
)

// -----------------------------------------------------------------------------

func TestSimpleBufSeq_New_BufSize(t *testing.T) {
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(-42)), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(0)), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1)), 1)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1e6)), int(1e6))
}

func TestSimpleBufSeq_FirstID(t *testing.T) {
	ensure.DeepEqual(t, <-NewSimpleBufSeq(1e2).GetStream(), ID(1))
}

func TestSimpleBufSeq_SingleClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	for id := range seq.GetStream() {
		ensure.DeepEqual(t, id, lastID+1)
		lastID = id
	}
}

func TestSimpleBufSeq_MultiClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	s1, s2, s3 := seq.GetStream(), seq.GetStream(), seq.GetStream()
	for {
		id1 := s1.Next()
		if id1 == 0 {
			break
		}
		ensure.DeepEqual(t, id1, lastID+1)
		id2 := s2.Next()
		if id2 == 0 {
			break
		}
		ensure.DeepEqual(t, id2, id1+1)
		id3 := s3.Next()
		if id3 == 0 {
			break
		}
		ensure.DeepEqual(t, id3, id2+1)
	}
}
<commit_msg>added TestSimpleBufSeq_ConcurrentClients256<commit_after>package seq

import (
	"sync"
	"testing"
	"time"

	"github.com/facebookgo/ensure"
)

// -----------------------------------------------------------------------------

// NOTE: run these tests with `go test -race -cpu 1,8,32`

func TestSimpleBufSeq_New_BufSize(t *testing.T) {
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(-42)), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(0)), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1)), 1)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1e6)), int(1e6))
}

func TestSimpleBufSeq_FirstID(t *testing.T) {
	ensure.DeepEqual(t, <-NewSimpleBufSeq(1e2).GetStream(), ID(1))
}

func TestSimpleBufSeq_SingleClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	for id := range seq.GetStream() {
		ensure.DeepEqual(t, id, lastID+1)
		lastID = id
	}
}

func TestSimpleBufSeq_MultiClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	s1, s2, s3 := seq.GetStream(), seq.GetStream(), seq.GetStream()
	for {
		id1 := s1.Next()
		if id1 == 0 {
			break
		}
		ensure.DeepEqual(t, id1, lastID+1)
		id2 := s2.Next()
		if id2 == 0 {
			break
		}
		ensure.DeepEqual(t, id2, id1+1)
		id3 := s3.Next()
		if id3 == 0 {
			break
		}
		ensure.DeepEqual(t, id3, id2+1)
	}
}

func TestSimpleBufSeq_ConcurrentClients256(t *testing.T) {
	seq := NewSimpleBufSeq(1024)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	wg := &sync.WaitGroup{}
	for i := 0; i < 256; i++ {
		wg.Add(1)
		go func() {
			for id := range seq.GetStream() {
				_ = id
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2010 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.

// This file contains support functionality for godoc.

package main

import (
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
	"sort"
	"strings"
	"sync"
	"time"
	"utf8"
)

// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
//
type RWValue struct {
	mutex     sync.RWMutex
	value     interface{}
	timestamp int64 // time of last set(), in seconds since epoch
}

func (v *RWValue) set(value interface{}) {
	v.mutex.Lock()
	v.value = value
	v.timestamp = time.Seconds()
	v.mutex.Unlock()
}

func (v *RWValue) get() (interface{}, int64) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v.value, v.timestamp
}

var cwd, _ = os.Getwd() // ignore errors

// canonicalizePaths takes a list of (directory/file) paths and returns
// the list of corresponding absolute paths in sorted (increasing) order.
// Relative paths are assumed to be relative to the current directory,
// empty and duplicate paths as well as paths for which filter(path) is
// false are discarded. filter may be nil in which case it is not used.
//
func canonicalizePaths(list []string, filter func(path string) bool) []string {
	i := 0
	for _, path := range list {
		path = strings.TrimSpace(path)
		if len(path) == 0 {
			continue // ignore empty paths (don't assume ".")
		}
		// len(path) > 0: normalize path
		if pathutil.IsAbs(path) {
			path = pathutil.Clean(path)
		} else {
			path = pathutil.Join(cwd, path)
		}
		// we have a non-empty absolute path
		if filter != nil && !filter(path) {
			continue
		}
		// keep the path
		list[i] = path
		i++
	}
	list = list[0:i]

	// sort the list and remove duplicate entries
	sort.SortStrings(list)
	i = 0
	prev := ""
	for _, path := range list {
		if path != prev {
			list[i] = path
			i++
			prev = path
		}
	}

	return list[0:i]
}

// writeFileAtomically writes data to a temporary file and then
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
	f, err := ioutil.TempFile(cwd, filename)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err != nil {
		return err
	}
	if n < len(data) {
		return io.ErrShortWrite
	}
	return os.Rename(f.Name(), filename)
}

// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
func isText(s []byte) bool {
	const max = 1024 // at least utf8.UTFMax
	if len(s) > max {
		s = s[0:max]
	}
	for i, c := range string(s) {
		if i+utf8.UTFMax > len(s) {
			// last char may be incomplete - ignore
			break
		}
		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
			// decoding error or control character - not a text file
			return false
		}
	}
	return true
}

// TODO(gri): Should have a mapping from extension to handler, eventually.

// textExt[x] is true if the extension x indicates a text file, and false otherwise.
var textExt = map[string]bool{
	".css": false, // must be served raw
	".js":  false, // must be served raw
}

// isTextFile returns true if the file has a known extension indicating
// a text file, or if a significant chunk of the specified file looks like
// correct UTF-8; that is, if it is likely that the file contains human-
// readable text.
//
func isTextFile(filename string) bool {
	// if the extension is known, use it for decision making
	if isText, found := textExt[pathutil.Ext(filename)]; found {
		return isText
	}

	// the extension is not known; read an initial chunk
	// of the file and check if it looks like text
	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return false
	}
	defer f.Close()

	var buf [1024]byte
	n, err := f.Read(buf[0:])
	if err != nil {
		return false
	}

	return isText(buf[0:n])
}
<commit_msg>godoc: fix writeFileAtomically utility function<commit_after>// Copyright 2010 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.

// This file contains support functionality for godoc.

package main

import (
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
	"sort"
	"strings"
	"sync"
	"time"
	"utf8"
)

// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
//
type RWValue struct {
	mutex     sync.RWMutex
	value     interface{}
	timestamp int64 // time of last set(), in seconds since epoch
}

func (v *RWValue) set(value interface{}) {
	v.mutex.Lock()
	v.value = value
	v.timestamp = time.Seconds()
	v.mutex.Unlock()
}

func (v *RWValue) get() (interface{}, int64) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v.value, v.timestamp
}

var cwd, _ = os.Getwd() // ignore errors

// canonicalizePaths takes a list of (directory/file) paths and returns
// the list of corresponding absolute paths in sorted (increasing) order.
// Relative paths are assumed to be relative to the current directory,
// empty and duplicate paths as well as paths for which filter(path) is
// false are discarded. filter may be nil in which case it is not used.
//
func canonicalizePaths(list []string, filter func(path string) bool) []string {
	i := 0
	for _, path := range list {
		path = strings.TrimSpace(path)
		if len(path) == 0 {
			continue // ignore empty paths (don't assume ".")
		}
		// len(path) > 0: normalize path
		if pathutil.IsAbs(path) {
			path = pathutil.Clean(path)
		} else {
			path = pathutil.Join(cwd, path)
		}
		// we have a non-empty absolute path
		if filter != nil && !filter(path) {
			continue
		}
		// keep the path
		list[i] = path
		i++
	}
	list = list[0:i]

	// sort the list and remove duplicate entries
	sort.SortStrings(list)
	i = 0
	prev := ""
	for _, path := range list {
		if path != prev {
			list[i] = path
			i++
			prev = path
		}
	}

	return list[0:i]
}

// writeFileAtomically writes data to a temporary file and then
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
	f, err := ioutil.TempFile(pathutil.Split(filename))
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err != nil {
		return err
	}
	if n < len(data) {
		return io.ErrShortWrite
	}
	return os.Rename(f.Name(), filename)
}

// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
func isText(s []byte) bool {
	const max = 1024 // at least utf8.UTFMax
	if len(s) > max {
		s = s[0:max]
	}
	for i, c := range string(s) {
		if i+utf8.UTFMax > len(s) {
			// last char may be incomplete - ignore
			break
		}
		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
			// decoding error or control character - not a text file
			return false
		}
	}
	return true
}

// TODO(gri): Should have a mapping from extension to handler, eventually.

// textExt[x] is true if the extension x indicates a text file, and false otherwise.
var textExt = map[string]bool{
	".css": false, // must be served raw
	".js":  false, // must be served raw
}

// isTextFile returns true if the file has a known extension indicating
// a text file, or if a significant chunk of the specified file looks like
// correct UTF-8; that is, if it is likely that the file contains human-
// readable text.
//
func isTextFile(filename string) bool {
	// if the extension is known, use it for decision making
	if isText, found := textExt[pathutil.Ext(filename)]; found {
		return isText
	}

	// the extension is not known; read an initial chunk
	// of the file and check if it looks like text
	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return false
	}
	defer f.Close()

	var buf [1024]byte
	n, err := f.Read(buf[0:])
	if err != nil {
		return false
	}

	return isText(buf[0:n])
}
<|endoftext|>


<commit_before>// Copyright 2009 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 main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io/ioutil"
	"os"
	pathutil "path"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")

	// debugging support
	comments = flag.Bool("comments", true, "print comments")
	trace    = flag.Bool("trace", false, "print parse trace")
	printAST = flag.Bool("ast", false, "print AST (before rewrites)")

	// layout control
	tabWidth  = flag.Int("tabwidth", 8, "tab width")
	tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
	useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
)

var (
	fset        = token.NewFileSet()
	exitCode    = 0
	rewrite     func(*ast.File) *ast.File
	parserMode  uint
	printerMode uint
)

func report(err os.Error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func initParserMode() {
	parserMode = uint(0)
	if *comments {
		parserMode |= parser.ParseComments
	}
	if *trace {
		parserMode |= parser.Trace
	}
}

func initPrinterMode() {
	printerMode = uint(0)
	if *tabIndent {
		printerMode |= printer.TabIndent
	}
	if *useSpaces {
		printerMode |= printer.UseSpaces
	}
}

func isGoFile(f *os.FileInfo) bool {
	// ignore non-Go files
	return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
}

func processFile(f *os.File) os.Error {
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}

	file, err := parser.ParseFile(fset, f.Name(), src, parserMode)

	if err != nil {
		return err
	}

	if *printAST {
		ast.Print(file)
	}

	if rewrite != nil {
		file = rewrite(file)
	}

	if *simplifyAST {
		simplify(file)
	}

	var res bytes.Buffer
	_, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, fset, file)
	if err != nil {
		return err
	}

	if bytes.Compare(src, res.Bytes()) != 0 {
		// formatting has changed
		if *list {
			fmt.Fprintln(os.Stdout, f.Name())
		}
		if *write {
			err = ioutil.WriteFile(f.Name(), res.Bytes(), 0)
			if err != nil {
				return err
			}
		}
	}

	if !*list && !*write {
		_, err = os.Stdout.Write(res.Bytes())
	}

	return err
}

func processFileByName(filename string) os.Error {
	file, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer file.Close()
	return processFile(file)
}

type fileVisitor chan os.Error

func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
	return true
}

func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
	if isGoFile(f) {
		v <- nil // synchronize error handler
		if err := processFileByName(path); err != nil {
			v <- err
		}
	}
}

func walkDir(path string) {
	// start an error handler
	done := make(chan bool)
	v := make(fileVisitor)
	go func() {
		for err := range v {
			if err != nil {
				report(err)
			}
		}
		done <- true
	}()
	// walk the tree
	pathutil.Walk(path, v, v)
	close(v) // terminate error handler loop
	<-done   // wait for all errors to be reported
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *tabWidth < 0 {
		fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
		os.Exit(2)
	}

	initParserMode()
	initPrinterMode()
	initRewrite()

	if flag.NArg() == 0 {
		if err := processFile(os.Stdin); err != nil {
			report(err)
		}
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsRegular():
			if err := processFileByName(path); err != nil {
				report(err)
			}
		case dir.IsDirectory():
			walkDir(path)
		}
	}

	os.Exit(exitCode)
}
<commit_msg>gofmt: no need for lexical compare of src and res (optimization)<commit_after>// Copyright 2009 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 main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io/ioutil"
	"os"
	pathutil "path"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")

	// debugging support
	comments = flag.Bool("comments", true, "print comments")
	trace    = flag.Bool("trace", false, "print parse trace")
	printAST = flag.Bool("ast", false, "print AST (before rewrites)")

	// layout control
	tabWidth  = flag.Int("tabwidth", 8, "tab width")
	tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
	useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
)

var (
	fset        = token.NewFileSet()
	exitCode    = 0
	rewrite     func(*ast.File) *ast.File
	parserMode  uint
	printerMode uint
)

func report(err os.Error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func initParserMode() {
	parserMode = uint(0)
	if *comments {
		parserMode |= parser.ParseComments
	}
	if *trace {
		parserMode |= parser.Trace
	}
}

func initPrinterMode() {
	printerMode = uint(0)
	if *tabIndent {
		printerMode |= printer.TabIndent
	}
	if *useSpaces {
		printerMode |= printer.UseSpaces
	}
}

func isGoFile(f *os.FileInfo) bool {
	// ignore non-Go files
	return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
}

func processFile(f *os.File) os.Error {
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}

	file, err := parser.ParseFile(fset, f.Name(), src, parserMode)

	if err != nil {
		return err
	}

	if *printAST {
		ast.Print(file)
	}

	if rewrite != nil {
		file = rewrite(file)
	}

	if *simplifyAST {
		simplify(file)
	}

	var buf bytes.Buffer
	_, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&buf, fset, file)
	if err != nil {
		return err
	}
	res := buf.Bytes()

	if !bytes.Equal(src, res) {
		// formatting has changed
		if *list {
			fmt.Fprintln(os.Stdout, f.Name())
		}
		if *write {
			err = ioutil.WriteFile(f.Name(), res, 0)
			if err != nil {
				return err
			}
		}
	}

	if !*list && !*write {
		_, err = os.Stdout.Write(res)
	}

	return err
}

func processFileByName(filename string) os.Error {
	file, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer file.Close()
	return processFile(file)
}

type fileVisitor chan os.Error

func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
	return true
}

func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
	if isGoFile(f) {
		v <- nil // synchronize error handler
		if err := processFileByName(path); err != nil {
			v <- err
		}
	}
}

func walkDir(path string) {
	// start an error handler
	done := make(chan bool)
	v := make(fileVisitor)
	go func() {
		for err := range v {
			if err != nil {
				report(err)
			}
		}
		done <- true
	}()
	// walk the tree
	pathutil.Walk(path, v, v)
	close(v) // terminate error handler loop
	<-done   // wait for all errors to be reported
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *tabWidth < 0 {
		fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
		os.Exit(2)
	}

	initParserMode()
	initPrinterMode()
	initRewrite()

	if flag.NArg() == 0 {
		if err := processFile(os.Stdin); err != nil {
			report(err)
		}
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsRegular():
			if err := processFileByName(path); err != nil {
				report(err)
			}
		case dir.IsDirectory():
			walkDir(path)
		}
	}

	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>// Copyright 2009 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 main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")

	// layout control
	comments  = flag.Bool("comments", true, "print comments")
	tabWidth  = flag.Int("tabwidth", 8, "tab width")
	tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
	useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")

	// debugging
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)

var (
	fset        = token.NewFileSet()
	exitCode    = 0
	rewrite     func(*ast.File) *ast.File
	parserMode  uint
	printerMode uint
)

func report(err os.Error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func initParserMode() {
	parserMode = uint(0)
	if *comments {
		parserMode |= parser.ParseComments
	}
}

func initPrinterMode() {
	printerMode = uint(0)
	if *tabIndent {
		printerMode |= printer.TabIndent
	}
	if *useSpaces {
		printerMode |= printer.UseSpaces
	}
}

func isGoFile(f *os.FileInfo) bool {
	// ignore non-Go files
	return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
}

// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer) os.Error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err != nil {
		return err
	}

	if rewrite != nil {
		file = rewrite(file)
	}

	if *simplifyAST {
		simplify(file)
	}

	var buf bytes.Buffer
	_, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
	if err != nil {
		return err
	}
	res := buf.Bytes()

	if !bytes.Equal(src, res) {
		// formatting has changed
		if *list {
			fmt.Fprintln(out, filename)
		}
		if *write {
			err = ioutil.WriteFile(filename, res, 0)
			if err != nil {
				return err
			}
		}
	}

	if !*list && !*write {
		_, err = out.Write(res)
	}

	return err
}

type fileVisitor chan os.Error

func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
	return true
}

func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
	if isGoFile(f) {
		v <- nil // synchronize error handler
		if err := processFile(path, nil, os.Stdout); err != nil {
			v <- err
		}
	}
}

func walkDir(path string) {
	v := make(fileVisitor)
	go func() {
		filepath.Walk(path, v, v)
		close(v)
	}()
	for err := range v {
		if err != nil {
			report(err)
		}
	}
}

func main() {
	// call gofmtMain in a separate function
	// so that it can use defer and have them
	// run before the exit.
	gofmtMain()
	os.Exit(exitCode)
}

func gofmtMain() {
	flag.Usage = usage
	flag.Parse()
	if *tabWidth < 0 {
		fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
		exitCode = 2
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
			exitCode = 2
			return
		}
		defer f.Close()
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	initParserMode()
	initPrinterMode()
	initRewrite()

	if flag.NArg() == 0 {
		if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
			report(err)
		}
		return
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsRegular():
			if err := processFile(path, nil, os.Stdout); err != nil {
				report(err)
			}
		case dir.IsDirectory():
			walkDir(path)
		}
	}
}
<commit_msg>gofmt: add -diff<commit_after>// Copyright 2009 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 main

import (
	"bytes"
	"exec"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")
	doDiff      = flag.Bool("d", false, "display diffs instead of rewriting files")

	// layout control
	comments  = flag.Bool("comments", true, "print comments")
	tabWidth  = flag.Int("tabwidth", 8, "tab width")
	tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
	useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")

	// debugging
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)

var (
	fset        = token.NewFileSet()
	exitCode    = 0
	rewrite     func(*ast.File) *ast.File
	parserMode  uint
	printerMode uint
)

func report(err os.Error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func initParserMode() {
	parserMode = uint(0)
	if *comments {
		parserMode |= parser.ParseComments
	}
}

func initPrinterMode() {
	printerMode = uint(0)
	if *tabIndent {
		printerMode |= printer.TabIndent
	}
	if *useSpaces {
		printerMode |= printer.UseSpaces
	}
}

func isGoFile(f *os.FileInfo) bool {
	// ignore non-Go files
	return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
}

// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer) os.Error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	file, err := parser.ParseFile(fset, filename, src, parserMode)
	if err != nil {
		return err
	}

	if rewrite != nil {
		file = rewrite(file)
	}

	if *simplifyAST {
		simplify(file)
	}

	var buf bytes.Buffer
	_, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
	if err != nil {
		return err
	}
	res := buf.Bytes()

	if !bytes.Equal(src, res) {
		// formatting has changed
		if *list {
			fmt.Fprintln(out, filename)
		}
		if *write {
			err = ioutil.WriteFile(filename, res, 0)
			if err != nil {
				return err
			}
		}
		if *doDiff {
			data, err := diff(src, res)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			fmt.Printf("diff %s fixed/%s\n", filename, filename)
			out.Write(data)
		}
	}

	if !*list && !*write && !*doDiff {
		_, err = out.Write(res)
	}

	return err
}

type fileVisitor chan os.Error

func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
	return true
}

func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
	if isGoFile(f) {
		v <- nil // synchronize error handler
		if err := processFile(path, nil, os.Stdout); err != nil {
			v <- err
		}
	}
}

func walkDir(path string) {
	v := make(fileVisitor)
	go func() {
		filepath.Walk(path, v, v)
		close(v)
	}()
	for err := range v {
		if err != nil {
			report(err)
		}
	}
}

func main() {
	// call gofmtMain in a separate function
	// so that it can use defer and have them
	// run before the exit.
	gofmtMain()
	os.Exit(exitCode)
}

func gofmtMain() {
	flag.Usage = usage
	flag.Parse()
	if *tabWidth < 0 {
		fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", *tabWidth)
		exitCode = 2
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
			exitCode = 2
			return
		}
		defer f.Close()
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	initParserMode()
	initPrinterMode()
	initRewrite()

	if flag.NArg() == 0 {
		if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
			report(err)
		}
		return
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsRegular():
			if err := processFile(path, nil, os.Stdout); err != nil {
				report(err)
			}
		case dir.IsDirectory():
			walkDir(path)
		}
	}
}

func diff(b1, b2 []byte) (data []byte, err os.Error) {
	f1, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	diffcmd, err := exec.LookPath("diff")
	if err != nil {
		return nil, err
	}

	c, err := exec.Run(diffcmd, []string{"diff", "-u", f1.Name(), f2.Name()},
		nil, "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	return ioutil.ReadAll(c.Stdout)
}
<|endoftext|>


<commit_before>package singletonqueue

import (
	"encoding/json"
	"testing"
	"time"
)

type incQueueImpl struct {
	lastValue int
	t         *testing.T
}

func (q *incQueueImpl) GetID() string {
	return "test-ordered-process"
}
func (q *incQueueImpl) Process(message Message) error {
	var value int
	json.Unmarshal(message.Payload, &value)
	if value != q.lastValue+1 {
		q.t.Error("Expected:", q.lastValue+1, "got:", value)
	}
	q.lastValue = value
	return nil
}

func TestOrderedProcess(t *testing.T) {
	incQueue := incQueueImpl{-1, t}

	for i := 0; i < 10; i++ {
		marshaled, _ := json.Marshal(i)
		Push(&incQueue, marshaled)
	}

	startTime := time.Now()
	var err error
	for ret := 1; ret > 0; ret, err = Length(&incQueue) {
		if err != nil {
			t.Error(err)
			return
		}

		if time.Since(startTime) < 3*time.Second {
			time.Sleep(time.Millisecond * 50)
		} else {
			t.Error("Not all jobs processed after 3 seconds")
			return
		}
	}

}
<commit_msg>implement new in test<commit_after>package singletonqueue

import (
	"encoding/json"
	"strings"
	"testing"
	"time"
)

const (
	testPrefix = "test-ordered-process"
)

type incQueueImpl struct {
	lastValue int
	t         *testing.T
}

type testMessage struct {
	Value int
}

func (q *incQueueImpl) New(queueID string) Interface {
	if strings.HasPrefix(queueID, testPrefix) {
		newQ := incQueueImpl{-1, q.t}
		return &newQ
	}
	return nil
}

func (q *incQueueImpl) QueueID() string {
	return testPrefix
}

func (q *incQueueImpl) Process(message Message) error {
	var msg testMessage
	json.Unmarshal(message.Payload, &msg)
	if msg.Value != q.lastValue+1 {
		q.t.Error("Expected:", q.lastValue+1, "got:", msg.Value)
	}
	q.lastValue = msg.Value
	return nil
}

func TestOrderedProcess(t *testing.T) {
	incQueue := incQueueImpl{-1, t}

	for i := 0; i < 10; i++ {
		marshaled, _ := json.Marshal(testMessage{
			Value: i,
		})
		Push(&incQueue, marshaled)
	}

	startTime := time.Now()
	var err error
	for ret := 1; ret > 0; ret, err = Length(&incQueue) {
		if err != nil {
			t.Error(err)
			return
		}

		if time.Since(startTime) < 3*time.Second {
			time.Sleep(time.Millisecond * 50)
		} else {
			t.Error("Not all jobs processed after 3 seconds")
			return
		}
	}

}
<|endoftext|>


<commit_before>package shell

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"io"
)

func init() {
	commands = append(commands, &commandCollectionList{})
}

type commandCollectionList struct {
}

func (c *commandCollectionList) Name() string {
	return "collection.list"
}

func (c *commandCollectionList) Help() string {
	return `list all collections`
}

func (c *commandCollectionList) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {

	var resp *master_pb.CollectionListResponse
	ctx := context.Background()
	err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
		resp, err = client.CollectionList(ctx, &master_pb.CollectionListRequest{})
		return err
	})

	if err != nil {
		return err
	}

	for _, c := range resp.Collections {
		fmt.Fprintf(writer, "collection:\"%s\"\n", c.GetName())
	}

	fmt.Fprintf(writer, "Total %d collections.\n", len(resp.Collections))

	return nil
}
<commit_msg>refactoring<commit_after>package shell

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"io"
)

func init() {
	commands = append(commands, &commandCollectionList{})
}

type commandCollectionList struct {
}

func (c *commandCollectionList) Name() string {
	return "collection.list"
}

func (c *commandCollectionList) Help() string {
	return `list all collections`
}

func (c *commandCollectionList) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {

	collections, err := ListCollectionNames(commandEnv)

	if err != nil {
		return err
	}

	for _, c := range collections {
		fmt.Fprintf(writer, "collection:\"%s\"\n", c)
	}

	fmt.Fprintf(writer, "Total %d collections.\n", len(collections))

	return nil
}

func ListCollectionNames(commandEnv *commandEnv) (collections []string, err error) {
	var resp *master_pb.CollectionListResponse
	ctx := context.Background()
	err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
		resp, err = client.CollectionList(ctx, &master_pb.CollectionListRequest{})
		return err
	})
	if err != nil {
		return
	}
	for _, c := range resp.Collections {
		collections = append(collections, c.Name)
	}
	return
}
<|endoftext|>