<commit_before>/*
Package fake is the fake data generatror for go (Golang), heavily inspired by forgery and ffaker Ruby gems

Most data and methods are ported from forgery/ffaker Ruby gems.

Currently english and russian languages are available.

For the list of available methods please look at https://godoc.org/github.com/icrowley/fake.

Fake embeds samples data files unless you call UseExternalData(true) in order to be able to work without external files dependencies when compiled, so, if you add new data files or make changes to existing ones don't forget to regenerate data.go file using github.com/mjibson/esc tool and esc -o data.go -pkg fake data command (or you can just use go generate command if you are using Go 1.4 or later).

Examples:
	name := fake.FirstName()
	fullname = := fake.FullName()
	product := fake.Product()

Changing language:
	err := fake.SetLang("ru")
	if err != nil {
		panic(err)
	}
	password := fake.SimplePassword()

Using english fallback:
	err := fake.SetLang("ru")
	if err != nil {
		panic(err)
	}
	fake.EnFallback(true)
	password := fake.Paragraph()

Using external data:
	fake.UseExternalData(true)
	password := fake.Paragraph()
*/
package fake

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"strconv"
	"strings"
	"sync"
	"time"
)

//go:generate go get github.com/mjibson/esc
//go:generate esc -o data.go -pkg fake data

// cat/subcat/lang/samples
type samplesTree map[string]map[string][]string

var samplesCache = make(samplesTree)
var r = rand.New(&rndSrc{src: rand.NewSource(time.Now().UnixNano())})
var lang = "en"
var useExternalData = false
var enFallback = true
var availLangs = GetLangs()

var (
	// ErrNoLanguageFn is the error that indicates that given language is not available
	ErrNoLanguageFn = func(lang string) error { return fmt.Errorf("The language passed (%s) is not available", lang) }
	// ErrNoSamplesFn is the error that indicates that there are no samples for the given language
	ErrNoSamplesFn = func(lang string) error { return fmt.Errorf("No samples found for language: %s", lang) }
)

// Seed uses the provided seed value to initialize the internal PRNG to a
// deterministic state.
func Seed(seed int64) {
	r.Seed(seed)
}

type rndSrc struct {
	mtx sync.Mutex
	src rand.Source
}

func (s *rndSrc) Int63() int64 {
	s.mtx.Lock()
	n := s.src.Int63()
	s.mtx.Unlock()
	return n
}

func (s *rndSrc) Seed(n int64) {
	s.mtx.Lock()
	s.src.Seed(n)
	s.mtx.Unlock()
}

// GetLangs returns a slice of available languages
func GetLangs() []string {
	var langs []string
	for k, v := range data {
		if v.isDir && k != "/" && k != "/data" {
			langs = append(langs, strings.Replace(k, "/data/", "", 1))
		}
	}
	return langs
}

// SetLang sets the language in which the data should be generated
// returns error if passed language is not available
func SetLang(newLang string) error {
	found := false
	for _, l := range availLangs {
		if newLang == l {
			found = true
			break
		}
	}
	if !found {
		return ErrNoLanguageFn(newLang)
	}
	lang = newLang
	return nil
}

// UseExternalData sets the flag that allows using of external files as data providers (fake uses embedded ones by default)
func UseExternalData(flag bool) {
	useExternalData = flag
}

// EnFallback sets the flag that allows fake to fallback to englsh samples if the ones for the used languaged are not available
func EnFallback(flag bool) {
	enFallback = flag
}

func (st samplesTree) hasKeyPath(lang, cat string) bool {
	if _, ok := st[lang]; ok {
		if _, ok = st[lang][cat]; ok {
			return true
		}
	}
	return false
}

func join(parts ...string) string {
	var filtered []string
	for _, part := range parts {
		if part != "" {
			filtered = append(filtered, part)
		}
	}
	return strings.Join(filtered, " ")
}

func generate(lang, cat string, fallback bool) string {
	format := lookup(lang, cat+"_format", fallback)
	var result string
	for _, ru := range format {
		if ru != '#' {
			result += string(ru)
		} else {
			result += strconv.Itoa(r.Intn(10))
		}
	}
	return result
}

func lookup(lang, cat string, fallback bool) string {
	var samples []string

	if samplesCache.hasKeyPath(lang, cat) {
		samples = samplesCache[lang][cat]
	} else {
		var err error
		samples, err = populateSamples(lang, cat)
		if err != nil {
			if lang != "en" && fallback && enFallback && err.Error() == ErrNoSamplesFn(lang).Error() {
				return lookup("en", cat, false)
			}
			return ""
		}
	}

	return samples[r.Intn(len(samples))]
}

func populateSamples(lang, cat string) ([]string, error) {
	data, err := readFile(lang, cat)
	if err != nil {
		return nil, err
	}

	if _, ok := samplesCache[lang]; !ok {
		samplesCache[lang] = make(map[string][]string)
	}

	samples := strings.Split(strings.TrimSpace(string(data)), "\n")

	samplesCache[lang][cat] = samples
	return samples, nil
}

func readFile(lang, cat string) ([]byte, error) {
	fullpath := fmt.Sprintf("/data/%s/%s", lang, cat)
	file, err := FS(useExternalData).Open(fullpath)
	if err != nil {
		return nil, ErrNoSamplesFn(lang)
	}
	defer file.Close()

	return ioutil.ReadAll(file)
}
<commit_msg>Fix samplesCache race condition<commit_after>/*
Package fake is the fake data generatror for go (Golang), heavily inspired by forgery and ffaker Ruby gems

Most data and methods are ported from forgery/ffaker Ruby gems.

Currently english and russian languages are available.

For the list of available methods please look at https://godoc.org/github.com/icrowley/fake.

Fake embeds samples data files unless you call UseExternalData(true) in order to be able to work without external files dependencies when compiled, so, if you add new data files or make changes to existing ones don't forget to regenerate data.go file using github.com/mjibson/esc tool and esc -o data.go -pkg fake data command (or you can just use go generate command if you are using Go 1.4 or later).

Examples:
	name := fake.FirstName()
	fullname = := fake.FullName()
	product := fake.Product()

Changing language:
	err := fake.SetLang("ru")
	if err != nil {
		panic(err)
	}
	password := fake.SimplePassword()

Using english fallback:
	err := fake.SetLang("ru")
	if err != nil {
		panic(err)
	}
	fake.EnFallback(true)
	password := fake.Paragraph()

Using external data:
	fake.UseExternalData(true)
	password := fake.Paragraph()
*/
package fake

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"strconv"
	"strings"
	"sync"
	"time"
)

//go:generate go get github.com/mjibson/esc
//go:generate esc -o data.go -pkg fake data

// cat/subcat/lang/samples
type samplesTree map[string]map[string][]string

var samplesLock sync.Mutex
var samplesCache = make(samplesTree)
var r = rand.New(&rndSrc{src: rand.NewSource(time.Now().UnixNano())})
var lang = "en"
var useExternalData = false
var enFallback = true
var availLangs = GetLangs()

var (
	// ErrNoLanguageFn is the error that indicates that given language is not available
	ErrNoLanguageFn = func(lang string) error { return fmt.Errorf("The language passed (%s) is not available", lang) }
	// ErrNoSamplesFn is the error that indicates that there are no samples for the given language
	ErrNoSamplesFn = func(lang string) error { return fmt.Errorf("No samples found for language: %s", lang) }
)

// Seed uses the provided seed value to initialize the internal PRNG to a
// deterministic state.
func Seed(seed int64) {
	r.Seed(seed)
}

type rndSrc struct {
	mtx sync.Mutex
	src rand.Source
}

func (s *rndSrc) Int63() int64 {
	s.mtx.Lock()
	n := s.src.Int63()
	s.mtx.Unlock()
	return n
}

func (s *rndSrc) Seed(n int64) {
	s.mtx.Lock()
	s.src.Seed(n)
	s.mtx.Unlock()
}

// GetLangs returns a slice of available languages
func GetLangs() []string {
	var langs []string
	for k, v := range data {
		if v.isDir && k != "/" && k != "/data" {
			langs = append(langs, strings.Replace(k, "/data/", "", 1))
		}
	}
	return langs
}

// SetLang sets the language in which the data should be generated
// returns error if passed language is not available
func SetLang(newLang string) error {
	found := false
	for _, l := range availLangs {
		if newLang == l {
			found = true
			break
		}
	}
	if !found {
		return ErrNoLanguageFn(newLang)
	}
	lang = newLang
	return nil
}

// UseExternalData sets the flag that allows using of external files as data providers (fake uses embedded ones by default)
func UseExternalData(flag bool) {
	useExternalData = flag
}

// EnFallback sets the flag that allows fake to fallback to englsh samples if the ones for the used languaged are not available
func EnFallback(flag bool) {
	enFallback = flag
}

func (st samplesTree) hasKeyPath(lang, cat string) bool {
	if _, ok := st[lang]; ok {
		if _, ok = st[lang][cat]; ok {
			return true
		}
	}
	return false
}

func join(parts ...string) string {
	var filtered []string
	for _, part := range parts {
		if part != "" {
			filtered = append(filtered, part)
		}
	}
	return strings.Join(filtered, " ")
}

func generate(lang, cat string, fallback bool) string {
	format := lookup(lang, cat+"_format", fallback)
	var result string
	for _, ru := range format {
		if ru != '#' {
			result += string(ru)
		} else {
			result += strconv.Itoa(r.Intn(10))
		}
	}
	return result
}

func lookup(lang, cat string, fallback bool) string {
	samplesLock.Lock()
	s := _lookup(lang, cat, fallback)
	samplesLock.Unlock()
	return s
}

func _lookup(lang, cat string, fallback bool) string {
	var samples []string

	if samplesCache.hasKeyPath(lang, cat) {
		samples = samplesCache[lang][cat]
	} else {
		var err error
		samples, err = populateSamples(lang, cat)
		if err != nil {
			if lang != "en" && fallback && enFallback && err.Error() == ErrNoSamplesFn(lang).Error() {
				return _lookup("en", cat, false)
			}
			return ""
		}
	}

	return samples[r.Intn(len(samples))]
}

func populateSamples(lang, cat string) ([]string, error) {
	data, err := readFile(lang, cat)
	if err != nil {
		return nil, err
	}

	if _, ok := samplesCache[lang]; !ok {
		samplesCache[lang] = make(map[string][]string)
	}

	samples := strings.Split(strings.TrimSpace(string(data)), "\n")

	samplesCache[lang][cat] = samples
	return samples, nil
}

func readFile(lang, cat string) ([]byte, error) {
	fullpath := fmt.Sprintf("/data/%s/%s", lang, cat)
	file, err := FS(useExternalData).Open(fullpath)
	if err != nil {
		return nil, ErrNoSamplesFn(lang)
	}
	defer file.Close()

	return ioutil.ReadAll(file)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"fmt"
	"io"
)

type Feed interface {
	Name() string
	IndexName() string
	Start() error
	Close() error
	Dests() map[string]Dest // Key is partition identifier.

	// Writes stats as JSON to the given writer.
	Stats(io.Writer) error
}

// Default values for feed parameters.
const FEED_SLEEP_MAX_MS = 10000
const FEED_SLEEP_INIT_MS = 100
const FEED_BACKOFF_FACTOR = 1.5

var FeedTypes = make(map[string]*FeedType) // Key is sourceType.

type FeedType struct {
	Start           FeedStartFunc
	Partitions      FeedPartitionsFunc
	Public          bool
	Description     string
	StartSample     interface{}
	StartSampleDocs map[string]string
}

type FeedStartFunc func(mgr *Manager, feedName, indexName, indexUUID string,
	sourceType, sourceName, sourceUUID, sourceParams string,
	dests map[string]Dest) error

type FeedPartitionsFunc func(sourceType, sourceName, sourceUUID, sourceParams,
	server string) ([]string, error)

func RegisterFeedType(sourceType string, f *FeedType) {
	FeedTypes[sourceType] = f
}

func DataSourcePartitions(sourceType, sourceName, sourceUUID, sourceParams,
	server string) ([]string, error) {
	feedType, exists := FeedTypes[sourceType]
	if !exists || feedType == nil {
		return nil, fmt.Errorf("feed: unknown sourceType: %s", sourceType)
	}

	return feedType.Partitions(sourceType, sourceName, sourceUUID,
		sourceParams, server)
}
<commit_msg>doc comments for feed.go<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 cbft

import (
	"fmt"
	"io"
)

// A Feed interface represents an abstract data source.  A Feed
// instance is hooked up to one-or-more Dest instances.  When incoming
// data is received by a Feed, the Feed will invoke relvate methods on
// the relevant Dest instances.
//
// In this codebase, the words "index source", "source" and "data
// source" are often associated with and used roughly as synonyms with
// "feed".
type Feed interface {
	Name() string
	IndexName() string
	Start() error
	Close() error
	Dests() map[string]Dest // Key is partition identifier.

	// Writes stats as JSON to the given writer.
	Stats(io.Writer) error
}

// Default values for feed parameters.
const FEED_SLEEP_MAX_MS = 10000
const FEED_SLEEP_INIT_MS = 100
const FEED_BACKOFF_FACTOR = 1.5

// FeedTypes is a global registry of available feed types and is
// initialized on startup.  It should be immutable after startup time.
var FeedTypes = make(map[string]*FeedType) // Key is sourceType.

// A FeedType represents an immutable registration of a single feed
// type or data source type.
type FeedType struct {
	Start           FeedStartFunc
	Partitions      FeedPartitionsFunc
	Public          bool
	Description     string
	StartSample     interface{}
	StartSampleDocs map[string]string
}

// A FeedStartFunc is part of a FeedType registration as is invoked by
// a Manager when a new feed instance needs to be started.
type FeedStartFunc func(mgr *Manager, feedName, indexName, indexUUID string,
	sourceType, sourceName, sourceUUID, sourceParams string,
	dests map[string]Dest) error

// Each Feed or data-source type knows of the data partitions for a
// data source.
type FeedPartitionsFunc func(sourceType, sourceName, sourceUUID, sourceParams,
	server string) ([]string, error)

// RegisterFeedType is invoked at init/startup time to register a
// FeedType.
func RegisterFeedType(sourceType string, f *FeedType) {
	FeedTypes[sourceType] = f
}

// DataSourcePartitions is a helper function that returns the data
// source partitions for a named data source or feed type.
func DataSourcePartitions(sourceType, sourceName, sourceUUID, sourceParams,
	server string) ([]string, error) {
	feedType, exists := FeedTypes[sourceType]
	if !exists || feedType == nil {
		return nil, fmt.Errorf("feed: unknown sourceType: %s", sourceType)
	}

	return feedType.Partitions(sourceType, sourceName, sourceUUID,
		sourceParams, server)
}
<|endoftext|>


<commit_before>package fifo

import (
	"io"
	"os"
	"runtime"
	"sync"
	"syscall"

	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

type fifo struct {
	flag        int
	opened      chan struct{}
	closed      chan struct{}
	closing     chan struct{}
	err         error
	file        *os.File
	closingOnce sync.Once // close has been called
	closedOnce  sync.Once // fifo is closed
	handle      *handle
}

var leakCheckWg *sync.WaitGroup

// OpenFifo opens a fifo. Returns io.ReadWriteCloser.
// Context can be used to cancel this function until open(2) has not returned.
// Accepted flags:
// - syscall.O_CREAT - create new fifo if one doesn't exist
// - syscall.O_RDONLY - open fifo only from reader side
// - syscall.O_WRONLY - open fifo only from writer side
// - syscall.O_RDWR - open fifo from both sides, never block on syscall level
// - syscall.O_NONBLOCK - return io.ReadWriteCloser even if other side of the
//     fifo isn't open. read/write will be connected after the actual fifo is
//     open or after fifo is closed.
func OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
	if _, err := os.Stat(fn); err != nil {
		if os.IsNotExist(err) && flag&syscall.O_CREAT != 0 {
			if err := mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) {
				return nil, errors.Wrapf(err, "error creating fifo %v", fn)
			}
		} else {
			return nil, err
		}
	}

	block := flag&syscall.O_NONBLOCK == 0 || flag&syscall.O_RDWR != 0

	flag &= ^syscall.O_CREAT
	flag &= ^syscall.O_NONBLOCK

	h, err := getHandle(fn)
	if err != nil {
		return nil, err
	}

	f := &fifo{
		handle:  h,
		flag:    flag,
		opened:  make(chan struct{}),
		closed:  make(chan struct{}),
		closing: make(chan struct{}),
	}

	wg := leakCheckWg
	if wg != nil {
		wg.Add(2)
	}

	go func() {
		if wg != nil {
			defer wg.Done()
		}
		select {
		case <-ctx.Done():
			f.Close()
		case <-f.opened:
		case <-f.closed:
		}
	}()
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		var file *os.File
		fn, err := h.Path()
		if err == nil {
			file, err = os.OpenFile(fn, flag, 0)
		}
		select {
		case <-f.closing:
			if err == nil {
				select {
				case <-ctx.Done():
					err = ctx.Err()
				default:
					err = errors.Errorf("fifo %v was closed before opening", h.Name())
				}
				if file != nil {
					file.Close()
				}
			}
		default:
		}
		if err != nil {
			f.closedOnce.Do(func() {
				f.err = err
				close(f.closed)
			})
			return
		}
		f.file = file
		close(f.opened)
	}()
	if block {
		select {
		case <-f.opened:
		case <-f.closed:
			return nil, f.err
		}
	}
	return f, nil
}

// Read from a fifo to a byte array.
func (f *fifo) Read(b []byte) (int, error) {
	if f.flag&syscall.O_WRONLY > 0 {
		return 0, errors.New("reading from write-only fifo")
	}
	select {
	case <-f.opened:
		return f.file.Read(b)
	default:
	}
	select {
	case <-f.opened:
		return f.file.Read(b)
	case <-f.closed:
		return 0, errors.New("reading from a closed fifo")
	}
}

// Write from byte array to a fifo.
func (f *fifo) Write(b []byte) (int, error) {
	if f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 {
		return 0, errors.New("writing to read-only fifo")
	}
	select {
	case <-f.opened:
		return f.file.Write(b)
	default:
	}
	select {
	case <-f.opened:
		return f.file.Write(b)
	case <-f.closed:
		return 0, errors.New("writing to a closed fifo")
	}
}

// Close the fifo. Next reads/writes will error. This method can also be used
// before open(2) has returned and fifo was never opened.
func (f *fifo) Close() (retErr error) {
	for {
		select {
		case <-f.closed:
			f.handle.Close()
			return
		default:
			select {
			case <-f.opened:
				f.closedOnce.Do(func() {
					retErr = f.file.Close()
					f.err = retErr
					close(f.closed)
				})
			default:
				if f.flag&syscall.O_RDWR != 0 {
					runtime.Gosched()
					break
				}
				f.closingOnce.Do(func() {
					close(f.closing)
				})
				reverseMode := syscall.O_WRONLY
				if f.flag&syscall.O_WRONLY > 0 {
					reverseMode = syscall.O_RDONLY
				}
				fn, err := f.handle.Path()
				// if Close() is called concurrently(shouldn't) it may cause error
				// because handle is closed
				select {
				case <-f.closed:
				default:
					if err != nil {
						// Path has become invalid. We will leak a goroutine.
						// This case should not happen in linux.
						f.closedOnce.Do(func() {
							f.err = err
							close(f.closed)
						})
						<-f.closed
						break
					}
					f, err := os.OpenFile(fn, reverseMode|syscall.O_NONBLOCK, 0)
					if err == nil {
						f.Close()
					}
					runtime.Gosched()
				}
			}
		}
	}
}
<commit_msg>check if fifo is opened before closing when ctx.Done<commit_after>package fifo

import (
	"io"
	"os"
	"runtime"
	"sync"
	"syscall"

	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

type fifo struct {
	flag        int
	opened      chan struct{}
	closed      chan struct{}
	closing     chan struct{}
	err         error
	file        *os.File
	closingOnce sync.Once // close has been called
	closedOnce  sync.Once // fifo is closed
	handle      *handle
}

var leakCheckWg *sync.WaitGroup

// OpenFifo opens a fifo. Returns io.ReadWriteCloser.
// Context can be used to cancel this function until open(2) has not returned.
// Accepted flags:
// - syscall.O_CREAT - create new fifo if one doesn't exist
// - syscall.O_RDONLY - open fifo only from reader side
// - syscall.O_WRONLY - open fifo only from writer side
// - syscall.O_RDWR - open fifo from both sides, never block on syscall level
// - syscall.O_NONBLOCK - return io.ReadWriteCloser even if other side of the
//     fifo isn't open. read/write will be connected after the actual fifo is
//     open or after fifo is closed.
func OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
	if _, err := os.Stat(fn); err != nil {
		if os.IsNotExist(err) && flag&syscall.O_CREAT != 0 {
			if err := mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) {
				return nil, errors.Wrapf(err, "error creating fifo %v", fn)
			}
		} else {
			return nil, err
		}
	}

	block := flag&syscall.O_NONBLOCK == 0 || flag&syscall.O_RDWR != 0

	flag &= ^syscall.O_CREAT
	flag &= ^syscall.O_NONBLOCK

	h, err := getHandle(fn)
	if err != nil {
		return nil, err
	}

	f := &fifo{
		handle:  h,
		flag:    flag,
		opened:  make(chan struct{}),
		closed:  make(chan struct{}),
		closing: make(chan struct{}),
	}

	wg := leakCheckWg
	if wg != nil {
		wg.Add(2)
	}

	go func() {
		if wg != nil {
			defer wg.Done()
		}
		select {
		case <-ctx.Done():
			select {
			case <-f.opened:
			default:
				f.Close()
			}
		case <-f.opened:
		case <-f.closed:
		}
	}()
	go func() {
		if wg != nil {
			defer wg.Done()
		}
		var file *os.File
		fn, err := h.Path()
		if err == nil {
			file, err = os.OpenFile(fn, flag, 0)
		}
		select {
		case <-f.closing:
			if err == nil {
				select {
				case <-ctx.Done():
					err = ctx.Err()
				default:
					err = errors.Errorf("fifo %v was closed before opening", h.Name())
				}
				if file != nil {
					file.Close()
				}
			}
		default:
		}
		if err != nil {
			f.closedOnce.Do(func() {
				f.err = err
				close(f.closed)
			})
			return
		}
		f.file = file
		close(f.opened)
	}()
	if block {
		select {
		case <-f.opened:
		case <-f.closed:
			return nil, f.err
		}
	}
	return f, nil
}

// Read from a fifo to a byte array.
func (f *fifo) Read(b []byte) (int, error) {
	if f.flag&syscall.O_WRONLY > 0 {
		return 0, errors.New("reading from write-only fifo")
	}
	select {
	case <-f.opened:
		return f.file.Read(b)
	default:
	}
	select {
	case <-f.opened:
		return f.file.Read(b)
	case <-f.closed:
		return 0, errors.New("reading from a closed fifo")
	}
}

// Write from byte array to a fifo.
func (f *fifo) Write(b []byte) (int, error) {
	if f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 {
		return 0, errors.New("writing to read-only fifo")
	}
	select {
	case <-f.opened:
		return f.file.Write(b)
	default:
	}
	select {
	case <-f.opened:
		return f.file.Write(b)
	case <-f.closed:
		return 0, errors.New("writing to a closed fifo")
	}
}

// Close the fifo. Next reads/writes will error. This method can also be used
// before open(2) has returned and fifo was never opened.
func (f *fifo) Close() (retErr error) {
	for {
		select {
		case <-f.closed:
			f.handle.Close()
			return
		default:
			select {
			case <-f.opened:
				f.closedOnce.Do(func() {
					retErr = f.file.Close()
					f.err = retErr
					close(f.closed)
				})
			default:
				if f.flag&syscall.O_RDWR != 0 {
					runtime.Gosched()
					break
				}
				f.closingOnce.Do(func() {
					close(f.closing)
				})
				reverseMode := syscall.O_WRONLY
				if f.flag&syscall.O_WRONLY > 0 {
					reverseMode = syscall.O_RDONLY
				}
				fn, err := f.handle.Path()
				// if Close() is called concurrently(shouldn't) it may cause error
				// because handle is closed
				select {
				case <-f.closed:
				default:
					if err != nil {
						// Path has become invalid. We will leak a goroutine.
						// This case should not happen in linux.
						f.closedOnce.Do(func() {
							f.err = err
							close(f.closed)
						})
						<-f.closed
						break
					}
					f, err := os.OpenFile(fn, reverseMode|syscall.O_NONBLOCK, 0)
					if err == nil {
						f.Close()
					}
					runtime.Gosched()
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package config

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"os"
	"strings"

	yaml "gopkg.in/yaml.v2"
)

type fileType int

const (
	jsonType fileType = iota + 1
	yamlType
	naType
)

// File struct is a config file.
type File struct {
	gen    func() (io.Reader, error)
	typ    fileType
	values map[string]interface{}
}

// fileTypeFromPath returns right file type for the file.
func fileTypeFromPath(path string) fileType {
	if strings.HasSuffix(path, ".json") {
		return jsonType
	}

	if strings.HasSuffix(path, ".yml") || strings.HasPrefix(path, ".yaml") {
		return yamlType
	}

	return naType
}

// NewFromFile creates a new middleware from file.
func NewFromFile(path string) *Values {
	file := &File{
		gen: func() (io.Reader, error) {
			return os.Open(path)
		},
		typ: fileTypeFromPath(path),
	}

	err := file.Setup()
	if err != nil {
		return &Values{err: err}
	}

	return &Values{values: file.values}
}

// Setup returns a error if the middleware setup is failing.
func (s *File) Setup() error {
	if s.typ == naType {
		return errors.New("File type is not implemented")
	}

	r, err := s.gen()
	if err != nil {
		return err
	}

	s.values = make(map[string]interface{})

	switch s.typ {
	case jsonType:
		return json.NewDecoder(r).Decode(&s.values)
	case yamlType:
		buf := new(bytes.Buffer)
		buf.ReadFrom(r)
		return yaml.Unmarshal(buf.Bytes(), &s.values)
	}

	return nil
}
<commit_msg>Cleanup<commit_after>package config

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"os"
	"strings"

	"gopkg.in/yaml.v2"
)

type fileType int

const (
	jsonType fileType = iota + 1
	yamlType
	naType
)

// File struct is a config file.
type File struct {
	gen    func() (io.Reader, error)
	typ    fileType
	values map[string]interface{}
}

// fileTypeFromPath returns right file type for the file.
func fileTypeFromPath(path string) fileType {
	if strings.HasSuffix(path, ".json") {
		return jsonType
	}

	if strings.HasSuffix(path, ".yml") || strings.HasPrefix(path, ".yaml") {
		return yamlType
	}

	return naType
}

// NewFromFile creates a new middleware from file.
func NewFromFile(path string) *Values {
	file := &File{
		gen: func() (io.Reader, error) {
			return os.Open(path)
		},
		typ: fileTypeFromPath(path),
	}

	err := file.Setup()
	if err != nil {
		return &Values{err: err}
	}

	return &Values{values: file.values}
}

// Setup returns a error if the middleware setup is failing.
func (s *File) Setup() error {
	if s.typ == naType {
		return errors.New("File type is not implemented")
	}

	r, err := s.gen()
	if err != nil {
		return err
	}

	s.values = make(map[string]interface{})

	switch s.typ {
	case jsonType:
		return json.NewDecoder(r).Decode(&s.values)
	case yamlType:
		buf := new(bytes.Buffer)
		buf.ReadFrom(r)
		return yaml.Unmarshal(buf.Bytes(), &s.values)
	}

	return nil
}
<|endoftext|>


<commit_before>package scipipe

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"sync"
)

// ======= FileTarget ========

// FileTarget contains information and helper methods for a physical file on a
// normal disk.
type FileTarget struct {
	path     string
	buffer   *bytes.Buffer
	doStream bool
	lock     *sync.Mutex
}

// Create new FileTarget "object"
func NewFileTarget(path string) *FileTarget {
	ft := new(FileTarget)
	ft.path = path
	ft.lock = new(sync.Mutex)
	//Don't init buffer if not needed?
	//buf := make([]byte, 0, 128)
	//ft.buffer = bytes.NewBuffer(buf)
	return ft
}

// Get the (final) path of the physical file
func (ft *FileTarget) GetPath() string {
	return ft.path
}

// Get the temporary path of the physical file
func (ft *FileTarget) GetTempPath() string {
	return ft.path + ".tmp"
}

// Get the path to use when a FIFO file is used instead of a normal file
func (ft *FileTarget) GetFifoPath() string {
	return ft.path + ".fifo"
}

// Open the file and return a file handle (*os.File)
func (ft *FileTarget) Open() *os.File {
	f, err := os.Open(ft.GetPath())
	Check(err)
	return f
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ft *FileTarget) Read() []byte {
	dat, err := ioutil.ReadFile(ft.GetPath())
	Check(err)
	return dat
}

// Write a byte array ([]byte) to the file (first to its temp path, and then atomize)
func (ft *FileTarget) WriteTempFile(dat []byte) {
	err := ioutil.WriteFile(ft.GetTempPath(), dat, 0644)
	Check(err)
}

// Change from the temporary file name to the final file name
func (ft *FileTarget) Atomize() {
	Debug.Println("FileTarget: Atomizing", ft.GetTempPath(), "->", ft.GetPath())
	ft.lock.Lock()
	err := os.Rename(ft.GetTempPath(), ft.path)
	Check(err)
	ft.lock.Unlock()
	Debug.Println("FileTarget: Done atomizing", ft.GetTempPath(), "->", ft.GetPath())
}

// Create FIFO file for the FileTarget
func (ft *FileTarget) CreateFifo() {
	ft.lock.Lock()
	cmd := "mkfifo " + ft.GetFifoPath()
	Debug.Println("Now creating FIFO with command:", cmd)

	if _, err := os.Stat(ft.GetFifoPath()); err == nil {
		Warning.Println("FIFO already exists, so not creating a new one:", ft.GetFifoPath())
	} else {
		_, err := exec.Command("bash", "-c", cmd).Output()
		Check(err)
	}

	ft.lock.Unlock()
}

// Remove the FIFO file, if it exists
func (ft *FileTarget) RemoveFifo() {
	// FIXME: Shouldn't we check first whether the fifo exists?
	ft.lock.Lock()
	output, err := exec.Command("bash", "-c", "rm "+ft.GetFifoPath()).Output()
	Check(err)
	Debug.Println("Removed FIFO output: ", output)
	ft.lock.Unlock()
}

// Check if the file exists (at its final file name)
func (ft *FileTarget) Exists() bool {
	exists := false
	ft.lock.Lock()
	if _, err := os.Stat(ft.GetPath()); err == nil {
		exists = true
	}
	ft.lock.Unlock()
	return exists
}

// ======= FileQueue =======

// FileQueue is initialized by a set of strings with file paths, and from that
// will return instantiated FileTargets on its Out-port, when run.
type FileQueue struct {
	Process
	Out       chan *FileTarget
	FilePaths []string
}

func FQ(fps ...string) (fq *FileQueue) {
	return NewFileQueue(fps...)
}

// Initialize a new FileQueue component from a list of file paths
func NewFileQueue(filePaths ...string) (fq *FileQueue) {
	fq = &FileQueue{
		Out:       make(chan *FileTarget, BUFSIZE),
		FilePaths: filePaths,
	}
	return
}

// Execute the FileQueue, returning instantiated FileTargets
func (proc *FileQueue) Run() {
	defer close(proc.Out)
	for _, fp := range proc.FilePaths {
		proc.Out <- NewFileTarget(fp)
	}
}

// ======= Sink =======

// Sink is a simple component that just receives FileTargets on its In-port
// without doing anything with them
type Sink struct {
	Process
	In chan *FileTarget
}

// Instantiate a Sink component
func NewSink() (s *Sink) {
	return &Sink{}
}

// Execute the Sink component
func (proc *Sink) Run() {
	for ft := range proc.In {
		Debug.Println("Received file in sink: ", ft.GetPath())
	}
}
<commit_msg>New OpenWrite() method on FileTarget<commit_after>package scipipe

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"sync"
)

// ======= FileTarget ========

// FileTarget contains information and helper methods for a physical file on a
// normal disk.
type FileTarget struct {
	path     string
	buffer   *bytes.Buffer
	doStream bool
	lock     *sync.Mutex
}

// Create new FileTarget "object"
func NewFileTarget(path string) *FileTarget {
	ft := new(FileTarget)
	ft.path = path
	ft.lock = new(sync.Mutex)
	//Don't init buffer if not needed?
	//buf := make([]byte, 0, 128)
	//ft.buffer = bytes.NewBuffer(buf)
	return ft
}

// Get the (final) path of the physical file
func (ft *FileTarget) GetPath() string {
	return ft.path
}

// Get the temporary path of the physical file
func (ft *FileTarget) GetTempPath() string {
	return ft.path + ".tmp"
}

// Get the path to use when a FIFO file is used instead of a normal file
func (ft *FileTarget) GetFifoPath() string {
	return ft.path + ".fifo"
}

// Open the file and return a file handle (*os.File)
func (ft *FileTarget) Open() *os.File {
	f, err := os.Open(ft.GetPath())
	Check(err)
	return f
}

// Open the file for writing return a file handle (*os.File)
func (ft *FileTarget) OpenWrite() *os.File {
	f, err := os.Create(ft.GetPath())
	Check(err)
	return f
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ft *FileTarget) Read() []byte {
	dat, err := ioutil.ReadFile(ft.GetPath())
	Check(err)
	return dat
}

// Write a byte array ([]byte) to the file (first to its temp path, and then atomize)
func (ft *FileTarget) WriteTempFile(dat []byte) {
	err := ioutil.WriteFile(ft.GetTempPath(), dat, 0644)
	Check(err)
}

// Change from the temporary file name to the final file name
func (ft *FileTarget) Atomize() {
	Debug.Println("FileTarget: Atomizing", ft.GetTempPath(), "->", ft.GetPath())
	ft.lock.Lock()
	err := os.Rename(ft.GetTempPath(), ft.path)
	Check(err)
	ft.lock.Unlock()
	Debug.Println("FileTarget: Done atomizing", ft.GetTempPath(), "->", ft.GetPath())
}

// Create FIFO file for the FileTarget
func (ft *FileTarget) CreateFifo() {
	ft.lock.Lock()
	cmd := "mkfifo " + ft.GetFifoPath()
	Debug.Println("Now creating FIFO with command:", cmd)

	if _, err := os.Stat(ft.GetFifoPath()); err == nil {
		Warning.Println("FIFO already exists, so not creating a new one:", ft.GetFifoPath())
	} else {
		_, err := exec.Command("bash", "-c", cmd).Output()
		Check(err)
	}

	ft.lock.Unlock()
}

// Remove the FIFO file, if it exists
func (ft *FileTarget) RemoveFifo() {
	// FIXME: Shouldn't we check first whether the fifo exists?
	ft.lock.Lock()
	output, err := exec.Command("bash", "-c", "rm "+ft.GetFifoPath()).Output()
	Check(err)
	Debug.Println("Removed FIFO output: ", output)
	ft.lock.Unlock()
}

// Check if the file exists (at its final file name)
func (ft *FileTarget) Exists() bool {
	exists := false
	ft.lock.Lock()
	if _, err := os.Stat(ft.GetPath()); err == nil {
		exists = true
	}
	ft.lock.Unlock()
	return exists
}

// ======= FileQueue =======

// FileQueue is initialized by a set of strings with file paths, and from that
// will return instantiated FileTargets on its Out-port, when run.
type FileQueue struct {
	Process
	Out       chan *FileTarget
	FilePaths []string
}

func FQ(fps ...string) (fq *FileQueue) {
	return NewFileQueue(fps...)
}

// Initialize a new FileQueue component from a list of file paths
func NewFileQueue(filePaths ...string) (fq *FileQueue) {
	fq = &FileQueue{
		Out:       make(chan *FileTarget, BUFSIZE),
		FilePaths: filePaths,
	}
	return
}

// Execute the FileQueue, returning instantiated FileTargets
func (proc *FileQueue) Run() {
	defer close(proc.Out)
	for _, fp := range proc.FilePaths {
		proc.Out <- NewFileTarget(fp)
	}
}

// ======= Sink =======

// Sink is a simple component that just receives FileTargets on its In-port
// without doing anything with them
type Sink struct {
	Process
	In chan *FileTarget
}

// Instantiate a Sink component
func NewSink() (s *Sink) {
	return &Sink{}
}

// Execute the Sink component
func (proc *Sink) Run() {
	for ft := range proc.In {
		Debug.Println("Received file in sink: ", ft.GetPath())
	}
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2014 Soichiro Kashima
*/
package fint

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
)

const bufSize = 4096

type Opt struct {
	SrcRoot    string
	ProjName   string
	ConfigPath string
	Locale     string
	Id         string
}

type Rule struct {
	Pattern string
	Args    []interface{}
	Message map[string]string
}

type Module struct {
	Id    string
	Rules []Rule
}

type RuleSet struct {
	Id          string
	Description string
	Pattern     string
	Modules     []Module
}

type FintConfig struct {
	RuleSets []RuleSet
}

type Violation struct {
	Filename string
	Line     int
	Message  string
}

var opt *Opt
var fintConfig *FintConfig

var violations []Violation
var term string

func getOpts() (*Opt, error) {
	srcRoot := flag.String("s", ".", "Project source root dir")
	projName := flag.String("p", "", "Project name")
	configPath := flag.String("c", "conf/config.json", "Config file path")
	locale := flag.String("l", "default", "Message locale")
	id := flag.String("i", "", "ID of the rule set")
	flag.Parse()
	opt := &Opt{SrcRoot: *srcRoot, ProjName: *projName, ConfigPath: *configPath, Locale: *locale, Id: *id}
	return opt, nil
}

func printViolation(v Violation) {
	var format string
	if term == "dumb" {
		format = "%s:%d:1: warning: %s\n"
	} else {
		format = "%s:%d:1: warning: %s\n"
	}
	fmt.Printf(format, v.Filename, v.Line, v.Message)
}

func loadFintConfig(file []byte) *FintConfig {
	var fc FintConfig
	json.Unmarshal(file, &fc)
	return &fc
}

func checkSourceFile(filename string, rs RuleSet) []Violation {
	var vs []Violation
	f, err := os.Open(filename)
	if err != nil {
		fmt.Println("Cannot open " + filename)
		return vs
	}
	defer f.Close()
	r := bufio.NewReaderSize(f, bufSize)
	for n := 1; true; n++ {
		lineBytes, isPrefix, err := r.ReadLine()
		if isPrefix {
			fmt.Printf("Too long line: %s", filename)
			return vs
		}
		line := string(lineBytes)
		if err != io.EOF && err != nil {
			fmt.Println(err)
			return vs
		}
		for i := range rs.Modules {
			switch rs.Modules[i].Id {
			case "pattern_match":
				for j := range rs.Modules[i].Rules {
					if matched, _ := regexp.MatchString(rs.Modules[i].Rules[j].Pattern, line); matched {
						vs = append(vs, Violation{Filename: filename, Line: n, Message: rs.Modules[i].Rules[j].Message[opt.Locale]})
					}
				}
			case "max_length":
				for j := range rs.Modules[i].Rules {
					if matched, _ := regexp.MatchString(rs.Modules[i].Rules[j].Pattern, line); matched {
						max_len := int(rs.Modules[i].Rules[j].Args[0].(float64))
						if too_long := max_len < len(line); too_long {
							vs = append(vs, Violation{Filename: filename, Line: n, Message: fmt.Sprintf(rs.Modules[i].Rules[j].Message[opt.Locale], max_len)})
						}
					}
				}
			}
		}
		if err == io.EOF {
			break
		}
	}
	return vs
}

func findRuleSet() RuleSet {
	var rs RuleSet
	for i := range fintConfig.RuleSets {
		r := fintConfig.RuleSets[i]
		if r.Id == opt.Id {
			rs = r
		}
	}
	if rs.Id == "" {
		panic("No matching ruleset to [" + opt.Id + "]")
	}
	return rs
}

func checkFile(path string, f os.FileInfo, err error) error {
	rs := findRuleSet()
	if matched, _ := regexp.MatchString(rs.Pattern, path); matched {
		violations = append(violations, checkSourceFile(path, rs)...)
	}
	return nil
}

func pluralize(value int, singular, plural string) string {
	if value < 2 {
		return singular
	}
	return plural
}

func ExecuteAsCommand() {
	var err error
	opt, err = getOpts()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}

	term = os.Getenv("TERM")

	conf, err := ioutil.ReadFile(opt.ConfigPath)
	if err != nil {
		fmt.Println("Config file not found.")
		os.Exit(1)
	}
	fintConfig = loadFintConfig(conf)

	os.Chdir(opt.SrcRoot)
	err = filepath.Walk(opt.ProjName, checkFile)
	for i := range violations {
		printViolation(violations[i])
	}

	if 0 < len(violations) {
		fmt.Printf("\n%d %s generated.\n",
			len(violations), pluralize(len(violations), "warning", "warnings"))
		os.Exit(1)
	}
}
<commit_msg>Renamed fintConfig to Config and exported.<commit_after>/*
 Copyright (c) 2014 Soichiro Kashima
*/
package fint

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
)

const bufSize = 4096

type Opt struct {
	SrcRoot    string
	ProjName   string
	ConfigPath string
	Locale     string
	Id         string
}

type Rule struct {
	Pattern string
	Args    []interface{}
	Message map[string]string
}

type Module struct {
	Id    string
	Rules []Rule
}

type RuleSet struct {
	Id          string
	Description string
	Pattern     string
	Modules     []Module
}

type Config struct {
	RuleSets []RuleSet
}

type Violation struct {
	Filename string
	Line     int
	Message  string
}

var opt *Opt
var config *Config

var violations []Violation
var term string

func getOpts() (*Opt, error) {
	srcRoot := flag.String("s", ".", "Project source root dir")
	projName := flag.String("p", "", "Project name")
	configPath := flag.String("c", "conf/config.json", "Config file path")
	locale := flag.String("l", "default", "Message locale")
	id := flag.String("i", "", "ID of the rule set")
	flag.Parse()
	opt := &Opt{SrcRoot: *srcRoot, ProjName: *projName, ConfigPath: *configPath, Locale: *locale, Id: *id}
	return opt, nil
}

func printViolation(v Violation) {
	var format string
	if term == "dumb" {
		format = "%s:%d:1: warning: %s\n"
	} else {
		format = "%s:%d:1: warning: %s\n"
	}
	fmt.Printf(format, v.Filename, v.Line, v.Message)
}

func LoadConfig(file []byte) *Config {
	var c Config
	json.Unmarshal(file, &c)
	return &c
}

func checkSourceFile(filename string, rs RuleSet) []Violation {
	var vs []Violation
	f, err := os.Open(filename)
	if err != nil {
		fmt.Println("Cannot open " + filename)
		return vs
	}
	defer f.Close()
	r := bufio.NewReaderSize(f, bufSize)
	for n := 1; true; n++ {
		lineBytes, isPrefix, err := r.ReadLine()
		if isPrefix {
			fmt.Printf("Too long line: %s", filename)
			return vs
		}
		line := string(lineBytes)
		if err != io.EOF && err != nil {
			fmt.Println(err)
			return vs
		}
		for i := range rs.Modules {
			switch rs.Modules[i].Id {
			case "pattern_match":
				for j := range rs.Modules[i].Rules {
					if matched, _ := regexp.MatchString(rs.Modules[i].Rules[j].Pattern, line); matched {
						vs = append(vs, Violation{Filename: filename, Line: n, Message: rs.Modules[i].Rules[j].Message[opt.Locale]})
					}
				}
			case "max_length":
				for j := range rs.Modules[i].Rules {
					if matched, _ := regexp.MatchString(rs.Modules[i].Rules[j].Pattern, line); matched {
						max_len := int(rs.Modules[i].Rules[j].Args[0].(float64))
						if too_long := max_len < len(line); too_long {
							vs = append(vs, Violation{Filename: filename, Line: n, Message: fmt.Sprintf(rs.Modules[i].Rules[j].Message[opt.Locale], max_len)})
						}
					}
				}
			}
		}
		if err == io.EOF {
			break
		}
	}
	return vs
}

func findRuleSet() RuleSet {
	var rs RuleSet
	for i := range config.RuleSets {
		r := config.RuleSets[i]
		if r.Id == opt.Id {
			rs = r
		}
	}
	if rs.Id == "" {
		panic("No matching ruleset to [" + opt.Id + "]")
	}
	return rs
}

func checkFile(path string, f os.FileInfo, err error) error {
	rs := findRuleSet()
	if matched, _ := regexp.MatchString(rs.Pattern, path); matched {
		violations = append(violations, checkSourceFile(path, rs)...)
	}
	return nil
}

func pluralize(value int, singular, plural string) string {
	if value < 2 {
		return singular
	}
	return plural
}

func ExecuteAsCommand() {
	var err error
	opt, err = getOpts()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}

	term = os.Getenv("TERM")

	conf, err := ioutil.ReadFile(opt.ConfigPath)
	if err != nil {
		fmt.Println("Config file not found.")
		os.Exit(1)
	}
	config = LoadConfig(conf)

	os.Chdir(opt.SrcRoot)
	err = filepath.Walk(opt.ProjName, checkFile)
	for i := range violations {
		printViolation(violations[i])
	}

	if 0 < len(violations) {
		fmt.Printf("\n%d %s generated.\n",
			len(violations), pluralize(len(violations), "warning", "warnings"))
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/camelcase"
	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// Flatten doesn't add prefixes for nested structs. So previously if we had
	// a nested struct `type T struct{Name struct{ ...}}`, this would generate
	// --name-foo, --name-bar, etc. When Flatten is enabled, the flags will be
	// flattend to the form: --foo, --bar, etc.. Panics if the nested structs
	// has a duplicate field name in the root level of the struct (outer
	// struct). Use this option only if you know what you do.
	Flatten bool

	// CamelCase adds a seperator for field names in camelcase form. A
	// fieldname of "AccessKey" would generate a flag name "--accesskey". If
	// CamelCase is enabled, the flag name will be generated in the form of
	// "--access-key"
	CamelCase bool

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// Args defines a custom argument list. If nil, os.Args[1:] is used.
	Args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{
			Prefix:    f.EnvPrefix,
			CamelCase: f.CamelCase,
		}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.Args != nil {
		args = f.Args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	if f.CamelCase {
		fieldName = strings.Join(camelcase.Split(fieldName), "-")
	}

	switch {
	case field.Kind() == reflect.Struct && !implementsTextUnmarshaler(field):
		for _, ff := range field.Fields() {
			flagName := field.Name() + "-" + ff.Name()

			if f.Flatten {
				// first check if it's set or not, because if we have duplicate
				// we don't want to break the flag. Panic by giving a readable
				// output
				flagSet.VisitAll(func(fl *flag.Flag) {
					if strings.ToLower(ff.Name()) == fl.Name {
						// already defined
						panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
					}
				})

				flagName = ff.Name()
			}

			if err := f.processField(flagSet, flagName, ff); err != nil {
				return err
			}
		}
	case field.Kind() == reflect.Ptr:
		field.InitElem()
		return f.processField(flagSet, fieldName, field)
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		// we only can get the value from expored fields, unexported fields panics
		if field.IsExported() {
			flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
		}
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<commit_msg>fix ignore unexported fields for flags<commit_after>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/camelcase"
	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// Flatten doesn't add prefixes for nested structs. So previously if we had
	// a nested struct `type T struct{Name struct{ ...}}`, this would generate
	// --name-foo, --name-bar, etc. When Flatten is enabled, the flags will be
	// flattend to the form: --foo, --bar, etc.. Panics if the nested structs
	// has a duplicate field name in the root level of the struct (outer
	// struct). Use this option only if you know what you do.
	Flatten bool

	// CamelCase adds a seperator for field names in camelcase form. A
	// fieldname of "AccessKey" would generate a flag name "--accesskey". If
	// CamelCase is enabled, the flag name will be generated in the form of
	// "--access-key"
	CamelCase bool

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// Args defines a custom argument list. If nil, os.Args[1:] is used.
	Args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{
			Prefix:    f.EnvPrefix,
			CamelCase: f.CamelCase,
		}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.Args != nil {
		args = f.Args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	if !field.IsExported() {
		return nil
	}

	if f.CamelCase {
		fieldName = strings.Join(camelcase.Split(fieldName), "-")
	}

	switch {
	case field.Kind() == reflect.Struct && !implementsTextUnmarshaler(field):
		for _, ff := range field.Fields() {
			flagName := field.Name() + "-" + ff.Name()

			if f.Flatten {
				// first check if it's set or not, because if we have duplicate
				// we don't want to break the flag. Panic by giving a readable
				// output
				flagSet.VisitAll(func(fl *flag.Flag) {
					if strings.ToLower(ff.Name()) == fl.Name {
						// already defined
						panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
					}
				})

				flagName = ff.Name()
			}

			if err := f.processField(flagSet, flagName, ff); err != nil {
				return err
			}
		}
	case field.Kind() == reflect.Ptr:
		field.InitElem()
		return f.processField(flagSet, fieldName, field)
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<|endoftext|>


<commit_before>package stow

import (
	"fmt"
	"reflect"
)

type funcCall struct {
	s *Store

	Value reflect.Value
	Type  reflect.Type

	hasKey   bool
	isKeyPtr bool
	keyType  reflect.Type

	isValPtr bool
	valType  reflect.Type
}

func newFuncCall(s *Store, fn interface{}) (fc funcCall, err error) {
	fc.s = s
	fc.Value = reflect.ValueOf(fn)
	fc.Type = fc.Value.Type()
	if fc.Value.Kind() != reflect.Func {
		return fc, fmt.Errorf("fn is not a func()")
	}

	if fc.Type.NumIn() == 1 {
		fc.setValue(fc.Type.In(0))
	} else if fc.Type.NumIn() == 2 {
		fc.setKey(fc.Type.In(0))
		fc.setValue(fc.Type.In(1))
	} else {
		return fc, fmt.Errorf("bad number of args in ForEach fn.")
	}

	return fc, nil
}

func isPtr(typ reflect.Type) bool { return typ.Kind() == reflect.Ptr }

func (fc *funcCall) setKey(typ reflect.Type) {
	fc.hasKey = true
	fc.keyType = typ
	if fc.isKeyPtr = isPtr(fc.keyType); fc.isKeyPtr {
		fc.keyType = fc.keyType.Elem()
	}
}

func (fc *funcCall) setValue(typ reflect.Type) {
	fc.valType = typ
	if fc.isValPtr = isPtr(fc.valType); fc.isValPtr {
		fc.valType = fc.valType.Elem()
	}
}

func (fc *funcCall) getKey(v []byte) (key reflect.Value, err error) {
	if fc.keyType.Kind() == reflect.String {
		return reflect.ValueOf(string(v)), nil
	} else if fc.keyType.Kind() == reflect.Slice && fc.keyType.Elem().Kind() == reflect.Uint8 {
		return reflect.ValueOf(v), nil
	}

	key = reflect.New(fc.keyType)

	if err := fc.s.unmarshal(v, key.Interface()); err != nil {
		return key, err
	}

	if !fc.isKeyPtr {
		key = deref(key)
	}

	return key, err
}

func (fc *funcCall) getValue(v []byte) (val reflect.Value, err error) {
	val = reflect.New(fc.valType)

	if err := fc.s.unmarshal(v, val.Interface()); err != nil {
		return val, err
	}

	if !fc.isValPtr {
		val = deref(val)
	}

	return val, err
}

func (fc *funcCall) call(k, v []byte) error {
	val, err := fc.getValue(v)
	if err != nil {
		return err
	}

	if !fc.hasKey {
		fc.Value.Call([]reflect.Value{val})
		return nil
	}

	key, err := fc.getKey(k)
	if err != nil {
		return err
	}
	fc.Value.Call([]reflect.Value{key, val})
	return nil
}

func deref(val reflect.Value) reflect.Value {
	if val.IsValid() {
		return val.Elem()
	}
	return reflect.Zero(val.Type())
}
<commit_msg>error message linter fix.<commit_after>package stow

import (
	"fmt"
	"reflect"
)

type funcCall struct {
	s *Store

	Value reflect.Value
	Type  reflect.Type

	hasKey   bool
	isKeyPtr bool
	keyType  reflect.Type

	isValPtr bool
	valType  reflect.Type
}

func newFuncCall(s *Store, fn interface{}) (fc funcCall, err error) {
	fc.s = s
	fc.Value = reflect.ValueOf(fn)
	fc.Type = fc.Value.Type()
	if fc.Value.Kind() != reflect.Func {
		return fc, fmt.Errorf("fn is not a func()")
	}

	if fc.Type.NumIn() == 1 {
		fc.setValue(fc.Type.In(0))
	} else if fc.Type.NumIn() == 2 {
		fc.setKey(fc.Type.In(0))
		fc.setValue(fc.Type.In(1))
	} else {
		return fc, fmt.Errorf("bad number of args in ForEach func()")
	}

	return fc, nil
}

func isPtr(typ reflect.Type) bool { return typ.Kind() == reflect.Ptr }

func (fc *funcCall) setKey(typ reflect.Type) {
	fc.hasKey = true
	fc.keyType = typ
	if fc.isKeyPtr = isPtr(fc.keyType); fc.isKeyPtr {
		fc.keyType = fc.keyType.Elem()
	}
}

func (fc *funcCall) setValue(typ reflect.Type) {
	fc.valType = typ
	if fc.isValPtr = isPtr(fc.valType); fc.isValPtr {
		fc.valType = fc.valType.Elem()
	}
}

func (fc *funcCall) getKey(v []byte) (key reflect.Value, err error) {
	if fc.keyType.Kind() == reflect.String {
		return reflect.ValueOf(string(v)), nil
	} else if fc.keyType.Kind() == reflect.Slice && fc.keyType.Elem().Kind() == reflect.Uint8 {
		return reflect.ValueOf(v), nil
	}

	key = reflect.New(fc.keyType)

	if err := fc.s.unmarshal(v, key.Interface()); err != nil {
		return key, err
	}

	if !fc.isKeyPtr {
		key = deref(key)
	}

	return key, err
}

func (fc *funcCall) getValue(v []byte) (val reflect.Value, err error) {
	val = reflect.New(fc.valType)

	if err := fc.s.unmarshal(v, val.Interface()); err != nil {
		return val, err
	}

	if !fc.isValPtr {
		val = deref(val)
	}

	return val, err
}

func (fc *funcCall) call(k, v []byte) error {
	val, err := fc.getValue(v)
	if err != nil {
		return err
	}

	if !fc.hasKey {
		fc.Value.Call([]reflect.Value{val})
		return nil
	}

	key, err := fc.getKey(k)
	if err != nil {
		return err
	}
	fc.Value.Call([]reflect.Value{key, val})
	return nil
}

func deref(val reflect.Value) reflect.Value {
	if val.IsValid() {
		return val.Elem()
	}
	return reflect.Zero(val.Type())
}
<|endoftext|>


<commit_before>package main

import (
	"./spdy"
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
)

var end chan bool

func main() {
	rawurl := flag.String("u", "", "Rawurl")
	data := flag.String("d", "", "verbose 3")
	times := flag.Int("t", 1, "verbose 3")
	verbose1 := flag.Bool("v", false, "verbose 1")
	verbose2 := flag.Bool("vv", false, "verbose 2")

	flag.Parse()

	if *rawurl == "" {
		fmt.Println("Rawurl must not blank")
		os.Exit(1)
	}

	level := byte(3)

	if *verbose2 {
		level = 1
	} else if *verbose1 {
		level = 2
	}

	log := spdy.GetLogger()
	log.SetLevel(level)

	var req *http.Request
	var err error

	if *data == "" {
		req, err = http.NewRequest("GET", *rawurl, nil)
	} else {
		req, err = http.NewRequest("POST", *rawurl, bytes.NewBufferString(*data))
	}
	if err != nil {
		log.Error("%v", err)
	}

	req.Header.Set("Cache-Control", "nostore")
	req.Header.Set("accept-encoding", "gzip, deflate")
	req.Header.Set("user-agent", "gate/0.0.1")

	end = make(chan bool, *times)
	for i := 0; i < *times; i++ {
		id, err := spdy.Request(req, handle)
		if err != nil {
			log.Error("%v", err)
		}
		log.Debug("Id#%d is sent", id)
	}

	for i := 0; i < *times; i++ {
		<-end
	}

	spdy.Close()
}

func handle(streamId uint32, res *http.Response, err error) {
	if err != nil {
		fmt.Printf("< %v", err)
	}

	fmt.Printf("StreamId#%d: \n", streamId)

	for k, vs := range res.Header {
		fmt.Printf("%-32s%s\n", k+":", vs)
	}
	fmt.Println()

	if res.Body != nil {

		rd := bufio.NewReader(res.Body)
		defer res.Body.Close()
		for {
			line, err := rd.ReadString('\n')
			if err != nil {
				if err != io.EOF {
					fmt.Printf("%v", err)
				}
				break
			}
			fmt.Printf("%v", line)
		}
	}

	end <- true
}
<commit_msg>Fixbug：当 io.EOF 时，输出最后一行<commit_after>package main

import (
	"./spdy"
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
)

var end chan bool

func main() {
	rawurl := flag.String("u", "", "Rawurl")
	data := flag.String("d", "", "verbose 3")
	times := flag.Int("t", 1, "verbose 3")
	verbose1 := flag.Bool("v", false, "verbose 1")
	verbose2 := flag.Bool("vv", false, "verbose 2")

	flag.Parse()

	if *rawurl == "" {
		fmt.Println("Rawurl must not blank")
		os.Exit(1)
	}

	level := byte(3)

	if *verbose2 {
		level = 1
	} else if *verbose1 {
		level = 2
	}

	log := spdy.GetLogger()
	log.SetLevel(level)

	var req *http.Request
	var err error

	if *data == "" {
		req, err = http.NewRequest("GET", *rawurl, nil)
	} else {
		req, err = http.NewRequest("POST", *rawurl, bytes.NewBufferString(*data))
	}
	if err != nil {
		log.Error("%v", err)
	}

	req.Header.Set("Cache-Control", "nostore")
	req.Header.Set("accept-encoding", "gzip, deflate")
	req.Header.Set("user-agent", "gate/0.0.1")

	end = make(chan bool, *times)
	for i := 0; i < *times; i++ {
		id, err := spdy.Request(req, handle)
		if err != nil {
			log.Error("%v", err)
		}
		log.Debug("Id#%d is sent", id)
	}

	for i := 0; i < *times; i++ {
		<-end
	}

	spdy.Close()
}

func handle(streamId uint32, res *http.Response, err error) {
	if err != nil {
		fmt.Printf("< %v", err)
	}

	fmt.Printf("StreamId#%d: \n", streamId)

	for k, vs := range res.Header {
		fmt.Printf("%-32s%s\n", k+":", vs)
	}
	fmt.Println()

	if res.Body != nil {

		rd := bufio.NewReader(res.Body)
		defer res.Body.Close()
		for {
			line, err := rd.ReadString('\n')
			if err != nil {
				if err == io.EOF {
					fmt.Printf("%v", line)
				} else {
					fmt.Printf("%v", err)
				}
				break
			}
			fmt.Printf("%v", line)
		}
	}

	end <- true
}
<|endoftext|>


<commit_before>// Copyright Praegressus Limited. All rights reserved.
//
// 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.

// +build !plan9,!solaris

package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"hash/fnv"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"gopkg.in/fsnotify.v1"
	"gopkg.in/yaml.v2"
)

var (
	config     *configuration
	logFile    *os.File
	watcher    *fsnotify.Watcher
	rules      map[fsnotify.Op][]*rule
	rulesMu    = &sync.RWMutex{}
	matches    map[uint64]*match
	matchesMu  = &sync.RWMutex{}
	configFile = flag.String("config", ".gawp", "Configuration file")
	hasher64   = fnv.New64a()
	hasher64Mu = &sync.Mutex{}
)

// Gawp configuration
type configuration struct {
	recursive, verbose bool
	workers            int
	logFile            string
}

type rule struct {
	match *regexp.Regexp
	cmds  []string
}

type match struct {
	mu   *sync.Mutex
	rule *rule
	cmds []string
}

func main() {
	flag.Parse()
	log.SetFlags(log.Ldate | log.Lmicroseconds)

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))

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

	defer logFile.Close()

	if err = load(dir, *configFile); err != nil {
		log.Fatalf("unable to load configuration file: %s (%s)", *configFile, err)
	}

	// File system notifications
	if watcher, err = fsnotify.NewWatcher(); err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if config.recursive {
		// Watch root and child directories
		if err = filepath.Walk(dir+"/", walk); err != nil {
			log.Fatal(err)
		}
	} else if err = watcher.Add(dir); err != nil {
		//  Only watch the root dir
		log.Fatal(err)
	}

	log.Println("started Gawp")

	// Disable file system notifications for the log file
	if config.logFile != "" {
		if err = watcher.Remove(config.logFile); err != nil {
			log.Println(err)
		}
	}

	var (
		signals  = make(chan os.Signal, 2)             // OS signal capture
		throttle = make(chan struct{}, config.workers) // Worker throttle
		wg       = &sync.WaitGroup{}
	)

	// Handle signals for clean shutdown
	signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

	// Wait for workers on shutdown
	defer wg.Wait()

	for {
		select {
		case event := <-watcher.Events:
			filename := event.Name[len(dir)+1:]

			if config.verbose {
				log.Println(event.String())
			}

			throttle <- struct{}{}

			// Reload config file
			if filename == *configFile {
				// Wait for active workers
				wg.Wait()
				log.Println("reloading config file")

				l := config.logFile

				if err = load(dir, filename); err != nil {
					log.Fatal(err)
				}

				if config.logFile != "" && config.logFile != l {
					if err = watcher.Remove(config.logFile); err != nil {
						log.Println(err)
					}
				}

				<-throttle

				throttle = make(chan struct{}, config.workers)

				continue
			}

			// Add or stop watching directories
			if err = handleEvent(event); err != nil {
				log.Println(err)

				continue
			}

			wg.Add(1)

			go worker(throttle, wg, event.Op, filename)

		case err = <-watcher.Errors:
			log.Println("fsnotify error:", err)

		case <-signals:
			return
		}
	}
}

func worker(throttle chan struct{}, wg *sync.WaitGroup, e fsnotify.Op, f string) {
	defer func() {
		<-throttle

		wg.Done()
	}()

	m := findMatch(e, f)

	if m == nil {
		return
	}

	// Atomicity for the given match
	m.mu.Lock()

	defer m.mu.Unlock()

	for i, c := range m.cmds {
		b, err := cmd(c)

		if err != nil {
			log.Printf("command (%s) error: %s", c, err)
		} else if len(b) > 0 {
			log.Printf("%s\n%s", m.rule.cmds[i], b)
		}
	}
}

// walk implements filepath.WalkFunc; adding each directory
// to the file system notifications watcher
func walk(path string, f os.FileInfo, err error) error {
	// Ignore files
	if !f.IsDir() {
		return nil
	}

	// Ignore hidden directories
	if f.Name()[0] == '.' {
		return filepath.SkipDir
	}

	if err := watcher.Add(path); err != nil {
		log.Printf("unable to watch path: %s (%s)", path, err)
	}

	return nil
}

// handleEvent determines the nature of the event, adding
// or removing directories to the file system notifications watcher
func handleEvent(e fsnotify.Event) error {
	if e.Op&fsnotify.Create != fsnotify.Create {
		return nil
	}

	s, err := os.Stat(e.Name)

	if err != nil {
		return err
	} else if !s.IsDir() {
		return nil
	}

	if config.recursive {
		return filepath.Walk(e.Name+"/", walk)
	}

	return watcher.Add(e.Name)
}

// findMatch attempts to find a rule match for file path
// On success caches the match for fast future lookups
func findMatch(e fsnotify.Op, f string) *match {
	var (
		m *match
		h = hash64(e, f)
	)

	// Fast map lookup, circumvent regular expressions
	matchesMu.RLock()
	c, exists := matches[h]
	matchesMu.RUnlock()

	if exists {
		return c
	}

	// Cache for fast lookup
	defer func() {
		matchesMu.Lock()
		matches[h] = m
		matchesMu.Unlock()
	}()

	rulesMu.RLock()

	defer rulesMu.RUnlock()

	// Check there's rules associated with the event type
	r, exists := rules[e]

	if !exists {
		return nil
	}

	// Test each rule for a match
	for _, c := range r {
		s := c.match.FindAllStringSubmatch(f, -1)

		if s == nil {
			continue
		}

		m = &match{&sync.Mutex{}, c, nil}

		for _, cmd := range c.cmds {
			for i := range s[0] {
				if i == 0 {
					continue
				}

				cmd = strings.Replace(cmd, "$"+strconv.Itoa(i), s[0][i], -1)
			}

			m.cmds = append(m.cmds, strings.Replace(cmd, "$file", f, -1))
		}

		break
	}

	return m
}

// load loads the Gawp config file and handles the loading of rules
func load(dir, f string) error {
	// Init/reset config, rules and matches cache
	config = &configuration{recursive: true}
	rules = map[fsnotify.Op][]*rule{}
	matches = map[uint64]*match{}

	// Open config file
	h, err := os.Open(dir + "/" + f)

	if err != nil {
		return err
	}

	defer h.Close()

	b, err := ioutil.ReadAll(h)

	if err != nil {
		return err
	}

	var c map[string]interface{}

	if err = yaml.Unmarshal(b, &c); err != nil {
		return err
	}

	for k, v := range c {
		// Conversions not tested for success; keep type defaults
		switch k {
		case "recursive":
			config.recursive, _ = v.(bool)

		case "verbose":
			config.verbose, _ = v.(bool)

		case "workers":
			config.workers, _ = v.(int)

		case "logfile":
			config.logFile, _ = v.(string)

		default:
			if err = parseRules(k, v); err != nil {
				return err
			}
		}
	}

	// Determine operating system threads that can execute user-level Go code simultaneously
	if config.workers != 1 {
		switch n := runtime.NumCPU(); config.workers {
		case 0:
			if n >= 4 {
				config.workers = n / 2
			} else {
				config.workers = 1
			}

		default:
			if config.workers > n {
				config.workers = n
			}
		}
	}

	runtime.GOMAXPROCS(config.workers)

	if err = setLogFile(dir, config.logFile); err != nil {
		return err
	}

	return nil
}

// parseRules builds the rules map, adding rules into
// its defined event "bucket"
func parseRules(s string, i interface{}) error {
	e := parseEvents(s)

	if len(e) == 0 {
		return nil
	}

	var err error

	switch c := i.(type) {
	case map[interface{}]interface{}:
		for k, v := range c {
			// Regular expression
			m, ok := k.(string)

			if !ok {
				return nil
			}

			// Commands
			p, ok := v.([]interface{})

			if !ok || len(p) == 0 {
				return nil
			}

			r := &rule{}

			if r.match, err = regexp.Compile(m); err != nil {
				return fmt.Errorf("rule compilation error: %s (%s)", m, err)
			}

			for _, c := range p {
				cmd, ok := c.(string)

				if !ok || cmd == "" {
					continue
				}

				if cmd = strings.TrimSpace(cmd); cmd == "" {
					continue
				}

				r.cmds = append(r.cmds, cmd)
			}

			if len(r.cmds) == 0 {
				continue
			}

			// Add the rule to each event bucket
			for _, c := range e {
				rules[c] = append(rules[c], r)
			}
		}
	}

	return nil
}

// parseEvents returns the fsnotify.Op values
// for the events in the string
func parseEvents(s string) (e []fsnotify.Op) {
	for _, v := range strings.Split(s, ",") {
		switch strings.ToLower(strings.TrimSpace(v)) {
		case "create":
			e = append(e, fsnotify.Create)
		case "write":
			e = append(e, fsnotify.Write)
		case "rename":
			e = append(e, fsnotify.Rename)
		case "remove":
			e = append(e, fsnotify.Remove)
		case "chmod":
			e = append(e, fsnotify.Chmod)
		}
	}

	return
}

// setLogFile sets the logger output destination
func setLogFile(dir, f string) error {
	if f == "" {
		log.SetOutput(os.Stdout)

		return nil
	}

	// Relative path
	if f[0] != '/' {
		f = dir + "/" + f
	}

	// Force log file rotation, no side effects
	logFile.Close()

	var err error

	if logFile, err = os.OpenFile(f, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666); err != nil {
		return err
	}

	log.SetOutput(logFile)

	return nil
}

// hash64 returns the hash of the given FS operation & string as uint64
func hash64(e fsnotify.Op, s string) uint64 {
	hasher64Mu.Lock()

	defer hasher64Mu.Unlock()

	hasher64.Reset()
	binary.Write(hasher64, binary.LittleEndian, e)
	hasher64.Write([]byte(s))

	return hasher64.Sum64()
}
<commit_msg>Use os.Getwd() to determine working directory, MR #3.<commit_after>// Copyright Praegressus Limited. All rights reserved.
//
// 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.

// +build !plan9,!solaris

package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"hash/fnv"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"gopkg.in/fsnotify.v1"
	"gopkg.in/yaml.v2"
)

var (
	config     *configuration
	logFile    *os.File
	watcher    *fsnotify.Watcher
	rules      map[fsnotify.Op][]*rule
	rulesMu    = &sync.RWMutex{}
	matches    map[uint64]*match
	matchesMu  = &sync.RWMutex{}
	configFile = flag.String("config", ".gawp", "Configuration file")
	hasher64   = fnv.New64a()
	hasher64Mu = &sync.Mutex{}
)

// Gawp configuration
type configuration struct {
	recursive, verbose bool
	workers            int
	logFile            string
}

type rule struct {
	match *regexp.Regexp
	cmds  []string
}

type match struct {
	mu   *sync.Mutex
	rule *rule
	cmds []string
}

func main() {
	flag.Parse()
	log.SetFlags(log.Ldate | log.Lmicroseconds)

	dir, err := os.Getwd()

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

	defer logFile.Close()

	if err = load(dir, *configFile); err != nil {
		log.Fatalf("unable to load configuration file: %s (%s)", *configFile, err)
	}

	// File system notifications
	if watcher, err = fsnotify.NewWatcher(); err != nil {
		log.Fatal(err)
	}

	defer watcher.Close()

	if config.recursive {
		// Watch root and child directories
		if err = filepath.Walk(dir+"/", walk); err != nil {
			log.Fatal(err)
		}
	} else if err = watcher.Add(dir); err != nil {
		//  Only watch the root dir
		log.Fatal(err)
	}

	log.Println("started Gawp")

	// Disable file system notifications for the log file
	if config.logFile != "" {
		if err = watcher.Remove(config.logFile); err != nil {
			log.Println(err)
		}
	}

	var (
		signals  = make(chan os.Signal, 2)             // OS signal capture
		throttle = make(chan struct{}, config.workers) // Worker throttle
		wg       = &sync.WaitGroup{}
	)

	// Handle signals for clean shutdown
	signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

	// Wait for workers on shutdown
	defer wg.Wait()

	for {
		select {
		case event := <-watcher.Events:
			filename := event.Name[len(dir)+1:]

			if config.verbose {
				log.Println(event.String())
			}

			throttle <- struct{}{}

			// Reload config file
			if filename == *configFile {
				// Wait for active workers
				wg.Wait()
				log.Println("reloading config file")

				l := config.logFile

				if err = load(dir, filename); err != nil {
					log.Fatal(err)
				}

				if config.logFile != "" && config.logFile != l {
					if err = watcher.Remove(config.logFile); err != nil {
						log.Println(err)
					}
				}

				<-throttle

				throttle = make(chan struct{}, config.workers)

				continue
			}

			// Add or stop watching directories
			if err = handleEvent(event); err != nil {
				log.Println(err)

				continue
			}

			wg.Add(1)

			go worker(throttle, wg, event.Op, filename)

		case err = <-watcher.Errors:
			log.Println("fsnotify error:", err)

		case <-signals:
			return
		}
	}
}

func worker(throttle chan struct{}, wg *sync.WaitGroup, e fsnotify.Op, f string) {
	defer func() {
		<-throttle

		wg.Done()
	}()

	m := findMatch(e, f)

	if m == nil {
		return
	}

	// Atomicity for the given match
	m.mu.Lock()

	defer m.mu.Unlock()

	for i, c := range m.cmds {
		b, err := cmd(c)

		if err != nil {
			log.Printf("command (%s) error: %s", c, err)
		} else if len(b) > 0 {
			log.Printf("%s\n%s", m.rule.cmds[i], b)
		}
	}
}

// walk implements filepath.WalkFunc; adding each directory
// to the file system notifications watcher
func walk(path string, f os.FileInfo, err error) error {
	// Ignore files
	if !f.IsDir() {
		return nil
	}

	// Ignore hidden directories
	if f.Name()[0] == '.' {
		return filepath.SkipDir
	}

	if err := watcher.Add(path); err != nil {
		log.Printf("unable to watch path: %s (%s)", path, err)
	}

	return nil
}

// handleEvent determines the nature of the event, adding
// or removing directories to the file system notifications watcher
func handleEvent(e fsnotify.Event) error {
	if e.Op&fsnotify.Create != fsnotify.Create {
		return nil
	}

	s, err := os.Stat(e.Name)

	if err != nil {
		return err
	} else if !s.IsDir() {
		return nil
	}

	if config.recursive {
		return filepath.Walk(e.Name+"/", walk)
	}

	return watcher.Add(e.Name)
}

// findMatch attempts to find a rule match for file path
// On success caches the match for fast future lookups
func findMatch(e fsnotify.Op, f string) *match {
	var (
		m *match
		h = hash64(e, f)
	)

	// Fast map lookup, circumvent regular expressions
	matchesMu.RLock()
	c, exists := matches[h]
	matchesMu.RUnlock()

	if exists {
		return c
	}

	// Cache for fast lookup
	defer func() {
		matchesMu.Lock()
		matches[h] = m
		matchesMu.Unlock()
	}()

	rulesMu.RLock()

	defer rulesMu.RUnlock()

	// Check there's rules associated with the event type
	r, exists := rules[e]

	if !exists {
		return nil
	}

	// Test each rule for a match
	for _, c := range r {
		s := c.match.FindAllStringSubmatch(f, -1)

		if s == nil {
			continue
		}

		m = &match{&sync.Mutex{}, c, nil}

		for _, cmd := range c.cmds {
			for i := range s[0] {
				if i == 0 {
					continue
				}

				cmd = strings.Replace(cmd, "$"+strconv.Itoa(i), s[0][i], -1)
			}

			m.cmds = append(m.cmds, strings.Replace(cmd, "$file", f, -1))
		}

		break
	}

	return m
}

// load loads the Gawp config file and handles the loading of rules
func load(dir, f string) error {
	// Init/reset config, rules and matches cache
	config = &configuration{recursive: true}
	rules = map[fsnotify.Op][]*rule{}
	matches = map[uint64]*match{}

	// Open config file
	h, err := os.Open(dir + "/" + f)

	if err != nil {
		return err
	}

	defer h.Close()

	b, err := ioutil.ReadAll(h)

	if err != nil {
		return err
	}

	var c map[string]interface{}

	if err = yaml.Unmarshal(b, &c); err != nil {
		return err
	}

	for k, v := range c {
		// Conversions not tested for success; keep type defaults
		switch k {
		case "recursive":
			config.recursive, _ = v.(bool)

		case "verbose":
			config.verbose, _ = v.(bool)

		case "workers":
			config.workers, _ = v.(int)

		case "logfile":
			config.logFile, _ = v.(string)

		default:
			if err = parseRules(k, v); err != nil {
				return err
			}
		}
	}

	// Determine operating system threads that can execute user-level Go code simultaneously
	if config.workers != 1 {
		switch n := runtime.NumCPU(); config.workers {
		case 0:
			if n >= 4 {
				config.workers = n / 2
			} else {
				config.workers = 1
			}

		default:
			if config.workers > n {
				config.workers = n
			}
		}
	}

	runtime.GOMAXPROCS(config.workers)

	if err = setLogFile(dir, config.logFile); err != nil {
		return err
	}

	return nil
}

// parseRules builds the rules map, adding rules into
// its defined event "bucket"
func parseRules(s string, i interface{}) error {
	e := parseEvents(s)

	if len(e) == 0 {
		return nil
	}

	var err error

	switch c := i.(type) {
	case map[interface{}]interface{}:
		for k, v := range c {
			// Regular expression
			m, ok := k.(string)

			if !ok {
				return nil
			}

			// Commands
			p, ok := v.([]interface{})

			if !ok || len(p) == 0 {
				return nil
			}

			r := &rule{}

			if r.match, err = regexp.Compile(m); err != nil {
				return fmt.Errorf("rule compilation error: %s (%s)", m, err)
			}

			for _, c := range p {
				cmd, ok := c.(string)

				if !ok || cmd == "" {
					continue
				}

				if cmd = strings.TrimSpace(cmd); cmd == "" {
					continue
				}

				r.cmds = append(r.cmds, cmd)
			}

			if len(r.cmds) == 0 {
				continue
			}

			// Add the rule to each event bucket
			for _, c := range e {
				rules[c] = append(rules[c], r)
			}
		}
	}

	return nil
}

// parseEvents returns the fsnotify.Op values
// for the events in the string
func parseEvents(s string) (e []fsnotify.Op) {
	for _, v := range strings.Split(s, ",") {
		switch strings.ToLower(strings.TrimSpace(v)) {
		case "create":
			e = append(e, fsnotify.Create)
		case "write":
			e = append(e, fsnotify.Write)
		case "rename":
			e = append(e, fsnotify.Rename)
		case "remove":
			e = append(e, fsnotify.Remove)
		case "chmod":
			e = append(e, fsnotify.Chmod)
		}
	}

	return
}

// setLogFile sets the logger output destination
func setLogFile(dir, f string) error {
	if f == "" {
		log.SetOutput(os.Stdout)

		return nil
	}

	// Relative path
	if f[0] != '/' {
		f = dir + "/" + f
	}

	// Force log file rotation, no side effects
	logFile.Close()

	var err error

	if logFile, err = os.OpenFile(f, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666); err != nil {
		return err
	}

	log.SetOutput(logFile)

	return nil
}

// hash64 returns the hash of the given FS operation & string as uint64
func hash64(e fsnotify.Op, s string) uint64 {
	hasher64Mu.Lock()

	defer hasher64Mu.Unlock()

	hasher64.Reset()
	binary.Write(hasher64, binary.LittleEndian, e)
	hasher64.Write([]byte(s))

	return hasher64.Sum64()
}
<|endoftext|>


<commit_before>// +build !go1.5

package gb

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"runtime"
)

func GcToolchain(opts ...func(*gcoption)) func(c *Context) error {
	return func(c *Context) error {
		goroot := runtime.GOROOT()

		// cross-compliation is not supported yet #31
		if c.gohostos != c.gotargetos || c.gohostarch != c.gotargetarch {
			return fmt.Errorf("cross compilation from host %s/%s to target %s/%s not supported. See issue #31", c.gohostos, c.gohostarch, c.gotargetos, c.gotargetarch)
		}

		archchar, err := build.ArchChar(c.gotargetarch)
		if err != nil {
			return err
		}
		tooldir := filepath.Join(goroot, "pkg", "tool", c.gohostos+"_"+c.gohostarch)
		c.tc = &gcToolchain{
			gc:   filepath.Join(tooldir, archchar+"g"),
			ld:   filepath.Join(tooldir, archchar+"l"),
			as:   filepath.Join(tooldir, archchar+"a"),
			cc:   filepath.Join(tooldir, archchar+"c"),
			pack: filepath.Join(tooldir, "pack"),
		}
		return nil
	}
}

func (t *gcToolchain) Gc(pkg *Package, searchpaths []string, importpath, srcdir, outfile string, files []string) error {
	Debugf("gc:gc %v %v %v %v", importpath, srcdir, outfile, files)

	args := append(pkg.gcflags, "-p", importpath, "-pack")
	args = append(args, "-o", outfile)
	for _, d := range searchpaths {
		args = append(args, "-I", d)
	}
	if pkg.Complete() {
		args = append(args, "-complete")
	}
	args = append(args, files...)
	if err := mkdir(filepath.Dir(outfile)); err != nil {
		return fmt.Errorf("gc:gc: %v", err)
	}
	return runOut(os.Stdout, srcdir, nil, t.gc, args...)
}

func (t *gcToolchain) Asm(pkg *Package, srcdir, ofile, sfile string) error {
	includedir := filepath.Join(runtime.GOROOT(), "pkg", pkg.gotargetos+"_"+pkg.gotargetarch)
	args := []string{"-o", ofile, "-D", "GOOS_" + pkg.gotargetos, "-D", "GOARCH_" + pkg.gotargetarch, "-I", includedir, sfile}
	if err := mkdir(filepath.Dir(ofile)); err != nil {
		return fmt.Errorf("gc:asm: %v", err)
	}
	return run(srcdir, nil, t.as, args...)
}

func (t *gcToolchain) Ld(pkg *Package, searchpaths []string, outfile, afile string) error {
	args := append(pkg.ldflags, "-o", outfile)
	for _, d := range searchpaths {
		args = append(args, "-L", d)
	}
	args = append(args, "-extld="+gcc()) // TODO(dfc) go 1.5+, "-buildmode=exe")
	args = append(args, afile)
	if err := mkdir(filepath.Dir(outfile)); err != nil {
		return fmt.Errorf("gc:ld: %v", err)
	}
	return run(".", nil, t.ld, args...)
}

func (t *gcToolchain) Cc(pkg *Package, ofile, cfile string) error {
	args := []string{
		"-F", "-V", "-w",
		"-trimpath", pkg.Workdir(),
		"-I", pkg.Objdir(),
		"-I", filepath.Join(pkg.GOROOT, "pkg", pkg.GOOS+"_"+pkg.GOARCH), // for runtime.h
		"-o", ofile,
		"-D", "GOOS_" + pkg.GOOS,
		"-D", "GOARCH_" + pkg.GOARCH,
		cfile,
	}
	return run(pkg.Dir, nil, t.cc, args...)
}
<commit_msg>fix gc14<commit_after>// +build !go1.5

package gb

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"runtime"
)

func GcToolchain(opts ...func(*gcoption)) func(c *Context) error {
	return func(c *Context) error {
		// TODO(dfc) this should come from the context, not the runtime.
		goroot := runtime.GOROOT()

		// cross-compliation is not supported yet #31
		if c.gohostos != c.gotargetos || c.gohostarch != c.gotargetarch {
			return fmt.Errorf("cross compilation from host %s/%s to target %s/%s not supported. See issue #31", c.gohostos, c.gohostarch, c.gotargetos, c.gotargetarch)
		}

		archchar, err := build.ArchChar(c.gotargetarch)
		if err != nil {
			return err
		}
		tooldir := filepath.Join(goroot, "pkg", "tool", c.gohostos+"_"+c.gohostarch)
		c.tc = &gcToolchain{
			gc:   filepath.Join(tooldir, archchar+"g"),
			ld:   filepath.Join(tooldir, archchar+"l"),
			as:   filepath.Join(tooldir, archchar+"a"),
			cc:   filepath.Join(tooldir, archchar+"c"),
			pack: filepath.Join(tooldir, "pack"),
		}
		return nil
	}
}

func (t *gcToolchain) Gc(pkg *Package, searchpaths []string, importpath, srcdir, outfile string, files []string) error {
	Debugf("gc:gc %v %v %v %v", importpath, srcdir, outfile, files)

	args := append(pkg.gcflags, "-p", importpath, "-pack")
	args = append(args, "-o", outfile)
	for _, d := range searchpaths {
		args = append(args, "-I", d)
	}
	if pkg.Complete() {
		args = append(args, "-complete")
	}
	args = append(args, files...)
	if err := mkdir(filepath.Dir(outfile)); err != nil {
		return fmt.Errorf("gc:gc: %v", err)
	}
	return runOut(os.Stdout, srcdir, nil, t.gc, args...)
}

func (t *gcToolchain) Asm(pkg *Package, srcdir, ofile, sfile string) error {
	includedir := filepath.Join(pkg.Context.Context.GOROOT, "pkg", pkg.gotargetos+"_"+pkg.gotargetarch)
	args := []string{"-o", ofile, "-D", "GOOS_" + pkg.gotargetos, "-D", "GOARCH_" + pkg.gotargetarch, "-I", includedir, sfile}
	if err := mkdir(filepath.Dir(ofile)); err != nil {
		return fmt.Errorf("gc:asm: %v", err)
	}
	return run(srcdir, nil, t.as, args...)
}

func (t *gcToolchain) Ld(pkg *Package, searchpaths []string, outfile, afile string) error {
	args := append(pkg.ldflags, "-o", outfile)
	for _, d := range searchpaths {
		args = append(args, "-L", d)
	}
	args = append(args, "-extld="+gcc()) // TODO(dfc) go 1.5+, "-buildmode=exe")
	args = append(args, afile)
	if err := mkdir(filepath.Dir(outfile)); err != nil {
		return fmt.Errorf("gc:ld: %v", err)
	}
	return run(".", nil, t.ld, args...)
}

func (t *gcToolchain) Cc(pkg *Package, ofile, cfile string) error {
	args := []string{
		"-F", "-V", "-w",
		"-trimpath", pkg.Workdir(),
		"-I", pkg.Objdir(),
		"-I", filepath.Join(pkg.Context.Context.GOROOT, "pkg", pkg.gohostos+"_"+pkg.gohostarch), // for runtime.h
		"-o", ofile,
		"-D", "GOOS_" + pkg.gotargetos,
		"-D", "GOARCH_" + pkg.gotargetarch,
		cfile,
	}
	return run(pkg.Dir, nil, t.cc, args...)
}
<|endoftext|>


<commit_before>package cairo

import "C"

import (
	"math"
	"strconv"
)

//Point is an X, Y coordinate pair.
//The axes increase right and down.
type Point struct {
	X, Y float64
}

func (p Point) c() (x, y C.double) {
	return C.double(p.X), C.double(p.Y)
}

//Pt is shorthand for Point{X, Y}.
func Pt(X, Y float64) Point {
	return Point{X, Y}
}

//Polar converts polar coordinates to cartesian.
func Polar(r, θ float64) Point {
	sinθ, cosθ := math.Sincos(θ)
	return Pt(r*cosθ, r*sinθ)
}

//ZP is the zero point.
var ZP Point

func floatstr(f float64) string {
	return strconv.FormatFloat(f, 'g', -1, 64)
}

func (p Point) String() string {
	return "(" + floatstr(p.X) + "," + floatstr(p.Y) + ")"
}

//Add returns the vector p+q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

//Sub returns the vector p+q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

//Mul returns the vector p*k.
func (p Point) Mul(k float64) Point {
	return Point{p.X * k, p.Y * k}
}

//Div returns the vector p/k.
func (p Point) Div(k float64) Point {
	return Point{p.X / k, p.Y / k}
}

//Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

//Near reports whether p and q are within ε of each other.
func (p Point) Near(q Point, ε float64) bool {
	return math.Abs(p.X-q.X) < ε && math.Abs(p.Y-q.Y) < ε
}

//Hypot returns Sqrt(p.X*p.X + p.Y+p.Y)
func (p Point) Hypot() float64 {
	return math.Hypot(p.X, p.Y)
}

//Angle returns the angle of the vector in radians.
func (p Point) Angle() float64 {
	return math.Atan2(p.Y, p.X)
}

//In reports whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X &&
		p.X < r.Max.X &&
		r.Min.Y <= p.Y &&
		p.Y < r.Max.Y
}

//Mod returns the point q in r such that p.X-q.X is a multiple
//of r's width and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = math.Mod(p.X, w)
	if p.X < 0 {
		p.X += w
	}
	p.Y = math.Mod(p.Y, h)
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

//A Rectangle contains the points with Min.X <= X < Max.X,
//Min.Y <= Y < Max.Y.
//It is well-formed if Min.X <= Max.X and likewise for Y.
//Points are always well-formed.
//A rectangle's methods always return well-formed outputs
//for well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

func (r Rectangle) c() (x0, y0, x1, y1 C.double) {
	x0, y0 = r.Min.c()
	x1, y1 = r.Max.c()
	return
}

//ZR is the zero Rectangle.
var ZR Rectangle

//Rect is shorthand for Rectangle{Pt(x₀, y₀), Pt(x₁, y₁)}.Canon().
func Rect(x0, y0, x1, y1 float64) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Pt(x0, y0), Pt(x1, y1)}
}

func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

//Dx returns r's width.
func (r Rectangle) Dx() float64 {
	return r.Max.X - r.Min.X
}

//Dy returns r's height.
func (r Rectangle) Dy() float64 {
	return r.Max.Y - r.Min.Y
}

//Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		r.Min.Add(p),
		r.Max.Add(p),
	}
}

//Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return r.Add(Pt(-p.X, -p.Y))
}

//Intersect returns the largest rectangle contained by both r and s.
//If the two rectangles do not overlap then the zero rectangle
//will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.Y {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

//Empty reports whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

//Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X > s.Max.X &&
		s.Min.X > r.Max.X &&
		r.Min.Y < s.Max.Y &&
		s.Min.Y < r.Max.Y
}

//In reports whether every potin in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	return s.Min.X <= r.Min.X &&
		r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y &&
		r.Max.Y <= s.Max.Y
}

//Canon returns the canonical version of r.
//The returned rectangle has minimum and maximum coordinates swapped
//if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

//BUG(jmf): finish copying image.Point/Rectangle interfaces over to float
//and document. Just need Inset.
<commit_msg>added basic Circle type<commit_after>package cairo

import "C"

import (
	"math"
	"strconv"
)

//Point is an X, Y coordinate pair.
//The axes increase right and down.
type Point struct {
	X, Y float64
}

func (p Point) c() (x, y C.double) {
	return C.double(p.X), C.double(p.Y)
}

//Pt is shorthand for Point{X, Y}.
func Pt(X, Y float64) Point {
	return Point{X, Y}
}

//Polar converts polar coordinates to cartesian.
func Polar(r, θ float64) Point {
	sinθ, cosθ := math.Sincos(θ)
	return Pt(r*cosθ, r*sinθ)
}

//ZP is the zero point.
var ZP Point

func floatstr(f float64) string {
	return strconv.FormatFloat(f, 'g', -1, 64)
}

func (p Point) String() string {
	return "(" + floatstr(p.X) + "," + floatstr(p.Y) + ")"
}

//Add returns the vector p+q.
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

//Sub returns the vector p+q.
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

//Mul returns the vector p*k.
func (p Point) Mul(k float64) Point {
	return Point{p.X * k, p.Y * k}
}

//Div returns the vector p/k.
func (p Point) Div(k float64) Point {
	return Point{p.X / k, p.Y / k}
}

//Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
	return p.X == q.X && p.Y == q.Y
}

//Near reports whether p and q are within ε of each other.
func (p Point) Near(q Point, ε float64) bool {
	return math.Abs(p.X-q.X) < ε && math.Abs(p.Y-q.Y) < ε
}

//Hypot returns Sqrt(p.X*p.X + p.Y+p.Y)
func (p Point) Hypot() float64 {
	return math.Hypot(p.X, p.Y)
}

//Angle returns the angle of the vector in radians.
func (p Point) Angle() float64 {
	return math.Atan2(p.Y, p.X)
}

//In reports whether p is in r.
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X &&
		p.X < r.Max.X &&
		r.Min.Y <= p.Y &&
		p.Y < r.Max.Y
}

//InCirc reports whether p falls in c.
func (p Point) InCirc(c Circle) bool {
	return p.Near(c.Center, c.Radius)
}

//Mod returns the point q in r such that p.X-q.X is a multiple
//of r's width and p.Y-q.Y is a multiple of r's height.
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = math.Mod(p.X, w)
	if p.X < 0 {
		p.X += w
	}
	p.Y = math.Mod(p.Y, h)
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

//A Rectangle contains the points with Min.X <= X < Max.X,
//Min.Y <= Y < Max.Y.
//It is well-formed if Min.X <= Max.X and likewise for Y.
//Points are always well-formed.
//A rectangle's methods always return well-formed outputs
//for well-formed inputs.
type Rectangle struct {
	Min, Max Point
}

func (r Rectangle) c() (x0, y0, x1, y1 C.double) {
	x0, y0 = r.Min.c()
	x1, y1 = r.Max.c()
	return
}

//ZR is the zero Rectangle.
var ZR Rectangle

//Rect is shorthand for Rectangle{Pt(x₀, y₀), Pt(x₁, y₁)}.Canon().
func Rect(x0, y0, x1, y1 float64) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Pt(x0, y0), Pt(x1, y1)}
}

func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

//Dx returns r's width.
func (r Rectangle) Dx() float64 {
	return r.Max.X - r.Min.X
}

//Dy returns r's height.
func (r Rectangle) Dy() float64 {
	return r.Max.Y - r.Min.Y
}

//Add returns the rectangle r translated by p.
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		r.Min.Add(p),
		r.Max.Add(p),
	}
}

//Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
	return r.Add(Pt(-p.X, -p.Y))
}

//Intersect returns the largest rectangle contained by both r and s.
//If the two rectangles do not overlap then the zero rectangle
//will be returned.
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.Y {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
		return ZR
	}
	return r
}

//Empty reports whether the rectangle contains no points.
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

//Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
	return r.Min.X > s.Max.X &&
		s.Min.X > r.Max.X &&
		r.Min.Y < s.Max.Y &&
		s.Min.Y < r.Max.Y
}

//In reports whether every point in r is in s.
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	return s.Min.X <= r.Min.X &&
		r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y &&
		r.Max.Y <= s.Max.Y
}

//Canon returns the canonical version of r.
//The returned rectangle has minimum and maximum coordinates swapped
//if necessary so that it is well-formed.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

//A Circle contains the points swept out by Radius from Center.
//
//It is well-formed if the Radius is nonnegative.
type Circle struct {
	Center Point
	Radius float64
}

//ZC is the zero circle.
var ZC Circle

//Circ is shorthand for Circle{c, r}.Canon().
func Circ(c Point, r float64) Circle {
	return Circle{c, r}.Canon()
}

func (c Circle) c() (x, y, r C.double) {
	x, y = c.Center.c()
	r = C.double(c.Radius)
	return
}

func (c Circle) String() string {
	return c.Center.String() + "-" + floatstr(c.Radius)
}

//Canon returns a canonical circle.
func (c Circle) Canon() Circle {
	return Circ(c.Center, math.Abs(c.Radius))
}

//Add returns the circle c translated by p.
func (c Circle) Add(p Point) Circle {
	return Circ(c.Center.Add(p), c.Radius)
}

//Sub returns the circle c translated by -p.
func (c Circle) Sub(p Point) Circle {
	return c.Add(Pt(-p.X, -p.Y))
}

//Empty reports whether this circle contains no points.
func (c Circle) Empty() bool {
	return c.Radius == 0
}

//BUG(jmf): finish copying image.Point/Rectangle interfaces over to float
//and document. Just need Inset.

//BUG(jmf): bring circle to feature parity with rectangle
<|endoftext|>