<commit_before>package unilog

import "io"

// UnilogReader wraps an existing io.Reader and adds the ability to
// perform a graceful shutdown by reading from the underlying Reader
// up through the next newline character, and then start returning
// EOF.
type UnilogReader struct {
	inner io.Reader
	// Was the last character read a newline?
	nl           bool
	shuttingDown bool
}

// Creates a new UnilogReader. Once shutdown becomes readable, the
// returned Reader will start reading from the underlying Reader one
// byte at a time until newline, and then start returning EOF.
func NewUnilogReader(in io.Reader, shutdown <-chan struct{}) io.Reader {
	r := &UnilogReader{inner: in}
	go func() {
		<-shutdown
		r.shuttingDown = true
	}()
	return r
}

func (u *UnilogReader) Read(buf []byte) (int, error) {
	if u.nl && u.shuttingDown {
		return 0, io.EOF
	}

	if u.shuttingDown {
		buf = buf[:1]
	}

	n, e := u.inner.Read(buf)
	if n > 0 {
		u.nl = buf[n-1] == '\n'
	}
	return n, e
}
<commit_msg>Make reader less race-y<commit_after>package unilog

import (
	"io"
	"sync"
)

// UnilogReader wraps an existing io.Reader and adds the ability to
// perform a graceful shutdown by reading from the underlying Reader
// up through the next newline character, and then start returning
// EOF.
type UnilogReader struct {
	inner io.Reader
	// Was the last character read a newline?
	nl           bool
	shuttingDown bool
	mtx          sync.Mutex
}

// Creates a new UnilogReader. Once shutdown becomes readable, the
// returned Reader will start reading from the underlying Reader one
// byte at a time until newline, and then start returning EOF.
func NewUnilogReader(in io.Reader, shutdown <-chan struct{}) io.Reader {
	r := &UnilogReader{inner: in}
	go func() {
		<-shutdown
		r.mtx.Lock()
		r.shuttingDown = true
		r.mtx.Unlock()
	}()
	return r
}

func (r *UnilogReader) isShuttingDown() bool {
	r.mtx.Lock()
	defer r.mtx.Unlock()
	return r.shuttingDown
}

func (r *UnilogReader) Read(buf []byte) (int, error) {
	if r.nl && r.isShuttingDown() {
		return 0, io.EOF
	}

	if r.isShuttingDown() {
		buf = buf[:1]
	}

	n, e := r.inner.Read(buf)
	if n > 0 {
		r.nl = buf[n-1] == '\n'
	}
	return n, e
}
<|endoftext|>


<commit_before>package wav

import (
	"bufio"
	"encoding/binary"
	"errors"
	"math"

	"github.com/youpy/go-riff"
)

type Reader struct {
	r         *riff.Reader
	riffChunk *riff.RIFFChunk
	format    *WavFormat
	*WavData
}

func NewReader(r riff.RIFFReader) *Reader {
	riffReader := riff.NewReader(r)
	return &Reader{r: riffReader}
}

func (r *Reader) Format() (format *WavFormat, err error) {
	if r.format == nil {
		format, err = r.readFormat()
		if err != nil {
			return
		}
		r.format = format
	} else {
		format = r.format
	}

	return
}

func (r *Reader) Read(p []byte) (n int, err error) {
	if r.WavData == nil {
		data, err := r.readData()
		if err != nil {
			return n, err
		}
		r.WavData = data
	}

	return r.WavData.Read(p)
}

func (r *Reader) ReadSamples(params ...uint32) (samples []Sample, err error) {
	var bytes []byte
	var numSamples, b, n int

	if len(params) > 0 {
		numSamples = int(params[0])
	} else {
		numSamples = 2048
	}

	format, err := r.Format()
	if err != nil {
		return
	}

	numChannels := int(format.NumChannels)
	blockAlign := int(format.BlockAlign)
	bitsPerSample := int(format.BitsPerSample)

	bytes = make([]byte, numSamples*blockAlign)
	n, err = r.Read(bytes)

	if err != nil {
		return
	}

	numSamples = n / blockAlign
	r.WavData.pos += uint32(numSamples * blockAlign)
	samples = make([]Sample, numSamples)
	offset := 0

	for i := 0; i < numSamples; i++ {
		if format.AudioFormat == AudioFormatIEEEFloat {
			for j := 0; j < numChannels; j++ {
				soffset := offset + (j * bitsPerSample / 8)

				bits :=
					uint32((int(bytes[soffset+3]) << 24) +
						(int(bytes[soffset+2]) << 16) +
						(int(bytes[soffset+1]) << 8) +
						int(bytes[soffset]))
				samples[i].Values[j] = int(math.MaxInt32 * math.Float32frombits(bits))
			}
		} else {
			for j := 0; j < numChannels; j++ {
				soffset := offset + (j * bitsPerSample / 8)

				var val uint
				for b = 0; b*8 < bitsPerSample; b++ {
					val += uint(bytes[soffset+b]) << uint(b*8)
				}

				samples[i].Values[j] = toInt(val, bitsPerSample)
			}
		}

		offset += blockAlign
	}

	return
}

func (r *Reader) IntValue(sample Sample, channel uint) int {
	return sample.Values[channel]
}

func (r *Reader) FloatValue(sample Sample, channel uint) float64 {
	// XXX
	return float64(r.IntValue(sample, channel)) / math.Pow(2, float64(r.format.BitsPerSample))
}

func (r *Reader) readFormat() (fmt *WavFormat, err error) {
	var riffChunk *riff.RIFFChunk

	fmt = new(WavFormat)

	if r.riffChunk == nil {
		riffChunk, err = r.r.Read()
		if err != nil {
			return
		}

		r.riffChunk = riffChunk
	} else {
		riffChunk = r.riffChunk
	}

	fmtChunk := findChunk(riffChunk, "fmt ")

	if fmtChunk == nil {
		err = errors.New("Format chunk is not found")
		return
	}

	err = binary.Read(fmtChunk, binary.LittleEndian, fmt)
	if err != nil {
		return
	}

	return
}

func (r *Reader) readData() (data *WavData, err error) {
	var riffChunk *riff.RIFFChunk

	if r.riffChunk == nil {
		riffChunk, err = r.r.Read()
		if err != nil {
			return
		}

		r.riffChunk = riffChunk
	} else {
		riffChunk = r.riffChunk
	}

	dataChunk := findChunk(riffChunk, "data")
	if dataChunk == nil {
		err = errors.New("Data chunk is not found")
		return
	}

	data = &WavData{bufio.NewReader(dataChunk), dataChunk.ChunkSize, 0}

	return
}

func findChunk(riffChunk *riff.RIFFChunk, id string) (chunk *riff.Chunk) {
	for _, ch := range riffChunk.Chunks {
		if string(ch.ChunkID[:]) == id {
			chunk = ch
			break
		}
	}

	return
}

func toInt(value uint, bits int) int {
	var result int

	switch bits {
	case 32:
		result = int(int32(value))
	case 16:
		result = int(int16(value))
	case 8:
		result = int(value)
	default:
		msb := uint(1 << (uint(bits) - 1))

		if value >= msb {
			result = -int((1 << uint(bits)) - value)
		} else {
			result = int(value)
		}
	}

	return result
}
<commit_msg>Update reader.go<commit_after>package wav

import (
	"bufio"
	"encoding/binary"
	"errors"
	"math"

	"github.com/youpy/go-riff"
)

type Reader struct {
	r         *riff.Reader
	riffChunk *riff.RIFFChunk
	format    *WavFormat
	*WavData
}

func NewReader(r riff.RIFFReader) *Reader {
	riffReader := riff.NewReader(r)
	return &Reader{r: riffReader}
}

func (r *Reader) Format() (format *WavFormat, err error) {
	if r.format == nil {
		format, err = r.readFormat()
		if err != nil {
			return
		}
		r.format = format
	} else {
		format = r.format
	}

	return
}

func (r *Reader) Read(p []byte) (n int, err error) {
	if r.WavData == nil {
		data, err := r.readData()
		if err != nil {
			return n, err
		}
		r.WavData = data
	}

	return r.WavData.Read(p)
}

func (r *Reader) ReadSamples(params ...uint32) (samples []Sample, err error) {
	var bytes []byte
	var numSamples, b, n int

	if len(params) > 0 {
		numSamples = int(params[0])
	} else {
		numSamples = 2048
	}

	format, err := r.Format()
	if err != nil {
		return
	}

	numChannels := int(format.NumChannels)
	blockAlign := int(format.BlockAlign)
	bitsPerSample := int(format.BitsPerSample)

	bytes = make([]byte, numSamples*blockAlign)
	n, err = r.Read(bytes)

	if err != nil {
		return
	}

	numSamples = n / blockAlign
	r.WavData.pos += uint32(numSamples * blockAlign)
	samples = make([]Sample, numSamples)
	offset := 0

	for i := 0; i < numSamples; i++ {
		if format.AudioFormat == AudioFormatIEEEFloat {
			for j := 0; j < numChannels; j++ {
				soffset := offset + (j * bitsPerSample / 8)

				bits :=
					uint32((int(bytes[soffset+3]) << 24) +
						(int(bytes[soffset+2]) << 16) +
						(int(bytes[soffset+1]) << 8) +
						int(bytes[soffset]))
				samples[i].Values[j] = int(math.MaxInt32 * math.Float32frombits(bits))
			}
		} else {
			for j := 0; j < numChannels; j++ {
				soffset := offset + (j * bitsPerSample / 8)

				var val uint
				for b = 0; b*8 < bitsPerSample; b++ {
					val += uint(bytes[soffset+b]) << uint(b*8)
				}

				samples[i].Values[j] = toInt(val, bitsPerSample)
			}
		}

		offset += blockAlign
	}

	return
}

func (r *Reader) IntValue(sample Sample, channel uint) int {
	return sample.Values[channel]
}

func (r *Reader) FloatValue(sample Sample, channel uint) float64 {
	return float64(r.IntValue(sample, channel)) / math.Pow(2, float64(r.format.BitsPerSample)-1)
}

func (r *Reader) readFormat() (fmt *WavFormat, err error) {
	var riffChunk *riff.RIFFChunk

	fmt = new(WavFormat)

	if r.riffChunk == nil {
		riffChunk, err = r.r.Read()
		if err != nil {
			return
		}

		r.riffChunk = riffChunk
	} else {
		riffChunk = r.riffChunk
	}

	fmtChunk := findChunk(riffChunk, "fmt ")

	if fmtChunk == nil {
		err = errors.New("Format chunk is not found")
		return
	}

	err = binary.Read(fmtChunk, binary.LittleEndian, fmt)
	if err != nil {
		return
	}

	return
}

func (r *Reader) readData() (data *WavData, err error) {
	var riffChunk *riff.RIFFChunk

	if r.riffChunk == nil {
		riffChunk, err = r.r.Read()
		if err != nil {
			return
		}

		r.riffChunk = riffChunk
	} else {
		riffChunk = r.riffChunk
	}

	dataChunk := findChunk(riffChunk, "data")
	if dataChunk == nil {
		err = errors.New("Data chunk is not found")
		return
	}

	data = &WavData{bufio.NewReader(dataChunk), dataChunk.ChunkSize, 0}

	return
}

func findChunk(riffChunk *riff.RIFFChunk, id string) (chunk *riff.Chunk) {
	for _, ch := range riffChunk.Chunks {
		if string(ch.ChunkID[:]) == id {
			chunk = ch
			break
		}
	}

	return
}

func toInt(value uint, bits int) int {
	var result int

	switch bits {
	case 32:
		result = int(int32(value))
	case 16:
		result = int(int16(value))
	case 8:
		result = int(value)
	default:
		msb := uint(1 << (uint(bits) - 1))

		if value >= msb {
			result = -int((1 << uint(bits)) - value)
		} else {
			result = int(value)
		}
	}

	return result
}
<|endoftext|>


<commit_before>//
// Copyright © 2011-2013 Guy M. Allard
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package stompngo

import (
	"strconv"
	"strings"
	"time"
)

/*
	Logical network reader.

	Read STOMP frames from the connection, create MessageData
	structures from the received data, and push the MessageData to the client.
*/
func (c *Connection) reader() {
	//
	q := false // Shutdown indicator

	for {
		f, e := c.readFrame()
		if e != nil {
			h := f.Headers.Add("connection_read_error", e.Error())
			md := MessageData{Message{f.Command, h, f.Body}, e}
			c.handleReadError(md)
			break
		}

		if f.Command == "" && q {
			break
		}

		m := Message(f)
		c.mets.tfr += 1 // Total frames read
		// Headers already decoded
		c.mets.tbr += m.Size(false) // Total bytes read
		d := MessageData{m, e}
		if sid, ok := f.Headers.Contains("subscription"); ok {
			c.subsLock.Lock()
			c.subs[sid] <- d
			c.subsLock.Unlock()
		} else {
			c.input <- d
		}

		c.log("RECEIVE", m.Command, m.Headers)

		select {
		case q = <-c.rsd:
		default:
		}

		if q {
			break
		}

	}
	c.log("reader shutdown", time.Now())
}

/*
	Physical frame reader.

	This parses a single STOMP frame from data off of the wire, and
	returns a Frame, with a possible error.

	Note: this functionality could hang or exhibit other erroneous behavior
	if running against a non-compliant STOMP server.
*/
func (c *Connection) readFrame() (f Frame, e error) {
	f = Frame{"", Headers{}, NULLBUFF}
	// Read f.Command or line ends (maybe heartbeats)
	for {
		s, e := c.rdr.ReadString('\n')
		if s == "" {
			return f, e
		}
		if e != nil {
			return f, e
		}
		if c.hbd != nil {
			c.hbd.lr = time.Now().UnixNano() // Latest good read
		}
		f.Command = s[0 : len(s)-1]
		if s != "\n" {
			break
		}
		// c.log("read slash n")
	}
	// Read f.Headers
	for {
		s, e := c.rdr.ReadString('\n')
		if e != nil {
			return f, e
		}
		if c.hbd != nil {
			c.hbd.lr = time.Now().UnixNano() // Latest good read
		}
		if s == "\n" {
			break
		}
		s = s[0 : len(s)-1]
		p := strings.SplitN(s, ":", 2)
		if len(p) != 2 {
			return f, EUNKHDR
		}
		if c.Protocol() != SPL_10 && f.Command != CONNECTED {
			p[0] = decode(p[0])
			p[1] = decode(p[1])
		}
		f.Headers = append(f.Headers, p[0], p[1])
	}
	// Read f.Body
	if v, ok := f.Headers.Contains("content-length"); ok {
		l, e := strconv.Atoi(strings.TrimSpace(v))
		if e != nil {
			return f, e
		}
		if l == 0 {
			f.Body, e = readUntilNul(c.rdr)
		} else {
			f.Body, e = readBody(c.rdr, l)
		}
	} else {
		// content-length not present
		f.Body, e = readUntilNul(c.rdr)
	}
	if e != nil {
		return f, e
	}
	if c.hbd != nil {
		c.hbd.lr = time.Now().UnixNano() // Latest good read
	}
	//
	return f, e
}
<commit_msg>Remove extraneous check for CONNECTED.<commit_after>//
// Copyright © 2011-2013 Guy M. Allard
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package stompngo

import (
	"strconv"
	"strings"
	"time"
)

/*
	Logical network reader.

	Read STOMP frames from the connection, create MessageData
	structures from the received data, and push the MessageData to the client.
*/
func (c *Connection) reader() {
	//
	q := false // Shutdown indicator

	for {
		f, e := c.readFrame()
		if e != nil {
			h := f.Headers.Add("connection_read_error", e.Error())
			md := MessageData{Message{f.Command, h, f.Body}, e}
			c.handleReadError(md)
			break
		}

		if f.Command == "" && q {
			break
		}

		m := Message(f)
		c.mets.tfr += 1 // Total frames read
		// Headers already decoded
		c.mets.tbr += m.Size(false) // Total bytes read
		d := MessageData{m, e}
		if sid, ok := f.Headers.Contains("subscription"); ok {
			c.subsLock.Lock()
			c.subs[sid] <- d
			c.subsLock.Unlock()
		} else {
			c.input <- d
		}

		c.log("RECEIVE", m.Command, m.Headers)

		select {
		case q = <-c.rsd:
		default:
		}

		if q {
			break
		}

	}
	c.log("reader shutdown", time.Now())
}

/*
	Physical frame reader.

	This parses a single STOMP frame from data off of the wire, and
	returns a Frame, with a possible error.

	Note: this functionality could hang or exhibit other erroneous behavior
	if running against a non-compliant STOMP server.
*/
func (c *Connection) readFrame() (f Frame, e error) {
	f = Frame{"", Headers{}, NULLBUFF}
	// Read f.Command or line ends (maybe heartbeats)
	for {
		s, e := c.rdr.ReadString('\n')
		if s == "" {
			return f, e
		}
		if e != nil {
			return f, e
		}
		if c.hbd != nil {
			c.hbd.lr = time.Now().UnixNano() // Latest good read
		}
		f.Command = s[0 : len(s)-1]
		if s != "\n" {
			break
		}
		// c.log("read slash n")
	}
	// Read f.Headers
	for {
		s, e := c.rdr.ReadString('\n')
		if e != nil {
			return f, e
		}
		if c.hbd != nil {
			c.hbd.lr = time.Now().UnixNano() // Latest good read
		}
		if s == "\n" {
			break
		}
		s = s[0 : len(s)-1]
		p := strings.SplitN(s, ":", 2)
		if len(p) != 2 {
			return f, EUNKHDR
		}
		if c.Protocol() != SPL_10 {
			p[0] = decode(p[0])
			p[1] = decode(p[1])
		}
		f.Headers = append(f.Headers, p[0], p[1])
	}
	// Read f.Body
	if v, ok := f.Headers.Contains("content-length"); ok {
		l, e := strconv.Atoi(strings.TrimSpace(v))
		if e != nil {
			return f, e
		}
		if l == 0 {
			f.Body, e = readUntilNul(c.rdr)
		} else {
			f.Body, e = readBody(c.rdr, l)
		}
	} else {
		// content-length not present
		f.Body, e = readUntilNul(c.rdr)
	}
	if e != nil {
		return f, e
	}
	if c.hbd != nil {
		c.hbd.lr = time.Now().UnixNano() // Latest good read
	}
	//
	return f, e
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"runtime"
	"time"

	"github.com/ready-steady/format/mat"
	"github.com/ready-steady/numeric/interpolation/adhier"
	"github.com/ready-steady/probability"
	"github.com/ready-steady/probability/uniform"
	"github.com/ready-steady/statistics/metric"

	"../internal"
)

func main() {
	internal.Run(command)
}

func command(config *internal.Config, problem *internal.Problem,
	fi *mat.File, fo *mat.File) error {

	target, err := internal.NewTarget(problem)
	if err != nil {
		return err
	}

	interpolator, err := internal.NewInterpolator(problem, target)
	if err != nil {
		return err
	}

	problem.Println(problem)
	problem.Println(target)

	surrogate := new(adhier.Surrogate)
	if fi == nil {
		return errors.New("an input file is required")
	}
	if err := fi.Get("surrogate", surrogate); err != nil {
		return err
	}

	problem.Println(surrogate)

	sc := config.Samples
	if sc == 0 {
		return errors.New("the number of samples is zero")
	}

	ic, oc := target.InputsOutputs()

	if config.Seed > 0 {
		rand.Seed(config.Seed)
	} else {
		rand.Seed(time.Now().Unix())
	}
	points := probability.Sample(uniform.New(0, 1), sc*ic)

	problem.Println("Evaluating the original model...")
	values := invoke(target, points)

	problem.Println("Evaluating the surrogate model...")
	approximations := interpolator.Evaluate(surrogate, points)

	fmt.Printf("NRMSE: %.2e\n", metric.NRMSE(approximations, values))

	if fo == nil {
		return nil
	}

	if err := fo.PutMatrix("points", points, ic, sc); err != nil {
		return err
	}
	if err := fo.PutMatrix("values", values, oc, sc); err != nil {
		return err
	}
	if err := fo.PutMatrix("approximations", approximations, oc, sc); err != nil {
		return err
	}

	return nil
}

func invoke(target internal.Target, points []float64) []float64 {
	workerCount := uint32(runtime.GOMAXPROCS(0))

	ic, oc := target.InputsOutputs()
	pc := uint32(len(points)) / ic

	values := make([]float64, pc*oc)
	jobs := make(chan uint32, pc)
	done := make(chan bool, pc)

	for i := uint32(0); i < workerCount; i++ {
		go func() {
			for j := range jobs {
				target.Evaluate(points[j*ic:(j+1)*ic], values[j*oc:(j+1)*oc], nil)
				done <- true
			}
		}()
	}

	for i := uint32(0); i < pc; i++ {
		jobs <- i
	}
	for i := uint32(0); i < pc; i++ {
		<-done
	}

	close(jobs)

	return values
}
<commit_msg>Print the number of nodes in cmd/check<commit_after>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"runtime"
	"time"

	"github.com/ready-steady/format/mat"
	"github.com/ready-steady/numeric/interpolation/adhier"
	"github.com/ready-steady/probability"
	"github.com/ready-steady/probability/uniform"
	"github.com/ready-steady/statistics/metric"

	"../internal"
)

func main() {
	internal.Run(command)
}

func command(config *internal.Config, problem *internal.Problem,
	fi *mat.File, fo *mat.File) error {

	target, err := internal.NewTarget(problem)
	if err != nil {
		return err
	}

	interpolator, err := internal.NewInterpolator(problem, target)
	if err != nil {
		return err
	}

	problem.Println(problem)
	problem.Println(target)

	surrogate := new(adhier.Surrogate)
	if fi == nil {
		return errors.New("an input file is required")
	}
	if err := fi.Get("surrogate", surrogate); err != nil {
		return err
	}

	problem.Println(surrogate)

	sc := config.Samples
	if sc == 0 {
		return errors.New("the number of samples is zero")
	}

	ic, oc := target.InputsOutputs()

	if config.Seed > 0 {
		rand.Seed(config.Seed)
	} else {
		rand.Seed(time.Now().Unix())
	}
	points := probability.Sample(uniform.New(0, 1), sc*ic)

	problem.Println("Evaluating the original model...")
	values := invoke(target, points)

	problem.Println("Evaluating the surrogate model...")
	approximations := interpolator.Evaluate(surrogate, points)

	fmt.Printf("Nodes: %d, NRMSE: %.2e\n", surrogate.Nodes,
		metric.NRMSE(approximations, values))

	if fo == nil {
		return nil
	}

	if err := fo.PutMatrix("points", points, ic, sc); err != nil {
		return err
	}
	if err := fo.PutMatrix("values", values, oc, sc); err != nil {
		return err
	}
	if err := fo.PutMatrix("approximations", approximations, oc, sc); err != nil {
		return err
	}

	return nil
}

func invoke(target internal.Target, points []float64) []float64 {
	workerCount := uint32(runtime.GOMAXPROCS(0))

	ic, oc := target.InputsOutputs()
	pc := uint32(len(points)) / ic

	values := make([]float64, pc*oc)
	jobs := make(chan uint32, pc)
	done := make(chan bool, pc)

	for i := uint32(0); i < workerCount; i++ {
		go func() {
			for j := range jobs {
				target.Evaluate(points[j*ic:(j+1)*ic], values[j*oc:(j+1)*oc], nil)
				done <- true
			}
		}()
	}

	for i := uint32(0); i < pc; i++ {
		jobs <- i
	}
	for i := uint32(0); i < pc; i++ {
		<-done
	}

	close(jobs)

	return values
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"sort"
	"text/tabwriter"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
	"github.com/golang/dep/gps/pkgtree"
	"github.com/pkg/errors"
	"io"
)

const statusShortHelp = `Report the status of the project's dependencies`
const statusLongHelp = `
With no arguments, print the status of each dependency of the project.

  PROJECT     Import path
  CONSTRAINT  Version constraint, from the manifest
  VERSION     Version chosen, from the lock
  REVISION    VCS revision of the chosen version
  LATEST      Latest VCS revision available
  PKGS USED   Number of packages from this project that are actually used

With one or more explicitly specified packages, or with the -detailed flag,
print an extended status output for each dependency of the project.

  TODO    Another column description
  FOOBAR  Another column description

Status returns exit code zero if all dependencies are in a "good state".
`

func (cmd *statusCommand) Name() string      { return "status" }
func (cmd *statusCommand) Args() string      { return "[package...]" }
func (cmd *statusCommand) ShortHelp() string { return statusShortHelp }
func (cmd *statusCommand) LongHelp() string  { return statusLongHelp }
func (cmd *statusCommand) Hidden() bool      { return false }

func (cmd *statusCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.detailed, "detailed", false, "report more detailed status")
	fs.BoolVar(&cmd.json, "json", false, "output in JSON format")
	fs.StringVar(&cmd.template, "f", "", "output in text/template format")
	fs.BoolVar(&cmd.dot, "dot", false, "output the dependency graph in GraphViz format")
	fs.BoolVar(&cmd.old, "old", false, "only show out-of-date dependencies")
	fs.BoolVar(&cmd.missing, "missing", false, "only show missing dependencies")
	fs.BoolVar(&cmd.unused, "unused", false, "only show unused dependencies")
	fs.BoolVar(&cmd.modified, "modified", false, "only show modified dependencies")
}

type statusCommand struct {
	detailed bool
	json     bool
	template string
	output   string
	dot      bool
	old      bool
	missing  bool
	unused   bool
	modified bool
}

type outputter interface {
	BasicHeader()
	BasicLine(*BasicStatus)
	BasicFooter()
	MissingHeader()
	MissingLine(*MissingStatus)
	MissingFooter()
}

type tableOutput struct{ w *tabwriter.Writer }

func (out *tableOutput) BasicHeader() {
	fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tVERSION\tREVISION\tLATEST\tPKGS USED\n")
}

func (out *tableOutput) BasicFooter() {
	out.w.Flush()
}

func (out *tableOutput) BasicLine(bs *BasicStatus) {
	var constraint string
	if v, ok := bs.Constraint.(gps.Version); ok {
		constraint = formatVersion(v)
	} else {
		constraint = bs.Constraint.String()
	}
	fmt.Fprintf(out.w,
		"%s\t%s\t%s\t%s\t%s\t%d\t\n",
		bs.ProjectRoot,
		constraint,
		formatVersion(bs.Version),
		formatVersion(bs.Revision),
		formatVersion(bs.Latest),
		bs.PackageCount,
	)
}

func (out *tableOutput) MissingHeader() {
	fmt.Fprintln(out.w, "PROJECT\tMISSING PACKAGES")
}

func (out *tableOutput) MissingLine(ms *MissingStatus) {
	fmt.Fprintf(out.w,
		"%s\t%s\t\n",
		ms.ProjectRoot,
		ms.MissingPackages,
	)
}

func (out *tableOutput) MissingFooter() {
	out.w.Flush()
}

type jsonOutput struct {
	w       io.Writer
	basic   []*BasicStatus
	missing []*MissingStatus
}

func (out *jsonOutput) BasicHeader() {
	out.basic = []*BasicStatus{}
}

func (out *jsonOutput) BasicFooter() {
	json.NewEncoder(out.w).Encode(out.basic)
}

func (out *jsonOutput) BasicLine(bs *BasicStatus) {
	out.basic = append(out.basic, bs)
}

func (out *jsonOutput) MissingHeader() {
	out.missing = []*MissingStatus{}
}

func (out *jsonOutput) MissingLine(ms *MissingStatus) {
	out.missing = append(out.missing, ms)
}

func (out *jsonOutput) MissingFooter() {
	json.NewEncoder(out.w).Encode(out.missing)
}

type dotOutput struct {
	w io.Writer
	o string
	g *graphviz
	p *dep.Project
}

func (out *dotOutput) BasicHeader() {
	out.g = new(graphviz).New()

	ptree, _ := pkgtree.ListPackages(out.p.AbsRoot, string(out.p.ImportRoot))
	prm, _ := ptree.ToReachMap(true, false, false, nil)

	out.g.createNode(string(out.p.ImportRoot), "", prm.Flatten(false))
}

func (out *dotOutput) BasicFooter() {
	gvo := out.g.output()
	fmt.Fprintf(out.w, gvo.String())
}

func (out *dotOutput) BasicLine(bs *BasicStatus) {
	out.g.createNode(bs.ProjectRoot, bs.Version.String(), bs.Children)
}

func (out *dotOutput) MissingHeader()                {}
func (out *dotOutput) MissingLine(ms *MissingStatus) {}
func (out *dotOutput) MissingFooter()                {}

func (cmd *statusCommand) Run(ctx *dep.Ctx, loggers *Loggers, args []string) error {
	p, err := ctx.LoadProject("")
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var out outputter
	switch {
	case cmd.detailed:
		return errors.Errorf("not implemented")
	case cmd.json:
		out = &jsonOutput{
			w: &logWriter{Logger: loggers.Out},
		}
	case cmd.dot:
		out = &dotOutput{
			p: p,
			o: cmd.output,
			w: &logWriter{Logger: loggers.Out},
		}
	default:
		out = &tableOutput{
			w: tabwriter.NewWriter(&logWriter{Logger: loggers.Out}, 0, 4, 2, ' ', 0),
		}
	}
	return runStatusAll(loggers, out, p, sm)
}

// A logWriter adapts a log.Logger to the io.Writer interface.
type logWriter struct {
	*log.Logger
}

func (l *logWriter) Write(b []byte) (n int, err error) {
	str := string(b)
	if len(str) == 0 {
		return 0, nil
	}

	l.Print(str)
	return len(b), err
}

// BasicStatus contains all the information reported about a single dependency
// in the summary/list status output mode.
type BasicStatus struct {
	ProjectRoot  string
	Children     []string
	Constraint   gps.Constraint
	Version      gps.UnpairedVersion
	Revision     gps.Revision
	Latest       gps.Version
	PackageCount int
}

type MissingStatus struct {
	ProjectRoot     string
	MissingPackages []string
}

func runStatusAll(loggers *Loggers, out outputter, p *dep.Project, sm *gps.SourceMgr) error {
	if p.Lock == nil {
		// TODO if we have no lock file, do...other stuff
		return nil
	}

	// While the network churns on ListVersions() requests, statically analyze
	// code from the current project.
	ptree, err := pkgtree.ListPackages(p.AbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Errorf("analysis of local packages failed: %v", err)
	}

	// Set up a solver in order to check the InputHash.
	params := gps.SolveParameters{
		ProjectAnalyzer: dep.Analyzer{},
		RootDir:         p.AbsRoot,
		RootPackageTree: ptree,
		Manifest:        p.Manifest,
		// Locks aren't a part of the input hash check, so we can omit it.
	}
	if loggers.Verbose {
		params.TraceLogger = loggers.Err
	}

	s, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Errorf("could not set up solver for input hashing: %s", err)
	}

	cm := collectConstraints(ptree, p, sm)

	// Get the project list and sort it so that the printed output users see is
	// deterministically ordered. (This may be superfluous if the lock is always
	// written in alpha order, but it doesn't hurt to double down.)
	slp := p.Lock.Projects()
	sort.Sort(dep.SortedLockedProjects(slp))

	if bytes.Equal(s.HashInputs(), p.Lock.Memo) {
		// If these are equal, we're guaranteed that the lock is a transitively
		// complete picture of all deps. That eliminates the need for at least
		// some checks.

		out.BasicHeader()

		for _, proj := range slp {
			bs := BasicStatus{
				ProjectRoot:  string(proj.Ident().ProjectRoot),
				PackageCount: len(proj.Packages()),
			}

			// Get children only for specific outputers
			// in order to avoid slower status process
			switch out.(type) {
			case *dotOutput:
				ptr, err := sm.ListPackages(proj.Ident(), proj.Version())

				if err != nil {
					return fmt.Errorf("analysis of %s package failed: %v", proj.Ident().ProjectRoot, err)
				}

				prm, _ := ptr.ToReachMap(true, false, false, nil)
				bs.Children = prm.Flatten(false)
			}

			// Split apart the version from the lock into its constituent parts
			switch tv := proj.Version().(type) {
			case gps.UnpairedVersion:
				bs.Version = tv
			case gps.Revision:
				bs.Revision = tv
			case gps.PairedVersion:
				bs.Version = tv.Unpair()
				bs.Revision = tv.Underlying()
			}

			// Check if the manifest has an override for this project. If so,
			// set that as the constraint.
			if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
				// TODO note somehow that it's overridden
				bs.Constraint = pp.Constraint
			} else {
				bs.Constraint = gps.Any()
				for _, c := range cm[bs.ProjectRoot] {
					bs.Constraint = c.Intersect(bs.Constraint)
				}
			}

			// Only if we have a non-rev and non-plain version do/can we display
			// anything wrt the version's updateability.
			if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
				c, has := p.Manifest.Dependencies[proj.Ident().ProjectRoot]
				if !has {
					c.Constraint = gps.Any()
				}
				// TODO: This constraint is only the constraint imposed by the
				// current project, not by any transitive deps. As a result,
				// transitive project deps will always show "any" here.
				bs.Constraint = c.Constraint

				vl, err := sm.ListVersions(proj.Ident())
				if err == nil {
					gps.SortPairedForUpgrade(vl)

					for _, v := range vl {
						// Because we've sorted the version list for
						// upgrade, the first version we encounter that
						// matches our constraint will be what we want.
						if c.Constraint.Matches(v) {
							bs.Latest = v.Underlying()
							break
						}
					}
				}
			}

			out.BasicLine(&bs)
		}
		out.BasicFooter()

		return nil
	}

	// Hash digest mismatch may indicate that some deps are no longer
	// needed, some are missing, or that some constraints or source
	// locations have changed.
	//
	// It's possible for digests to not match, but still have a correct
	// lock.
	rm, _ := ptree.ToReachMap(true, true, false, nil)

	external := rm.Flatten(false)
	roots := make(map[gps.ProjectRoot][]string, len(external))

	type fail struct {
		ex  string
		err error
	}
	var errs []fail
	for _, e := range external {
		root, err := sm.DeduceProjectRoot(e)
		if err != nil {
			errs = append(errs, fail{
				ex:  e,
				err: err,
			})
			continue
		}

		roots[root] = append(roots[root], e)
	}

	if len(errs) != 0 {
		// TODO this is just a fix quick so staticcheck doesn't complain.
		// Visually reconciling failure to deduce project roots with the rest of
		// the mismatch output is a larger problem.
		loggers.Err.Printf("Failed to deduce project roots for import paths:\n")
		for _, fail := range errs {
			loggers.Err.Printf("\t%s: %s\n", fail.ex, fail.err.Error())
		}

		return errors.New("address issues with undeducable import paths to get more status information.")
	}

	out.MissingHeader()

outer:
	for root, pkgs := range roots {
		// TODO also handle the case where the project is present, but there
		// are items missing from just the package list
		for _, lp := range slp {
			if lp.Ident().ProjectRoot == root {
				continue outer
			}
		}

		out.MissingLine(&MissingStatus{ProjectRoot: string(root), MissingPackages: pkgs})
	}
	out.MissingFooter()

	return nil
}

func formatVersion(v gps.Version) string {
	if v == nil {
		return ""
	}
	switch v.Type() {
	case gps.IsBranch:
		return "branch " + v.String()
	case gps.IsRevision:
		r := v.String()
		if len(r) > 7 {
			r = r[:7]
		}
		return r
	}
	return v.String()
}

func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm *gps.SourceMgr) map[string][]gps.Constraint {
	// TODO
	return map[string][]gps.Constraint{}
}
<commit_msg>cleanup<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"sort"
	"text/tabwriter"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
	"github.com/golang/dep/gps/pkgtree"
	"github.com/pkg/errors"
)

const statusShortHelp = `Report the status of the project's dependencies`
const statusLongHelp = `
With no arguments, print the status of each dependency of the project.

  PROJECT     Import path
  CONSTRAINT  Version constraint, from the manifest
  VERSION     Version chosen, from the lock
  REVISION    VCS revision of the chosen version
  LATEST      Latest VCS revision available
  PKGS USED   Number of packages from this project that are actually used

With one or more explicitly specified packages, or with the -detailed flag,
print an extended status output for each dependency of the project.

  TODO    Another column description
  FOOBAR  Another column description

Status returns exit code zero if all dependencies are in a "good state".
`

func (cmd *statusCommand) Name() string      { return "status" }
func (cmd *statusCommand) Args() string      { return "[package...]" }
func (cmd *statusCommand) ShortHelp() string { return statusShortHelp }
func (cmd *statusCommand) LongHelp() string  { return statusLongHelp }
func (cmd *statusCommand) Hidden() bool      { return false }

func (cmd *statusCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.detailed, "detailed", false, "report more detailed status")
	fs.BoolVar(&cmd.json, "json", false, "output in JSON format")
	fs.StringVar(&cmd.template, "f", "", "output in text/template format")
	fs.BoolVar(&cmd.dot, "dot", false, "output the dependency graph in GraphViz format")
	fs.BoolVar(&cmd.old, "old", false, "only show out-of-date dependencies")
	fs.BoolVar(&cmd.missing, "missing", false, "only show missing dependencies")
	fs.BoolVar(&cmd.unused, "unused", false, "only show unused dependencies")
	fs.BoolVar(&cmd.modified, "modified", false, "only show modified dependencies")
}

type statusCommand struct {
	detailed bool
	json     bool
	template string
	output   string
	dot      bool
	old      bool
	missing  bool
	unused   bool
	modified bool
}

type outputter interface {
	BasicHeader()
	BasicLine(*BasicStatus)
	BasicFooter()
	MissingHeader()
	MissingLine(*MissingStatus)
	MissingFooter()
}

type tableOutput struct{ w *tabwriter.Writer }

func (out *tableOutput) BasicHeader() {
	fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tVERSION\tREVISION\tLATEST\tPKGS USED\n")
}

func (out *tableOutput) BasicFooter() {
	out.w.Flush()
}

func (out *tableOutput) BasicLine(bs *BasicStatus) {
	var constraint string
	if v, ok := bs.Constraint.(gps.Version); ok {
		constraint = formatVersion(v)
	} else {
		constraint = bs.Constraint.String()
	}
	fmt.Fprintf(out.w,
		"%s\t%s\t%s\t%s\t%s\t%d\t\n",
		bs.ProjectRoot,
		constraint,
		formatVersion(bs.Version),
		formatVersion(bs.Revision),
		formatVersion(bs.Latest),
		bs.PackageCount,
	)
}

func (out *tableOutput) MissingHeader() {
	fmt.Fprintln(out.w, "PROJECT\tMISSING PACKAGES")
}

func (out *tableOutput) MissingLine(ms *MissingStatus) {
	fmt.Fprintf(out.w,
		"%s\t%s\t\n",
		ms.ProjectRoot,
		ms.MissingPackages,
	)
}

func (out *tableOutput) MissingFooter() {
	out.w.Flush()
}

type jsonOutput struct {
	w       io.Writer
	basic   []*BasicStatus
	missing []*MissingStatus
}

func (out *jsonOutput) BasicHeader() {
	out.basic = []*BasicStatus{}
}

func (out *jsonOutput) BasicFooter() {
	json.NewEncoder(out.w).Encode(out.basic)
}

func (out *jsonOutput) BasicLine(bs *BasicStatus) {
	out.basic = append(out.basic, bs)
}

func (out *jsonOutput) MissingHeader() {
	out.missing = []*MissingStatus{}
}

func (out *jsonOutput) MissingLine(ms *MissingStatus) {
	out.missing = append(out.missing, ms)
}

func (out *jsonOutput) MissingFooter() {
	json.NewEncoder(out.w).Encode(out.missing)
}

type dotOutput struct {
	w io.Writer
	o string
	g *graphviz
	p *dep.Project
}

func (out *dotOutput) BasicHeader() {
	out.g = new(graphviz).New()

	ptree, _ := pkgtree.ListPackages(out.p.AbsRoot, string(out.p.ImportRoot))
	prm, _ := ptree.ToReachMap(true, false, false, nil)

	out.g.createNode(string(out.p.ImportRoot), "", prm.Flatten(false))
}

func (out *dotOutput) BasicFooter() {
	gvo := out.g.output()
	fmt.Fprintf(out.w, gvo.String())
}

func (out *dotOutput) BasicLine(bs *BasicStatus) {
	out.g.createNode(bs.ProjectRoot, bs.Version.String(), bs.Children)
}

func (out *dotOutput) MissingHeader()                {}
func (out *dotOutput) MissingLine(ms *MissingStatus) {}
func (out *dotOutput) MissingFooter()                {}

func (cmd *statusCommand) Run(ctx *dep.Ctx, loggers *Loggers, args []string) error {
	p, err := ctx.LoadProject("")
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var out outputter
	switch {
	case cmd.detailed:
		return errors.Errorf("not implemented")
	case cmd.json:
		out = &jsonOutput{
			w: &logWriter{Logger: loggers.Out},
		}
	case cmd.dot:
		out = &dotOutput{
			p: p,
			o: cmd.output,
			w: &logWriter{Logger: loggers.Out},
		}
	default:
		out = &tableOutput{
			w: tabwriter.NewWriter(&logWriter{Logger: loggers.Out}, 0, 4, 2, ' ', 0),
		}
	}
	return runStatusAll(loggers, out, p, sm)
}

// A logWriter adapts a log.Logger to the io.Writer interface.
type logWriter struct {
	*log.Logger
}

func (l *logWriter) Write(b []byte) (n int, err error) {
	str := string(b)
	if len(str) == 0 {
		return 0, nil
	}

	l.Print(str)
	return len(b), err
}

// BasicStatus contains all the information reported about a single dependency
// in the summary/list status output mode.
type BasicStatus struct {
	ProjectRoot  string
	Children     []string
	Constraint   gps.Constraint
	Version      gps.UnpairedVersion
	Revision     gps.Revision
	Latest       gps.Version
	PackageCount int
}

type MissingStatus struct {
	ProjectRoot     string
	MissingPackages []string
}

func runStatusAll(loggers *Loggers, out outputter, p *dep.Project, sm *gps.SourceMgr) error {
	if p.Lock == nil {
		// TODO if we have no lock file, do...other stuff
		return nil
	}

	// While the network churns on ListVersions() requests, statically analyze
	// code from the current project.
	ptree, err := pkgtree.ListPackages(p.AbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Errorf("analysis of local packages failed: %v", err)
	}

	// Set up a solver in order to check the InputHash.
	params := gps.SolveParameters{
		ProjectAnalyzer: dep.Analyzer{},
		RootDir:         p.AbsRoot,
		RootPackageTree: ptree,
		Manifest:        p.Manifest,
		// Locks aren't a part of the input hash check, so we can omit it.
	}
	if loggers.Verbose {
		params.TraceLogger = loggers.Err
	}

	s, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Errorf("could not set up solver for input hashing: %s", err)
	}

	cm := collectConstraints(ptree, p, sm)

	// Get the project list and sort it so that the printed output users see is
	// deterministically ordered. (This may be superfluous if the lock is always
	// written in alpha order, but it doesn't hurt to double down.)
	slp := p.Lock.Projects()
	sort.Sort(dep.SortedLockedProjects(slp))

	if bytes.Equal(s.HashInputs(), p.Lock.Memo) {
		// If these are equal, we're guaranteed that the lock is a transitively
		// complete picture of all deps. That eliminates the need for at least
		// some checks.

		out.BasicHeader()

		for _, proj := range slp {
			bs := BasicStatus{
				ProjectRoot:  string(proj.Ident().ProjectRoot),
				PackageCount: len(proj.Packages()),
			}

			// Get children only for specific outputers
			// in order to avoid slower status process
			switch out.(type) {
			case *dotOutput:
				ptr, err := sm.ListPackages(proj.Ident(), proj.Version())

				if err != nil {
					return fmt.Errorf("analysis of %s package failed: %v", proj.Ident().ProjectRoot, err)
				}

				prm, _ := ptr.ToReachMap(true, false, false, nil)
				bs.Children = prm.Flatten(false)
			}

			// Split apart the version from the lock into its constituent parts
			switch tv := proj.Version().(type) {
			case gps.UnpairedVersion:
				bs.Version = tv
			case gps.Revision:
				bs.Revision = tv
			case gps.PairedVersion:
				bs.Version = tv.Unpair()
				bs.Revision = tv.Underlying()
			}

			// Check if the manifest has an override for this project. If so,
			// set that as the constraint.
			if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
				// TODO note somehow that it's overridden
				bs.Constraint = pp.Constraint
			} else {
				bs.Constraint = gps.Any()
				for _, c := range cm[bs.ProjectRoot] {
					bs.Constraint = c.Intersect(bs.Constraint)
				}
			}

			// Only if we have a non-rev and non-plain version do/can we display
			// anything wrt the version's updateability.
			if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
				c, has := p.Manifest.Dependencies[proj.Ident().ProjectRoot]
				if !has {
					c.Constraint = gps.Any()
				}
				// TODO: This constraint is only the constraint imposed by the
				// current project, not by any transitive deps. As a result,
				// transitive project deps will always show "any" here.
				bs.Constraint = c.Constraint

				vl, err := sm.ListVersions(proj.Ident())
				if err == nil {
					gps.SortPairedForUpgrade(vl)

					for _, v := range vl {
						// Because we've sorted the version list for
						// upgrade, the first version we encounter that
						// matches our constraint will be what we want.
						if c.Constraint.Matches(v) {
							bs.Latest = v.Underlying()
							break
						}
					}
				}
			}

			out.BasicLine(&bs)
		}
		out.BasicFooter()

		return nil
	}

	// Hash digest mismatch may indicate that some deps are no longer
	// needed, some are missing, or that some constraints or source
	// locations have changed.
	//
	// It's possible for digests to not match, but still have a correct
	// lock.
	rm, _ := ptree.ToReachMap(true, true, false, nil)

	external := rm.Flatten(false)
	roots := make(map[gps.ProjectRoot][]string, len(external))

	type fail struct {
		ex  string
		err error
	}
	var errs []fail
	for _, e := range external {
		root, err := sm.DeduceProjectRoot(e)
		if err != nil {
			errs = append(errs, fail{
				ex:  e,
				err: err,
			})
			continue
		}

		roots[root] = append(roots[root], e)
	}

	if len(errs) != 0 {
		// TODO this is just a fix quick so staticcheck doesn't complain.
		// Visually reconciling failure to deduce project roots with the rest of
		// the mismatch output is a larger problem.
		loggers.Err.Printf("Failed to deduce project roots for import paths:\n")
		for _, fail := range errs {
			loggers.Err.Printf("\t%s: %s\n", fail.ex, fail.err.Error())
		}

		return errors.New("address issues with undeducable import paths to get more status information.")
	}

	out.MissingHeader()

outer:
	for root, pkgs := range roots {
		// TODO also handle the case where the project is present, but there
		// are items missing from just the package list
		for _, lp := range slp {
			if lp.Ident().ProjectRoot == root {
				continue outer
			}
		}

		out.MissingLine(&MissingStatus{ProjectRoot: string(root), MissingPackages: pkgs})
	}
	out.MissingFooter()

	return nil
}

func formatVersion(v gps.Version) string {
	if v == nil {
		return ""
	}
	switch v.Type() {
	case gps.IsBranch:
		return "branch " + v.String()
	case gps.IsRevision:
		r := v.String()
		if len(r) > 7 {
			r = r[:7]
		}
		return r
	}
	return v.String()
}

func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm *gps.SourceMgr) map[string][]gps.Constraint {
	// TODO
	return map[string][]gps.Constraint{}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"sort"
	"text/tabwriter"

	"github.com/golang/dep"
	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
	"github.com/pkg/errors"
)

const statusShortHelp = `Report the status of the project's dependencies`
const statusLongHelp = `
With no arguments, print the status of each dependency of the project.

  PROJECT     Import path
  CONSTRAINT  Version constraint, from the manifest
  VERSION     Version chosen, from the lock
  REVISION    VCS revision of the chosen version
  LATEST      Latest VCS revision available
  PKGS USED   Number of packages from this project that are actually used

With one or more explicitly specified packages, or with the -detailed flag,
print an extended status output for each dependency of the project.

  TODO    Another column description
  FOOBAR  Another column description

Status returns exit code zero if all dependencies are in a "good state".
`

func (cmd *statusCommand) Name() string      { return "status" }
func (cmd *statusCommand) Args() string      { return "[package...]" }
func (cmd *statusCommand) ShortHelp() string { return statusShortHelp }
func (cmd *statusCommand) LongHelp() string  { return statusLongHelp }
func (cmd *statusCommand) Hidden() bool      { return false }

func (cmd *statusCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.detailed, "detailed", false, "report more detailed status")
	fs.BoolVar(&cmd.json, "json", false, "output in JSON format")
	fs.StringVar(&cmd.template, "f", "", "output in text/template format")
	fs.BoolVar(&cmd.dot, "dot", false, "output the dependency graph in GraphViz format")
	fs.BoolVar(&cmd.old, "old", false, "only show out-of-date dependencies")
	fs.BoolVar(&cmd.missing, "missing", false, "only show missing dependencies")
	fs.BoolVar(&cmd.unused, "unused", false, "only show unused dependencies")
	fs.BoolVar(&cmd.modified, "modified", false, "only show modified dependencies")
}

type statusCommand struct {
	detailed bool
	json     bool
	template string
	output   string
	dot      bool
	old      bool
	missing  bool
	unused   bool
	modified bool
}

type outputter interface {
	BasicHeader()
	BasicLine(*BasicStatus)
	BasicFooter()
	MissingHeader()
	MissingLine(*MissingStatus)
	MissingFooter()
}

type tableOutput struct{ w *tabwriter.Writer }

func (out *tableOutput) BasicHeader() {
	fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tVERSION\tREVISION\tLATEST\tPKGS USED\n")
}

func (out *tableOutput) BasicFooter() {
	out.w.Flush()
}

func (out *tableOutput) BasicLine(bs *BasicStatus) {
	var constraint string
	if v, ok := bs.Constraint.(gps.Version); ok {
		constraint = formatVersion(v)
	} else {
		constraint = bs.Constraint.String()
	}
	fmt.Fprintf(out.w,
		"%s\t%s\t%s\t%s\t%s\t%d\t\n",
		bs.ProjectRoot,
		constraint,
		formatVersion(bs.Version),
		formatVersion(bs.Revision),
		formatVersion(bs.Latest),
		bs.PackageCount,
	)
}

func (out *tableOutput) MissingHeader() {
	fmt.Fprintln(out.w, "PROJECT\tMISSING PACKAGES")
}

func (out *tableOutput) MissingLine(ms *MissingStatus) {
	fmt.Fprintf(out.w,
		"%s\t%s\t\n",
		ms.ProjectRoot,
		ms.MissingPackages,
	)
}

func (out *tableOutput) MissingFooter() {
	out.w.Flush()
}

type jsonOutput struct {
	w       io.Writer
	basic   []*BasicStatus
	missing []*MissingStatus
}

func (out *jsonOutput) BasicHeader() {
	out.basic = []*BasicStatus{}
}

func (out *jsonOutput) BasicFooter() {
	json.NewEncoder(out.w).Encode(out.basic)
}

func (out *jsonOutput) BasicLine(bs *BasicStatus) {
	out.basic = append(out.basic, bs)
}

func (out *jsonOutput) MissingHeader() {
	out.missing = []*MissingStatus{}
}

func (out *jsonOutput) MissingLine(ms *MissingStatus) {
	out.missing = append(out.missing, ms)
}

func (out *jsonOutput) MissingFooter() {
	json.NewEncoder(out.w).Encode(out.missing)
}

type dotOutput struct {
	w io.Writer
	o string
	g *graphviz
	p *dep.Project
}

func (out *dotOutput) BasicHeader() {
	out.g = new(graphviz).New()

	ptree, _ := pkgtree.ListPackages(out.p.AbsRoot, string(out.p.ImportRoot))
	prm, _ := ptree.ToReachMap(true, false, false, nil)

	out.g.createNode(string(out.p.ImportRoot), "", prm.Flatten(false))
}

func (out *dotOutput) BasicFooter() {
	gvo := out.g.output()
	fmt.Fprintf(out.w, gvo.String())
}

func (out *dotOutput) BasicLine(bs *BasicStatus) {
	out.g.createNode(bs.ProjectRoot, bs.Version.String(), bs.Children)
}

func (out *dotOutput) MissingHeader()                {}
func (out *dotOutput) MissingLine(ms *MissingStatus) {}
func (out *dotOutput) MissingFooter()                {}

func (cmd *statusCommand) Run(ctx *dep.Ctx, loggers *Loggers, args []string) error {
	p, err := ctx.LoadProject("")
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var out outputter
	switch {
	case cmd.detailed:
		return errors.Errorf("not implemented")
	case cmd.json:
		out = &jsonOutput{
			w: &logWriter{Logger: loggers.Out},
		}
	case cmd.dot:
		out = &dotOutput{
			p: p,
			o: cmd.output,
			w: &logWriter{Logger: loggers.Out},
		}
	default:
		out = &tableOutput{
			w: tabwriter.NewWriter(&logWriter{Logger: loggers.Out}, 0, 4, 2, ' ', 0),
		}
	}
	return runStatusAll(loggers, out, p, sm)
}

// A logWriter adapts a log.Logger to the io.Writer interface.
type logWriter struct {
	*log.Logger
}

func (l *logWriter) Write(b []byte) (n int, err error) {
	str := string(b)
	if len(str) == 0 {
		return 0, nil
	}

	l.Print(str)
	return len(b), err
}

// BasicStatus contains all the information reported about a single dependency
// in the summary/list status output mode.
type BasicStatus struct {
	ProjectRoot  string
	Children     []string
	Constraint   gps.Constraint
	Version      gps.UnpairedVersion
	Revision     gps.Revision
	Latest       gps.Version
	PackageCount int
}

type MissingStatus struct {
	ProjectRoot     string
	MissingPackages []string
}

func runStatusAll(loggers *Loggers, out outputter, p *dep.Project, sm gps.SourceManager) error {
	if p.Lock == nil {
		// TODO if we have no lock file, do...other stuff
		return nil
	}

	// While the network churns on ListVersions() requests, statically analyze
	// code from the current project.
	ptree, err := pkgtree.ListPackages(p.AbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Errorf("analysis of local packages failed: %v", err)
	}

	// Set up a solver in order to check the InputHash.
	params := gps.SolveParameters{
		ProjectAnalyzer: dep.Analyzer{},
		RootDir:         p.AbsRoot,
		RootPackageTree: ptree,
		Manifest:        p.Manifest,
		// Locks aren't a part of the input hash check, so we can omit it.
	}
	if loggers.Verbose {
		params.TraceLogger = loggers.Err
	}

	s, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Errorf("could not set up solver for input hashing: %s", err)
	}

	cm := collectConstraints(ptree, p, sm)

	// Get the project list and sort it so that the printed output users see is
	// deterministically ordered. (This may be superfluous if the lock is always
	// written in alpha order, but it doesn't hurt to double down.)
	slp := p.Lock.Projects()
	sort.Sort(dep.SortedLockedProjects(slp))

	if bytes.Equal(s.HashInputs(), p.Lock.Memo) {
		// If these are equal, we're guaranteed that the lock is a transitively
		// complete picture of all deps. That eliminates the need for at least
		// some checks.

		out.BasicHeader()

		for _, proj := range slp {
			bs := BasicStatus{
				ProjectRoot:  string(proj.Ident().ProjectRoot),
				PackageCount: len(proj.Packages()),
			}

			// Get children only for specific outputers
			// in order to avoid slower status process
			switch out.(type) {
			case *dotOutput:
				ptr, err := sm.ListPackages(proj.Ident(), proj.Version())

				if err != nil {
					return fmt.Errorf("analysis of %s package failed: %v", proj.Ident().ProjectRoot, err)
				}

				prm, _ := ptr.ToReachMap(true, false, false, nil)
				bs.Children = prm.Flatten(false)
			}

			// Split apart the version from the lock into its constituent parts
			switch tv := proj.Version().(type) {
			case gps.UnpairedVersion:
				bs.Version = tv
			case gps.Revision:
				bs.Revision = tv
			case gps.PairedVersion:
				bs.Version = tv.Unpair()
				bs.Revision = tv.Underlying()
			}

			// Check if the manifest has an override for this project. If so,
			// set that as the constraint.
			if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
				// TODO note somehow that it's overridden
				bs.Constraint = pp.Constraint
			} else {
				bs.Constraint = gps.Any()
				for _, c := range cm[bs.ProjectRoot] {
					bs.Constraint = c.Intersect(bs.Constraint)
				}
			}

			// Only if we have a non-rev and non-plain version do/can we display
			// anything wrt the version's updateability.
			if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
				c, has := p.Manifest.Dependencies[proj.Ident().ProjectRoot]
				if !has {
					c.Constraint = gps.Any()
				}
				// TODO: This constraint is only the constraint imposed by the
				// current project, not by any transitive deps. As a result,
				// transitive project deps will always show "any" here.
				bs.Constraint = c.Constraint

				vl, err := sm.ListVersions(proj.Ident())
				if err == nil {
					gps.SortPairedForUpgrade(vl)

					for _, v := range vl {
						// Because we've sorted the version list for
						// upgrade, the first version we encounter that
						// matches our constraint will be what we want.
						if c.Constraint.Matches(v) {
							bs.Latest = v.Underlying()
							break
						}
					}
				}
			}

			out.BasicLine(&bs)
		}
		out.BasicFooter()

		return nil
	}

	// Hash digest mismatch may indicate that some deps are no longer
	// needed, some are missing, or that some constraints or source
	// locations have changed.
	//
	// It's possible for digests to not match, but still have a correct
	// lock.
	rm, _ := ptree.ToReachMap(true, true, false, nil)

	external := rm.Flatten(false)
	roots := make(map[gps.ProjectRoot][]string, len(external))

	type fail struct {
		ex  string
		err error
	}
	var errs []fail
	for _, e := range external {
		root, err := sm.DeduceProjectRoot(e)
		if err != nil {
			errs = append(errs, fail{
				ex:  e,
				err: err,
			})
			continue
		}

		roots[root] = append(roots[root], e)
	}

	if len(errs) != 0 {
		// TODO this is just a fix quick so staticcheck doesn't complain.
		// Visually reconciling failure to deduce project roots with the rest of
		// the mismatch output is a larger problem.
		loggers.Err.Printf("Failed to deduce project roots for import paths:\n")
		for _, fail := range errs {
			loggers.Err.Printf("\t%s: %s\n", fail.ex, fail.err.Error())
		}

		return errors.New("address issues with undeducable import paths to get more status information.")
	}

	out.MissingHeader()

outer:
	for root, pkgs := range roots {
		// TODO also handle the case where the project is present, but there
		// are items missing from just the package list
		for _, lp := range slp {
			if lp.Ident().ProjectRoot == root {
				continue outer
			}
		}

		out.MissingLine(&MissingStatus{ProjectRoot: string(root), MissingPackages: pkgs})
	}
	out.MissingFooter()

	return nil
}

func formatVersion(v gps.Version) string {
	if v == nil {
		return ""
	}
	switch v.Type() {
	case gps.IsBranch:
		return "branch " + v.String()
	case gps.IsRevision:
		r := v.String()
		if len(r) > 7 {
			r = r[:7]
		}
		return r
	}
	return v.String()
}

func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm gps.SourceManager) map[string][]gps.Constraint {
	// TODO
	return map[string][]gps.Constraint{}
}
<commit_msg>buffer status output - fixes #532<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"sort"
	"text/tabwriter"

	"github.com/golang/dep"
	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
	"github.com/pkg/errors"
)

const statusShortHelp = `Report the status of the project's dependencies`
const statusLongHelp = `
With no arguments, print the status of each dependency of the project.

  PROJECT     Import path
  CONSTRAINT  Version constraint, from the manifest
  VERSION     Version chosen, from the lock
  REVISION    VCS revision of the chosen version
  LATEST      Latest VCS revision available
  PKGS USED   Number of packages from this project that are actually used

With one or more explicitly specified packages, or with the -detailed flag,
print an extended status output for each dependency of the project.

  TODO    Another column description
  FOOBAR  Another column description

Status returns exit code zero if all dependencies are in a "good state".
`

func (cmd *statusCommand) Name() string      { return "status" }
func (cmd *statusCommand) Args() string      { return "[package...]" }
func (cmd *statusCommand) ShortHelp() string { return statusShortHelp }
func (cmd *statusCommand) LongHelp() string  { return statusLongHelp }
func (cmd *statusCommand) Hidden() bool      { return false }

func (cmd *statusCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.detailed, "detailed", false, "report more detailed status")
	fs.BoolVar(&cmd.json, "json", false, "output in JSON format")
	fs.StringVar(&cmd.template, "f", "", "output in text/template format")
	fs.BoolVar(&cmd.dot, "dot", false, "output the dependency graph in GraphViz format")
	fs.BoolVar(&cmd.old, "old", false, "only show out-of-date dependencies")
	fs.BoolVar(&cmd.missing, "missing", false, "only show missing dependencies")
	fs.BoolVar(&cmd.unused, "unused", false, "only show unused dependencies")
	fs.BoolVar(&cmd.modified, "modified", false, "only show modified dependencies")
}

type statusCommand struct {
	detailed bool
	json     bool
	template string
	output   string
	dot      bool
	old      bool
	missing  bool
	unused   bool
	modified bool
}

type outputter interface {
	BasicHeader()
	BasicLine(*BasicStatus)
	BasicFooter()
	MissingHeader()
	MissingLine(*MissingStatus)
	MissingFooter()
}

type tableOutput struct{ w *tabwriter.Writer }

func (out *tableOutput) BasicHeader() {
	fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tVERSION\tREVISION\tLATEST\tPKGS USED\n")
}

func (out *tableOutput) BasicFooter() {
	out.w.Flush()
}

func (out *tableOutput) BasicLine(bs *BasicStatus) {
	var constraint string
	if v, ok := bs.Constraint.(gps.Version); ok {
		constraint = formatVersion(v)
	} else {
		constraint = bs.Constraint.String()
	}
	fmt.Fprintf(out.w,
		"%s\t%s\t%s\t%s\t%s\t%d\t\n",
		bs.ProjectRoot,
		constraint,
		formatVersion(bs.Version),
		formatVersion(bs.Revision),
		formatVersion(bs.Latest),
		bs.PackageCount,
	)
}

func (out *tableOutput) MissingHeader() {
	fmt.Fprintln(out.w, "PROJECT\tMISSING PACKAGES")
}

func (out *tableOutput) MissingLine(ms *MissingStatus) {
	fmt.Fprintf(out.w,
		"%s\t%s\t\n",
		ms.ProjectRoot,
		ms.MissingPackages,
	)
}

func (out *tableOutput) MissingFooter() {
	out.w.Flush()
}

type jsonOutput struct {
	w       io.Writer
	basic   []*BasicStatus
	missing []*MissingStatus
}

func (out *jsonOutput) BasicHeader() {
	out.basic = []*BasicStatus{}
}

func (out *jsonOutput) BasicFooter() {
	json.NewEncoder(out.w).Encode(out.basic)
}

func (out *jsonOutput) BasicLine(bs *BasicStatus) {
	out.basic = append(out.basic, bs)
}

func (out *jsonOutput) MissingHeader() {
	out.missing = []*MissingStatus{}
}

func (out *jsonOutput) MissingLine(ms *MissingStatus) {
	out.missing = append(out.missing, ms)
}

func (out *jsonOutput) MissingFooter() {
	json.NewEncoder(out.w).Encode(out.missing)
}

type dotOutput struct {
	w io.Writer
	o string
	g *graphviz
	p *dep.Project
}

func (out *dotOutput) BasicHeader() {
	out.g = new(graphviz).New()

	ptree, _ := pkgtree.ListPackages(out.p.AbsRoot, string(out.p.ImportRoot))
	prm, _ := ptree.ToReachMap(true, false, false, nil)

	out.g.createNode(string(out.p.ImportRoot), "", prm.Flatten(false))
}

func (out *dotOutput) BasicFooter() {
	gvo := out.g.output()
	fmt.Fprintf(out.w, gvo.String())
}

func (out *dotOutput) BasicLine(bs *BasicStatus) {
	out.g.createNode(bs.ProjectRoot, bs.Version.String(), bs.Children)
}

func (out *dotOutput) MissingHeader()                {}
func (out *dotOutput) MissingLine(ms *MissingStatus) {}
func (out *dotOutput) MissingFooter()                {}

func (cmd *statusCommand) Run(ctx *dep.Ctx, loggers *Loggers, args []string) error {
	p, err := ctx.LoadProject("")
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var buf bytes.Buffer
	var out outputter
	switch {
	case cmd.detailed:
		return errors.Errorf("not implemented")
	case cmd.json:
		out = &jsonOutput{
			w: &buf,
		}
	case cmd.dot:
		out = &dotOutput{
			p: p,
			o: cmd.output,
			w: &buf,
		}
	default:
		out = &tableOutput{
			w: tabwriter.NewWriter(&buf, 0, 4, 2, ' ', 0),
		}
	}

	if err := runStatusAll(loggers, out, p, sm); err != nil {
		return err
	}

	loggers.Out.Print(buf.String())
	return nil
}

// BasicStatus contains all the information reported about a single dependency
// in the summary/list status output mode.
type BasicStatus struct {
	ProjectRoot  string
	Children     []string
	Constraint   gps.Constraint
	Version      gps.UnpairedVersion
	Revision     gps.Revision
	Latest       gps.Version
	PackageCount int
}

type MissingStatus struct {
	ProjectRoot     string
	MissingPackages []string
}

func runStatusAll(loggers *Loggers, out outputter, p *dep.Project, sm gps.SourceManager) error {
	if p.Lock == nil {
		// TODO if we have no lock file, do...other stuff
		return nil
	}

	// While the network churns on ListVersions() requests, statically analyze
	// code from the current project.
	ptree, err := pkgtree.ListPackages(p.AbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Errorf("analysis of local packages failed: %v", err)
	}

	// Set up a solver in order to check the InputHash.
	params := gps.SolveParameters{
		ProjectAnalyzer: dep.Analyzer{},
		RootDir:         p.AbsRoot,
		RootPackageTree: ptree,
		Manifest:        p.Manifest,
		// Locks aren't a part of the input hash check, so we can omit it.
	}
	if loggers.Verbose {
		params.TraceLogger = loggers.Err
	}

	s, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Errorf("could not set up solver for input hashing: %s", err)
	}

	cm := collectConstraints(ptree, p, sm)

	// Get the project list and sort it so that the printed output users see is
	// deterministically ordered. (This may be superfluous if the lock is always
	// written in alpha order, but it doesn't hurt to double down.)
	slp := p.Lock.Projects()
	sort.Sort(dep.SortedLockedProjects(slp))

	if bytes.Equal(s.HashInputs(), p.Lock.Memo) {
		// If these are equal, we're guaranteed that the lock is a transitively
		// complete picture of all deps. That eliminates the need for at least
		// some checks.

		out.BasicHeader()

		for _, proj := range slp {
			bs := BasicStatus{
				ProjectRoot:  string(proj.Ident().ProjectRoot),
				PackageCount: len(proj.Packages()),
			}

			// Get children only for specific outputers
			// in order to avoid slower status process
			switch out.(type) {
			case *dotOutput:
				ptr, err := sm.ListPackages(proj.Ident(), proj.Version())

				if err != nil {
					return fmt.Errorf("analysis of %s package failed: %v", proj.Ident().ProjectRoot, err)
				}

				prm, _ := ptr.ToReachMap(true, false, false, nil)
				bs.Children = prm.Flatten(false)
			}

			// Split apart the version from the lock into its constituent parts
			switch tv := proj.Version().(type) {
			case gps.UnpairedVersion:
				bs.Version = tv
			case gps.Revision:
				bs.Revision = tv
			case gps.PairedVersion:
				bs.Version = tv.Unpair()
				bs.Revision = tv.Underlying()
			}

			// Check if the manifest has an override for this project. If so,
			// set that as the constraint.
			if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil {
				// TODO note somehow that it's overridden
				bs.Constraint = pp.Constraint
			} else {
				bs.Constraint = gps.Any()
				for _, c := range cm[bs.ProjectRoot] {
					bs.Constraint = c.Intersect(bs.Constraint)
				}
			}

			// Only if we have a non-rev and non-plain version do/can we display
			// anything wrt the version's updateability.
			if bs.Version != nil && bs.Version.Type() != gps.IsVersion {
				c, has := p.Manifest.Dependencies[proj.Ident().ProjectRoot]
				if !has {
					c.Constraint = gps.Any()
				}
				// TODO: This constraint is only the constraint imposed by the
				// current project, not by any transitive deps. As a result,
				// transitive project deps will always show "any" here.
				bs.Constraint = c.Constraint

				vl, err := sm.ListVersions(proj.Ident())
				if err == nil {
					gps.SortPairedForUpgrade(vl)

					for _, v := range vl {
						// Because we've sorted the version list for
						// upgrade, the first version we encounter that
						// matches our constraint will be what we want.
						if c.Constraint.Matches(v) {
							bs.Latest = v.Underlying()
							break
						}
					}
				}
			}

			out.BasicLine(&bs)
		}
		out.BasicFooter()

		return nil
	}

	// Hash digest mismatch may indicate that some deps are no longer
	// needed, some are missing, or that some constraints or source
	// locations have changed.
	//
	// It's possible for digests to not match, but still have a correct
	// lock.
	rm, _ := ptree.ToReachMap(true, true, false, nil)

	external := rm.Flatten(false)
	roots := make(map[gps.ProjectRoot][]string, len(external))

	type fail struct {
		ex  string
		err error
	}
	var errs []fail
	for _, e := range external {
		root, err := sm.DeduceProjectRoot(e)
		if err != nil {
			errs = append(errs, fail{
				ex:  e,
				err: err,
			})
			continue
		}

		roots[root] = append(roots[root], e)
	}

	if len(errs) != 0 {
		// TODO this is just a fix quick so staticcheck doesn't complain.
		// Visually reconciling failure to deduce project roots with the rest of
		// the mismatch output is a larger problem.
		loggers.Err.Printf("Failed to deduce project roots for import paths:\n")
		for _, fail := range errs {
			loggers.Err.Printf("\t%s: %s\n", fail.ex, fail.err.Error())
		}

		return errors.New("address issues with undeducable import paths to get more status information.")
	}

	out.MissingHeader()

outer:
	for root, pkgs := range roots {
		// TODO also handle the case where the project is present, but there
		// are items missing from just the package list
		for _, lp := range slp {
			if lp.Ident().ProjectRoot == root {
				continue outer
			}
		}

		out.MissingLine(&MissingStatus{ProjectRoot: string(root), MissingPackages: pkgs})
	}
	out.MissingFooter()

	return nil
}

func formatVersion(v gps.Version) string {
	if v == nil {
		return ""
	}
	switch v.Type() {
	case gps.IsBranch:
		return "branch " + v.String()
	case gps.IsRevision:
		r := v.String()
		if len(r) > 7 {
			r = r[:7]
		}
		return r
	}
	return v.String()
}

func collectConstraints(ptree pkgtree.PackageTree, p *dep.Project, sm gps.SourceManager) map[string][]gps.Constraint {
	// TODO
	return map[string][]gps.Constraint{}
}
<|endoftext|>


<commit_before>package ishell

import (
	"bytes"
	"sync"

	"gopkg.in/readline.v1"
)

type (
	lineString struct {
		line string
		err  error
	}

	shellReader struct {
		scanner      *readline.Instance
		consumers    []chan lineString
		reading      bool
		readingMulti bool
		buf          *bytes.Buffer
		prompt       string
		multiPrompt  string
		showPrompt   bool
		completer    readline.AutoCompleter
		sync.Mutex
	}
)

// rlPrompt returns the proper prompt for readline based on showPrompt and
// prompt members.
func (s *shellReader) rlPrompt() string {
	if s.showPrompt {
		if s.readingMulti {
			return s.multiPrompt
		}
		return s.prompt
	}
	return ""
}

func (s *shellReader) readPassword() string {
	password, _ := s.scanner.ReadPassword("")
	return string(password)
}

func (s *shellReader) setMultiMode(use bool) {
	s.readingMulti = use
}

func (s *shellReader) readLine(consumer chan lineString) {
	s.Lock()
	defer s.Unlock()
	s.consumers = append(s.consumers, consumer)
	// already reading
	if s.reading {
		return
	}
	s.reading = true
	// start reading
	go func() {
		// detect if print is called to
		// prevent readline lib from clearing line.
		// TODO find better way.
		shellPrompt := s.prompt
		prompt := s.rlPrompt()
		if s.buf.Len() > 0 {
			prompt += s.buf.String()
			s.buf.Truncate(0)
		}

		// use printed statement as prompt
		s.scanner.SetPrompt(prompt)

		line, err := s.scanner.Readline()

		// reset prompt
		s.scanner.SetPrompt(shellPrompt)

		ls := lineString{string(line), err}
		s.Lock()
		defer s.Unlock()
		for i := range s.consumers {
			c := s.consumers[i]
			go func(c chan lineString) {
				c <- ls
			}(c)
		}
		s.reading = false
	}()

}
<commit_msg>prevent clearing of line during ReadPassword<commit_after>package ishell

import (
	"bytes"
	"sync"

	"gopkg.in/readline.v1"
)

type (
	lineString struct {
		line string
		err  error
	}

	shellReader struct {
		scanner      *readline.Instance
		consumers    []chan lineString
		reading      bool
		readingMulti bool
		buf          *bytes.Buffer
		prompt       string
		multiPrompt  string
		showPrompt   bool
		completer    readline.AutoCompleter
		sync.Mutex
	}
)

// rlPrompt returns the proper prompt for readline based on showPrompt and
// prompt members.
func (s *shellReader) rlPrompt() string {
	if s.showPrompt {
		if s.readingMulti {
			return s.multiPrompt
		}
		return s.prompt
	}
	return ""
}

func (s *shellReader) readPassword() string {
	prompt := ""
	if s.buf.Len() > 0 {
		prompt = s.buf.String()
		s.buf.Truncate(0)
	}
	password, _ := s.scanner.ReadPassword(prompt)
	return string(password)
}

func (s *shellReader) setMultiMode(use bool) {
	s.readingMulti = use
}

func (s *shellReader) readLine(consumer chan lineString) {
	s.Lock()
	defer s.Unlock()
	s.consumers = append(s.consumers, consumer)
	// already reading
	if s.reading {
		return
	}
	s.reading = true
	// start reading
	go func() {
		// detect if print is called to
		// prevent readline lib from clearing line.
		// TODO find better way.
		shellPrompt := s.prompt
		prompt := s.rlPrompt()
		if s.buf.Len() > 0 {
			prompt += s.buf.String()
			s.buf.Truncate(0)
		}

		// use printed statement as prompt
		s.scanner.SetPrompt(prompt)

		line, err := s.scanner.Readline()

		// reset prompt
		s.scanner.SetPrompt(shellPrompt)

		ls := lineString{string(line), err}
		s.Lock()
		defer s.Unlock()
		for i := range s.consumers {
			c := s.consumers[i]
			go func(c chan lineString) {
				c <- ls
			}(c)
		}
		s.reading = false
	}()

}
<|endoftext|>


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

package main

import (
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"code.google.com/p/go.tools/blog"
	"code.google.com/p/go.tools/godoc/redirect"
)

const (
	blogRepo = "code.google.com/p/go.blog"
	blogURL  = "http://blog.golang.org/"
)

var (
	blogServer   http.Handler // set by blogInit
	blogInitOnce sync.Once
	playEnabled  bool
)

func init() {
	// Initialize blog only when first accessed.
	http.HandleFunc("/blog/", func(w http.ResponseWriter, r *http.Request) {
		blogInitOnce.Do(blogInit)
		blogServer.ServeHTTP(w, r)
	})
}

func blogInit() {
	// Binary distributions will include the blog content in "/blog".
	root := filepath.Join(runtime.GOROOT(), "blog")

	// Prefer content from go.blog repository if present.
	if pkg, err := build.Import(blogRepo, "", build.FindOnly); err == nil {
		root = pkg.Dir
	}

	// If content is not available fall back to redirect.
	if fi, err := os.Stat(root); err != nil || !fi.IsDir() {
		fmt.Fprintf(os.Stderr, "Blog content not available locally. "+
			"To install, run \n\tgo get %v\n", blogRepo)
		blogServer = redirect.PrefixHandler("/blog/", blogURL)
		return
	}

	s, err := blog.NewServer(blog.Config{
		BaseURL:      "/blog/",
		BasePath:     "/blog",
		ContentPath:  filepath.Join(root, "content"),
		TemplatePath: filepath.Join(root, "template"),
		HomeArticles: 5,
		PlayEnabled:  playEnabled,
	})
	if err != nil {
		log.Fatal(err)
	}
	blogServer = s
}
<commit_msg>go.tools/cmd/blog: handle "/blog/" redirect properly<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"code.google.com/p/go.tools/blog"
	"code.google.com/p/go.tools/godoc/redirect"
)

const (
	blogRepo = "code.google.com/p/go.blog"
	blogURL  = "http://blog.golang.org/"
	blogPath = "/blog/"
)

var (
	blogServer   http.Handler // set by blogInit
	blogInitOnce sync.Once
	playEnabled  bool
)

func init() {
	// Initialize blog only when first accessed.
	http.HandleFunc(blogPath, func(w http.ResponseWriter, r *http.Request) {
		blogInitOnce.Do(blogInit)
		blogServer.ServeHTTP(w, r)
	})
}

func blogInit() {
	// Binary distributions will include the blog content in "/blog".
	root := filepath.Join(runtime.GOROOT(), "blog")

	// Prefer content from go.blog repository if present.
	if pkg, err := build.Import(blogRepo, "", build.FindOnly); err == nil {
		root = pkg.Dir
	}

	// If content is not available fall back to redirect.
	if fi, err := os.Stat(root); err != nil || !fi.IsDir() {
		fmt.Fprintf(os.Stderr, "Blog content not available locally. "+
			"To install, run \n\tgo get %v\n", blogRepo)
		blogServer = http.HandlerFunc(blogRedirectHandler)
		return
	}

	s, err := blog.NewServer(blog.Config{
		BaseURL:      blogPath,
		BasePath:     strings.TrimSuffix(blogPath, "/"),
		ContentPath:  filepath.Join(root, "content"),
		TemplatePath: filepath.Join(root, "template"),
		HomeArticles: 5,
		PlayEnabled:  playEnabled,
	})
	if err != nil {
		log.Fatal(err)
	}
	blogServer = s
}

func blogRedirectHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == blogPath {
		http.Redirect(w, r, blogURL, http.StatusFound)
		return
	}
	blogPrefixHandler.ServeHTTP(w, r)
}

var blogPrefixHandler = redirect.PrefixHandler(blogPath, blogURL)
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/codegangsta/cli"
)

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	app := cli.NewApp()
	app.Name = "fractus"
	app.Usage = "task list on the command line"
	app.Version = "0.0.1"
	app.Author = "Chander"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Chander",
			Email: "jpochander@gmail.com",
		},
		cli.Author{
			Name:  "msetracer",
			Email: "msetracer@gmail.com",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config",
			Value: "fractal.json",
			Usage: "configuration file",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "default",
			ShortName: "d",
			Usage:     "reset params",
			Action:    actionDefault,
		},
		{
			Name:      "render",
			ShortName: "r",
			Usage:     "render the fractal",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "image",
					Value: "fractal.png",
					Usage: "destination image file name",
				},
			},
			Action: actionRender,
		},
		{
			Name:      "iter",
			ShortName: "i",
			Usage:     "set iters",
			Action:    actionIter,
		},
		{
			Name:      "scale",
			ShortName: "s",
			Usage:     "scale fractal",
			Action:    actionScale,
		},
		{
			Name:      "move",
			ShortName: "m",
			Usage:     "move center",
			Action:    actionMove,
		},
		{
			Name:      "palette",
			ShortName: "p",
			Usage:     "set palette period and shift",
			Action:    actionPalette,
		},
	}

	app.Run(os.Args)
}

func actionDefault(c *cli.Context) {

	configName := c.Parent().String("config")

	err := coreDefault(configName)
	if err != nil {
		log.Fatal(err)
	}
}

func actionRender(c *cli.Context) {

	configName := c.Parent().String("config")
	imageName := c.String("image")

	begin := time.Now()

	err := coreRender(configName, imageName)
	if err != nil {
		log.Fatal(err.Error())
	}

	log.Println("work duration:", time.Since(begin))
}

func actionIter(c *cli.Context) {

	configName := c.Parent().String("config")

	n, err := strconv.ParseInt(c.Args().First(), 10, 32)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreIter(configName, int(n))
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionScale(c *cli.Context) {

	configName := c.Parent().String("config")
	scaleFactor, err := strconv.ParseFloat(c.Args().First(), 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreScale(configName, scaleFactor)
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionMove(c *cli.Context) {

	// ./mset move -- -0.5 0.1

	configName := c.Parent().String("config")

	args := c.Args()

	factorX, err := strconv.ParseFloat(args[0], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	factorY, err := strconv.ParseFloat(args[1], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreMove(configName, factorX, factorY)
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionPalette(c *cli.Context) {

	configName := c.Parent().String("config")

	args := c.Args()

	palPeriod, err := strconv.ParseFloat(args[0], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	palShift, err := strconv.ParseFloat(args[1], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = corePalette(configName, palPeriod, palShift)
	if err != nil {
		log.Fatal(err.Error())
	}
}
<commit_msg>codegangsta -> urfave  cli<commit_after>package main

import (
	"log"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/urfave/cli"
)

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	app := cli.NewApp()
	app.Name = "fractus"
	app.Usage = "task list on the command line"
	app.Version = "0.0.1"
	app.Author = "Chander"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Chander",
			Email: "jpochander@gmail.com",
		},
		cli.Author{
			Name:  "msetracer",
			Email: "msetracer@gmail.com",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config",
			Value: "fractal.json",
			Usage: "configuration file",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "default",
			ShortName: "d",
			Usage:     "reset params",
			Action:    actionDefault,
		},
		{
			Name:      "render",
			ShortName: "r",
			Usage:     "render the fractal",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "image",
					Value: "fractal.png",
					Usage: "destination image file name",
				},
			},
			Action: actionRender,
		},
		{
			Name:      "iter",
			ShortName: "i",
			Usage:     "set iters",
			Action:    actionIter,
		},
		{
			Name:      "scale",
			ShortName: "s",
			Usage:     "scale fractal",
			Action:    actionScale,
		},
		{
			Name:      "move",
			ShortName: "m",
			Usage:     "move center",
			Action:    actionMove,
		},
		{
			Name:      "palette",
			ShortName: "p",
			Usage:     "set palette period and shift",
			Action:    actionPalette,
		},
	}

	app.Run(os.Args)
}

func actionDefault(c *cli.Context) {

	configName := c.Parent().String("config")

	err := coreDefault(configName)
	if err != nil {
		log.Fatal(err)
	}
}

func actionRender(c *cli.Context) {

	configName := c.Parent().String("config")
	imageName := c.String("image")

	begin := time.Now()

	err := coreRender(configName, imageName)
	if err != nil {
		log.Fatal(err.Error())
	}

	log.Println("work duration:", time.Since(begin))
}

func actionIter(c *cli.Context) {

	configName := c.Parent().String("config")

	n, err := strconv.ParseInt(c.Args().First(), 10, 32)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreIter(configName, int(n))
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionScale(c *cli.Context) {

	configName := c.Parent().String("config")
	scaleFactor, err := strconv.ParseFloat(c.Args().First(), 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreScale(configName, scaleFactor)
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionMove(c *cli.Context) {

	// ./mset move -- -0.5 0.1

	configName := c.Parent().String("config")

	args := c.Args()

	factorX, err := strconv.ParseFloat(args[0], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	factorY, err := strconv.ParseFloat(args[1], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = coreMove(configName, factorX, factorY)
	if err != nil {
		log.Fatal(err.Error())
	}
}

func actionPalette(c *cli.Context) {

	configName := c.Parent().String("config")

	args := c.Args()

	palPeriod, err := strconv.ParseFloat(args[0], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	palShift, err := strconv.ParseFloat(args[1], 64)
	if err != nil {
		log.Fatal(err.Error())
	}

	err = corePalette(configName, palPeriod, palShift)
	if err != nil {
		log.Fatal(err.Error())
	}
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
)

var cmdVersion = &Command{
	RunArgs:     runVersion,
	Usage:       "version",
	Description: "print version information",
	Flag:        flag.NewFlagSet("version", flag.ContinueOnError),
	Help: `Version prints version information about ht.
`,
}

var (
	version = "4.5.0"
)

func runVersion(cmd *Command, _ []string) {
	fmt.Printf("ht version %s\n", version)
}
<commit_msg>all: start development cycle for 4.6<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
)

var cmdVersion = &Command{
	RunArgs:     runVersion,
	Usage:       "version",
	Description: "print version information",
	Flag:        flag.NewFlagSet("version", flag.ContinueOnError),
	Help: `Version prints version information about ht.
`,
}

var (
	version = "4.6.0-beta"
)

func runVersion(cmd *Command, _ []string) {
	fmt.Printf("ht version %s\n", version)
}
<|endoftext|>


<commit_before>package main

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

	"github.com/tj/go-gracefully"
	"github.com/travisjeffery/jocko/broker"
	"github.com/travisjeffery/jocko/server"
	"github.com/travisjeffery/simplelog"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	logDir      = kingpin.Flag("logdir", "A comma separated list of directories under which to store log files").Default("/tmp/jocko").String()
	tcpAddr     = kingpin.Flag("tcpaddr", "HTTP Address to listen on").String()
	raftDir     = kingpin.Flag("raftdir", "Directory for raft to store data").String()
	raftAddr    = kingpin.Flag("raftaddr", "Address for Raft to bind on").String()
	raftPort    = kingpin.Flag("raftport", "Port for Raft to bind on").Int()
	serfPort    = kingpin.Flag("serfport", "Port for Serf to bind on").Default("7946").Int()
	serfMembers = kingpin.Flag("serfmembers", "List of existing serf members").String()
	brokerID    = kingpin.Flag("id", "Broker ID").Int32()
	debugLogs   = kingpin.Flag("debug", "Enable debug logs").Default("false").Bool()
)

func main() {
	kingpin.Parse()

	logLevel := simplelog.INFO
	if *debugLogs {
		logLevel = simplelog.DEBUG
	}
	logger := simplelog.New(os.Stdout, logLevel, "jocko")

	store, err := broker.New(*brokerID,
		broker.DataDir(*logDir),
		broker.LogDir(*logDir),
		broker.Logger(logger),
		broker.BindAddr(*raftAddr),
		broker.RaftPort(*raftPort),
		broker.SerfPort(*serfPort),
		broker.SerfMembers(strings.Split(*serfMembers, ",")),
	)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error with new broker: %s\n", err)
		os.Exit(1)
	}
	server := server.New(*tcpAddr, store, logger)
	if err := server.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "Error starting server: %s\n", err)
		os.Exit(1)
	}

	gracefully.Timeout = 10 * time.Second
	gracefully.Shutdown()

	if err := store.Shutdown(); err != nil {
		panic(err)
	}
	server.Close()
}
<commit_msg>use kingpin's Strings flag (#10)<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/tj/go-gracefully"
	"github.com/travisjeffery/jocko/broker"
	"github.com/travisjeffery/jocko/server"
	"github.com/travisjeffery/simplelog"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	logDir      = kingpin.Flag("logdir", "A comma separated list of directories under which to store log files").Default("/tmp/jocko").String()
	tcpAddr     = kingpin.Flag("tcpaddr", "HTTP Address to listen on").String()
	raftDir     = kingpin.Flag("raftdir", "Directory for raft to store data").String()
	raftAddr    = kingpin.Flag("raftaddr", "Address for Raft to bind on").String()
	raftPort    = kingpin.Flag("raftport", "Port for Raft to bind on").Int()
	serfPort    = kingpin.Flag("serfport", "Port for Serf to bind on").Default("7946").Int()
	serfMembers = kingpin.Flag("serfmembers", "List of existing serf members").Strings()
	brokerID    = kingpin.Flag("id", "Broker ID").Int32()
	debugLogs   = kingpin.Flag("debug", "Enable debug logs").Default("false").Bool()
)

func main() {
	kingpin.Parse()

	logLevel := simplelog.INFO
	if *debugLogs {
		logLevel = simplelog.DEBUG
	}
	logger := simplelog.New(os.Stdout, logLevel, "jocko")

	store, err := broker.New(*brokerID,
		broker.DataDir(*logDir),
		broker.LogDir(*logDir),
		broker.Logger(logger),
		broker.BindAddr(*raftAddr),
		broker.RaftPort(*raftPort),
		broker.SerfPort(*serfPort),
		broker.SerfMembers(*serfMembers),
	)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error with new broker: %s\n", err)
		os.Exit(1)
	}
	server := server.New(*tcpAddr, store, logger)
	if err := server.Start(); err != nil {
		fmt.Fprintf(os.Stderr, "Error starting server: %s\n", err)
		os.Exit(1)
	}

	gracefully.Timeout = 10 * time.Second
	gracefully.Shutdown()

	if err := store.Shutdown(); err != nil {
		panic(err)
	}
	server.Close()
}
<|endoftext|>