<commit_before>package runtime

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

	"google.golang.org/genproto/protobuf/field_mask"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protoreflect"
)

func getFieldByName(fields protoreflect.FieldDescriptors, name string) protoreflect.FieldDescriptor {
	fd := fields.ByName(protoreflect.Name(name))
	if fd != nil {
		return fd
	}

	return fields.ByJSONName(name)
}

// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body.
func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.FieldMask, error) {
	fm := &field_mask.FieldMask{}
	var root interface{}

	if err := json.NewDecoder(r).Decode(&root); err != nil {
		if err == io.EOF {
			return fm, nil
		}
		return nil, err
	}

	queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}}
	for len(queue) > 0 {
		// dequeue an item
		item := queue[0]
		queue = queue[1:]

		m, ok := item.node.(map[string]interface{})
		switch {
		case ok:
			// if the item is an object, then enqueue all of its children
			for k, v := range m {
				if item.msg == nil {
					return nil, fmt.Errorf("JSON structure did not match request type")
				}

				fd := getFieldByName(item.msg.Descriptor().Fields(), k)
				if fd == nil {
					return nil, fmt.Errorf("could not find field %q in %q", k, item.msg.Descriptor().FullName())
				}

				if isDynamicProtoMessage(fd.Message()) {
					for _, p := range buildPathsBlindly(k, v) {
						newPath := p
						if item.path != "" {
							newPath = item.path + "." + newPath
						}
						queue = append(queue, fieldMaskPathItem{path: newPath})
					}
					continue
				}

				child := fieldMaskPathItem{
					node: v,
				}
				if item.path == "" {
					child.path = string(fd.FullName().Name())
				} else {
					child.path = item.path + "." + string(fd.FullName().Name())
				}

				switch {
				case fd.IsList(), fd.IsMap():
					// As per: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto#L85-L86
					// Do not recurse into repeated fields. The repeated field goes on the end of the path and we stop.
					fm.Paths = append(fm.Paths, child.path)
				case fd.Message() != nil:
					child.msg = item.msg.Get(fd).Message()
					fallthrough
				default:
					queue = append(queue, child)
				}
			}
		case len(item.path) > 0:
			// otherwise, it's a leaf node so print its path
			fm.Paths = append(fm.Paths, item.path)
		}
	}

	return fm, nil
}

func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool {
	return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value")
}

// buildPathsBlindly does not attempt to match proto field names to the
// json value keys.  Instead it relies completely on the structure of
// the unmarshalled json contained within in.
// Returns a slice containing all subpaths with the root at the
// passed in name and json value.
func buildPathsBlindly(name string, in interface{}) []string {
	m, ok := in.(map[string]interface{})
	if !ok {
		return []string{name}
	}

	var paths []string
	queue := []fieldMaskPathItem{{path: name, node: m}}
	for len(queue) > 0 {
		cur := queue[0]
		queue = queue[1:]

		m, ok := cur.node.(map[string]interface{})
		if !ok {
			// This should never happen since we should always check that we only add
			// nodes of type map[string]interface{} to the queue.
			continue
		}
		for k, v := range m {
			if mi, ok := v.(map[string]interface{}); ok {
				queue = append(queue, fieldMaskPathItem{path: cur.path + "." + k, node: mi})
			} else {
				// This is not a struct, so there are no more levels to descend.
				curPath := cur.path + "." + k
				paths = append(paths, curPath)
			}
		}
	}
	return paths
}

// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask
type fieldMaskPathItem struct {
	// the list of prior fields leading up to node connected by dots
	path string

	// a generic decoded json object the current item to inspect for further path extraction
	node interface{}

	// parent message
	msg protoreflect.Message
}
<commit_msg>Make fieldmask output deterministic (#1950)<commit_after>package runtime

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

	"google.golang.org/genproto/protobuf/field_mask"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protoreflect"
)

func getFieldByName(fields protoreflect.FieldDescriptors, name string) protoreflect.FieldDescriptor {
	fd := fields.ByName(protoreflect.Name(name))
	if fd != nil {
		return fd
	}

	return fields.ByJSONName(name)
}

// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body.
func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.FieldMask, error) {
	fm := &field_mask.FieldMask{}
	var root interface{}

	if err := json.NewDecoder(r).Decode(&root); err != nil {
		if err == io.EOF {
			return fm, nil
		}
		return nil, err
	}

	queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}}
	for len(queue) > 0 {
		// dequeue an item
		item := queue[0]
		queue = queue[1:]

		m, ok := item.node.(map[string]interface{})
		switch {
		case ok:
			// if the item is an object, then enqueue all of its children
			for k, v := range m {
				if item.msg == nil {
					return nil, fmt.Errorf("JSON structure did not match request type")
				}

				fd := getFieldByName(item.msg.Descriptor().Fields(), k)
				if fd == nil {
					return nil, fmt.Errorf("could not find field %q in %q", k, item.msg.Descriptor().FullName())
				}

				if isDynamicProtoMessage(fd.Message()) {
					for _, p := range buildPathsBlindly(k, v) {
						newPath := p
						if item.path != "" {
							newPath = item.path + "." + newPath
						}
						queue = append(queue, fieldMaskPathItem{path: newPath})
					}
					continue
				}

				child := fieldMaskPathItem{
					node: v,
				}
				if item.path == "" {
					child.path = string(fd.FullName().Name())
				} else {
					child.path = item.path + "." + string(fd.FullName().Name())
				}

				switch {
				case fd.IsList(), fd.IsMap():
					// As per: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto#L85-L86
					// Do not recurse into repeated fields. The repeated field goes on the end of the path and we stop.
					fm.Paths = append(fm.Paths, child.path)
				case fd.Message() != nil:
					child.msg = item.msg.Get(fd).Message()
					fallthrough
				default:
					queue = append(queue, child)
				}
			}
		case len(item.path) > 0:
			// otherwise, it's a leaf node so print its path
			fm.Paths = append(fm.Paths, item.path)
		}
	}

	// Sort for deterministic output in the presence
	// of repeated fields.
	sort.Strings(fm.Paths)

	return fm, nil
}

func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool {
	return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value")
}

// buildPathsBlindly does not attempt to match proto field names to the
// json value keys.  Instead it relies completely on the structure of
// the unmarshalled json contained within in.
// Returns a slice containing all subpaths with the root at the
// passed in name and json value.
func buildPathsBlindly(name string, in interface{}) []string {
	m, ok := in.(map[string]interface{})
	if !ok {
		return []string{name}
	}

	var paths []string
	queue := []fieldMaskPathItem{{path: name, node: m}}
	for len(queue) > 0 {
		cur := queue[0]
		queue = queue[1:]

		m, ok := cur.node.(map[string]interface{})
		if !ok {
			// This should never happen since we should always check that we only add
			// nodes of type map[string]interface{} to the queue.
			continue
		}
		for k, v := range m {
			if mi, ok := v.(map[string]interface{}); ok {
				queue = append(queue, fieldMaskPathItem{path: cur.path + "." + k, node: mi})
			} else {
				// This is not a struct, so there are no more levels to descend.
				curPath := cur.path + "." + k
				paths = append(paths, curPath)
			}
		}
	}
	return paths
}

// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask
type fieldMaskPathItem struct {
	// the list of prior fields leading up to node connected by dots
	path string

	// a generic decoded json object the current item to inspect for further path extraction
	node interface{}

	// parent message
	msg protoreflect.Message
}
<|endoftext|>


<commit_before>package sirius

import (
	"strings"

	"context"
	"github.com/kayex/sirius/mqtt"
	"github.com/kayex/sirius/slack"
)

type SyncAction string

const (
	NEW    SyncAction = "new"
	UPDATE            = "update"
	DELETE            = "delete"
)

type SyncMessage struct {
	Type SyncAction
	ID   slack.SecureID
}

type Sync interface {
	Sync(s *Service)
}

type SyncedService struct {
	service *Service
	sync    Sync
}

func (s *SyncedService) Start(ctx context.Context, u []User) {
	go s.service.Start(ctx, u)
	s.sync.Sync(s.service)
}

type MQTTSync struct {
	mqtt    *mqtt.MQTT
	topic   string
	rmt     *Remote
	service *Service
}

func (s *Service) WithSync(sync Sync) *SyncedService {
	return &SyncedService{
		service: s,
		sync:    sync,
	}
}

func NewMQTTSync(rmt *Remote, cfg mqtt.Config, topic string) *MQTTSync {
	return &MQTTSync{
		mqtt:  mqtt.New(cfg),
		topic: topic,
		rmt:   rmt,
	}
}

func (m *MQTTSync) Sync(s *Service) {
	m.service = s
	err := m.mqtt.Connect(context.TODO())

	if err != nil {
		panic(err)
	}

	m.mqtt.Subscribe(m.topic)
	m.start()
}

func (m *MQTTSync) start() {
	for msg := range m.mqtt.Messages {
		msg, ok := parseSyncMessage(msg.Msg)

		if !ok {
			continue
		}

		switch msg.Type {
		case UPDATE:
			m.service.DropUser(msg.ID)
			fallthrough
		case NEW:
			u, err := m.rmt.GetUser(msg.ID)

			if err != nil {
				break
			}

			m.service.AddUser(u)
		case DELETE:
			m.service.DropUser(msg.ID)
		}
	}
}

func parseSyncMessage(msg string) (*SyncMessage, bool) {
	split := strings.Split(msg, ":")

	if len(split) != 2 {
		return nil, false
	}

	msgType := SyncAction(split[0])
	id := slack.SecureID{split[1]}

	switch msgType {
	case NEW, UPDATE, DELETE:
		return &SyncMessage{
			Type: msgType,
			ID:   id,
		}, true
	default:
		return nil, false
	}
}
<commit_msg>Return error instead of bool in parseSyncMessage<commit_after>package sirius

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/kayex/sirius/mqtt"
	"github.com/kayex/sirius/slack"
)

type SyncAction string

const (
	NEW    SyncAction = "new"
	UPDATE            = "update"
	DELETE            = "delete"
)

type SyncMessage struct {
	Type SyncAction
	ID   slack.SecureID
}

type Sync interface {
	Sync(s *Service)
}

type SyncedService struct {
	service *Service
	sync    Sync
}

func (s *SyncedService) Start(ctx context.Context, u []User) {
	go s.service.Start(ctx, u)
	s.sync.Sync(s.service)
}

type MQTTSync struct {
	mqtt    *mqtt.MQTT
	topic   string
	rmt     *Remote
	service *Service
}

func (s *Service) WithSync(sync Sync) *SyncedService {
	return &SyncedService{
		service: s,
		sync:    sync,
	}
}

func NewMQTTSync(rmt *Remote, cfg mqtt.Config, topic string) *MQTTSync {
	return &MQTTSync{
		mqtt:  mqtt.New(cfg),
		topic: topic,
		rmt:   rmt,
	}
}

func (m *MQTTSync) Sync(s *Service) {
	m.service = s
	err := m.mqtt.Connect(context.TODO())

	if err != nil {
		panic(err)
	}

	m.mqtt.Subscribe(m.topic)
	m.start()
}

func (m *MQTTSync) start() {
	for msg := range m.mqtt.Messages {
		msg, err := parseSyncMessage(msg.Msg)

		if err != nil {
			continue
		}

		switch msg.Type {
		case UPDATE:
			m.service.DropUser(msg.ID)
			fallthrough
		case NEW:
			u, err := m.rmt.GetUser(msg.ID)

			if err != nil {
				break
			}

			m.service.AddUser(u)
		case DELETE:
			m.service.DropUser(msg.ID)
		}
	}
}

func parseSyncMessage(msg string) (*SyncMessage, error) {
	split := strings.Split(msg, ":")

	if len(split) != 2 {
		return nil, errors.New(fmt.Sprintf("Invalid sync message %q", msg))
	}

	msgType := SyncAction(split[0])
	id := slack.SecureID{split[1]}

	switch msgType {
	case NEW, UPDATE, DELETE:
		return &SyncMessage{
			Type: msgType,
			ID:   id,
		}, nil
	default:
		return nil, errors.New(fmt.Sprintf("Unknown sync message type %q", msgType))
	}
}
<|endoftext|>


<commit_before>package shufn

import (
	"sync"
)

// Sync returns a concurrency-safe wrapper around Iter.
func Sync(i Iter) *syncIter {
	return &syncIter{Iter: i}
}

type syncIter struct {
	Iter
	mu sync.Mutex
}

var _ Iter = (*syncIter)(nil)

func (s *syncIter) Next() (v uint64, more bool) {
	s.mu.Lock()
	v, more = s.Iter.Next()
	s.mu.Unlock()
	return
}
<commit_msg>Once the Sync iterator is done, its done.<commit_after>package shufn

import (
	"sync"
)

// Sync returns a concurrency-safe wrapper around Iter.
func Sync(i Iter) *syncIter {
	return &syncIter{Iter: i}
}

type syncIter struct {
	Iter
	mu   sync.Mutex
	done bool
}

var _ Iter = (*syncIter)(nil)

func (s *syncIter) Next() (v uint64, more bool) {
	s.mu.Lock()
	if s.done {
		v, more = 0, false
	} else {
		v, more = s.Iter.Next()
	}
	s.mu.Unlock()
	return
}
<|endoftext|>


<commit_before>package archiver

import (
	"archive/tar"
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/counter"
	"github.com/itchio/wharf/eos"
	"github.com/itchio/wharf/state"
)

// Does not preserve users, nor permission, except the executable bit
func ExtractTar(archive string, dir string, settings ExtractSettings) (*ExtractResult, error) {
	settings.Consumer.Infof("Extracting %s to %s", archive, dir)

	dirCount := 0
	regCount := 0
	symlinkCount := 0

	file, err := eos.Open(archive)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	defer file.Close()

	err = Mkdir(dir)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	tarReader := tar.NewReader(file)

	for {
		header, err := tarReader.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				break
			}
			return nil, errors.Wrap(err, 1)
		}

		rel := header.Name
		filename := path.Join(dir, filepath.FromSlash(rel))

		switch header.Typeflag {
		case tar.TypeDir:
			err = Mkdir(filename)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			dirCount++

		case tar.TypeReg:
			settings.Consumer.Debugf("extract %s", filename)
			err = CopyFile(filename, os.FileMode(header.Mode&LuckyMode|ModeMask), tarReader)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			regCount++

		case tar.TypeSymlink:
			err = Symlink(header.Linkname, filename, settings.Consumer)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			symlinkCount++

		default:
			return nil, fmt.Errorf("Unable to untar entry of type %d", header.Typeflag)
		}
	}

	return &ExtractResult{
		Dirs:     dirCount,
		Files:    regCount,
		Symlinks: symlinkCount,
	}, nil
}

func CompressTar(archiveWriter io.Writer, dir string, consumer *state.Consumer) (*CompressResult, error) {
	var err error
	var uncompressedSize int64
	var compressedSize int64

	archiveCounter := counter.NewWriter(archiveWriter)

	tarWriter := tar.NewWriter(archiveCounter)
	defer tarWriter.Close()
	defer func() {
		if tarWriter != nil {
			if zErr := tarWriter.Close(); err == nil && zErr != nil {
				err = errors.Wrap(zErr, 1)
			}
		}
	}()

	err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		name, wErr := filepath.Rel(dir, path)
		if wErr != nil {
			return wErr
		}

		if name == "." {
			// don't add '.' to zip
			return nil
		}

		name = filepath.ToSlash(name)

		th, wErr := tar.FileInfoHeader(info, "")
		if wErr != nil {
			return wErr
		}

		th.Name = name

		if info.IsDir() {
			// good!
			wErr = tarWriter.WriteHeader(th)
			if wErr != nil {
				return wErr
			}
		} else if info.Mode()&os.ModeSymlink > 0 {
			dest, lErr := os.Readlink(path)
			if lErr != nil {
				return lErr
			}

			th.Linkname = dest

			lErr = tarWriter.WriteHeader(th)
			if lErr != nil {
				return lErr
			}
		} else if info.Mode().IsRegular() {
			wErr = tarWriter.WriteHeader(th)
			if wErr != nil {
				return wErr
			}

			reader, wErr := os.Open(path)
			if wErr != nil {
				return wErr
			}
			defer reader.Close()

			copiedBytes, wErr := io.Copy(tarWriter, reader)
			if wErr != nil {
				return wErr
			}

			uncompressedSize += copiedBytes
		}

		return nil
	})

	err = tarWriter.Close()
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}
	tarWriter = nil

	compressedSize = archiveCounter.Count()

	return &CompressResult{
		UncompressedSize: uncompressedSize,
		CompressedSize:   compressedSize,
	}, err
}
<commit_msg>Redact path in untar<commit_after>package archiver

import (
	"archive/tar"
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"

	"github.com/go-errors/errors"
	"github.com/itchio/wharf/counter"
	"github.com/itchio/wharf/eos"
	"github.com/itchio/wharf/state"
)

// Does not preserve users, nor permission, except the executable bit
func ExtractTar(archive string, dir string, settings ExtractSettings) (*ExtractResult, error) {
	settings.Consumer.Infof("Extracting %s to %s", eos.Redact(archive), dir)

	dirCount := 0
	regCount := 0
	symlinkCount := 0

	file, err := eos.Open(archive)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	defer file.Close()

	err = Mkdir(dir)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	tarReader := tar.NewReader(file)

	for {
		header, err := tarReader.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				break
			}
			return nil, errors.Wrap(err, 1)
		}

		rel := header.Name
		filename := path.Join(dir, filepath.FromSlash(rel))

		switch header.Typeflag {
		case tar.TypeDir:
			err = Mkdir(filename)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			dirCount++

		case tar.TypeReg:
			settings.Consumer.Debugf("extract %s", filename)
			err = CopyFile(filename, os.FileMode(header.Mode&LuckyMode|ModeMask), tarReader)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			regCount++

		case tar.TypeSymlink:
			err = Symlink(header.Linkname, filename, settings.Consumer)
			if err != nil {
				return nil, errors.Wrap(err, 1)
			}
			symlinkCount++

		default:
			return nil, fmt.Errorf("Unable to untar entry of type %d", header.Typeflag)
		}
	}

	return &ExtractResult{
		Dirs:     dirCount,
		Files:    regCount,
		Symlinks: symlinkCount,
	}, nil
}

func CompressTar(archiveWriter io.Writer, dir string, consumer *state.Consumer) (*CompressResult, error) {
	var err error
	var uncompressedSize int64
	var compressedSize int64

	archiveCounter := counter.NewWriter(archiveWriter)

	tarWriter := tar.NewWriter(archiveCounter)
	defer tarWriter.Close()
	defer func() {
		if tarWriter != nil {
			if zErr := tarWriter.Close(); err == nil && zErr != nil {
				err = errors.Wrap(zErr, 1)
			}
		}
	}()

	err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		name, wErr := filepath.Rel(dir, path)
		if wErr != nil {
			return wErr
		}

		if name == "." {
			// don't add '.' to zip
			return nil
		}

		name = filepath.ToSlash(name)

		th, wErr := tar.FileInfoHeader(info, "")
		if wErr != nil {
			return wErr
		}

		th.Name = name

		if info.IsDir() {
			// good!
			wErr = tarWriter.WriteHeader(th)
			if wErr != nil {
				return wErr
			}
		} else if info.Mode()&os.ModeSymlink > 0 {
			dest, lErr := os.Readlink(path)
			if lErr != nil {
				return lErr
			}

			th.Linkname = dest

			lErr = tarWriter.WriteHeader(th)
			if lErr != nil {
				return lErr
			}
		} else if info.Mode().IsRegular() {
			wErr = tarWriter.WriteHeader(th)
			if wErr != nil {
				return wErr
			}

			reader, wErr := os.Open(path)
			if wErr != nil {
				return wErr
			}
			defer reader.Close()

			copiedBytes, wErr := io.Copy(tarWriter, reader)
			if wErr != nil {
				return wErr
			}

			uncompressedSize += copiedBytes
		}

		return nil
	})

	err = tarWriter.Close()
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}
	tarWriter = nil

	compressedSize = archiveCounter.Count()

	return &CompressResult{
		UncompressedSize: uncompressedSize,
		CompressedSize:   compressedSize,
	}, err
}
<|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 imports

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"

	"golang.org/x/tools/go/ast/astutil"
)

// importToGroup is a list of functions which map from an import path to
// a group number.
var importToGroup = []func(importPath string) (num int, ok bool){}

func importGroup(importPath string) int {
	for _, fn := range importToGroup {
		if n, ok := fn(importPath); ok {
			return n
		}
	}
	return 0
}

func fixImports(fset *token.FileSet, f *ast.File, filename string) (added []string, err error) {
	// refs are a set of possible package references currently unsatisfied by imports.
	// first key: either base package (e.g. "fmt") or renamed package
	// second key: referenced package symbol (e.g. "Println")
	refs := make(map[string]map[string]bool)

	// decls are the current package imports. key is base package or renamed package.
	decls := make(map[string]*ast.ImportSpec)

	// collect potential uses of packages.
	var visitor visitFn
	visitor = visitFn(func(node ast.Node) ast.Visitor {
		if node == nil {
			return visitor
		}
		switch v := node.(type) {
		case *ast.ImportSpec:
			if v.Name != nil {
				decls[v.Name.Name] = v
			} else {
				local := importPathToName(strings.Trim(v.Path.Value, `\"`))
				decls[local] = v
			}
		case *ast.SelectorExpr:
			xident, ok := v.X.(*ast.Ident)
			if !ok {
				break
			}
			if xident.Obj != nil {
				// if the parser can resolve it, it's not a package ref
				break
			}
			pkgName := xident.Name
			if refs[pkgName] == nil {
				refs[pkgName] = make(map[string]bool)
			}
			if decls[pkgName] == nil {
				refs[pkgName][v.Sel.Name] = true
			}
		}
		return visitor
	})
	ast.Walk(visitor, f)

	// Nil out any unused ImportSpecs, to be removed in following passes
	unusedImport := map[string]string{}
	for pkg, is := range decls {
		if refs[pkg] == nil && pkg != "_" && pkg != "." {
			name := ""
			if is.Name != nil {
				name = is.Name.Name
			}
			unusedImport[strings.Trim(is.Path.Value, `"`)] = name
		}
	}
	for ipath, name := range unusedImport {
		if ipath == "C" {
			// Don't remove cgo stuff.
			continue
		}
		astutil.DeleteNamedImport(fset, f, name, ipath)
	}

	// Search for imports matching potential package references.
	searches := 0
	type result struct {
		ipath string
		name  string
		err   error
	}
	results := make(chan result)
	for pkgName, symbols := range refs {
		if len(symbols) == 0 {
			continue // skip over packages already imported
		}
		go func(pkgName string, symbols map[string]bool) {
			ipath, rename, err := findImport(pkgName, symbols, filename)
			r := result{ipath: ipath, err: err}
			if rename {
				r.name = pkgName
			}
			results <- r
		}(pkgName, symbols)
		searches++
	}
	for i := 0; i < searches; i++ {
		result := <-results
		if result.err != nil {
			return nil, result.err
		}
		if result.ipath != "" {
			if result.name != "" {
				astutil.AddNamedImport(fset, f, result.name, result.ipath)
			} else {
				astutil.AddImport(fset, f, result.ipath)
			}
			added = append(added, result.ipath)
		}
	}

	return added, nil
}

// importPathToName returns the package name for the given import path.
var importPathToName = importPathToNameGoPath

// importPathToNameBasic assumes the package name is the base of import path.
func importPathToNameBasic(importPath string) (packageName string) {
	return path.Base(importPath)
}

// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
// If there's a problem, it falls back to using importPathToNameBasic.
func importPathToNameGoPath(importPath string) (packageName string) {
	if buildPkg, err := build.Import(importPath, "", 0); err == nil {
		return buildPkg.Name
	} else {
		return importPathToNameBasic(importPath)
	}
}

type pkg struct {
	importpath string // full pkg import path, e.g. "net/http"
	dir        string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
}

var pkgIndexOnce = &sync.Once{}

var pkgIndex struct {
	sync.Mutex
	m map[string][]pkg // shortname => []pkg, e.g "http" => "net/http"
}

// gate is a semaphore for limiting concurrency.
type gate chan struct{}

func (g gate) enter() { g <- struct{}{} }
func (g gate) leave() { <-g }

// fsgate protects the OS & filesystem from too much concurrency.
// Too much disk I/O -> too many threads -> swapping and bad scheduling.
var fsgate = make(gate, 8)

func loadPkgIndex() {
	pkgIndex.Lock()
	pkgIndex.m = make(map[string][]pkg)
	pkgIndex.Unlock()

	var wg sync.WaitGroup
	for _, path := range build.Default.SrcDirs() {
		fsgate.enter()
		f, err := os.Open(path)
		if err != nil {
			fsgate.leave()
			fmt.Fprint(os.Stderr, err)
			continue
		}
		children, err := f.Readdir(-1)
		f.Close()
		fsgate.leave()
		if err != nil {
			fmt.Fprint(os.Stderr, err)
			continue
		}
		for _, child := range children {
			if child.IsDir() {
				wg.Add(1)
				go func(path, name string) {
					defer wg.Done()
					loadPkg(&wg, path, name)
				}(path, child.Name())
			}
		}
	}
	wg.Wait()
}

func loadPkg(wg *sync.WaitGroup, root, pkgrelpath string) {
	importpath := filepath.ToSlash(pkgrelpath)
	dir := filepath.Join(root, importpath)

	fsgate.enter()
	defer fsgate.leave()
	pkgDir, err := os.Open(dir)
	if err != nil {
		return
	}
	children, err := pkgDir.Readdir(-1)
	pkgDir.Close()
	if err != nil {
		return
	}
	// hasGo tracks whether a directory actually appears to be a
	// Go source code directory. If $GOPATH == $HOME, and
	// $HOME/src has lots of other large non-Go projects in it,
	// then the calls to importPathToName below can be expensive.
	hasGo := false
	for _, child := range children {
		// Avoid .foo, _foo, and testdata directory trees.
		name := child.Name()
		if name == "" || name[0] == '.' || name[0] == '_' || name == "testdata" {
			continue
		}
		if strings.HasSuffix(name, ".go") {
			hasGo = true
		}
		if child.IsDir() {
			wg.Add(1)
			go func(root, name string) {
				defer wg.Done()
				loadPkg(wg, root, name)
			}(root, filepath.Join(importpath, name))
		}
	}
	if hasGo {
		shortName := importPathToName(importpath)
		pkgIndex.Lock()
		pkgIndex.m[shortName] = append(pkgIndex.m[shortName], pkg{
			importpath: importpath,
			dir:        dir,
		})
		pkgIndex.Unlock()
	}

}

// loadExports returns a list exports for a package.
var loadExports = loadExportsGoPath

func loadExportsGoPath(dir string) map[string]bool {
	exports := make(map[string]bool)
	buildPkg, err := build.ImportDir(dir, 0)
	if err != nil {
		if strings.Contains(err.Error(), "no buildable Go source files in") {
			return nil
		}
		fmt.Fprintf(os.Stderr, "could not import %q: %v\n", dir, err)
		return nil
	}
	fset := token.NewFileSet()
	for _, files := range [...][]string{buildPkg.GoFiles, buildPkg.CgoFiles} {
		for _, file := range files {
			f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not parse %q: %v\n", file, err)
				continue
			}
			for name := range f.Scope.Objects {
				if ast.IsExported(name) {
					exports[name] = true
				}
			}
		}
	}
	return exports
}

// findImport searches for a package with the given symbols.
// If no package is found, findImport returns "".
// Declared as a variable rather than a function so goimports can be easily
// extended by adding a file with an init function.
var findImport = findImportGoPath

func findImportGoPath(pkgName string, symbols map[string]bool, filename string) (string, bool, error) {
	// Fast path for the standard library.
	// In the common case we hopefully never have to scan the GOPATH, which can
	// be slow with moving disks.
	if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok {
		return pkg, rename, nil
	}

	// TODO(sameer): look at the import lines for other Go files in the
	// local directory, since the user is likely to import the same packages
	// in the current Go file.  Return rename=true when the other Go files
	// use a renamed package that's also used in the current file.

	pkgIndexOnce.Do(loadPkgIndex)

	// Collect exports for packages with matching names.
	var (
		wg       sync.WaitGroup
		mu       sync.Mutex
		shortest string
	)
	pkgIndex.Lock()
	for _, pkg := range pkgIndex.m[pkgName] {
		if !canUse(filename, pkg.dir) {
			continue
		}
		wg.Add(1)
		go func(importpath, dir string) {
			defer wg.Done()
			exports := loadExports(dir)
			if exports == nil {
				return
			}
			// If it doesn't have the right symbols, stop.
			for symbol := range symbols {
				if !exports[symbol] {
					return
				}
			}

			// Devendorize for use in import statement.
			if i := strings.LastIndex(importpath, "/vendor/"); i >= 0 {
				importpath = importpath[i+len("/vendor/"):]
			} else if strings.HasPrefix(importpath, "vendor/") {
				importpath = importpath[len("vendor/"):]
			}

			// Save as the answer.
			// If there are multiple candidates, the shortest wins,
			// to prefer "bytes" over "github.com/foo/bytes".
			mu.Lock()
			if shortest == "" || len(importpath) < len(shortest) || len(importpath) == len(shortest) && importpath < shortest {
				shortest = importpath
			}
			mu.Unlock()
		}(pkg.importpath, pkg.dir)
	}
	pkgIndex.Unlock()
	wg.Wait()

	return shortest, false, nil
}

func canUse(filename, dir string) bool {
	dirSlash := filepath.ToSlash(dir)
	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
		return true
	}
	// Vendor or internal directory only visible from children of parent.
	// That means the path from the current directory to the target directory
	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
	// or bar/vendor or bar/internal.
	// After stripping all the leading ../, the only okay place to see vendor or internal
	// is at the very beginning of the path.
	abs, err := filepath.Abs(filename)
	if err != nil {
		return false
	}
	rel, err := filepath.Rel(abs, dir)
	if err != nil {
		return false
	}
	relSlash := filepath.ToSlash(rel)
	if i := strings.LastIndex(relSlash, "../"); i >= 0 {
		relSlash = relSlash[i+len("../"):]
	}
	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
}

type visitFn func(node ast.Node) ast.Visitor

func (fn visitFn) Visit(node ast.Node) ast.Visitor {
	return fn(node)
}

func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) {
	for symbol := range symbols {
		path := stdlib[shortPkg+"."+symbol]
		if path == "" {
			return "", false, false
		}
		if importPath != "" && importPath != path {
			// Ambiguous. Symbols pointed to different things.
			return "", false, false
		}
		importPath = path
	}
	return importPath, false, importPath != ""
}
<commit_msg>Add support for symlinks in the GOPATH<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 imports

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"

	"golang.org/x/tools/go/ast/astutil"
)

// importToGroup is a list of functions which map from an import path to
// a group number.
var importToGroup = []func(importPath string) (num int, ok bool){}

func importGroup(importPath string) int {
	for _, fn := range importToGroup {
		if n, ok := fn(importPath); ok {
			return n
		}
	}
	return 0
}

func fixImports(fset *token.FileSet, f *ast.File, filename string) (added []string, err error) {
	// refs are a set of possible package references currently unsatisfied by imports.
	// first key: either base package (e.g. "fmt") or renamed package
	// second key: referenced package symbol (e.g. "Println")
	refs := make(map[string]map[string]bool)

	// decls are the current package imports. key is base package or renamed package.
	decls := make(map[string]*ast.ImportSpec)

	// collect potential uses of packages.
	var visitor visitFn
	visitor = visitFn(func(node ast.Node) ast.Visitor {
		if node == nil {
			return visitor
		}
		switch v := node.(type) {
		case *ast.ImportSpec:
			if v.Name != nil {
				decls[v.Name.Name] = v
			} else {
				local := importPathToName(strings.Trim(v.Path.Value, `\"`))
				decls[local] = v
			}
		case *ast.SelectorExpr:
			xident, ok := v.X.(*ast.Ident)
			if !ok {
				break
			}
			if xident.Obj != nil {
				// if the parser can resolve it, it's not a package ref
				break
			}
			pkgName := xident.Name
			if refs[pkgName] == nil {
				refs[pkgName] = make(map[string]bool)
			}
			if decls[pkgName] == nil {
				refs[pkgName][v.Sel.Name] = true
			}
		}
		return visitor
	})
	ast.Walk(visitor, f)

	// Nil out any unused ImportSpecs, to be removed in following passes
	unusedImport := map[string]string{}
	for pkg, is := range decls {
		if refs[pkg] == nil && pkg != "_" && pkg != "." {
			name := ""
			if is.Name != nil {
				name = is.Name.Name
			}
			unusedImport[strings.Trim(is.Path.Value, `"`)] = name
		}
	}
	for ipath, name := range unusedImport {
		if ipath == "C" {
			// Don't remove cgo stuff.
			continue
		}
		astutil.DeleteNamedImport(fset, f, name, ipath)
	}

	// Search for imports matching potential package references.
	searches := 0
	type result struct {
		ipath string
		name  string
		err   error
	}
	results := make(chan result)
	for pkgName, symbols := range refs {
		if len(symbols) == 0 {
			continue // skip over packages already imported
		}
		go func(pkgName string, symbols map[string]bool) {
			ipath, rename, err := findImport(pkgName, symbols, filename)
			r := result{ipath: ipath, err: err}
			if rename {
				r.name = pkgName
			}
			results <- r
		}(pkgName, symbols)
		searches++
	}
	for i := 0; i < searches; i++ {
		result := <-results
		if result.err != nil {
			return nil, result.err
		}
		if result.ipath != "" {
			if result.name != "" {
				astutil.AddNamedImport(fset, f, result.name, result.ipath)
			} else {
				astutil.AddImport(fset, f, result.ipath)
			}
			added = append(added, result.ipath)
		}
	}

	return added, nil
}

// importPathToName returns the package name for the given import path.
var importPathToName = importPathToNameGoPath

// importPathToNameBasic assumes the package name is the base of import path.
func importPathToNameBasic(importPath string) (packageName string) {
	return path.Base(importPath)
}

// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
// If there's a problem, it falls back to using importPathToNameBasic.
func importPathToNameGoPath(importPath string) (packageName string) {
	if buildPkg, err := build.Import(importPath, "", 0); err == nil {
		return buildPkg.Name
	} else {
		return importPathToNameBasic(importPath)
	}
}

type pkg struct {
	importpath string // full pkg import path, e.g. "net/http"
	dir        string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
}

var pkgIndexOnce = &sync.Once{}

var pkgIndex struct {
	sync.Mutex
	m map[string][]pkg // shortname => []pkg, e.g "http" => "net/http"
}

// gate is a semaphore for limiting concurrency.
type gate chan struct{}

func (g gate) enter() { g <- struct{}{} }
func (g gate) leave() { <-g }

// fsgate protects the OS & filesystem from too much concurrency.
// Too much disk I/O -> too many threads -> swapping and bad scheduling.
var fsgate = make(gate, 8)

var visitedSymlinks struct {
	sync.Mutex
	m map[string]struct{}
}

func isSymlink(dir string, fi os.FileInfo) bool {
	if fi.Mode()&os.ModeSymlink == 0 {
		return false
	}
	path := filepath.Join(dir, fi.Name())
	target, err := filepath.EvalSymlinks(path)
	if err != nil {
		fmt.Fprint(os.Stderr, err)
		return false
	}
	ts, err := os.Stat(target)
	if err != nil {
		fmt.Fprint(os.Stderr, err)
		return false
	}
	if !ts.IsDir() {
		return false
	}
	realParent, err := filepath.EvalSymlinks(dir)
	if err != nil {
		fmt.Fprint(os.Stderr, err)
		return false
	}
	realPath := filepath.Join(realParent, fi.Name())
	visitedSymlinks.Lock()
	defer visitedSymlinks.Unlock()
	if visitedSymlinks.m == nil {
		visitedSymlinks.m = make(map[string]struct{})
	}
	if _, ok := visitedSymlinks.m[realPath]; ok {
		return false
	}
	visitedSymlinks.m[realPath] = struct{}{}
	return true
}

func loadPkgIndex() {
	pkgIndex.Lock()
	pkgIndex.m = make(map[string][]pkg)
	pkgIndex.Unlock()

	var wg sync.WaitGroup
	for _, path := range build.Default.SrcDirs() {
		fsgate.enter()
		f, err := os.Open(path)
		if err != nil {
			fsgate.leave()
			fmt.Fprint(os.Stderr, err)
			continue
		}
		children, err := f.Readdir(-1)
		f.Close()
		fsgate.leave()
		if err != nil {
			fmt.Fprint(os.Stderr, err)
			continue
		}
		for _, child := range children {
			if child.IsDir() || isSymlink(path, child) {
				wg.Add(1)
				go func(path, name string) {
					defer wg.Done()
					loadPkg(&wg, path, name)
				}(path, child.Name())
			}
		}
	}
	wg.Wait()
}

func loadPkg(wg *sync.WaitGroup, root, pkgrelpath string) {
	importpath := filepath.ToSlash(pkgrelpath)
	dir := filepath.Join(root, importpath)

	fsgate.enter()
	defer fsgate.leave()
	pkgDir, err := os.Open(dir)
	if err != nil {
		return
	}
	children, err := pkgDir.Readdir(-1)
	pkgDir.Close()
	if err != nil {
		return
	}
	// hasGo tracks whether a directory actually appears to be a
	// Go source code directory. If $GOPATH == $HOME, and
	// $HOME/src has lots of other large non-Go projects in it,
	// then the calls to importPathToName below can be expensive.
	hasGo := false
	for _, child := range children {
		// Avoid .foo, _foo, and testdata directory trees.
		name := child.Name()
		if name == "" || name[0] == '.' || name[0] == '_' || name == "testdata" {
			continue
		}
		if strings.HasSuffix(name, ".go") {
			hasGo = true
		}
		if child.IsDir() || isSymlink(dir, child) {
			wg.Add(1)
			go func(root, name string) {
				defer wg.Done()
				loadPkg(wg, root, name)
			}(root, filepath.Join(importpath, name))
		}
	}
	if hasGo {
		shortName := importPathToName(importpath)
		pkgIndex.Lock()
		pkgIndex.m[shortName] = append(pkgIndex.m[shortName], pkg{
			importpath: importpath,
			dir:        dir,
		})
		pkgIndex.Unlock()
	}

}

// loadExports returns a list exports for a package.
var loadExports = loadExportsGoPath

func loadExportsGoPath(dir string) map[string]bool {
	exports := make(map[string]bool)
	buildPkg, err := build.ImportDir(dir, 0)
	if err != nil {
		if strings.Contains(err.Error(), "no buildable Go source files in") {
			return nil
		}
		fmt.Fprintf(os.Stderr, "could not import %q: %v\n", dir, err)
		return nil
	}
	fset := token.NewFileSet()
	for _, files := range [...][]string{buildPkg.GoFiles, buildPkg.CgoFiles} {
		for _, file := range files {
			f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not parse %q: %v\n", file, err)
				continue
			}
			for name := range f.Scope.Objects {
				if ast.IsExported(name) {
					exports[name] = true
				}
			}
		}
	}
	return exports
}

// findImport searches for a package with the given symbols.
// If no package is found, findImport returns "".
// Declared as a variable rather than a function so goimports can be easily
// extended by adding a file with an init function.
var findImport = findImportGoPath

func findImportGoPath(pkgName string, symbols map[string]bool, filename string) (string, bool, error) {
	// Fast path for the standard library.
	// In the common case we hopefully never have to scan the GOPATH, which can
	// be slow with moving disks.
	if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok {
		return pkg, rename, nil
	}

	// TODO(sameer): look at the import lines for other Go files in the
	// local directory, since the user is likely to import the same packages
	// in the current Go file.  Return rename=true when the other Go files
	// use a renamed package that's also used in the current file.

	pkgIndexOnce.Do(loadPkgIndex)

	// Collect exports for packages with matching names.
	var (
		wg       sync.WaitGroup
		mu       sync.Mutex
		shortest string
	)
	pkgIndex.Lock()
	for _, pkg := range pkgIndex.m[pkgName] {
		if !canUse(filename, pkg.dir) {
			continue
		}
		wg.Add(1)
		go func(importpath, dir string) {
			defer wg.Done()
			exports := loadExports(dir)
			if exports == nil {
				return
			}
			// If it doesn't have the right symbols, stop.
			for symbol := range symbols {
				if !exports[symbol] {
					return
				}
			}

			// Devendorize for use in import statement.
			if i := strings.LastIndex(importpath, "/vendor/"); i >= 0 {
				importpath = importpath[i+len("/vendor/"):]
			} else if strings.HasPrefix(importpath, "vendor/") {
				importpath = importpath[len("vendor/"):]
			}

			// Save as the answer.
			// If there are multiple candidates, the shortest wins,
			// to prefer "bytes" over "github.com/foo/bytes".
			mu.Lock()
			if shortest == "" || len(importpath) < len(shortest) || len(importpath) == len(shortest) && importpath < shortest {
				shortest = importpath
			}
			mu.Unlock()
		}(pkg.importpath, pkg.dir)
	}
	pkgIndex.Unlock()
	wg.Wait()

	return shortest, false, nil
}

func canUse(filename, dir string) bool {
	dirSlash := filepath.ToSlash(dir)
	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
		return true
	}
	// Vendor or internal directory only visible from children of parent.
	// That means the path from the current directory to the target directory
	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
	// or bar/vendor or bar/internal.
	// After stripping all the leading ../, the only okay place to see vendor or internal
	// is at the very beginning of the path.
	abs, err := filepath.Abs(filename)
	if err != nil {
		return false
	}
	rel, err := filepath.Rel(abs, dir)
	if err != nil {
		return false
	}
	relSlash := filepath.ToSlash(rel)
	if i := strings.LastIndex(relSlash, "../"); i >= 0 {
		relSlash = relSlash[i+len("../"):]
	}
	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
}

type visitFn func(node ast.Node) ast.Visitor

func (fn visitFn) Visit(node ast.Node) ast.Visitor {
	return fn(node)
}

func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) {
	for symbol := range symbols {
		path := stdlib[shortPkg+"."+symbol]
		if path == "" {
			return "", false, false
		}
		if importPath != "" && importPath != path {
			// Ambiguous. Symbols pointed to different things.
			return "", false, false
		}
		importPath = path
	}
	return importPath, false, importPath != ""
}
<|endoftext|>


<commit_before>package signalfx

import "fmt"

// Error is the only error type returned from Submit
type Error struct {
	OriginalError error
	Message       string
}

func (f *Error) Error() string {
	return fmt.Sprintf("%s: %s", f.Message, f.OriginalError.Error())
}

// newError provides a convenient way to create an Error
func newError(msg string, err error) *Error {
	return &Error{
		OriginalError: err,
		Message:       msg,
	}
}
<commit_msg>update the error type<commit_after>package signalfx

import "fmt"

// sfxError is the only error type returned from Submit
type sfxError struct {
	OriginalError error
	Message       string
}

func (f *sfxError) Error() string {
	return fmt.Sprintf("%s: %s", f.Message, f.OriginalError.Error())
}

// newError provides a convenient way to create an sfxError
func newError(msg string, err error) *sfxError {
	return &sfxError{
		OriginalError: err,
		Message:       msg,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

const (
	LF = 10
)

func ErrorAndExit(format string, args ...interface{}) {
	if format[0] == LF {
		fmt.Printf(format[1:]+"\n", args...)
	} else {
		fmt.Printf(fmt.Sprintf("ERROR: %s\n", format), args...)
	}
	os.Exit(1)
}
<commit_msg>use stderr for errors<commit_after>package main

import (
	"fmt"
	"os"
)

const (
	LF = 10
)

func ErrorAndExit(format string, args ...interface{}) {
	if format[0] == LF {
		fmt.Errorf(format[1:]+"\n", args...)
	} else {
		fmt.Errorf(fmt.Sprintf("ERROR: %s\n", format), args...)
	}
	os.Exit(1)
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"io"
	"os"

	"github.com/pkg/errors"
)

type ErrorHandler struct {
	Out             io.Writer
	PrintStackTrace bool
}

// The default error handler
var E = ErrorHandler{
	Out:             os.Stderr,
	PrintStackTrace: true,
}

// New creates a new error variable
func (e *ErrorHandler) New(format string, a ...interface{}) error {
	return errors.New(fmt.Sprintf(format, a...))
}

// Annotate increases context information to the error
func (e *ErrorHandler) Annotate(err error, a ...interface{}) error {
	return errors.WithMessage(err, fmt.Sprint(a...))
}

// Print writes the error message to predefined io.Writer
func (e *ErrorHandler) Print(err error, a ...interface{}) {
	fmt.Fprint(e.Out, "Error: ")
	if len(a) > 0 {
		fmt.Fprint(e.Out, a...)
		fmt.Fprint(e.Out, ": ")
	}
	format := "%s\n"
	if e.PrintStackTrace {
		format = "%+v"
	}

	fmt.Fprintf(e.Out, format, err)
}

func (e *ErrorHandler) Panic(err error, a ...interface{}) {
	e.Print(err, a...)
	panic("Irrecoverable error")
}

// ErrorList is a list of errors that can be printed in a single go
type ErrorList struct {
	Message string
	errors  []error
}

// NewErrorList returns an initialized ErrorList
func NewErrorList(message string) (ret *ErrorList) {
	return &ErrorList{
		Message: message,
	}
}

// Append adds a new error to the list
func (e *ErrorList) Append(err error) {
	e.errors = append(e.errors, err)
}

// Error returns the error string generated from the list
func (e *ErrorList) Error() string {
	if len(e.errors) == 0 {
		return ""
	}

	ret := "Error: " + e.Message + ": "

	for i := range e.errors {
		ret = ret + fmt.Sprintf("Error %d: %s; ", i+1, e.errors[i])
	}

	return ret
}

// IsEmpty returns true if the error list is empty
func (e *ErrorList) IsEmpty() bool {
	return len(e.errors) == 0
}
<commit_msg>error: Add Fault() for top level error handling<commit_after>package util

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/pkg/errors"
)

type ErrorHandler struct {
	Out             io.Writer
	PrintStackTrace bool
}

// The default error handler
var E = ErrorHandler{
	Out:             os.Stderr,
	PrintStackTrace: true,
}

// New creates a new error variable
func (e *ErrorHandler) New(format string, a ...interface{}) error {
	return errors.New(fmt.Sprintf(format, a...))
}

// Annotate increases context information to the error
func (e *ErrorHandler) Annotate(err error, a ...interface{}) error {
	return errors.WithMessage(err, fmt.Sprint(a...))
}

// Print writes the error message to predefined io.Writer
func (e *ErrorHandler) Print(err error, a ...interface{}) {
	fmt.Fprint(e.Out, "Error: ")
	if len(a) > 0 {
		fmt.Fprint(e.Out, a...)
		fmt.Fprint(e.Out, ": ")
	}
	format := "%s\n"
	if e.PrintStackTrace {
		format = "%+v"
	}

	fmt.Fprintf(e.Out, format, err)
}

func (e *ErrorHandler) Panic(err error, a ...interface{}) {
	e.Print(err, a...)
	panic("Irrecoverable error")
}

// ErrorList is a list of errors that can be printed in a single go
type ErrorList struct {
	Message string
	errors  []error
}

// NewErrorList returns an initialized ErrorList
func NewErrorList(message string) (ret *ErrorList) {
	return &ErrorList{
		Message: message,
	}
}

// Append adds a new error to the list
func (e *ErrorList) Append(err error) {
	e.errors = append(e.errors, err)
}

// Error returns the error string generated from the list
func (e *ErrorList) Error() string {
	if len(e.errors) == 0 {
		return ""
	}

	ret := "Error: " + e.Message + ": "

	for i := range e.errors {
		ret = ret + fmt.Sprintf("Error %d: %s; ", i+1, e.errors[i])
	}

	return ret
}

// IsEmpty returns true if the error list is empty
func (e *ErrorList) IsEmpty() bool {
	return len(e.errors) == 0
}

// Fault checks if given err is != nil and if it is runs os.Exit(1). This
// should be used as a top level handling of errors in the main()
func Fault(err error, message string, arg ...string) {
	if err != nil {
		msg := ""
		if err != nil {
			msg = fmt.Sprintf(" (error: %s)", err)
		}
		fmt.Fprintf(os.Stderr, "Error: %s%s.%s\n", message, strings.Join(arg, " "), msg)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package integration

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("proxy", func() {
	var proxyURL, apiRegexp string

	BeforeEach(func() {
		proxyURL = "127.0.0.1:9999"
		apiRegexp = "(?:https:\\/\\/)*" + apiURL
	})

	Context("V2 Legacy", func() {
		It("handles a proxy", func() {
			session := helpers.CFWithEnv(map[string]string{"http_proxy": proxyURL}, "api", apiURL)
			Eventually(session).Should(Say("Error performing request: Get %s/v2/info: http: error connecting to proxy http://%s: dial tcp %s: getsockopt: connection refused", apiRegexp, proxyURL, proxyURL))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("V3", func() {
		It("handles a proxy", func() {
			session := helpers.CFWithEnv(map[string]string{"http_proxy": proxyURL}, "run-task", "app", "echo")
			Eventually(session.Err).Should(Say("Get %s: http: error connecting to proxy http://%s: dial tcp %s: getsockopt: connection refused", apiRegexp, proxyURL, proxyURL))
			Eventually(session).Should(Exit(1))
		})
	})
})
<commit_msg>windows has a slightly different message, so don't check the whole thing<commit_after>package integration

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("proxy", func() {
	var proxyURL, apiRegexp string

	BeforeEach(func() {
		proxyURL = "127.0.0.1:9999"
		apiRegexp = "(?:https:\\/\\/)*" + apiURL
	})

	Context("V2 Legacy", func() {
		It("handles a proxy", func() {
			session := helpers.CFWithEnv(map[string]string{"http_proxy": proxyURL}, "api", apiURL)
			Eventually(session).Should(Say("Error performing request: Get %s\\/v2\\/info: http: error connecting to proxy http:\\/\\/%s", apiRegexp, proxyURL))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("V3", func() {
		It("handles a proxy", func() {
			session := helpers.CFWithEnv(map[string]string{"http_proxy": proxyURL}, "run-task", "app", "echo")
			Eventually(session.Err).Should(Say("Get %s: http: error connecting to proxy http:\\/\\/%s", apiRegexp, proxyURL))
			Eventually(session).Should(Exit(1))
		})
	})
})
<|endoftext|>


<commit_before>// Package insecure provides an insecure, unencrypted implementation of the the SecureConn and SecureTransport interfaces.
//
// Recommended only for testing and other non-production usage.
package insecure

import (
	"context"
	"fmt"
	"net"

	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/sec"
	"github.com/libp2p/go-msgio"

	ci "github.com/libp2p/go-libp2p-core/crypto"
	pb "github.com/libp2p/go-libp2p-core/sec/insecure/pb"
)

// ID is the multistream-select protocol ID that should be used when identifying
// this security transport.
const ID = "/plaintext/2.0.0"

// Transport is a no-op stream security transport. It provides no
// security and simply mocks the security methods. Identity methods
// return the local peer's ID and private key, and whatever the remote
// peer presents as their ID and public key.
// No authentication of the remote identity is performed.
type Transport struct {
	id  peer.ID
	key ci.PrivKey
}

// New constructs a new insecure transport.
// Deprecated: use NewWithIdentity instead.
func New(id peer.ID) *Transport {
	return &Transport{
		id: id,
	}
}

// New constructs a new insecure transport. The provided private key
// is stored and returned from LocalPrivateKey to satisfy the
// SecureTransport interface, and the public key is sent to
// remote peers. No security is provided.
func NewWithIdentity(id peer.ID, key ci.PrivKey) *Transport {
	return &Transport{
		id:  id,
		key: key,
	}
}

// LocalPeer returns the transport's local peer ID.
func (t *Transport) LocalPeer() peer.ID {
	return t.id
}

// LocalPrivateKey returns the local private key.
// This key is used only for identity generation and provides no security.
func (t *Transport) LocalPrivateKey() ci.PrivKey {
	return t.key
}

// SecureInbound *pretends to secure* an outbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureInbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if a network error occurs during the ID exchange.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
	conn := &Conn{
		Conn:         insecure,
		local:        t.id,
		localPrivKey: t.key,
	}

	err := conn.runHandshakeSync()
	if err != nil {
		return nil, err
	}

	return conn, nil
}

// SecureOutbound *pretends to secure* an outbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureOutbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if the ID sent by the remote peer does not match the one dialed. It may
// also fail if a network error occurs during the ID exchange.
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
	conn := &Conn{
		Conn:         insecure,
		local:        t.id,
		localPrivKey: t.key,
	}

	err := conn.runHandshakeSync()
	if err != nil {
		return nil, err
	}

	if t.key != nil && p != conn.remote {
		return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s",
			p, conn.remote)
	}

	return conn, nil
}

// Conn is the connection type returned by the insecure transport.
type Conn struct {
	net.Conn

	local  peer.ID
	remote peer.ID

	localPrivKey ci.PrivKey
	remotePubKey ci.PubKey
}

func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
	keyMsg, err := ci.PublicKeyToProto(pubkey)
	if err != nil {
		return nil, err
	}
	id, err := peer.IDFromPublicKey(pubkey)
	if err != nil {
		return nil, err
	}

	return &pb.Exchange{
		Id:     []byte(id),
		Pubkey: keyMsg,
	}, nil
}

func (ic *Conn) runHandshakeSync() error {
	// If we were initialized without keys, behave as in plaintext/1.0.0 (do nothing)
	if ic.localPrivKey == nil {
		return nil
	}

	rw := msgio.NewReadWriter(ic.Conn)
	// Generate an Exchange message
	msg, err := makeExchangeMessage(ic.localPrivKey.GetPublic())
	if err != nil {
		return err
	}

	// Send our Exchange and read theirs
	remoteMsg, err := readWriteMsg(rw, msg)
	if err != nil {
		return err
	}

	// Pull remote ID and public key from message
	remotePubkey, err := ci.PublicKeyFromProto(remoteMsg.Pubkey)
	if err != nil {
		return err
	}

	remoteID, err := peer.IDFromPublicKey(remotePubkey)
	if err != nil {
		return err
	}

	// Validate that ID matches public key
	if !remoteID.MatchesPublicKey(remotePubkey) {
		calculatedID, _ := peer.IDFromPublicKey(remotePubkey)
		return fmt.Errorf("remote peer id does not match public key. id=%s calculated_id=%s",
			remoteID, calculatedID)
	}

	// Add remote ID and key to conn state
	ic.remotePubKey = remotePubkey
	ic.remote = remoteID
	return nil
}

// read and write a message at the same time.
func readWriteMsg(c msgio.ReadWriter, out *pb.Exchange) (*pb.Exchange, error) {
	outBytes, err := out.Marshal()
	if err != nil {
		return nil, err
	}
	wresult := make(chan error)
	go func() {
		wresult <- c.WriteMsg(outBytes)
	}()

	msg, err1 := c.ReadMsg()

	// Always wait for the read to finish.
	err2 := <-wresult

	if err1 != nil {
		return nil, err1
	}
	if err2 != nil {
		c.ReleaseMsg(msg)
		return nil, err2
	}
	inMsg := new(pb.Exchange)
	err = inMsg.Unmarshal(msg)
	return inMsg, err
}

// LocalPeer returns the local peer ID.
func (ic *Conn) LocalPeer() peer.ID {
	return ic.local
}

// RemotePeer returns the remote peer ID if we initiated the dial. Otherwise, it
// returns "" (because this connection isn't actually secure).
func (ic *Conn) RemotePeer() peer.ID {
	return ic.remote
}

// RemotePublicKey returns whatever public key was given by the remote peer.
// Note that no verification of ownership is done, as this connection is not secure.
func (ic *Conn) RemotePublicKey() ci.PubKey {
	return ic.remotePubKey
}

// LocalPrivateKey returns the private key for the local peer.
func (ic *Conn) LocalPrivateKey() ci.PrivKey {
	return ic.localPrivKey
}

var _ sec.SecureTransport = (*Transport)(nil)
var _ sec.SecureConn = (*Conn)(nil)
<commit_msg>use varints for delimiting plaintext 2.0 msgs (#74)<commit_after>// Package insecure provides an insecure, unencrypted implementation of the the SecureConn and SecureTransport interfaces.
//
// Recommended only for testing and other non-production usage.
package insecure

import (
	"context"
	"fmt"
	"io"
	"net"

	gogoio "github.com/gogo/protobuf/io"

	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/sec"

	ci "github.com/libp2p/go-libp2p-core/crypto"
	pb "github.com/libp2p/go-libp2p-core/sec/insecure/pb"
)

// ID is the multistream-select protocol ID that should be used when identifying
// this security transport.
const ID = "/plaintext/2.0.0"

// Transport is a no-op stream security transport. It provides no
// security and simply mocks the security methods. Identity methods
// return the local peer's ID and private key, and whatever the remote
// peer presents as their ID and public key.
// No authentication of the remote identity is performed.
type Transport struct {
	id  peer.ID
	key ci.PrivKey
}

// New constructs a new insecure transport.
// Deprecated: use NewWithIdentity instead.
func New(id peer.ID) *Transport {
	return &Transport{
		id: id,
	}
}

// New constructs a new insecure transport. The provided private key
// is stored and returned from LocalPrivateKey to satisfy the
// SecureTransport interface, and the public key is sent to
// remote peers. No security is provided.
func NewWithIdentity(id peer.ID, key ci.PrivKey) *Transport {
	return &Transport{
		id:  id,
		key: key,
	}
}

// LocalPeer returns the transport's local peer ID.
func (t *Transport) LocalPeer() peer.ID {
	return t.id
}

// LocalPrivateKey returns the local private key.
// This key is used only for identity generation and provides no security.
func (t *Transport) LocalPrivateKey() ci.PrivKey {
	return t.key
}

// SecureInbound *pretends to secure* an outbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureInbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if a network error occurs during the ID exchange.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
	conn := &Conn{
		Conn:         insecure,
		local:        t.id,
		localPrivKey: t.key,
	}

	err := conn.runHandshakeSync()
	if err != nil {
		return nil, err
	}

	return conn, nil
}

// SecureOutbound *pretends to secure* an outbound connection to the given peer.
// It sends the local peer's ID and public key, and receives the same from the remote peer.
// No validation is performed as to the authenticity or ownership of the provided public key,
// and the key exchange provides no security.
//
// SecureOutbound may fail if the remote peer sends an ID and public key that are inconsistent
// with each other, or if the ID sent by the remote peer does not match the one dialed. It may
// also fail if a network error occurs during the ID exchange.
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
	conn := &Conn{
		Conn:         insecure,
		local:        t.id,
		localPrivKey: t.key,
	}

	err := conn.runHandshakeSync()
	if err != nil {
		return nil, err
	}

	if t.key != nil && p != conn.remote {
		return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s",
			p, conn.remote)
	}

	return conn, nil
}

// Conn is the connection type returned by the insecure transport.
type Conn struct {
	net.Conn

	local  peer.ID
	remote peer.ID

	localPrivKey ci.PrivKey
	remotePubKey ci.PubKey
}

func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
	keyMsg, err := ci.PublicKeyToProto(pubkey)
	if err != nil {
		return nil, err
	}
	id, err := peer.IDFromPublicKey(pubkey)
	if err != nil {
		return nil, err
	}

	return &pb.Exchange{
		Id:     []byte(id),
		Pubkey: keyMsg,
	}, nil
}

func (ic *Conn) runHandshakeSync() error {
	// If we were initialized without keys, behave as in plaintext/1.0.0 (do nothing)
	if ic.localPrivKey == nil {
		return nil
	}

	// Generate an Exchange message
	msg, err := makeExchangeMessage(ic.localPrivKey.GetPublic())
	if err != nil {
		return err
	}

	// Send our Exchange and read theirs
	remoteMsg, err := readWriteMsg(ic.Conn, msg)
	if err != nil {
		return err
	}

	// Pull remote ID and public key from message
	remotePubkey, err := ci.PublicKeyFromProto(remoteMsg.Pubkey)
	if err != nil {
		return err
	}

	remoteID, err := peer.IDFromPublicKey(remotePubkey)
	if err != nil {
		return err
	}

	// Validate that ID matches public key
	if !remoteID.MatchesPublicKey(remotePubkey) {
		calculatedID, _ := peer.IDFromPublicKey(remotePubkey)
		return fmt.Errorf("remote peer id does not match public key. id=%s calculated_id=%s",
			remoteID, calculatedID)
	}

	// Add remote ID and key to conn state
	ic.remotePubKey = remotePubkey
	ic.remote = remoteID
	return nil
}

// read and write a message at the same time.
func readWriteMsg(rw io.ReadWriter, out *pb.Exchange) (*pb.Exchange, error) {
	const maxMsgSize = 1 << 16
	r := gogoio.NewDelimitedReader(rw, maxMsgSize)
	w := gogoio.NewDelimitedWriter(rw)
	wresult := make(chan error)
	go func() {
		wresult <- w.WriteMsg(out)
	}()

	inMsg := pb.Exchange{}
	err := r.ReadMsg(&inMsg)

	// Always wait for the write to finish.
	err2 := <-wresult

	if err != nil {
		return nil, err
	}
	if err2 != nil {
		return nil, err2
	}
	return &inMsg, err
}

// LocalPeer returns the local peer ID.
func (ic *Conn) LocalPeer() peer.ID {
	return ic.local
}

// RemotePeer returns the remote peer ID if we initiated the dial. Otherwise, it
// returns "" (because this connection isn't actually secure).
func (ic *Conn) RemotePeer() peer.ID {
	return ic.remote
}

// RemotePublicKey returns whatever public key was given by the remote peer.
// Note that no verification of ownership is done, as this connection is not secure.
func (ic *Conn) RemotePublicKey() ci.PubKey {
	return ic.remotePubKey
}

// LocalPrivateKey returns the private key for the local peer.
func (ic *Conn) LocalPrivateKey() ci.PrivKey {
	return ic.localPrivKey
}

var _ sec.SecureTransport = (*Transport)(nil)
var _ sec.SecureConn = (*Conn)(nil)
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"sync"
	"time"
)

type ServerProfilerFactory struct {
	Frequency int
	Duration  int
	QueueSize int
}

// New will be used to initialize a new server profiler for caduceus and get
// the gears in motion for aggregating data
func (spf ServerProfilerFactory) New() (serverProfiler ServerProfiler) {
	newCaduceusProfiler := &caduceusProfiler{
		ticker:       time.NewTicker(time.Duration(spf.Frequency) * time.Second),
		profilerRing: NewCaduceusRing(spf.Duration),
		inChan:       make(chan interface{}, spf.QueueSize),
	}

	go newCaduceusProfiler.aggregate()

	serverProfiler = newCaduceusProfiler
	return
}

type ServerProfiler interface {
	Send(interface{}) error
	Report() []interface{}
}

type caduceusProfiler struct {
	ticker       *time.Ticker
	profilerRing ServerRing
	inChan       chan interface{}
	rwMutex      sync.RWMutex
}

// Send will add data that we retrieve onto the
// data structure we use for gathering info
func (cp *caduceusProfiler) Send(inData interface{}) error {
	// send the data over to the structure
	select {
	case cp.inChan <- inData:
		return nil
	default:
		return errors.New("Channel full.")
	}
}

// Report will be used to retrieve data when the data the profiler
// stores is ready to be collected
func (cp *caduceusProfiler) Report() (values []interface{}) {
	cp.rwMutex.RLock()
	values = cp.profilerRing.Snapshot()
	cp.rwMutex.RUnlock()
	return
}

// aggregate runs on a timer and will take in data until a certain amount
// of time passes, then it will generate a report that it will share
func (cp *caduceusProfiler) aggregate() {
	var data []interface{}

	for {
		select {
		case <-cp.ticker.C:
			// add the data to the ring and clear the temporary structure
			cp.rwMutex.Lock()
			cp.profilerRing.Add(data)
			cp.rwMutex.Unlock()
			data = nil
		case inData := <-cp.inChan:
			// add the data to a temporary structure
			data = append(data, inData)
		}
	}
}
<commit_msg>Adding in changes that allow for you to close the profiler that you are using.<commit_after>package main

import (
	"errors"
	"sync"
	"time"
)

type ServerProfilerFactory struct {
	Frequency int
	Duration  int
	QueueSize int
}

// New will be used to initialize a new server profiler for caduceus and get
// the gears in motion for aggregating data
func (spf ServerProfilerFactory) New() (serverProfiler ServerProfiler) {
	newCaduceusProfiler := &caduceusProfiler{
		ticker:       time.NewTicker(time.Duration(spf.Frequency) * time.Second),
		profilerRing: NewCaduceusRing(spf.Duration),
		inChan:       make(chan interface{}, spf.QueueSize),
		quit:         make(chan struct{}),
	}

	go newCaduceusProfiler.aggregate()

	serverProfiler = newCaduceusProfiler
	return
}

type ServerProfiler interface {
	Send(interface{}) error
	Report() []interface{}
	Close()
}

type caduceusProfiler struct {
	ticker       *time.Ticker
	profilerRing ServerRing
	inChan       chan interface{}
	quit         chan struct{}
	rwMutex      sync.RWMutex
}

// Send will add data that we retrieve onto the
// data structure we use for gathering info
func (cp *caduceusProfiler) Send(inData interface{}) error {
	// send the data over to the structure
	select {
	case cp.inChan <- inData:
		return nil
	default:
		return errors.New("Channel full.")
	}
}

// Report will be used to retrieve data when the data the profiler
// stores is ready to be collected
func (cp *caduceusProfiler) Report() (values []interface{}) {
	cp.rwMutex.RLock()
	values = cp.profilerRing.Snapshot()
	cp.rwMutex.RUnlock()
	return
}

// Close will terminate the running aggregate method and do any cleanup necessary
func (cp *caduceusProfiler) Close() {
	close(cp.quit)
}

// aggregate runs on a timer and will take in data until a certain amount
// of time passes, then it will generate a report that it will share
func (cp *caduceusProfiler) aggregate() {
	var data []interface{}
	running := true

	for running {
		select {
		case <-cp.ticker.C:
			// add the data to the ring and clear the temporary structure
			cp.rwMutex.Lock()
			cp.profilerRing.Add(data)
			cp.rwMutex.Unlock()
			data = nil
		case inData := <-cp.inChan:
			// add the data to a temporary structure
			data = append(data, inData)
		case <-cp.quit:
			cp.ticker.Stop()
			running = false
		}
	}
}
<|endoftext|>


<commit_before>package ass

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

func WriteAss(v *Ass, outpath string) {
	f, err := os.Create(outpath)
	if err != nil {
		fmt.Println(err)
	}
	var outout []string
	// Write header
	outout = append(outout, v.ScriptInfo.Header)
	outout = append(outout, "Title: "+v.ScriptInfo.Body.Title)
	outout = append(outout, "ScriptType: "+v.ScriptInfo.Body.ScriptType)
	outout = append(outout, "WrapStyle: "+v.ScriptInfo.Body.WarpStyle)
	outout = append(outout, "ScaledBorderAndShadow: "+v.ScriptInfo.Body.SBaShadow)
	outout = append(outout, "YCbCr Matrix: "+v.ScriptInfo.Body.YCbCrMatrix)
	outout = append(outout, "PlayResX: "+strconv.Itoa(v.ScriptInfo.Body.PlayResX))
	outout = append(outout, "PlayResY: "+strconv.Itoa(v.ScriptInfo.Body.PlayResY))
	outout = append(outout, v.PGarbage.Header)
	outout = append(outout, "Audio File: "+v.PGarbage.Body.AudioFile)
	outout = append(outout, "Video File: "+v.PGarbage.Body.VideoFile)
	outout = append(outout, "Video AR Mode: "+v.PGarbage.Body.VideoARMode)
	outout = append(outout, "Video AR Value: "+strconv.FormatFloat(v.PGarbage.Body.VideoARValue, 'E', -1, 64))
	outout = append(outout, "Video Zoom Percent: "+strconv.FormatFloat(v.PGarbage.Body.VideoZoomPercent, 'E', -1, 64))
	outout = append(outout, "Scroll Position: "+strconv.Itoa(v.PGarbage.Body.ScrollPosition))
	outout = append(outout, "Active Line: "+strconv.Itoa(v.PGarbage.Body.ActiveLine))
	outout = append(outout, "Video Position: "+strconv.Itoa(v.PGarbage.Body.VideoPos))
	outout = append(outout, v.Styles.Header)
	outout = append(outout, v.Styles.Format)

	//Super ugly solution for merging entire object as deliniated by a string. There has to be a way to do this in a sane, programmatic
	// and idiomatic manner.

	for _, z := range v.Styles.Body {
		var astyle string
		astyle = z.Format + "," + z.Name + "," + z.Fontname + "," + strconv.Itoa(z.Fontsize)
		astyle = z.PrimaryColour + "," + z.SecondaryColour
		astyle = z.OutlineColour + "," + z.Backcolour + "," + strconv.Itoa(z.Bold) + "," + strconv.Itoa(z.Italic)
		astyle = strconv.Itoa(z.Underline) + "," + strconv.Itoa(z.StrikeOut) + "," + strconv.Itoa(z.ScaleX) + "," + strconv.Itoa(z.ScaleY)
		astyle = strconv.Itoa(z.Spacing) + "," + strconv.Itoa(z.Angle) + "," + strconv.Itoa(z.BorderStyle) + "," + strconv.Itoa(z.Outline)
		astyle = strconv.Itoa(z.Shadow) + "," + strconv.Itoa(z.Alignment) + "," + strconv.Itoa(z.MarginL) + "," + strconv.Itoa(z.MarginR)
		astyle = strconv.Itoa(z.MarginV) + "," + strconv.Itoa(z.Encoding) + "\n"
		outout = append(outout, astyle)
		astyle = ""
	}

	outout = append(outout, v.Events.Header)
	outout = append(outout, v.Events.Format)
	for _, e := range v.Events.Body {
		var anevent string
		anevent = e.Format + "," + strconv.Itoa(e.Layer) + "," + e.Start + "," + e.End
		anevent = e.Style + "," + e.Name + "," + strconv.Itoa(e.MarginL)
		anevent = strconv.Itoa(e.MarginR) + "," + strconv.Itoa(e.MarginV)
		anevent = e.Effect + "," + e.Text
		outout = append(outout, anevent)
		anevent = ""
	}

	fmt.Fprintf(f, "%", strings.Join(outout, ""))

}
<commit_msg>Update writeass.go<commit_after>package ass

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

func WriteAss(v *Ass, outpath string) {
	f, err := os.Create(outpath)
	if err != nil {
		fmt.Println(err)
	}
	var outout []string
	// Write header
	outout = append(outout, v.ScriptInfo.Header)
	outout = append(outout, "Title: "+v.ScriptInfo.Body.Title)
	outout = append(outout, "ScriptType: "+v.ScriptInfo.Body.ScriptType)
	outout = append(outout, "WrapStyle: "+v.ScriptInfo.Body.WarpStyle)
	outout = append(outout, "ScaledBorderAndShadow: "+v.ScriptInfo.Body.SBaShadow)
	outout = append(outout, "YCbCr Matrix: "+v.ScriptInfo.Body.YCbCrMatrix)
	outout = append(outout, "PlayResX: "+strconv.Itoa(v.ScriptInfo.Body.PlayResX))
	outout = append(outout, "PlayResY: "+strconv.Itoa(v.ScriptInfo.Body.PlayResY))
	outout = append(outout, v.PGarbage.Header)
	outout = append(outout, "Audio File: "+v.PGarbage.Body.AudioFile)
	outout = append(outout, "Video File: "+v.PGarbage.Body.VideoFile)
	outout = append(outout, "Video AR Mode: "+v.PGarbage.Body.VideoARMode)
	outout = append(outout, "Video AR Value: "+strconv.FormatFloat(v.PGarbage.Body.VideoARValue, 'E', -1, 64))
	outout = append(outout, "Video Zoom Percent: "+strconv.FormatFloat(v.PGarbage.Body.VideoZoomPercent, 'E', -1, 64))
	outout = append(outout, "Scroll Position: "+strconv.Itoa(v.PGarbage.Body.ScrollPosition))
	outout = append(outout, "Active Line: "+strconv.Itoa(v.PGarbage.Body.ActiveLine))
	outout = append(outout, "Video Position: "+strconv.Itoa(v.PGarbage.Body.VideoPos))
	outout = append(outout, v.Styles.Header)
	outout = append(outout, v.Styles.Format)

	//Super ugly solution for merging entire object as deliniated by a string. There has to be a way to do this in a sane, programmatic
	// and idiomatic manner.

	for _, z := range v.Styles.Body {
		var astyle string
		astyle = z.Format + "," + z.Name + "," + z.Fontname + "," + strconv.Itoa(z.Fontsize)
		astyle = z.PrimaryColour + "," + z.SecondaryColour
		astyle = z.OutlineColour + "," + z.Backcolour + "," + strconv.Itoa(z.Bold) + "," + strconv.Itoa(z.Italic)
		astyle = strconv.Itoa(z.Underline) + "," + strconv.Itoa(z.StrikeOut) + "," + strconv.Itoa(z.ScaleX) + "," + strconv.Itoa(z.ScaleY)
		astyle = strconv.Itoa(z.Spacing) + "," + strconv.Itoa(z.Angle) + "," + strconv.Itoa(z.BorderStyle) + "," + strconv.Itoa(z.Outline)
		astyle = strconv.Itoa(z.Shadow) + "," + strconv.Itoa(z.Alignment) + "," + strconv.Itoa(z.MarginL) + "," + strconv.Itoa(z.MarginR)
		astyle = strconv.Itoa(z.MarginV) + "," + strconv.Itoa(z.Encoding) + "\n"
		outout = append(outout, astyle)
	}

	outout = append(outout, v.Events.Header)
	outout = append(outout, v.Events.Format)
	for _, e := range v.Events.Body {
		var anevent string
		anevent = e.Format + "," + strconv.Itoa(e.Layer) + "," + e.Start + "," + e.End
		anevent = e.Style + "," + e.Name + "," + strconv.Itoa(e.MarginL)
		anevent = strconv.Itoa(e.MarginR) + "," + strconv.Itoa(e.MarginV)
		anevent = e.Effect + "," + e.Text
		outout = append(outout, anevent)
	}

	fmt.Fprintf(f, "%", strings.Join(outout, ""))

}
<|endoftext|>


<commit_before>// go-camo daemon (go-camod)
package main

import (
	"encoding/json"
	"flag"
	"go-camo/camoproxy"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"runtime"
	"time"
)

// Container for holding configuration parameters parsed from JSON config
// file.
type configParams struct {
	HmacKey   string
	Allowlist []string
	Denylist  []string
	MaxSize   int64
}

var hmacKeyFlag = flag.String("hmacKey", "", "HMAC Key")
var configFileFlag = flag.String("configFile", "", "JSON Config File")
var maxSize = flag.Int64("maxSize", 5120, "Max size in KB to allow")
var bindAddress = flag.String("bindAddress", "0.0.0.0:8080",
	"Address:Port to bind to")

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()

	config := &configParams{}
	if *configFileFlag != "" {
		b, err := ioutil.ReadFile(*configFileFlag)
		if err != nil {
			log.Fatal("Could not read configFile", err)
		}
		err = json.Unmarshal(b, &config)
		if err != nil {
			log.Fatal("Could not parse configFile", err)
		}
	}

	// flags override config file
	if *hmacKeyFlag != "" {
		config.HmacKey = *hmacKeyFlag
	}
	if config.MaxSize == 0 {
		config.MaxSize = *maxSize
	}

	tr := &http.Transport{
		Dial: func(netw, addr string) (net.Conn, error) {
			// 2 second timeout on requests
			timeout := time.Second * 2
			c, err := net.DialTimeout(netw, addr, timeout)
			if err != nil {
				return nil, err
			}
			// also set time limit on reading
			c.SetDeadline(time.Now().Add(timeout))
			return c, nil
		}}

	// spawn an idle conn trimmer
	go func() {
		time.Sleep(5 * time.Minute)
		tr.CloseIdleConnections()
	}()

	proxy := &camoproxy.ProxyHandler{
		Transport: tr,
		HMacKey:   []byte(config.HmacKey),
		MaxSize:   config.MaxSize * 1024}

	// build/compile regex
	proxy.RegexpAllowlist = make([]*regexp.Regexp, 0)
	proxy.RegexpDenylist = make([]*regexp.Regexp, 0)

	var c *regexp.Regexp
	var err error
	for _, v := range config.Denylist {
		c, err = regexp.Compile(v)
		if err != nil {
			log.Fatal(err)
		}
		proxy.RegexpDenylist = append(proxy.RegexpDenylist, c)
	}
	for _, v := range config.Allowlist {
		c, err = regexp.Compile(v)
		if err != nil {
			log.Fatal(err)
		}
		proxy.RegexpAllowlist = append(proxy.RegexpAllowlist, c)
	}

	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.Handle("/", proxy)
	log.Println("Starting server on", *bindAddress)
	log.Fatal(http.ListenAndServe(*bindAddress, nil))
}
<commit_msg>a few less globals<commit_after>// go-camo daemon (go-camod)
package main

import (
	"encoding/json"
	"flag"
	"go-camo/camoproxy"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"runtime"
	"time"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	// command line flags
	hmacKeyFlag := flag.String("hmacKey", "", "HMAC Key")
	configFileFlag := flag.String("configFile", "", "JSON Config File")
	maxSize := flag.Int64("maxSize", 5120, "Max size in KB to allow")
	bindAddress := flag.String("bindAddress", "0.0.0.0:8080",
		"Address:Port to bind to")
	// parse said flags
	flag.Parse()

	// Anonymous struct Container for holding configuration parameters parsed
	// from JSON config file.
	config := &struct {
		HmacKey   string
		Allowlist []string
		Denylist  []string
		MaxSize   int64}{}

	if *configFileFlag != "" {
		b, err := ioutil.ReadFile(*configFileFlag)
		if err != nil {
			log.Fatal("Could not read configFile", err)
		}
		err = json.Unmarshal(b, &config)
		if err != nil {
			log.Fatal("Could not parse configFile", err)
		}
	}

	// flags override config file
	if *hmacKeyFlag != "" {
		config.HmacKey = *hmacKeyFlag
	}
	if config.MaxSize == 0 {
		config.MaxSize = *maxSize
	}

	tr := &http.Transport{
		Dial: func(netw, addr string) (net.Conn, error) {
			// 2 second timeout on requests
			timeout := time.Second * 2
			c, err := net.DialTimeout(netw, addr, timeout)
			if err != nil {
				return nil, err
			}
			// also set time limit on reading
			c.SetDeadline(time.Now().Add(timeout))
			return c, nil
		}}

	// spawn an idle conn trimmer
	go func() {
		time.Sleep(5 * time.Minute)
		tr.CloseIdleConnections()
	}()

	proxy := &camoproxy.ProxyHandler{
		Transport: tr,
		HMacKey:   []byte(config.HmacKey),
		MaxSize:   config.MaxSize * 1024}

	// build/compile regex
	proxy.RegexpAllowlist = make([]*regexp.Regexp, 0)
	proxy.RegexpDenylist = make([]*regexp.Regexp, 0)

	var c *regexp.Regexp
	var err error
	for _, v := range config.Denylist {
		c, err = regexp.Compile(v)
		if err != nil {
			log.Fatal(err)
		}
		proxy.RegexpDenylist = append(proxy.RegexpDenylist, c)
	}
	for _, v := range config.Allowlist {
		c, err = regexp.Compile(v)
		if err != nil {
			log.Fatal(err)
		}
		proxy.RegexpAllowlist = append(proxy.RegexpAllowlist, c)
	}

	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.Handle("/", proxy)
	log.Println("Starting server on", *bindAddress)
	log.Fatal(http.ListenAndServe(*bindAddress, nil))
}
<|endoftext|>


<commit_before>package formatter

import (
	"fmt"
	"sync"

	units "src/github.com/docker/go-units"
)

const (
	winOSType                  = "windows"
	defaultStatsTableFormat    = "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"
	winDefaultStatsTableFormat = "table {{.Container}}\t{{.CPUPerc}}\t{{{.MemUsage}}\t{.NetIO}}\t{{.BlockIO}}"
	emptyStatsTableFormat      = "Waiting for statistics..."

	containerHeader  = "CONTAINER"
	cpuPercHeader    = "CPU %"
	netIOHeader      = "NET I/O"
	blockIOHeader    = "BLOCK I/O"
	winMemPercHeader = "PRIV WORKING SET"  // Used only on Window
	memPercHeader    = "MEM %"             // Used only on Linux
	memUseHeader     = "MEM USAGE / LIMIT" // Used only on Linux
	pidsHeader       = "PIDS"              // Used only on Linux
)

// StatsEntry represents represents the statistics data collected from a container
type StatsEntry struct {
	Name             string
	CPUPercentage    float64
	Memory           float64 // On Windows this is the private working set
	MemoryLimit      float64 // Not used on Windows
	MemoryPercentage float64 // Not used on Windows
	NetworkRx        float64
	NetworkTx        float64
	BlockRead        float64
	BlockWrite       float64
	PidsCurrent      uint64 // Not used on Windows
	IsInvalid        bool
	OSType           string
}

// ContainerStats represents an entity to store containers statistics synchronously
type ContainerStats struct {
	mutex sync.Mutex
	StatsEntry
	err error
}

// GetError returns the container statistics error.
// This is used to determine whether the statistics are valid or not
func (cs *ContainerStats) GetError() error {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.err
}

// SetErrorAndReset zeroes all the container statistics and store the error.
// It is used when receiving time out error during statistics collecting to reduce lock overhead
func (cs *ContainerStats) SetErrorAndReset(err error) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	cs.CPUPercentage = 0
	cs.Memory = 0
	cs.MemoryPercentage = 0
	cs.MemoryLimit = 0
	cs.NetworkRx = 0
	cs.NetworkTx = 0
	cs.BlockRead = 0
	cs.BlockWrite = 0
	cs.PidsCurrent = 0
	cs.err = err
	cs.IsInvalid = true
}

// SetError sets container statistics error
func (cs *ContainerStats) SetError(err error) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	cs.err = err
	if err != nil {
		cs.IsInvalid = true
	}
}

// SetStatistics set the container statistics
func (cs *ContainerStats) SetStatistics(s StatsEntry) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	s.Name = cs.Name
	s.OSType = cs.OSType
	cs.StatsEntry = s
}

// GetStatistics returns container statistics with other meta data such as the container name
func (cs *ContainerStats) GetStatistics() StatsEntry {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.StatsEntry
}

// NewStatsFormat returns a format for rendering an CStatsContext
func NewStatsFormat(source, osType string) Format {
	if source == TableFormatKey {
		if osType == winOSType {
			return Format(winDefaultStatsTableFormat)
		}
		return Format(defaultStatsTableFormat)
	}
	return Format(source)
}

// NewContainerStats returns a new ContainerStats entity and sets in it the given name
func NewContainerStats(name, osType string) *ContainerStats {
	return &ContainerStats{
		StatsEntry: StatsEntry{Name: name, OSType: osType},
	}
}

// ContainerStatsWrite renders the context for a list of containers statistics
func ContainerStatsWrite(ctx Context, containerStats []StatsEntry) error {
	render := func(format func(subContext subContext) error) error {
		for _, cstats := range containerStats {
			containerStatsCtx := &containerStatsContext{
				s: cstats,
			}
			if err := format(containerStatsCtx); err != nil {
				return err
			}
		}
		return nil
	}
	return ctx.Write(&containerStatsContext{}, render)
}

type containerStatsContext struct {
	HeaderContext
	s StatsEntry
}

func (c *containerStatsContext) Container() string {
	c.AddHeader(containerHeader)
	return c.s.Name
}

func (c *containerStatsContext) CPUPerc() string {
	c.AddHeader(cpuPercHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%.2f%%", c.s.CPUPercentage)
}

func (c *containerStatsContext) MemUsage() string {
	c.AddHeader(memUseHeader)
	if c.s.IsInvalid || c.s.OSType == winOSType {
		return fmt.Sprintf("-- / --")
	}
	return fmt.Sprintf("%s / %s", units.BytesSize(c.s.Memory), units.BytesSize(c.s.MemoryLimit))
}

func (c *containerStatsContext) MemPerc() string {
	header := memPercHeader
	if c.s.OSType == winOSType {
		header = winMemPercHeader
	}
	c.AddHeader(header)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%.2f%%", c.s.MemoryPercentage)
}

func (c *containerStatsContext) NetIO() string {
	c.AddHeader(netIOHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.NetworkRx, 3), units.HumanSizeWithPrecision(c.s.NetworkTx, 3))
}

func (c *containerStatsContext) BlockIO() string {
	c.AddHeader(blockIOHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.BlockRead, 3), units.HumanSizeWithPrecision(c.s.BlockWrite, 3))
}

func (c *containerStatsContext) PIDs() string {
	c.AddHeader(pidsHeader)
	if c.s.IsInvalid || c.s.OSType == winOSType {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%d", c.s.PidsCurrent)
}
<commit_msg>Correct go-units import in cli/command/formatter/stats.go from src/github.com/docker/go-units -> github.com/docker/go-units<commit_after>package formatter

import (
	"fmt"
	"sync"

	units "github.com/docker/go-units"
)

const (
	winOSType                  = "windows"
	defaultStatsTableFormat    = "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"
	winDefaultStatsTableFormat = "table {{.Container}}\t{{.CPUPerc}}\t{{{.MemUsage}}\t{.NetIO}}\t{{.BlockIO}}"
	emptyStatsTableFormat      = "Waiting for statistics..."

	containerHeader  = "CONTAINER"
	cpuPercHeader    = "CPU %"
	netIOHeader      = "NET I/O"
	blockIOHeader    = "BLOCK I/O"
	winMemPercHeader = "PRIV WORKING SET"  // Used only on Window
	memPercHeader    = "MEM %"             // Used only on Linux
	memUseHeader     = "MEM USAGE / LIMIT" // Used only on Linux
	pidsHeader       = "PIDS"              // Used only on Linux
)

// StatsEntry represents represents the statistics data collected from a container
type StatsEntry struct {
	Name             string
	CPUPercentage    float64
	Memory           float64 // On Windows this is the private working set
	MemoryLimit      float64 // Not used on Windows
	MemoryPercentage float64 // Not used on Windows
	NetworkRx        float64
	NetworkTx        float64
	BlockRead        float64
	BlockWrite       float64
	PidsCurrent      uint64 // Not used on Windows
	IsInvalid        bool
	OSType           string
}

// ContainerStats represents an entity to store containers statistics synchronously
type ContainerStats struct {
	mutex sync.Mutex
	StatsEntry
	err error
}

// GetError returns the container statistics error.
// This is used to determine whether the statistics are valid or not
func (cs *ContainerStats) GetError() error {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.err
}

// SetErrorAndReset zeroes all the container statistics and store the error.
// It is used when receiving time out error during statistics collecting to reduce lock overhead
func (cs *ContainerStats) SetErrorAndReset(err error) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	cs.CPUPercentage = 0
	cs.Memory = 0
	cs.MemoryPercentage = 0
	cs.MemoryLimit = 0
	cs.NetworkRx = 0
	cs.NetworkTx = 0
	cs.BlockRead = 0
	cs.BlockWrite = 0
	cs.PidsCurrent = 0
	cs.err = err
	cs.IsInvalid = true
}

// SetError sets container statistics error
func (cs *ContainerStats) SetError(err error) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	cs.err = err
	if err != nil {
		cs.IsInvalid = true
	}
}

// SetStatistics set the container statistics
func (cs *ContainerStats) SetStatistics(s StatsEntry) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	s.Name = cs.Name
	s.OSType = cs.OSType
	cs.StatsEntry = s
}

// GetStatistics returns container statistics with other meta data such as the container name
func (cs *ContainerStats) GetStatistics() StatsEntry {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.StatsEntry
}

// NewStatsFormat returns a format for rendering an CStatsContext
func NewStatsFormat(source, osType string) Format {
	if source == TableFormatKey {
		if osType == winOSType {
			return Format(winDefaultStatsTableFormat)
		}
		return Format(defaultStatsTableFormat)
	}
	return Format(source)
}

// NewContainerStats returns a new ContainerStats entity and sets in it the given name
func NewContainerStats(name, osType string) *ContainerStats {
	return &ContainerStats{
		StatsEntry: StatsEntry{Name: name, OSType: osType},
	}
}

// ContainerStatsWrite renders the context for a list of containers statistics
func ContainerStatsWrite(ctx Context, containerStats []StatsEntry) error {
	render := func(format func(subContext subContext) error) error {
		for _, cstats := range containerStats {
			containerStatsCtx := &containerStatsContext{
				s: cstats,
			}
			if err := format(containerStatsCtx); err != nil {
				return err
			}
		}
		return nil
	}
	return ctx.Write(&containerStatsContext{}, render)
}

type containerStatsContext struct {
	HeaderContext
	s StatsEntry
}

func (c *containerStatsContext) Container() string {
	c.AddHeader(containerHeader)
	return c.s.Name
}

func (c *containerStatsContext) CPUPerc() string {
	c.AddHeader(cpuPercHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%.2f%%", c.s.CPUPercentage)
}

func (c *containerStatsContext) MemUsage() string {
	c.AddHeader(memUseHeader)
	if c.s.IsInvalid || c.s.OSType == winOSType {
		return fmt.Sprintf("-- / --")
	}
	return fmt.Sprintf("%s / %s", units.BytesSize(c.s.Memory), units.BytesSize(c.s.MemoryLimit))
}

func (c *containerStatsContext) MemPerc() string {
	header := memPercHeader
	if c.s.OSType == winOSType {
		header = winMemPercHeader
	}
	c.AddHeader(header)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%.2f%%", c.s.MemoryPercentage)
}

func (c *containerStatsContext) NetIO() string {
	c.AddHeader(netIOHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.NetworkRx, 3), units.HumanSizeWithPrecision(c.s.NetworkTx, 3))
}

func (c *containerStatsContext) BlockIO() string {
	c.AddHeader(blockIOHeader)
	if c.s.IsInvalid {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.BlockRead, 3), units.HumanSizeWithPrecision(c.s.BlockWrite, 3))
}

func (c *containerStatsContext) PIDs() string {
	c.AddHeader(pidsHeader)
	if c.s.IsInvalid || c.s.OSType == winOSType {
		return fmt.Sprintf("--")
	}
	return fmt.Sprintf("%d", c.s.PidsCurrent)
}
<|endoftext|>