<commit_before>package frame

import (
	"github.com/as/drawcache"
	"github.com/as/frame/box"
	"github.com/as/frame/font"
	"image"
	"image/draw"
)

const (
	FrElastic = 1 << iota
	FrUTF8
)

// Frame is a write-only container for editable text
type Frame struct {
	b *image.RGBA
	r image.Rectangle
	box.Run
	ir *box.Run

	p0 int64
	p1 int64

	flags int

	Font *font.Font
	Color
	Ticked bool
	Scroll func(int)
	drawcache.Drawer
	op draw.Op

	maxtab int
	full   int

	tick      draw.Image
	tickback  draw.Image
	tickscale int
	tickoff   bool
	maxlines  int
	modified  bool
	noredraw  bool

	pts     [][2]image.Point
	hexFont *font.Font
	hex     []draw.Image

	// Points to the font subpackage's StringN?BG or RuneN?BG functions
	stringBG     func(draw.Image, image.Point, image.Image, image.Point, *font.Font, []byte, image.Image, image.Point) int
	stringNBG    func(draw.Image, image.Point, image.Image, image.Point, *font.Font, []byte) int
	newRulerFunc func(s []byte, ft *font.Font) box.Ruler

	elastic bool
}

func (f *Frame) SetFlags(flat int) {
	//TODO(as)
}

func newRuneFrame(r image.Rectangle, ft *font.Font, b *image.RGBA, cols Color, flag ...int) *Frame {
	fl := getflag(flag)
	mintab := ft.Measure(' ')
	maxtab := mintab * 4
	elastic := fl&FrElastic != 0
	if elastic {
		mintab = maxtab
	}
	f := &Frame{
		Font:         ft,
		maxtab:       maxtab,
		Color:        cols,
		Run:          box.NewRun(mintab, 5000, ft, box.NewRuneRuler),
		stringBG:     font.RuneBG,
		stringNBG:    font.RuneNBG,
		newRulerFunc: box.NewRuneRuler,
		op:           draw.Src,
	}
	f.setrects(r, b)
	f.inittick()
	run := box.NewRun(mintab, 5000, ft, box.NewRuneRuler)
	f.ir = &run
	f.Drawer = drawcache.New()
	return f
}

func getflag(flag []int) int {
	if len(flag) == 0 {
		return 0
	}
	return flag[0]
}

// New creates a new frame on b with bounds r. The image b is used
// as the frame's internal bitmap cache.
func New(r image.Rectangle, ft *font.Font, b *image.RGBA, cols Color, flag ...int) *Frame {
	fl := getflag(flag)
	if fl&FrUTF8 != 0 {
		return newRuneFrame(r, ft, b, cols, flag...)
	}
	mintab := ft.Measure(' ')
	maxtab := mintab * 4
	elastic := fl&FrElastic != 0
	if elastic {
		mintab = maxtab
	}
	f := &Frame{
		Font:         ft,
		maxtab:       maxtab,
		Color:        cols,
		Run:          box.NewRun(mintab, 5000, ft),
		stringBG:     font.StringBG,
		stringNBG:    font.StringNBG,
		newRulerFunc: box.NewByteRuler,
		op:           draw.Src,
		elastic:      elastic,
	}
	f.setrects(r, b)
	f.inittick()
	run := box.NewRun(mintab, 5000, ft)
	f.ir = &run
	f.Drawer = drawcache.New()
	return f
}

func (f *Frame) RGBA() *image.RGBA {
	return f.b
}
func (f *Frame) Size() image.Point {
	r := f.RGBA().Bounds()
	return image.Pt(r.Dx(), r.Dy())
}

// Dirty returns true if the contents of the frame have changes since the last redraw
func (f *Frame) Dirty() bool {
	return f.modified
}

// SetDirty alters the frame's internal state
func (f *Frame) SetDirty(dirty bool) {
	f.modified = dirty
}

func (f *Frame) SetOp(op draw.Op) {
	f.op = op

}

// Close closes the frame
func (f *Frame) Close() error {
	return nil
}

// Reset resets the frame to display on image b with bounds r and font ft.
func (f *Frame) Reset(r image.Rectangle, b *image.RGBA, ft *font.Font) {
	f.r = r
	f.b = b
	f.SetFont(ft)
}

func (f *Frame) SetFont(ft *font.Font) {
	f.Font = ft
	f.Run.Reset(ft)
	f.Refresh()
}

// Bounds returns the frame's clipping rectangle
func (f *Frame) Bounds() image.Rectangle {
	return f.r.Bounds()
}

// Full returns true if the last line in the frame is full
func (f *Frame) Full() bool {
	return f.full == 1
}

// Maxline returns the max number of wrapped lines fitting on the frame
func (f *Frame) MaxLine() int {
	return f.maxlines
}

// Line returns the number of wrapped lines currently in the frame
func (f *Frame) Line() int {
	return f.Nlines
}

// Len returns the number of bytes currently in the frame
func (f *Frame) Len() int64 {
	return f.Nchars
}

// Dot returns the range of the selected text
func (f *Frame) Dot() (p0, p1 int64) {
	return f.p0, f.p1
}

func (f *Frame) setrects(r image.Rectangle, b *image.RGBA) {
	f.b = b
	f.r = r
	f.r.Max.Y -= f.r.Dy() % f.Font.Dy()
	f.maxlines = f.r.Dy() / f.Font.Dy()
}

func (f *Frame) clear(freeall bool) {
	if f.Nbox != 0 {
		f.Run.Delete(0, f.Nbox-1)
	}
	if f.Box != nil {
		free(f.Box)
	}
	if freeall {
		// TODO: unnecessary
		freeimage(f.tick)
		freeimage(f.tickback)
		f.tick = nil
		f.tickback = nil
	}
	f.Box = nil
	f.Ticked = false
}

func free(i interface{}) {
}
func freeimage(i image.Image) {
}
<commit_msg>add ForceUTF8 and ForceElastic<commit_after>package frame

import (
	"github.com/as/drawcache"
	"github.com/as/frame/box"
	"github.com/as/frame/font"
	"image"
	"image/draw"
)

var(
	ForceElastic bool
	ForceUTF8 bool
)

const (
	FrElastic = 1 << iota
	FrUTF8
)

// Frame is a write-only container for editable text
type Frame struct {
	b *image.RGBA
	r image.Rectangle
	box.Run
	ir *box.Run

	p0 int64
	p1 int64

	flags int

	Font *font.Font
	Color
	Ticked bool
	Scroll func(int)
	drawcache.Drawer
	op draw.Op

	maxtab int
	full   int

	tick      draw.Image
	tickback  draw.Image
	tickscale int
	tickoff   bool
	maxlines  int
	modified  bool
	noredraw  bool

	pts     [][2]image.Point
	hexFont *font.Font
	hex     []draw.Image

	// Points to the font subpackage's StringN?BG or RuneN?BG functions
	stringBG     func(draw.Image, image.Point, image.Image, image.Point, *font.Font, []byte, image.Image, image.Point) int
	stringNBG    func(draw.Image, image.Point, image.Image, image.Point, *font.Font, []byte) int
	newRulerFunc func(s []byte, ft *font.Font) box.Ruler

	elastic bool
}

func (f *Frame) SetFlags(flat int) {
	//TODO(as)
}

func newRuneFrame(r image.Rectangle, ft *font.Font, b *image.RGBA, cols Color, flag ...int) *Frame {
	fl := getflag(flag)
	mintab := ft.Measure(' ')
	maxtab := mintab * 4
	elastic := fl&FrElastic != 0
	if elastic {
		mintab = maxtab
	}
	f := &Frame{
		Font:         ft,
		maxtab:       maxtab,
		Color:        cols,
		Run:          box.NewRun(mintab, 5000, ft, box.NewRuneRuler),
		stringBG:     font.RuneBG,
		stringNBG:    font.RuneNBG,
		newRulerFunc: box.NewRuneRuler,
		op:           draw.Src,
	}
	f.setrects(r, b)
	f.inittick()
	run := box.NewRun(mintab, 5000, ft, box.NewRuneRuler)
	f.ir = &run
	f.Drawer = drawcache.New()
	return f
}

func getflag(flag []int) (fl int) {
	if len(flag) != 0 {
		fl = flag[0]
	}
	if ForceElastic{
		fl |= FrElastic
	}
	if ForceUTF8{
		fl |= FrUTF8
	}
	return fl
}

// New creates a new frame on b with bounds r. The image b is used
// as the frame's internal bitmap cache.
func New(r image.Rectangle, ft *font.Font, b *image.RGBA, cols Color, flag ...int) *Frame {
	fl := getflag(flag)
	if fl&FrUTF8 != 0 {
		return newRuneFrame(r, ft, b, cols, flag...)
	}
	mintab := ft.Measure(' ')
	maxtab := mintab * 4
	elastic := fl&FrElastic != 0
	if elastic {
		mintab = maxtab
	}
	f := &Frame{
		Font:         ft,
		maxtab:       maxtab,
		Color:        cols,
		Run:          box.NewRun(mintab, 5000, ft),
		stringBG:     font.StringBG,
		stringNBG:    font.StringNBG,
		newRulerFunc: box.NewByteRuler,
		op:           draw.Src,
		elastic:      elastic,
	}
	f.setrects(r, b)
	f.inittick()
	run := box.NewRun(mintab, 5000, ft)
	f.ir = &run
	f.Drawer = drawcache.New()
	return f
}

func (f *Frame) RGBA() *image.RGBA {
	return f.b
}
func (f *Frame) Size() image.Point {
	r := f.RGBA().Bounds()
	return image.Pt(r.Dx(), r.Dy())
}

// Dirty returns true if the contents of the frame have changes since the last redraw
func (f *Frame) Dirty() bool {
	return f.modified
}

// SetDirty alters the frame's internal state
func (f *Frame) SetDirty(dirty bool) {
	f.modified = dirty
}

func (f *Frame) SetOp(op draw.Op) {
	f.op = op

}

// Close closes the frame
func (f *Frame) Close() error {
	return nil
}

// Reset resets the frame to display on image b with bounds r and font ft.
func (f *Frame) Reset(r image.Rectangle, b *image.RGBA, ft *font.Font) {
	f.r = r
	f.b = b
	f.SetFont(ft)
}

func (f *Frame) SetFont(ft *font.Font) {
	f.Font = ft
	f.Run.Reset(ft)
	f.Refresh()
}

// Bounds returns the frame's clipping rectangle
func (f *Frame) Bounds() image.Rectangle {
	return f.r.Bounds()
}

// Full returns true if the last line in the frame is full
func (f *Frame) Full() bool {
	return f.full == 1
}

// Maxline returns the max number of wrapped lines fitting on the frame
func (f *Frame) MaxLine() int {
	return f.maxlines
}

// Line returns the number of wrapped lines currently in the frame
func (f *Frame) Line() int {
	return f.Nlines
}

// Len returns the number of bytes currently in the frame
func (f *Frame) Len() int64 {
	return f.Nchars
}

// Dot returns the range of the selected text
func (f *Frame) Dot() (p0, p1 int64) {
	return f.p0, f.p1
}

func (f *Frame) setrects(r image.Rectangle, b *image.RGBA) {
	f.b = b
	f.r = r
	f.r.Max.Y -= f.r.Dy() % f.Font.Dy()
	f.maxlines = f.r.Dy() / f.Font.Dy()
}

func (f *Frame) clear(freeall bool) {
	if f.Nbox != 0 {
		f.Run.Delete(0, f.Nbox-1)
	}
	if f.Box != nil {
		free(f.Box)
	}
	if freeall {
		// TODO: unnecessary
		freeimage(f.tick)
		freeimage(f.tickback)
		f.tick = nil
		f.tickback = nil
	}
	f.Box = nil
	f.Ticked = false
}

func free(i interface{}) {
}
func freeimage(i image.Image) {
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"encoding/json"
	"math"

	"github.com/ii/xds-test-harness/internal/types"
	"github.com/cucumber/godog"
	"github.com/cucumber/godog/colors"
	"github.com/rs/zerolog/log"
)

const (
	passedEmoji    = "✅"
	skippedEmoji   = "➖"
	failedEmoji    = "❌"
	undefinedEmoji = "❓"
	pendingEmoji   = "🚧"
)

var (
	red   = colors.Red
	green = colors.Green
)

func init() {
	godog.Format("emoji", "Progress formatter with emojis", emojiFormatterFunc)
}

func emojiFormatterFunc(suite string, out io.Writer) godog.Formatter {
	return newEmojiFmt(suite, out)
}

type emojiFmt struct {
	*godog.ProgressFmt

	out io.Writer
}

func newEmojiFmt(suite string, out io.Writer) *emojiFmt {
	return &emojiFmt{
		ProgressFmt: godog.NewProgressFmt(suite, out),
		out:         out,
	}
}

type StepOrder int
const (
	First StepOrder = iota
	Middle
	Last
)

type StepResultStatus int
const (
	// order based on godog's internal model.StepResultStatus
	// but it is internal, and so cannot be used.
	Passed StepResultStatus = iota
	Failed
	Skipped
	Undefined
	Pending
)

// func (f *emojiFmt) TestRunStarted() {}

func (f *emojiFmt) Passed(scenario *godog.Scenario, step *godog.Step, match *godog.StepDefinition) {
	f.ProgressFmt.Base.Passed(scenario, step, match)
	f.ProgressFmt.Base.Lock.Lock()
	defer f.ProgressFmt.Base.Lock.Unlock()
	f.step(step.Id, scenario)
}

func (f *emojiFmt) Skipped(scenario *godog.Scenario, step *godog.Step, match *godog.StepDefinition) {
	f.ProgressFmt.Base.Skipped(scenario, step, match)
	f.ProgressFmt.Base.Lock.Lock()
	defer f.ProgressFmt.Base.Lock.Unlock()
	f.step(step.Id, scenario)
}

func (f *emojiFmt) Undefined(scenario *godog.Scenario, step *godog.Step, match *godog.StepDefinition) {
	f.ProgressFmt.Base.Undefined(scenario, step, match)
	f.ProgressFmt.Base.Lock.Lock()
	defer f.ProgressFmt.Base.Lock.Unlock()
	f.step(step.Id, scenario)
}

func (f *emojiFmt) Failed(scenario *godog.Scenario, step *godog.Step, match *godog.StepDefinition, err error) {
	f.ProgressFmt.Base.Failed(scenario, step, match, err)
	f.ProgressFmt.Base.Lock.Lock()
	defer f.ProgressFmt.Base.Lock.Unlock()
	f.step(step.Id, scenario)
}

func (f *emojiFmt) Pending(scenario *godog.Scenario, step *godog.Step, match *godog.StepDefinition) {
	f.ProgressFmt.Base.Pending(scenario, step, match)
	f.ProgressFmt.Base.Lock.Lock()
	defer f.ProgressFmt.Base.Lock.Unlock()
	f.step(step.Id, scenario)
}

func (f *emojiFmt) Summary() {
	results := &types.VariantResults{}
	results.Passed = f.countByStatus(Passed)
	results.Failed = f.countByStatus(Failed)
	results.Skipped = f.countByStatus(Skipped)
	results.Undefined = f.countByStatus(Undefined)
	results.Pending = f.countByStatus(Pending)
	results.FailedScenarios = f.gatherFailedScenarios()
	data, err := json.MarshalIndent(results, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
	fmt.Fprintf(f.out, "%s\n",string(data))
}

func (f *emojiFmt) step(pickleStepID string, scenario *godog.Scenario) {
	pickleStepResult := f.Storage.MustGetPickleStepResult(pickleStepID)
	position := scenarioPosition(pickleStepID, scenario)
	if position == Last {
		passed := true
		var failedStep string
		results := f.Storage.MustGetPickleStepResultsByPickleID(scenario.Id)
		for _, result := range results {
			r := fmt.Sprintf("%v", result.Status)
			if r == "failed" {
				passed = false
				failedStep = "this is the failed step"
				break
			}
		}
		if passed {
			log.Info().Msgf("[%v]%v", green("PASSED"), scenario.Name)
		} else {
			log.Info().Str("failed step", failedStep).Msgf("[%v]%v", red("FAILED"), scenario.Name)
		}
	} else {
		switch pickleStepResult.Status {
		case godog.StepPassed:
			fmt.Printf(" %s", passedEmoji)
		case godog.StepSkipped:
			fmt.Printf(" %s", skippedEmoji)
		case godog.StepFailed:
			fmt.Printf(" %s", failedEmoji)
		case godog.StepUndefined:
			fmt.Printf(" %s", undefinedEmoji)
		case godog.StepPending:
			fmt.Printf(" %s", pendingEmoji)
		}

	}
	*f.Steps++

	if math.Mod(float64(*f.Steps), float64(f.StepsPerRow)) == 0 {
		fmt.Fprintf(f.out, " %d\n", *f.Steps)
	}
}

func (f *emojiFmt) countByStatus(status StepResultStatus) int {
	switch status {
	case Passed:
		return len(f.Storage.MustGetPickleStepResultsByStatus(0))
	case Failed:
		return len(f.Storage.MustGetPickleStepResultsByStatus(1))
	case Skipped:
		return len(f.Storage.MustGetPickleStepResultsByStatus(2))
	case Undefined:
		return len(f.Storage.MustGetPickleStepResultsByStatus(3))
	case Pending:
		return len(f.Storage.MustGetPickleStepResultsByStatus(4))
	default:
		return 0
	}
}

func (f *emojiFmt) gatherFailedScenarios () (failedScenarios []types.FailedScenario) {
	failedSteps := f.Storage.MustGetPickleStepResultsByStatus(1)
	for _, failure := range failedSteps {
		scenario := f.Storage.MustGetPickle(failure.PickleID)
		feature := f.Storage.MustGetFeature(scenario.Uri)
		pickleStep := f.Storage.MustGetPickleStep(failure.PickleStepID)
		step := feature.FindStep(pickleStep.AstNodeIds[0])

		fs := types.FailedScenario{
			Name:       scenario.Name,
			FailedStep: step.Text,
			Line:       fmt.Sprintf("%v:%v",feature.Uri,step.Location.Line),
		}

		failedScenarios = append(failedScenarios, fs)
	}
	return failedScenarios
}

func scenarioPosition(stepId string, scenario *godog.Scenario) StepOrder {
	stepIds := []string{}
	lastIndex := len(scenario.Steps) - 1
	for _, step := range scenario.Steps {
		stepIds = append(stepIds, step.Id)
	}
	index := indexOf(stepId, stepIds)
	if index == 0 {
		return First
	}
	if index == lastIndex {
		return Last
	}
	return Middle

}

func indexOf(val string, arr []string) int {
	for i, v := range arr {
		if v == val {
			return i
		}
	}
	return -1
}
<commit_msg>delete wip formatter<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"index/suffixarray"
	"runtime"
	"sort"
	"sync"
)

type line struct {
	off   int    // Offset of line
	value []byte // One line from source slice
}

type delta struct {
	off   int // Offset of existing value
	index int // Index of replacement value
}

// TODO Are there any errors that need handling?
func producer(input <-chan line, index *replaceIndex) []delta {

	var wg sync.WaitGroup
	runtime.GOMAXPROCS(runtime.NumCPU()) // Maximum CPU utilisation please!
	maxGophers := runtime.GOMAXPROCS(0)
	wg.Add(maxGophers)

	deltaChan := make(chan []delta)
	done := make(chan bool)
	defer close(done)

	fmt.Printf("Launching %v gophers ...\n", maxGophers)

	for i := 0; i < maxGophers; i++ {
		go func() {
			for t := range input {
				select {
				case deltaChan <- makeDeltas(t, index, i):
				case <-done:
					return
				}
			}
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(deltaChan)
	}()

	fmt.Printf("Collecting deltas: \n")
	deltas := make([]delta, 0)
	for d := range deltaChan {
		if len(d) > 0 {
			deltas = append(deltas, d...)
		}
	}

	fmt.Printf("\nGot %v deltas.\n", len(deltas))

	sort.Sort(ByLine(deltas))
	return deltas
}

// Make deltas
func makeDeltas(t line, index *replaceIndex, id int) []delta {

	s := make([]delta, 0)

	lineIndex := suffixarray.New(t.value)

	for i := 0; i < index.len(); i++ {
		results := lineIndex.Lookup(index.readItem(i).find, -1)
		if len(results) > 0 {
			for _, p := range results {
				d := delta{off: t.off + p, index: i}
				fmt.Printf(".")
				s = append(s, d)
			}
		}
	}

	return s
}

type ByLine []delta

func (d ByLine) Len() int {
	return len(d)
}

func (d ByLine) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

func (d ByLine) Less(i, j int) bool {
	return d[i].off < d[j].off
}
<commit_msg>Fixed partial word match bug.<commit_after>package main

import (
	"fmt"
	"index/suffixarray"
	"regexp/syntax"
	"runtime"
	"sort"
	"sync"
)

type line struct {
	off   int    // Offset of line
	value []byte // One line from source slice
}

type delta struct {
	off   int // Offset of existing value
	index int // Index of replacement value
}

// TODO Are there any errors that need handling?
func producer(input <-chan line, index *replaceIndex) []delta {

	var wg sync.WaitGroup
	runtime.GOMAXPROCS(runtime.NumCPU()) // Maximum CPU utilisation please!
	maxGophers := runtime.GOMAXPROCS(0)
	wg.Add(maxGophers)

	deltaChan := make(chan []delta)
	done := make(chan bool)
	defer close(done)

	fmt.Printf("Launching %v gophers ...\n", maxGophers)

	for i := 0; i < maxGophers; i++ {
		go func() {
			for t := range input {
				select {
				case deltaChan <- makeDeltas(t, index, i):
				case <-done:
					return
				}
			}
			wg.Done()
		}()
	}

	go func() {
		wg.Wait()
		close(deltaChan)
	}()

	fmt.Printf("Collecting deltas... \n")
	deltas := make([]delta, 0)
	for d := range deltaChan {
		if len(d) > 0 {
			deltas = append(deltas, d...)
		}
	}

	fmt.Printf("Got %v deltas.\n", len(deltas))

	sort.Sort(ByLine(deltas))
	return deltas
}

// Make deltas
func makeDeltas(t line, index *replaceIndex, id int) []delta {

	s := make([]delta, 0)

	lineIndex := suffixarray.New(t.value)

	for i := 0; i < index.len(); i++ {
		results := lineIndex.Lookup(index.readItem(i).find, -1)
		if len(results) > 0 {
			for _, p := range results {
				// It's not a match if it's a partial word
				x := p + len(index.readItem(i).find) - 1
				if x < len(t.value) {
					if syntax.IsWordChar(rune(t.value[x])) && !syntax.IsWordChar(rune(t.value[x+1])) {
						d := delta{off: t.off + p, index: i}
						s = append(s, d)
					}
				} else {
					d := delta{off: t.off + p, index: i}
					s = append(s, d)
				}
			}
		}
	}

	// TODO Optional memory optimiser. Use less system RAM at the expense of CPU.
	// debug.FreeOSMemory()

	return s
}

type ByLine []delta

func (d ByLine) Len() int {
	return len(d)
}

func (d ByLine) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

func (d ByLine) Less(i, j int) bool {
	return d[i].off < d[j].off
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/errors"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/progress"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

var (
	filterSmudgeSkip = false
)

func clean(to io.Writer, reader io.Reader, fileName string) error {
	var cb progress.CopyCallback
	var file *os.File
	var fileSize int64
	if len(fileName) > 0 {
		stat, err := os.Stat(fileName)
		if err == nil && stat != nil {
			fileSize = stat.Size()

			localCb, localFile, err := lfs.CopyCallbackFile("clean", fileName, 1, 1)
			if err != nil {
				Error(err.Error())
			} else {
				cb = localCb
				file = localFile
			}
		}
	}

	cleaned, err := lfs.PointerClean(reader, fileName, fileSize, cb)
	if file != nil {
		file.Close()
	}

	if cleaned != nil {
		defer cleaned.Teardown()
	}

	if errors.IsCleanPointerError(err) {
		// If the contents read from the working directory was _already_
		// a pointer, we'll get a `CleanPointerError`, with the context
		// containing the bytes that we should write back out to Git.
		_, err = to.Write(errors.GetContext(err, "bytes").([]byte))
		return err
	}

	if err != nil {
		Panic(err, "Error cleaning asset.")
	}

	tmpfile := cleaned.Filename
	mediafile, err := lfs.LocalMediaPath(cleaned.Oid)
	if err != nil {
		Panic(err, "Unable to get local media path.")
	}

	if stat, _ := os.Stat(mediafile); stat != nil {
		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
		}
		Debug("%s exists", mediafile)
	} else {
		if err := os.Rename(tmpfile, mediafile); err != nil {
			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
		}

		Debug("Writing %s", mediafile)
	}

	_, err = cleaned.Pointer.Encode(to)
	return err
}

func smudge(to io.Writer, reader io.Reader, filename string) error {
	var pbuf bytes.Buffer
	reader = io.TeeReader(reader, &pbuf)

	ptr, err := lfs.DecodePointer(reader)
	if err != nil {
		// If we tried to decode a pointer out of the data given to us,
		// and the file was _empty_, write out an empty file in
		// response. This occurs because when the clean filter
		// encounters an empty file, and writes out an empty file,
		// instead of a pointer.
		//
		// TODO(taylor): figure out if there is more data on the reader,
		// and buffer that as well.
		if len(pbuf.Bytes()) == 0 {
			if _, cerr := io.Copy(to, &pbuf); cerr != nil {
				Panic(cerr, "Error writing data to stdout:")
			}
			return nil
		}

		return err
	}

	lfs.LinkOrCopyFromReference(ptr.Oid, ptr.Size)

	cb, file, err := lfs.CopyCallbackFile("smudge", filename, 1, 1)
	if err != nil {
		Error(err.Error())
	}

	cfg := config.Config
	download := lfs.FilenamePassesIncludeExcludeFilter(filename, cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	if filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false) {
		download = false
	}

	sbuf := new(bytes.Buffer)
	err = ptr.Smudge(sbuf, filename, download, TransferManifest(), cb)
	if file != nil {
		file.Close()
	}

	if err != nil {
		// Download declined error is ok to skip if we weren't requesting download
		if !(errors.IsDownloadDeclinedError(err) && !download) {
			LoggedError(err, "Error downloading object: %s (%s)", filename, ptr.Oid)
			if !cfg.SkipDownloadErrors() {
				// TODO: What to do best here?
				os.Exit(2)
			}
		}

		_, err = ptr.Encode(to)
		return err
	}

	_, err = ptr.Encode(to)
	return err
}

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewObjectScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

Scan:
	for s.Scan() {
		var err error
		var w io.Writer

		switch req := s.Request(); req.Header["command"] {
		case "clean":
			w = git.NewPacketWriter(os.Stdout, cleanFilterBufferCapacity)
			err = clean(w, req.Payload, req.Header["pathname"])
		case "smudge":
			w = git.NewPacketWriter(os.Stdout, smudgeFilterBufferCapacity)
			err = smudge(w, req.Payload, req.Header["pathname"])
		default:
			fmt.Errorf("Unknown command %s", cmd)
			break Scan
		}

		if err == nil {
			_, err = w.Write(nil)
		}

		var status string
		if err != nil && err != io.EOF {
			status = "error"
		} else {
			status = "success"
		}
		s.WriteStatus(status)
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

func init() {
	RegisterCommand("filter", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<commit_msg>commands/filter: smudge the file, not the buffer<commit_after>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/errors"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/progress"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

var (
	filterSmudgeSkip = false
)

func clean(to io.Writer, reader io.Reader, fileName string) error {
	var cb progress.CopyCallback
	var file *os.File
	var fileSize int64
	if len(fileName) > 0 {
		stat, err := os.Stat(fileName)
		if err == nil && stat != nil {
			fileSize = stat.Size()

			localCb, localFile, err := lfs.CopyCallbackFile("clean", fileName, 1, 1)
			if err != nil {
				Error(err.Error())
			} else {
				cb = localCb
				file = localFile
			}
		}
	}

	cleaned, err := lfs.PointerClean(reader, fileName, fileSize, cb)
	if file != nil {
		file.Close()
	}

	if cleaned != nil {
		defer cleaned.Teardown()
	}

	if errors.IsCleanPointerError(err) {
		// If the contents read from the working directory was _already_
		// a pointer, we'll get a `CleanPointerError`, with the context
		// containing the bytes that we should write back out to Git.
		_, err = to.Write(errors.GetContext(err, "bytes").([]byte))
		return err
	}

	if err != nil {
		Panic(err, "Error cleaning asset.")
	}

	tmpfile := cleaned.Filename
	mediafile, err := lfs.LocalMediaPath(cleaned.Oid)
	if err != nil {
		Panic(err, "Unable to get local media path.")
	}

	if stat, _ := os.Stat(mediafile); stat != nil {
		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
		}
		Debug("%s exists", mediafile)
	} else {
		if err := os.Rename(tmpfile, mediafile); err != nil {
			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
		}

		Debug("Writing %s", mediafile)
	}

	_, err = cleaned.Pointer.Encode(to)
	return err
}

func smudge(to io.Writer, reader io.Reader, filename string) error {
	var pbuf bytes.Buffer
	reader = io.TeeReader(reader, &pbuf)

	ptr, err := lfs.DecodePointer(reader)
	if err != nil {
		// If we tried to decode a pointer out of the data given to us,
		// and the file was _empty_, write out an empty file in
		// response. This occurs because when the clean filter
		// encounters an empty file, and writes out an empty file,
		// instead of a pointer.
		//
		// TODO(taylor): figure out if there is more data on the reader,
		// and buffer that as well.
		if len(pbuf.Bytes()) == 0 {
			if _, cerr := io.Copy(to, &pbuf); cerr != nil {
				Panic(cerr, "Error writing data to stdout:")
			}
			return nil
		}

		return err
	}

	lfs.LinkOrCopyFromReference(ptr.Oid, ptr.Size)

	cb, file, err := lfs.CopyCallbackFile("smudge", filename, 1, 1)
	if err != nil {
		Error(err.Error())
	}

	cfg := config.Config
	download := lfs.FilenamePassesIncludeExcludeFilter(filename, cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	if filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false) {
		download = false
	}

	err = ptr.Smudge(to, filename, download, TransferManifest(), cb)
	if file != nil {
		file.Close()
	}

	if err != nil {
		// Download declined error is ok to skip if we weren't requesting download
		if !(errors.IsDownloadDeclinedError(err) && !download) {
			LoggedError(err, "Error downloading object: %s (%s)", filename, ptr.Oid)
			if !cfg.SkipDownloadErrors() {
				// TODO: What to do best here?
				os.Exit(2)
			}
		}

		_, err = ptr.Encode(to)
		return err
	}

	return nil
}

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewObjectScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

Scan:
	for s.Scan() {
		var err error
		var w io.Writer

		switch req := s.Request(); req.Header["command"] {
		case "clean":
			w = git.NewPacketWriter(os.Stdout, cleanFilterBufferCapacity)
			err = clean(w, req.Payload, req.Header["pathname"])
		case "smudge":
			w = git.NewPacketWriter(os.Stdout, smudgeFilterBufferCapacity)
			err = smudge(w, req.Payload, req.Header["pathname"])
		default:
			fmt.Errorf("Unknown command %s", cmd)
			break Scan
		}

		if err == nil {
			_, err = w.Write(nil)
		}

		var status string
		if err != nil && err != io.EOF {
			status = "error"
		} else {
			status = "success"
		}
		s.WriteStatus(status)
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

func init() {
	RegisterCommand("filter", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.107"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.74", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.108 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.108"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.75", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/errors"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/progress"
	"github.com/spf13/cobra"
)

var (
	filterSmudgeSkip = false
)

func clean(reader io.Reader, fileName string) ([]byte, error) {
	var cb progress.CopyCallback
	var file *os.File
	var fileSize int64
	if len(fileName) > 0 {
		stat, err := os.Stat(fileName)
		if err == nil && stat != nil {
			fileSize = stat.Size()

			localCb, localFile, err := lfs.CopyCallbackFile("clean", fileName, 1, 1)
			if err != nil {
				Error(err.Error())
			} else {
				cb = localCb
				file = localFile
			}
		}
	}

	cleaned, err := lfs.PointerClean(reader, fileName, fileSize, cb)
	if file != nil {
		file.Close()
	}

	if cleaned != nil {
		defer cleaned.Teardown()
	}

	if errors.IsCleanPointerError(err) {
		// TODO: report errors differently!
		// os.Stdout.Write(errors.GetContext(err, "bytes").([]byte))
		return errors.GetContext(err, "bytes").([]byte), nil
	}

	if err != nil {
		Panic(err, "Error cleaning asset.")
	}

	tmpfile := cleaned.Filename
	mediafile, err := lfs.LocalMediaPath(cleaned.Oid)
	if err != nil {
		Panic(err, "Unable to get local media path.")
	}

	if stat, _ := os.Stat(mediafile); stat != nil {
		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
		}
		Debug("%s exists", mediafile)
	} else {
		if err := os.Rename(tmpfile, mediafile); err != nil {
			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
		}

		Debug("Writing %s", mediafile)
	}

	return []byte(cleaned.Pointer.Encoded()), nil
}

func smudge(reader io.Reader, filename string) ([]byte, error) {
	ptr, err := lfs.DecodePointer(reader)
	if err != nil {
		// mr := io.MultiReader(b, reader)
		// _, err := io.Copy(os.Stdout, mr)
		// if err != nil {
		// 	Panic(err, "Error writing data to stdout:")
		// }
		var content []byte
		reader.Read(content)
		return content, nil
	}

	lfs.LinkOrCopyFromReference(ptr.Oid, ptr.Size)

	cb, file, err := lfs.CopyCallbackFile("smudge", filename, 1, 1)
	if err != nil {
		Error(err.Error())
	}

	cfg := config.Config
	download := lfs.FilenamePassesIncludeExcludeFilter(filename, cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	if filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false) {
		download = false
	}

	buf := new(bytes.Buffer)
	err = ptr.Smudge(buf, filename, download, TransferManifest(), cb)
	if file != nil {
		file.Close()
	}

	if err != nil {
		// Download declined error is ok to skip if we weren't requesting download
		if !(errors.IsDownloadDeclinedError(err) && !download) {
			LoggedError(err, "Error downloading object: %s (%s)", filename, ptr.Oid)
			if !cfg.SkipDownloadErrors() {
				// TODO: What to do best here?
				os.Exit(2)
			}
		}

		return []byte(ptr.Encoded()), nil
	}

	return buf.Bytes(), nil
}

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewObjectScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

Scan:
	for s.Scan() {
		req := s.Request()

		// TODO:
		// clean/smudge should also take a Writer instead of returning []byte
		var outputData []byte
		var err error

		switch req.Header["command"] {
		case "clean":
			outputData, err = clean(req.Payload, req.Header["pathname"])
		case "smudge":
			outputData, err = smudge(req.Payload, req.Header["pathname"])
		default:
			fmt.Errorf("Unknown command %s", cmd)
			break Scan
		}

		if err != nil {
			s.WriteStatus("error")

		} else {
			s.WriteStatus("success")
			s.WriteResponse(outputData)
		}
	}

	if err := s.Err(); err != nil {
		ExitWithError(err)
	}
}

func init() {
	RegisterCommand("filter", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<commit_msg>commands: remove superfluous line<commit_after>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"github.com/github/git-lfs/config"
	"github.com/github/git-lfs/errors"
	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/progress"
	"github.com/spf13/cobra"
)

var (
	filterSmudgeSkip = false
)

func clean(reader io.Reader, fileName string) ([]byte, error) {
	var cb progress.CopyCallback
	var file *os.File
	var fileSize int64
	if len(fileName) > 0 {
		stat, err := os.Stat(fileName)
		if err == nil && stat != nil {
			fileSize = stat.Size()

			localCb, localFile, err := lfs.CopyCallbackFile("clean", fileName, 1, 1)
			if err != nil {
				Error(err.Error())
			} else {
				cb = localCb
				file = localFile
			}
		}
	}

	cleaned, err := lfs.PointerClean(reader, fileName, fileSize, cb)
	if file != nil {
		file.Close()
	}

	if cleaned != nil {
		defer cleaned.Teardown()
	}

	if errors.IsCleanPointerError(err) {
		// TODO: report errors differently!
		// os.Stdout.Write(errors.GetContext(err, "bytes").([]byte))
		return errors.GetContext(err, "bytes").([]byte), nil
	}

	if err != nil {
		Panic(err, "Error cleaning asset.")
	}

	tmpfile := cleaned.Filename
	mediafile, err := lfs.LocalMediaPath(cleaned.Oid)
	if err != nil {
		Panic(err, "Unable to get local media path.")
	}

	if stat, _ := os.Stat(mediafile); stat != nil {
		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
		}
		Debug("%s exists", mediafile)
	} else {
		if err := os.Rename(tmpfile, mediafile); err != nil {
			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
		}

		Debug("Writing %s", mediafile)
	}

	return []byte(cleaned.Pointer.Encoded()), nil
}

func smudge(reader io.Reader, filename string) ([]byte, error) {
	ptr, err := lfs.DecodePointer(reader)
	if err != nil {
		// mr := io.MultiReader(b, reader)
		// _, err := io.Copy(os.Stdout, mr)
		// if err != nil {
		// 	Panic(err, "Error writing data to stdout:")
		// }
		var content []byte
		reader.Read(content)
		return content, nil
	}

	lfs.LinkOrCopyFromReference(ptr.Oid, ptr.Size)

	cb, file, err := lfs.CopyCallbackFile("smudge", filename, 1, 1)
	if err != nil {
		Error(err.Error())
	}

	cfg := config.Config
	download := lfs.FilenamePassesIncludeExcludeFilter(filename, cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	if filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false) {
		download = false
	}

	buf := new(bytes.Buffer)
	err = ptr.Smudge(buf, filename, download, TransferManifest(), cb)
	if file != nil {
		file.Close()
	}

	if err != nil {
		// Download declined error is ok to skip if we weren't requesting download
		if !(errors.IsDownloadDeclinedError(err) && !download) {
			LoggedError(err, "Error downloading object: %s (%s)", filename, ptr.Oid)
			if !cfg.SkipDownloadErrors() {
				// TODO: What to do best here?
				os.Exit(2)
			}
		}

		return []byte(ptr.Encoded()), nil
	}

	return buf.Bytes(), nil
}

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewObjectScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

Scan:
	for s.Scan() {
		req := s.Request()

		// TODO:
		// clean/smudge should also take a Writer instead of returning []byte
		var outputData []byte
		var err error

		switch req.Header["command"] {
		case "clean":
			outputData, err = clean(req.Payload, req.Header["pathname"])
		case "smudge":
			outputData, err = smudge(req.Payload, req.Header["pathname"])
		default:
			fmt.Errorf("Unknown command %s", cmd)
			break Scan
		}

		if err != nil {
			s.WriteStatus("error")
		} else {
			s.WriteStatus("success")
			s.WriteResponse(outputData)
		}
	}

	if err := s.Err(); err != nil {
		ExitWithError(err)
	}
}

func init() {
	RegisterCommand("filter", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.206"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.173", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.207 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.207"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.174", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package logging

import (
	"fmt"
	"path/filepath"
	"strings"
	"unicode"
)

// Formatter objects are used by their Handlers to format events into a single
// string that the Handler can write (or not write) somewhere else.  The same
// Formatter object should not be used by multiple Handlers.
type Formatter interface {
	// Format takes the event object and formats it into a string for its
	// Handler to do something with.
	Format(event *Event) string
}

// FormatterFunc implements the Formatter interface through a single function.
type FormatterFunc func(e *Event) string

// Format implements Formatter by calling the format message.
func (f FormatterFunc) Format(e *Event) string { return f(e) }

// DefaultFormatter Sprintf's all of the information within its provided Event
// in an arbitrarily decided format that *I* just happen to like.
// Your mileage may vary.
type DefaultFormatter struct{}

// Format returns the event with the following layout:
//
//    yyyy-mm-dd HH:MM:SS:  Level:  LoggerName:  at FuncName in File, line Line:
//    	fmt.Sprintf(Msg, Args...)
func (f DefaultFormatter) Format(event *Event) string {
	year, month, day := event.Time.Date()
	hour, minute, second := event.Time.Clock()
	levelString := event.Level.String()
	rightAlignedLevel := strings.Repeat(" ", 8-len(levelString)) + levelString
	msg := event.Msg
	if len(event.Args) > 0 {
		msg = fmt.Sprintf(event.Msg, event.Args...)
	}
	lines := strings.Split(msg, "\n")
	for i, line := range lines {
		lines[i] = "\t" + line
	}
	msg = strings.Join(lines, "\n")
	return fmt.Sprintf(
		"%d-%02d-%02d %02d:%02d:%02d:  %s:  %s:  at %s in %s, line %d:\n%s\n\n",
		year, month, day, hour, minute, second,
		rightAlignedLevel, event.Name, event.FuncName,
		filepath.Base(event.File), event.Line,
		strings.TrimRightFunc(msg, unicode.IsSpace))
}

type GoFormatter struct{}

func (f GoFormatter) Format(event *Event) string {
	year, month, day := event.Time.Date()
	hour, minute, second := event.Time.Clock()
	levelString := event.Level.String()
	rightAlignedLevel := strings.Repeat(" ", 8-len(levelString)) + levelString
	msg := event.Msg
	if len(event.Args) > 0 {
		msg = fmt.Sprintf(event.Msg, event.Args...)
	}
	lines := strings.Split(msg, "\n")
	for i, line := range lines {
		lines[i] = "\t" + line
	}
	msg = strings.Join(lines, "\n")
	return fmt.Sprintf(
		"%d-%02d-%02d %02d:%02d:%02d:  %s:  %s:  %s:  %s\n\t%s:%d\n",
		year, month, day, hour, minute, second,
		rightAlignedLevel, event.Name,
		strings.TrimRightFunc(msg, unicode.IsSpace),
		event.FuncName,
		event.File, event.Line,
	)
}
<commit_msg>fix: extend level field in GoFormatter<commit_after>package logging

import (
	"fmt"
	"path/filepath"
	"strings"
	"unicode"
)

// Formatter objects are used by their Handlers to format events into a single
// string that the Handler can write (or not write) somewhere else.  The same
// Formatter object should not be used by multiple Handlers.
type Formatter interface {
	// Format takes the event object and formats it into a string for its
	// Handler to do something with.
	Format(event *Event) string
}

// FormatterFunc implements the Formatter interface through a single function.
type FormatterFunc func(e *Event) string

// Format implements Formatter by calling the format message.
func (f FormatterFunc) Format(e *Event) string { return f(e) }

// DefaultFormatter Sprintf's all of the information within its provided Event
// in an arbitrarily decided format that *I* just happen to like.
// Your mileage may vary.
type DefaultFormatter struct{}

// Format returns the event with the following layout:
//
//    yyyy-mm-dd HH:MM:SS:  Level:  LoggerName:  at FuncName in File, line Line:
//    	fmt.Sprintf(Msg, Args...)
func (f DefaultFormatter) Format(event *Event) string {
	year, month, day := event.Time.Date()
	hour, minute, second := event.Time.Clock()
	levelString := event.Level.String()
	rightAlignedLevel := strings.Repeat(" ", 8-len(levelString)) + levelString
	msg := event.Msg
	if len(event.Args) > 0 {
		msg = fmt.Sprintf(event.Msg, event.Args...)
	}
	lines := strings.Split(msg, "\n")
	for i, line := range lines {
		lines[i] = "\t" + line
	}
	msg = strings.Join(lines, "\n")
	return fmt.Sprintf(
		"%d-%02d-%02d %02d:%02d:%02d:  %s:  %s:  at %s in %s, line %d:\n%s\n\n",
		year, month, day, hour, minute, second,
		rightAlignedLevel, event.Name, event.FuncName,
		filepath.Base(event.File), event.Line,
		strings.TrimRightFunc(msg, unicode.IsSpace))
}

type GoFormatter struct{}

func (f GoFormatter) Format(event *Event) string {
	year, month, day := event.Time.Date()
	hour, minute, second := event.Time.Clock()
	levelString := event.Level.String()
	rightAlignedLevel := strings.Repeat(" ", 20-len(levelString)) + levelString
	msg := event.Msg
	if len(event.Args) > 0 {
		msg = fmt.Sprintf(event.Msg, event.Args...)
	}
	lines := strings.Split(msg, "\n")
	for i, line := range lines {
		lines[i] = "\t" + line
	}
	msg = strings.Join(lines, "\n")
	return fmt.Sprintf(
		"%d-%02d-%02d %02d:%02d:%02d:  %s:  %s:  %s:  %s\n\t%s:%d\n",
		year, month, day, hour, minute, second,
		rightAlignedLevel, event.Name,
		strings.TrimRightFunc(msg, unicode.IsSpace),
		event.FuncName,
		event.File, event.Line,
	)
}
<|endoftext|>


<commit_before>package fs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	ds "github.com/jbenet/go-datastore"
	query "github.com/jbenet/go-datastore/query"
)

var ObjectKeySuffix = ".dsobject"

// Datastore uses a standard Go map for internal storage.
type Datastore struct {
	path string
}

// NewDatastore returns a new fs Datastore at given `path`
func NewDatastore(path string) (ds.Datastore, error) {
	if !isDir(path) {
		return nil, fmt.Errorf("Failed to find directory at: %v (file? perms?)", path)
	}

	return &Datastore{path: path}, nil
}

// KeyFilename returns the filename associated with `key`
func (d *Datastore) KeyFilename(key ds.Key) string {
	return filepath.Join(d.path, key.String(), ObjectKeySuffix)
}

// Put stores the given value.
func (d *Datastore) Put(key ds.Key, value interface{}) (err error) {

	// TODO: maybe use io.Readers/Writers?
	// r, err := dsio.CastAsReader(value)
	// if err != nil {
	// 	return err
	// }

	val, ok := value.([]byte)
	if !ok {
		return ds.ErrInvalidType
	}

	fn := d.KeyFilename(key)

	// mkdirall above.
	err = os.MkdirAll(filepath.Dir(fn), 0755)
	if err != nil {
		return err
	}

	return ioutil.WriteFile(fn, val, 0666)
}

// Get returns the value for given key
func (d *Datastore) Get(key ds.Key) (value interface{}, err error) {
	fn := d.KeyFilename(key)
	if !isFile(fn) {
		return nil, ds.ErrNotFound
	}

	return ioutil.ReadFile(fn)
}

// Has returns whether the datastore has a value for a given key
func (d *Datastore) Has(key ds.Key) (exists bool, err error) {
	return ds.GetBackedHas(d, key)
}

// Delete removes the value for given key
func (d *Datastore) Delete(key ds.Key) (err error) {
	fn := d.KeyFilename(key)
	if !isFile(fn) {
		return ds.ErrNotFound
	}

	return os.Remove(fn)
}

// KeyList returns a list of all keys in the datastore
func (d *Datastore) KeyList() ([]ds.Key, error) {

	keys := []ds.Key{}

	walkFn := func(path string, info os.FileInfo, err error) error {
		// remove ds path prefix
		if strings.HasPrefix(path, d.path) {
			path = path[len(d.path):]
		}

		if !info.IsDir() {
			key := ds.NewKey(path)
			keys = append(keys, key)
		}
		return nil
	}

	filepath.Walk(d.path, walkFn)
	return keys, nil
}

// Query implements Datastore.Query
func (d *Datastore) Query(q query.Query) (*query.Results, error) {

	entries := make(chan query.Entry)

	walkFn := func(path string, info os.FileInfo, err error) error {
		// remove ds path prefix
		if strings.HasPrefix(path, d.path) {
			path = path[len(d.path):]
		}

		if !info.IsDir() {
			if strings.HasSuffix(path, ObjectKeySuffix) {
				path = path[:len(path)-len(ObjectKeySuffix)]
			}
			key := ds.NewKey(path)
			entries <- query.Entry{Key: key.String(), Value: query.NotFetched}
		}
		return nil
	}

	go func() {
		filepath.Walk(d.path, walkFn)
		close(entries)
	}()
	r := query.ResultsWithEntriesChan(q, entries)
	r = q.ApplyTo(r)
	return r, nil
}

// isDir returns whether given path is a directory
func isDir(path string) bool {
	finfo, err := os.Stat(path)
	if err != nil {
		return false
	}

	return finfo.IsDir()
}

// isFile returns whether given path is a file
func isFile(path string) bool {
	finfo, err := os.Stat(path)
	if err != nil {
		return false
	}

	return !finfo.IsDir()
}
<commit_msg>stray KeyList<commit_after>package fs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	ds "github.com/jbenet/go-datastore"
	query "github.com/jbenet/go-datastore/query"
)

var ObjectKeySuffix = ".dsobject"

// Datastore uses a standard Go map for internal storage.
type Datastore struct {
	path string
}

// NewDatastore returns a new fs Datastore at given `path`
func NewDatastore(path string) (ds.Datastore, error) {
	if !isDir(path) {
		return nil, fmt.Errorf("Failed to find directory at: %v (file? perms?)", path)
	}

	return &Datastore{path: path}, nil
}

// KeyFilename returns the filename associated with `key`
func (d *Datastore) KeyFilename(key ds.Key) string {
	return filepath.Join(d.path, key.String(), ObjectKeySuffix)
}

// Put stores the given value.
func (d *Datastore) Put(key ds.Key, value interface{}) (err error) {

	// TODO: maybe use io.Readers/Writers?
	// r, err := dsio.CastAsReader(value)
	// if err != nil {
	// 	return err
	// }

	val, ok := value.([]byte)
	if !ok {
		return ds.ErrInvalidType
	}

	fn := d.KeyFilename(key)

	// mkdirall above.
	err = os.MkdirAll(filepath.Dir(fn), 0755)
	if err != nil {
		return err
	}

	return ioutil.WriteFile(fn, val, 0666)
}

// Get returns the value for given key
func (d *Datastore) Get(key ds.Key) (value interface{}, err error) {
	fn := d.KeyFilename(key)
	if !isFile(fn) {
		return nil, ds.ErrNotFound
	}

	return ioutil.ReadFile(fn)
}

// Has returns whether the datastore has a value for a given key
func (d *Datastore) Has(key ds.Key) (exists bool, err error) {
	return ds.GetBackedHas(d, key)
}

// Delete removes the value for given key
func (d *Datastore) Delete(key ds.Key) (err error) {
	fn := d.KeyFilename(key)
	if !isFile(fn) {
		return ds.ErrNotFound
	}

	return os.Remove(fn)
}

// Query implements Datastore.Query
func (d *Datastore) Query(q query.Query) (*query.Results, error) {

	entries := make(chan query.Entry)

	walkFn := func(path string, info os.FileInfo, err error) error {
		// remove ds path prefix
		if strings.HasPrefix(path, d.path) {
			path = path[len(d.path):]
		}

		if !info.IsDir() {
			if strings.HasSuffix(path, ObjectKeySuffix) {
				path = path[:len(path)-len(ObjectKeySuffix)]
			}
			key := ds.NewKey(path)
			entries <- query.Entry{Key: key.String(), Value: query.NotFetched}
		}
		return nil
	}

	go func() {
		filepath.Walk(d.path, walkFn)
		close(entries)
	}()
	r := query.ResultsWithEntriesChan(q, entries)
	r = q.ApplyTo(r)
	return r, nil
}

// isDir returns whether given path is a directory
func isDir(path string) bool {
	finfo, err := os.Stat(path)
	if err != nil {
		return false
	}

	return finfo.IsDir()
}

// isFile returns whether given path is a file
func isFile(path string) bool {
	finfo, err := os.Stat(path)
	if err != nil {
		return false
	}

	return !finfo.IsDir()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"
	"time"
)

var Configuration Settings

func main() {
	fmt.Println("Starting...")

	Configuration = LoadSettings()

	loop := make(chan bool)
	go dns_loop(loop)

	ret := <-loop

	if !ret {
		fmt.Println("Dns loop exited...")
		close(loop)

		os.Exit(1)
	}
}

func dns_loop(loop chan bool) {

	for {

		domain_id := get_domain(Configuration.Domain)

		currentIP, _ := get_currentIP(Configuration.IP_Url)
		sub_domain_id, ip := get_subdomain(domain_id, Configuration.Sub_domain)

		fmt.Printf("currentIp is:%s\n", currentIP)

		//Continue to check the IP of sub-domain
		if len(ip) > 0 && !strings.Contains(currentIP, ip) {

			fmt.Println("Start to update record IP...")
			update_ip(domain_id, sub_domain_id, Configuration.Sub_domain, currentIP)

		} else {
			fmt.Println("Current IP is same as domain IP, no need to update...")
		}

		//Interval is 5 minutes
		time.Sleep(time.Second * 60 * 5)
	}
}
<commit_msg>test travis ci<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

var Configuration Settings

func main() {
	fmt.Println("Starting...")

	Configuration = LoadSettings()

	loop := make(chan bool)
	go dns_loop(loop)

	ret := <-loop

	if !ret {
		fmt.Println("Dns loop exited...")
		close(loop)

		os.Exit(1)
	}
}

func dns_loop(loop chan bool) {

	for {

		domain_id := get_domain(Configuration.Domain)

		currentIP, _ := get_currentIP(Configuration.IP_Url)
		sub_domain_id, ip := get_subdomain(domain_id, Configuration.Sub_domain)

		fmt.Printf("currentIp is:%s\n", currentIP)

		//Continue to check the IP of sub-domain
		if len(ip) > 0 && !strings.Contains(currentIP, ip) {

			fmt.Println("Start to update record IP...")
			update_ip(domain_id, sub_domain_id, Configuration.Sub_domain, currentIP)

		} else {
			fmt.Println("Current IP is same as domain IP, no need to update...")
		}

		//Interval is 5 minutes
		time.Sleep(time.Second * 60 * 5)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mitchellh/go-homedir"
)

const alphanumericRegex = "^[a-zA-Z0-9_-]*$"
const dbFile = "~/.golog"

var dbPath, _ = homedir.Expand(dbFile)
var repository = TaskCsvRepository{Path: dbPath}
var transformer = Transformer{}
var commands = []cli.Command{
	{
		Name:   "start",
		Usage:  "Start tracking a given task",
		Action: Start,
	},
	{
		Name:   "stop",
		Usage:  "Stop tracking a given task",
		Action: Stop,
	},
	{
		Name:   "status",
		Usage:  "Give status of all tasks",
		Action: Status,
	},
	{
		Name:   "list",
		Usage:  "List all tasks",
		Action: List,
	},
}

// Start a given task
func Start(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	repository.save(Task{Identifier: identifier, Action: "start", At: time.Now().Format(time.RFC3339)})

	fmt.Println("Started tracking ", identifier)
}

// Stop a given task
func Stop(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	repository.save(Task{Identifier: identifier, Action: "stop", At: time.Now().Format(time.RFC3339)})

	fmt.Println("Stopped tracking ", identifier)
}

// Status display tasks being tracked
func Status(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	transformer.LoadedTasks = repository.load().getByIdentifier(identifier)
	fmt.Println(transformer.Transform()[identifier])
}

// List lists all tasks
func List(context *cli.Context) {
	transformer.LoadedTasks = repository.load()
	for _, task := range transformer.Transform() {
		fmt.Println(task)
	}
}

// IsValidIdentifier checks if the string passed is a valid task identifier
func IsValidIdentifier(identifier string) bool {
	re := regexp.MustCompile(alphanumericRegex)
	return len(identifier) > 0 && re.MatchString(identifier)
}

func checkInitialDbFile() {
	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
		os.Create(dbPath)
	}
}

func main() {
	// @todo remove this from here, should be in file repo implementation
	checkInitialDbFile()
	app := cli.NewApp()
	app.Name = "Golog"
	app.Usage = "Easy CLI time tracker for your tasks"
	app.Version = "0.1"
	app.Commands = commands
	app.Run(os.Args)
}
<commit_msg>add autocomplete<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mitchellh/go-homedir"
)

const alphanumericRegex = "^[a-zA-Z0-9_-]*$"
const dbFile = "~/.golog"

var dbPath, _ = homedir.Expand(dbFile)
var repository = TaskCsvRepository{Path: dbPath}
var transformer = Transformer{}
var commands = []cli.Command{
	{
		Name:         "start",
		Usage:        "Start tracking a given task",
		Action:       Start,
		BashComplete: AutocompleteTasks,
	},
	{
		Name:         "stop",
		Usage:        "Stop tracking a given task",
		Action:       Stop,
		BashComplete: AutocompleteTasks,
	},
	{
		Name:         "status",
		Usage:        "Give status of all tasks",
		Action:       Status,
		BashComplete: AutocompleteTasks,
	},
	{
		Name:   "list",
		Usage:  "List all tasks",
		Action: List,
	},
}

// Start a given task
func Start(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	repository.save(Task{Identifier: identifier, Action: "start", At: time.Now().Format(time.RFC3339)})

	fmt.Println("Started tracking ", identifier)
}

// Stop a given task
func Stop(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	repository.save(Task{Identifier: identifier, Action: "stop", At: time.Now().Format(time.RFC3339)})

	fmt.Println("Stopped tracking ", identifier)
}

// Status display tasks being tracked
func Status(context *cli.Context) {
	identifier := context.Args().First()
	if !IsValidIdentifier(identifier) {
		cli.ShowCommandHelp(context, context.Command.FullName())
	}

	transformer.LoadedTasks = repository.load().getByIdentifier(identifier)
	fmt.Println(transformer.Transform()[identifier])
}

// List lists all tasks
func List(context *cli.Context) {
	transformer.LoadedTasks = repository.load()
	for _, task := range transformer.Transform() {
		fmt.Println(task)
	}
}

// AutocompleteTasks loads tasks from repository and show them for completion
func AutocompleteTasks(context *cli.Context) {
	// This will complete if no args are passed
	if len(context.Args()) > 0 {
		return
	}
	transformer.LoadedTasks = repository.load()
	for _, task := range transformer.LoadedTasks.Items {
		fmt.Println(task.getIdentifier())
	}
}

// IsValidIdentifier checks if the string passed is a valid task identifier
func IsValidIdentifier(identifier string) bool {
	re := regexp.MustCompile(alphanumericRegex)
	return len(identifier) > 0 && re.MatchString(identifier)
}

func checkInitialDbFile() {
	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
		os.Create(dbPath)
	}
}

func main() {
	// @todo remove this from here, should be in file repo implementation
	checkInitialDbFile()
	app := cli.NewApp()
	app.Name = "Golog"
	app.Usage = "Easy CLI time tracker for your tasks"
	app.Version = "0.1"
	app.EnableBashCompletion = true
	app.Commands = commands
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package goson

import (
    "encoding/json"
    "strings"
    "errors"
    "strconv"
)

/**
 * Created by tuxer on 9/6/17.
 */

type JsonObject struct {
    parsed      map[string]interface{}
}

func (j *JsonObject) Parse(data []byte)    {
    json.Unmarshal(data, &j.parsed)
}

func (j *JsonObject) GetJsonArray(path string) []JsonObject    {
    obj := j.get(path)

    values, ok := obj.([]interface{})

    if !ok  {
        return nil
    }
    var arrJson []JsonObject
    for _, value := range values   {
        mapValue, ok := value.(map[string]interface{})
        if ok   {
            jo := JsonObject{parsed: mapValue}
            arrJson = append(arrJson, jo)
        }
    }
    return arrJson
}
func (j *JsonObject) GetJsonObject(path string) *JsonObject    {
    obj := j.get(path)

    v, ok := obj.(map[string]interface{})
    if ok   {
        jo := JsonObject{ parsed: v }
        return &jo
    }
    return nil
}

func (j *JsonObject) GetInt(path string) (int, error) {
    obj := j.get(path)

    switch obj.(type) {
    case float64:
        float, _ := obj.(float64)
        return int(float), nil
    case string:
        str, _ := obj.(string)
        i, e := strconv.Atoi(str)
        if e != nil {
            return 0, e
        }
        return i, nil
    default:
        return 0, errors.New(`unable to get ` + path + `, is not int`)
    }
}
func (j *JsonObject) GetString(path string) (string, error) {
    obj := j.get(path)

    switch obj.(type) {
    case string:
        str, _ := obj.(string)
        return str, nil
    case float64:
        float, _ := obj.(float64)
        str := strconv.FormatFloat(float, 'f', -1, 64)
        return str, nil
    default:
        return ``, errors.New(`unable to get ` + path + `, is not string`)
    }

}

func (j *JsonObject) get(path string) interface{} {
    splittedPath := strings.Split(path, `.`)

    var jsonMap interface{}
    jsonMap = j.parsed
    var val interface{}
    for _, pathItem := range splittedPath   {
        if jsonMap == nil   {
            return nil
        }
        val = jsonMap.(map[string]interface{})[pathItem]

        switch val.(type) {
        case map[string]interface{}:
            jsonMap = val
        default:
            jsonMap = nil
        }
    }
    return val
}
<commit_msg>add put<commit_after>package goson

import (
    "encoding/json"
    "strings"
    "errors"
    "strconv"
)

/**
 * Created by tuxer on 9/6/17.
 */

type JsonObject struct {
    dataMap map[string]interface{}
}

func (j *JsonObject) Parse(data []byte)    {
    json.Unmarshal(data, &j.dataMap)
}

func (j *JsonObject) GetJsonArray(path string) []JsonObject    {
    obj := j.get(path)

    values, ok := obj.([]interface{})

    if !ok  {
        return nil
    }
    var arrJson []JsonObject
    for _, value := range values   {
        mapValue, ok := value.(map[string]interface{})
        if ok   {
            jo := JsonObject{dataMap: mapValue}
            arrJson = append(arrJson, jo)
        }
    }
    return arrJson
}
func (j *JsonObject) GetJsonObject(path string) *JsonObject    {
    obj := j.get(path)

    v, ok := obj.(map[string]interface{})
    if ok   {
        jo := JsonObject{ dataMap: v }
        return &jo
    }
    return nil
}

func (j *JsonObject) GetInt(path string) (int, error) {
    obj := j.get(path)

    switch obj.(type) {
    case float64:
        float, _ := obj.(float64)
        return int(float), nil
    case string:
        str, _ := obj.(string)
        i, e := strconv.Atoi(str)
        if e != nil {
            return 0, e
        }
        return i, nil
    default:
        return 0, errors.New(`unable to get ` + path + `, is not int`)
    }
}
func (j *JsonObject) GetString(path string) *string {
    obj := j.get(path)

    switch obj.(type) {
    case string:
        str, _ := obj.(string)
        return &str
    case float64:
        float, _ := obj.(float64)
        str := strconv.FormatFloat(float, 'f', -1, 64)
        return &str
    default:
        return nil
    }
}

func (j *JsonObject) Put(path string, value interface{})   {
    splittedPath := strings.Split(path, `.`)
    if j.dataMap == nil  {
        j.dataMap = make(map[string]interface{})
    }
    jsonMap := j.dataMap

    for index, pathItem := range splittedPath   {
        if index < len(splittedPath) - 1    {
            jo := make(map[string]interface{})
            jsonMap[pathItem] = jo
            jsonMap = jo

        } else {
            jsonMap[pathItem] = value
        }
    }
    j.dataMap = jsonMap
}

func (j *JsonObject) get(path string) interface{} {
    splittedPath := strings.Split(path, `.`)

    var jsonMap interface{}
    jsonMap = j.dataMap
    var val interface{}
    for _, pathItem := range splittedPath   {
        if jsonMap == nil   {
            return nil
        }
        val = jsonMap.(map[string]interface{})[pathItem]

        switch val.(type) {
        case map[string]interface{}:
            jsonMap = val
        default:
            jsonMap = nil
        }
    }
    return val
}

func ParseJson(data []byte) *JsonObject    {
    jo := JsonObject{}
    jo.Parse(data)
    return &jo
}<|endoftext|>


<commit_before>// Copyright ©2014 The gonum 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 graph

import "math"

// Node is a graph node. It returns a graph-unique integer ID.
type Node interface {
	ID() int
}

// Edge is a graph edge. In directed graphs, the direction of the
// edge is given from -> to, otherwise the edge is semantically
// unordered.
type Edge interface {
	From() Node
	To() Node
}

// Graph is a generalized graph.
type Graph interface {
	// Has returns whether the node exists within the graph.
	Has(Node) bool

	// Nodes returns all the nodes in the graph.
	Nodes() []Node

	// From returns all nodes that can be reached from
	// the given node.
	From(Node) []Node

	// HasEdge returns whether an edge exists between
	// nodes x and y without considering direction.
	HasEdge(x, y Node) bool

	// Edge returns the edge between nodes u and v when
	// the nodes returned by From(u) include v.
	Edge(u, v Node) Edge
}

// Undirected is an undirected graph.
type Undirected interface {
	Graph

	// EdgeBetween returns the edge between nodes u and v.
	EdgeBetween(u, v Node) Edge
}

// Directed is a directed graph.
type Directed interface {
	Graph

	// EdgeFromTo returns the edge leading from u to v.
	EdgeFromTo(u, v Node) Edge

	// To returns all nodes that can be lead to the
	// given node.
	To(Node) []Node
}

// EdgeLister wraps the Edges method.
type EdgeLister interface {
	Edges() []Edge
}

// Weighter wraps the Weight method.
type Weighter interface {
	// Weight returns the edge weight for the parameter,
	Weight(Edge) float64
}

// Mutable wraps generalized graph alteration methods.
type Mutable interface {
	// NewNode returns a node with a unique arbitrary ID.
	NewNode() Node

	// Adds a node to the graph. AddNode panics if
	// the added node ID matches an existing node ID.
	AddNode(Node)

	// RemoveNode removes a node from the graph, as
	// well as any edges attached to it. If the node
	// is not in the graph it is a no-op.
	RemoveNode(Node)

	// SetEdge adds an edge from one node to another.
	// If the nodes do not exist, they are added.
	// SetEdge will panic if the IDs of the e.From
	// and e.To are equal.
	SetEdge(e Edge, cost float64)

	// RemoveEdge removes the given edge, leaving the
	// terminal nodes. If the edge does not exist it
	// is a no-op.
	RemoveEdge(Edge)
}

// MutableUndirected is an undirected graph that can be arbitrarily altered.
type MutableUndirected interface {
	Undirected
	Mutable
}

// MutableDirected is a directed graph that can be arbitrarily altered.
type MutableDirected interface {
	Directed
	Mutable
}

// WeightFunc is a mapping between an edge and an edge weight.
type WeightFunc func(Edge) float64

// UniformCost is a WeightFunc that returns an edge cost of 1 for a non-nil Edge
// and Inf for a nil Edge.
func UniformCost(e Edge) float64 {
	if e == nil {
		return math.Inf(1)
	}
	return 1
}

// CopyUndirected copies nodes and edges as undirected edges from the source to the
// destination without first clearing the destination. If the source does not
// provide edge weights, UniformCost is used.
func CopyUndirected(dst MutableUndirected, src Graph) {
	var weight WeightFunc
	if g, ok := src.(Weighter); ok {
		weight = g.Weight
	} else {
		weight = UniformCost
	}

	for _, node := range src.Nodes() {
		succs := src.From(node)
		dst.AddNode(node)
		for _, succ := range succs {
			edge := src.Edge(node, succ)
			dst.SetEdge(edge, weight(edge))
		}
	}
}

// CopyDirected copies nodes and edges as directed edges from the source to the
// destination without first clearing the destination. If src is undirected both
// directions will be present in the destination after the copy is complete. If
// the source does not provide edge weights, UniformCost is used.
func CopyDirected(dst MutableDirected, src Graph) {
	var weight WeightFunc
	if g, ok := src.(Weighter); ok {
		weight = g.Weight
	} else {
		weight = UniformCost
	}

	for _, node := range src.Nodes() {
		succs := src.From(node)
		dst.AddNode(node)
		for _, succ := range succs {
			edge := src.Edge(node, succ)
			dst.SetEdge(edge, weight(edge))
		}
	}
}
<commit_msg>graph: add caveat for digraph -> graph copy<commit_after>// Copyright ©2014 The gonum 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 graph

import "math"

// Node is a graph node. It returns a graph-unique integer ID.
type Node interface {
	ID() int
}

// Edge is a graph edge. In directed graphs, the direction of the
// edge is given from -> to, otherwise the edge is semantically
// unordered.
type Edge interface {
	From() Node
	To() Node
}

// Graph is a generalized graph.
type Graph interface {
	// Has returns whether the node exists within the graph.
	Has(Node) bool

	// Nodes returns all the nodes in the graph.
	Nodes() []Node

	// From returns all nodes that can be reached from
	// the given node.
	From(Node) []Node

	// HasEdge returns whether an edge exists between
	// nodes x and y without considering direction.
	HasEdge(x, y Node) bool

	// Edge returns the edge between nodes u and v when
	// the nodes returned by From(u) include v.
	Edge(u, v Node) Edge
}

// Undirected is an undirected graph.
type Undirected interface {
	Graph

	// EdgeBetween returns the edge between nodes u and v.
	EdgeBetween(u, v Node) Edge
}

// Directed is a directed graph.
type Directed interface {
	Graph

	// EdgeFromTo returns the edge leading from u to v.
	EdgeFromTo(u, v Node) Edge

	// To returns all nodes that can be lead to the
	// given node.
	To(Node) []Node
}

// EdgeLister wraps the Edges method.
type EdgeLister interface {
	Edges() []Edge
}

// Weighter wraps the Weight method.
type Weighter interface {
	// Weight returns the edge weight for the parameter,
	Weight(Edge) float64
}

// Mutable wraps generalized graph alteration methods.
type Mutable interface {
	// NewNode returns a node with a unique arbitrary ID.
	NewNode() Node

	// Adds a node to the graph. AddNode panics if
	// the added node ID matches an existing node ID.
	AddNode(Node)

	// RemoveNode removes a node from the graph, as
	// well as any edges attached to it. If the node
	// is not in the graph it is a no-op.
	RemoveNode(Node)

	// SetEdge adds an edge from one node to another.
	// If the nodes do not exist, they are added.
	// SetEdge will panic if the IDs of the e.From
	// and e.To are equal.
	SetEdge(e Edge, cost float64)

	// RemoveEdge removes the given edge, leaving the
	// terminal nodes. If the edge does not exist it
	// is a no-op.
	RemoveEdge(Edge)
}

// MutableUndirected is an undirected graph that can be arbitrarily altered.
type MutableUndirected interface {
	Undirected
	Mutable
}

// MutableDirected is a directed graph that can be arbitrarily altered.
type MutableDirected interface {
	Directed
	Mutable
}

// WeightFunc is a mapping between an edge and an edge weight.
type WeightFunc func(Edge) float64

// UniformCost is a WeightFunc that returns an edge cost of 1 for a non-nil Edge
// and Inf for a nil Edge.
func UniformCost(e Edge) float64 {
	if e == nil {
		return math.Inf(1)
	}
	return 1
}

// CopyUndirected copies nodes and edges as undirected edges from the source to the
// destination without first clearing the destination. If the source does not
// provide edge weights, UniformCost is used.
//
// Note that if the source is a directed graph and a fundamental cycle exists with
// two node where the edge weights differ, the resulting destination graph's edge
// weight between those nodes is undefined.
func CopyUndirected(dst MutableUndirected, src Graph) {
	var weight WeightFunc
	if g, ok := src.(Weighter); ok {
		weight = g.Weight
	} else {
		weight = UniformCost
	}

	for _, node := range src.Nodes() {
		succs := src.From(node)
		dst.AddNode(node)
		for _, succ := range succs {
			edge := src.Edge(node, succ)
			dst.SetEdge(edge, weight(edge))
		}
	}
}

// CopyDirected copies nodes and edges as directed edges from the source to the
// destination without first clearing the destination. If src is undirected both
// directions will be present in the destination after the copy is complete. If
// the source does not provide edge weights, UniformCost is used.
func CopyDirected(dst MutableDirected, src Graph) {
	var weight WeightFunc
	if g, ok := src.(Weighter); ok {
		weight = g.Weight
	} else {
		weight = UniformCost
	}

	for _, node := range src.Nodes() {
		succs := src.From(node)
		dst.AddNode(node)
		for _, succ := range succs {
			edge := src.Edge(node, succ)
			dst.SetEdge(edge, weight(edge))
		}
	}
}
<|endoftext|>


<commit_before>package goraph

import (
	"sort"
)

// The Graph interface is implemented by all graph types.
type Graph interface {
	NewVertex() Vertex
	AddEdge(v1, v2 Vertex)
	Vertices() []Vertex
	Edges() []Edge
	Neighbours(v Vertex) []Vertex
}

var (
	_ Graph = &DirectedGraph{}
	_ Graph = &AdjacencyList{}
)

// Vertex represents a node in the graph. Users should create
// new Vertex values with NewVertex.
type Vertex int

// Edge represents an edge between two vertices.
// In a directed graph the edge is from v1 to v2.
type Edge struct{ U, V Vertex }

// AdjacencyList implements an undirected graph using an adjacency list.
type AdjacencyList struct {
	edges      map[Vertex][]Vertex
	nextVertex Vertex
}

// NewAdjacencyList creates an empty graph.
func NewAdjacencyList() *AdjacencyList {
	return &AdjacencyList{edges: make(map[Vertex][]Vertex)}
}

// NewVertex adds a new vertex.
func (g *AdjacencyList) NewVertex() Vertex {
	v := g.nextVertex
	g.edges[v] = make([]Vertex, 0)
	g.nextVertex++
	return v
}

// AddEdge adds an edge between v1 and v2.2.
func (g *AdjacencyList) AddEdge(v1, v2 Vertex) {
	if v2 < v1 {
		v1, v2 = v2, v1
	}
	edges := g.edges[v1]
	g.edges[v1] = append(edges, v2)
}

type vertexSlice []Vertex

func (p vertexSlice) Len() int           { return len(p) }
func (p vertexSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p vertexSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p vertexSlice) Sort()              { sort.Sort(p) }

type edgeSlice []Edge

func (p edgeSlice) Len() int { return len(p) }
func (p edgeSlice) Less(i, j int) bool {
	if p[i].U == p[j].U {
		return p[i].V < p[j].V
	} else {
		return p[i].U < p[j].U
	}
}
func (p edgeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p edgeSlice) Sort()         { sort.Sort(p) }

// Vertices returns a slice of all vertices.
func (g *AdjacencyList) Vertices() []Vertex {
	vertices := make(vertexSlice, len(g.edges))
	var i int
	for k := range g.edges {
		vertices[i] = k
		i++
	}
	return vertices
}

// Edges returns a slice of all edges.
func (g *AdjacencyList) Edges() []Edge {
	var edges []Edge
	for k, neighbors := range g.edges {
		for _, n := range neighbors {
			edges = append(edges, Edge{k, n})
		}
	}
	return edges
}

// Neighbours returns a slice of v's neighbours.
func (g *AdjacencyList) Neighbours(v Vertex) []Vertex {
	return g.edges[v]
}

// DirectedGraph provides a space-efficient directed graph.
type DirectedGraph struct {
	edges      map[Vertex][]Vertex
	nextVertex Vertex
}

// NewDirectedGraph creates and initializes a DirectedGraph.
func NewDirectedGraph() *DirectedGraph {
	g := &DirectedGraph{edges: make(map[Vertex][]Vertex)}
	return g
}

// addVertex adds v to the graph in an idempotent fashion. The return value
// indicates whether or not the vertex was already in the graph; if false,
// the value was not in the graph before it was added.
func (g *DirectedGraph) addVertex(v Vertex) bool {
	_, ok := g.edges[v]
	if !ok {
		g.edges[v] = make([]Vertex, 0)
	}
	return ok
}

// AddEdge connects vertices v1 and v2 in the graph.
func (g *DirectedGraph) AddEdge(v1, v2 Vertex) {
	g.addVertex(v1)
	g.addVertex(v2)
	g.edges[v1] = append(g.edges[v1], v2)
}

// NewVertex creates a new Vertex, adds it to the graph, and returns it.
func (g *DirectedGraph) NewVertex() Vertex {
	v := g.nextVertex
	g.addVertex(v)
	g.nextVertex++
	return v
}

// Vertices returns a slice of the vertices that are in the graph.
func (g *DirectedGraph) Vertices() []Vertex {
	vertices := make([]Vertex, len(g.edges))
	var i int
	for k := range g.edges {
		vertices[i] = k
		i++
	}
	return vertices
}

// Edges returns all the outgoing edges of the graph.
func (g *DirectedGraph) Edges() []Edge {
	var edges []Edge
	for k, neighbors := range g.edges {
		for _, n := range neighbors {
			edges = append(edges, Edge{k, n})
		}
	}
	return edges
}

// Neighbours returns a slice of v's neighbours.
func (g *DirectedGraph) Neighbours(v Vertex) []Vertex {
	return g.edges[v]
}

// incomingEdges finds the vertices that connect to v
func (g *DirectedGraph) incomingEdges(v Vertex) []Vertex {
	result := make([]Vertex, 0)
	for w, vlist := range g.edges {
		for _, x := range vlist {
			if v == x {
				result = append(result, w)
				break
			}
		}
	}
	return result
}

// countIncomingEdges is like incomingEdges but only delivers a count.
func (g *DirectedGraph) countIncomingEdges(v Vertex) int {
	result := 0
	for _, vlist := range g.edges {
		for _, x := range vlist {
			if v == x {
				result += 1
				break
			}
		}
	}
	return result
}
<commit_msg>Fix docs<commit_after>package goraph

import (
	"sort"
)

// The Graph interface is implemented by all graph types.
type Graph interface {
	NewVertex() Vertex
	AddEdge(v1, v2 Vertex)
	Vertices() []Vertex
	Edges() []Edge
	Neighbours(v Vertex) []Vertex
}

var (
	_ Graph = &DirectedGraph{}
	_ Graph = &AdjacencyList{}
)

// Vertex represents a node in the graph. Users should create
// new Vertex values with NewVertex.
type Vertex int

// Edge represents an edge between two vertices.
// In a directed graph, the edge is from U to V.
type Edge struct{ U, V Vertex }

// AdjacencyList implements an undirected graph using an adjacency list.
type AdjacencyList struct {
	edges      map[Vertex][]Vertex
	nextVertex Vertex
}

// NewAdjacencyList creates an empty graph.
func NewAdjacencyList() *AdjacencyList {
	return &AdjacencyList{edges: make(map[Vertex][]Vertex)}
}

// NewVertex adds a new vertex.
func (g *AdjacencyList) NewVertex() Vertex {
	v := g.nextVertex
	g.edges[v] = make([]Vertex, 0)
	g.nextVertex++
	return v
}

// AddEdge adds an edge between v1 and v2.2.
func (g *AdjacencyList) AddEdge(v1, v2 Vertex) {
	if v2 < v1 {
		v1, v2 = v2, v1
	}
	edges := g.edges[v1]
	g.edges[v1] = append(edges, v2)
}

type vertexSlice []Vertex

func (p vertexSlice) Len() int           { return len(p) }
func (p vertexSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p vertexSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p vertexSlice) Sort()              { sort.Sort(p) }

type edgeSlice []Edge

func (p edgeSlice) Len() int { return len(p) }
func (p edgeSlice) Less(i, j int) bool {
	if p[i].U == p[j].U {
		return p[i].V < p[j].V
	} else {
		return p[i].U < p[j].U
	}
}
func (p edgeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p edgeSlice) Sort()         { sort.Sort(p) }

// Vertices returns a slice of all vertices.
func (g *AdjacencyList) Vertices() []Vertex {
	vertices := make(vertexSlice, len(g.edges))
	var i int
	for k := range g.edges {
		vertices[i] = k
		i++
	}
	return vertices
}

// Edges returns a slice of all edges.
func (g *AdjacencyList) Edges() []Edge {
	var edges []Edge
	for k, neighbors := range g.edges {
		for _, n := range neighbors {
			edges = append(edges, Edge{k, n})
		}
	}
	return edges
}

// Neighbours returns a slice of v's neighbours.
func (g *AdjacencyList) Neighbours(v Vertex) []Vertex {
	return g.edges[v]
}

// DirectedGraph provides a space-efficient directed graph.
type DirectedGraph struct {
	edges      map[Vertex][]Vertex
	nextVertex Vertex
}

// NewDirectedGraph creates and initializes a DirectedGraph.
func NewDirectedGraph() *DirectedGraph {
	g := &DirectedGraph{edges: make(map[Vertex][]Vertex)}
	return g
}

// addVertex adds v to the graph in an idempotent fashion. The return value
// indicates whether or not the vertex was already in the graph; if false,
// the value was not in the graph before it was added.
func (g *DirectedGraph) addVertex(v Vertex) bool {
	_, ok := g.edges[v]
	if !ok {
		g.edges[v] = make([]Vertex, 0)
	}
	return ok
}

// AddEdge connects vertices v1 and v2 in the graph.
func (g *DirectedGraph) AddEdge(v1, v2 Vertex) {
	g.addVertex(v1)
	g.addVertex(v2)
	g.edges[v1] = append(g.edges[v1], v2)
}

// NewVertex creates a new Vertex, adds it to the graph, and returns it.
func (g *DirectedGraph) NewVertex() Vertex {
	v := g.nextVertex
	g.addVertex(v)
	g.nextVertex++
	return v
}

// Vertices returns a slice of the vertices that are in the graph.
func (g *DirectedGraph) Vertices() []Vertex {
	vertices := make([]Vertex, len(g.edges))
	var i int
	for k := range g.edges {
		vertices[i] = k
		i++
	}
	return vertices
}

// Edges returns all the outgoing edges of the graph.
func (g *DirectedGraph) Edges() []Edge {
	var edges []Edge
	for k, neighbors := range g.edges {
		for _, n := range neighbors {
			edges = append(edges, Edge{k, n})
		}
	}
	return edges
}

// Neighbours returns a slice of v's neighbours.
func (g *DirectedGraph) Neighbours(v Vertex) []Vertex {
	return g.edges[v]
}

// incomingEdges finds the vertices that connect to v
func (g *DirectedGraph) incomingEdges(v Vertex) []Vertex {
	result := make([]Vertex, 0)
	for w, vlist := range g.edges {
		for _, x := range vlist {
			if v == x {
				result = append(result, w)
				break
			}
		}
	}
	return result
}

// countIncomingEdges is like incomingEdges but only delivers a count.
func (g *DirectedGraph) countIncomingEdges(v Vertex) int {
	result := 0
	for _, vlist := range g.edges {
		for _, x := range vlist {
			if v == x {
				result += 1
				break
			}
		}
	}
	return result
}
<|endoftext|>