<commit_before>package util

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"syscall"
	"time"

	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/format"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
)

const (
	dirPerms  = syscall.S_IRWXU
	filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP
)

func createFile(filename string) error {
	if file, err := os.Create(filename); err != nil {
		return err
	} else {
		// Don't wait for finaliser to close, otherwise we can have too many
		// open files.
		file.Close()
		return nil
	}
}

func unpack(fs *filesystem.FileSystem, objectsGetter objectserver.ObjectsGetter,
	dirname string, logger log.Logger) error {
	for _, entry := range fs.EntryList {
		if entry.Name == ".inodes" {
			return errors.New("cannot unpack a file-system with /.inodes")
		}
	}
	os.Mkdir(dirname, dirPerms)
	inodesDir := path.Join(dirname, ".inodes")
	if err := os.Mkdir(inodesDir, dirPerms); err != nil {
		return err
	}
	defer os.RemoveAll(inodesDir)
	var statfs syscall.Statfs_t
	if err := syscall.Statfs(inodesDir, &statfs); err != nil {
		return errors.New(fmt.Sprintf("Unable to Statfs: %s %s\n",
			inodesDir, err))
	}
	if fs.TotalDataBytes > uint64(statfs.Bsize)*statfs.Bfree {
		return errors.New("image will not fit on file-system")
	}
	hashes, inums, lengths := getHashes(fs)
	err := writeObjects(objectsGetter, hashes, inums, lengths, inodesDir,
		logger)
	if err != nil {
		return err
	}
	startWriteTime := time.Now()
	if err := writeInodes(fs.InodeTable, inodesDir); err != nil {
		return err
	}
	if err = fs.DirectoryInode.Write(dirname); err != nil {
		return err
	}
	startBuildTime := time.Now()
	writeDuration := startBuildTime.Sub(startWriteTime)
	err = buildTree(&fs.DirectoryInode, dirname, "", inodesDir)
	if err != nil {
		return err
	}
	buildDuration := time.Since(startBuildTime)
	logger.Printf("Unpacked file-system: made inodes in %s, built tree in %s\n",
		format.Duration(writeDuration), format.Duration(buildDuration))
	return nil
}

func getHashes(fs *filesystem.FileSystem) ([]hash.Hash, []uint64, []uint64) {
	hashes := make([]hash.Hash, 0, fs.NumRegularInodes)
	inums := make([]uint64, 0, fs.NumRegularInodes)
	lengths := make([]uint64, 0, fs.NumRegularInodes)
	for inum, inode := range fs.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				hashes = append(hashes, inode.Hash)
				inums = append(inums, inum)
				lengths = append(lengths, inode.Size)
			}
		}
	}
	return hashes, inums, lengths
}

func writeObjects(objectsGetter objectserver.ObjectsGetter, hashes []hash.Hash,
	inums []uint64, lengths []uint64, inodesDir string,
	logger log.Logger) error {
	startTime := time.Now()
	objectsReader, err := objectsGetter.GetObjects(hashes)
	if err != nil {
		return fmt.Errorf("error getting object reader: %s\n", err)
	}
	defer objectsReader.Close()
	var totalLength uint64
	buffer := make([]byte, 32<<10)
	for index := range hashes {
		err = writeObject(objectsReader, inums[index], lengths[index],
			inodesDir, buffer)
		if err != nil {
			return err
		}
		totalLength += lengths[index]
	}
	duration := time.Since(startTime)
	speed := uint64(float64(totalLength) / duration.Seconds())
	logger.Printf("Copied %d objects (%s) in %s (%s/s)\n",
		len(hashes), format.FormatBytes(totalLength), format.Duration(duration),
		format.FormatBytes(speed))
	return nil
}

func writeObject(objectsReader objectserver.ObjectsReader, inodeNumber uint64,
	length uint64, inodesDir string, buffer []byte) error {
	rlength, reader, err := objectsReader.NextObject()
	if err != nil {
		return err
	}
	defer reader.Close()
	if rlength != length {
		return errors.New("mismatched lengths")
	}
	filename := path.Join(inodesDir, fmt.Sprintf("%d", inodeNumber))
	destFile, err := os.OpenFile(filename,
		os.O_CREATE|os.O_TRUNC|os.O_WRONLY, filePerms)
	if err != nil {
		return err
	}
	doClose := true
	defer func() {
		if doClose {
			destFile.Close()
		}
	}()
	iLength := int64(length)
	nCopied, err := io.CopyBuffer(destFile, io.LimitReader(reader, iLength),
		buffer)
	if err != nil {
		return fmt.Errorf("error copying: %s", err)
	}
	if nCopied != iLength {
		return fmt.Errorf("expected length: %d, got: %d for: %s\n",
			length, nCopied, filename)
	}
	doClose = false
	return destFile.Close()
}

func writeInode(inode filesystem.GenericInode, filename string) error {
	switch inode := inode.(type) {
	case *filesystem.RegularInode:
		if inode.Size < 1 {
			if err := createFile(filename); err != nil {
				return err
			}
		}
		if err := inode.WriteMetadata(filename); err != nil {
			return err
		}
	case *filesystem.ComputedRegularInode:
		if err := createFile(filename); err != nil {
			return err
		}
		tmpInode := &filesystem.RegularInode{
			Mode: inode.Mode,
			Uid:  inode.Uid,
			Gid:  inode.Gid,
		}
		if err := tmpInode.WriteMetadata(filename); err != nil {
			return err
		}
	case *filesystem.SymlinkInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	case *filesystem.SpecialInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	case *filesystem.DirectoryInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	default:
		return errors.New("unsupported inode type")
	}
	return nil
}

func writeInodes(inodeTable filesystem.InodeTable, inodesDir string) error {
	for inodeNumber, inode := range inodeTable {
		filename := path.Join(inodesDir, fmt.Sprintf("%d", inodeNumber))
		if err := writeInode(inode, filename); err != nil {
			return err
		}
	}
	return nil
}

func buildTree(directory *filesystem.DirectoryInode,
	rootDir, mySubPathName, inodesDir string) error {
	for _, dirent := range directory.EntryList {
		oldPath := path.Join(inodesDir, fmt.Sprintf("%d", dirent.InodeNumber))
		newSubPath := path.Join(mySubPathName, dirent.Name)
		newFullPath := path.Join(rootDir, newSubPath)
		if inode := dirent.Inode(); inode == nil {
			panic("no inode pointer for: " + newSubPath)
		} else if dinode, ok := inode.(*filesystem.DirectoryInode); ok {
			if err := renameDir(oldPath, newFullPath, dinode); err != nil {
				return err
			}
			err := buildTree(dinode, rootDir, newSubPath, inodesDir)
			if err != nil {
				return err
			}
		} else {
			if err := link(oldPath, newFullPath, inode); err != nil {
				if !os.IsNotExist(err) {
					return err
				}
			}
		}
	}
	return nil
}

func link(oldname, newname string, inode filesystem.GenericInode) error {
	if err := os.Link(oldname, newname); err == nil {
		return nil
	}
	if finode, ok := inode.(*filesystem.RegularInode); ok {
		if finode.Size > 0 {
			reader, err := os.Open(oldname)
			if err != nil {
				return err
			}
			writer, err := os.Create(newname)
			if err != nil {
				return err
			}
			if _, err := io.Copy(writer, reader); err != nil {
				return err
			}
		}
	}
	if err := writeInode(inode, newname); err != nil {
		return err
	}
	if err := os.Remove(oldname); err != nil {
		return err
	}
	return nil
}

func renameDir(oldpath, newpath string,
	inode *filesystem.DirectoryInode) error {
	if err := os.Rename(oldpath, newpath); err == nil {
		return nil
	}
	if oldFi, err := os.Lstat(oldpath); err != nil {
		return err
	} else {
		if !oldFi.IsDir() {
			return fmt.Errorf("%s is not a directory", oldpath)
		}
	}
	if newFi, err := os.Lstat(newpath); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		if err := inode.Write(newpath); err != nil {
			return err
		}
	} else {
		if !newFi.IsDir() {
			return fmt.Errorf("%s is not a directory", newpath)
		}
		if err := inode.WriteMetadata(newpath); err != nil {
			return err
		}
	}
	if err := os.Remove(oldpath); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix file leak in lib/filesystem/util.link() function.<commit_after>package util

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"syscall"
	"time"

	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/format"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
)

const (
	dirPerms  = syscall.S_IRWXU
	filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP
)

func createEmptyFile(filename string) error {
	if file, err := os.Create(filename); err != nil {
		return err
	} else {
		// Don't wait for finaliser to close, otherwise we can have too many
		// open files.
		file.Close()
		return nil
	}
}

func unpack(fs *filesystem.FileSystem, objectsGetter objectserver.ObjectsGetter,
	dirname string, logger log.Logger) error {
	for _, entry := range fs.EntryList {
		if entry.Name == ".inodes" {
			return errors.New("cannot unpack a file-system with /.inodes")
		}
	}
	os.Mkdir(dirname, dirPerms)
	inodesDir := path.Join(dirname, ".inodes")
	if err := os.Mkdir(inodesDir, dirPerms); err != nil {
		return err
	}
	defer os.RemoveAll(inodesDir)
	var statfs syscall.Statfs_t
	if err := syscall.Statfs(inodesDir, &statfs); err != nil {
		return errors.New(fmt.Sprintf("Unable to Statfs: %s %s\n",
			inodesDir, err))
	}
	if fs.TotalDataBytes > uint64(statfs.Bsize)*statfs.Bfree {
		return errors.New("image will not fit on file-system")
	}
	hashes, inums, lengths := getHashes(fs)
	err := writeObjects(objectsGetter, hashes, inums, lengths, inodesDir,
		logger)
	if err != nil {
		return err
	}
	startWriteTime := time.Now()
	if err := writeInodes(fs.InodeTable, inodesDir); err != nil {
		return err
	}
	if err = fs.DirectoryInode.Write(dirname); err != nil {
		return err
	}
	startBuildTime := time.Now()
	writeDuration := startBuildTime.Sub(startWriteTime)
	err = buildTree(&fs.DirectoryInode, dirname, "", inodesDir)
	if err != nil {
		return err
	}
	buildDuration := time.Since(startBuildTime)
	logger.Printf("Unpacked file-system: made inodes in %s, built tree in %s\n",
		format.Duration(writeDuration), format.Duration(buildDuration))
	return nil
}

func getHashes(fs *filesystem.FileSystem) ([]hash.Hash, []uint64, []uint64) {
	hashes := make([]hash.Hash, 0, fs.NumRegularInodes)
	inums := make([]uint64, 0, fs.NumRegularInodes)
	lengths := make([]uint64, 0, fs.NumRegularInodes)
	for inum, inode := range fs.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				hashes = append(hashes, inode.Hash)
				inums = append(inums, inum)
				lengths = append(lengths, inode.Size)
			}
		}
	}
	return hashes, inums, lengths
}

func writeObjects(objectsGetter objectserver.ObjectsGetter, hashes []hash.Hash,
	inums []uint64, lengths []uint64, inodesDir string,
	logger log.Logger) error {
	startTime := time.Now()
	objectsReader, err := objectsGetter.GetObjects(hashes)
	if err != nil {
		return fmt.Errorf("error getting object reader: %s\n", err)
	}
	defer objectsReader.Close()
	var totalLength uint64
	buffer := make([]byte, 32<<10)
	for index := range hashes {
		err = writeObject(objectsReader, inums[index], lengths[index],
			inodesDir, buffer)
		if err != nil {
			return err
		}
		totalLength += lengths[index]
	}
	duration := time.Since(startTime)
	speed := uint64(float64(totalLength) / duration.Seconds())
	logger.Printf("Copied %d objects (%s) in %s (%s/s)\n",
		len(hashes), format.FormatBytes(totalLength), format.Duration(duration),
		format.FormatBytes(speed))
	return nil
}

func writeObject(objectsReader objectserver.ObjectsReader, inodeNumber uint64,
	length uint64, inodesDir string, buffer []byte) error {
	rlength, reader, err := objectsReader.NextObject()
	if err != nil {
		return err
	}
	defer reader.Close()
	if rlength != length {
		return errors.New("mismatched lengths")
	}
	filename := path.Join(inodesDir, fmt.Sprintf("%d", inodeNumber))
	destFile, err := os.OpenFile(filename,
		os.O_CREATE|os.O_TRUNC|os.O_WRONLY, filePerms)
	if err != nil {
		return err
	}
	doClose := true
	defer func() {
		if doClose {
			destFile.Close()
		}
	}()
	iLength := int64(length)
	nCopied, err := io.CopyBuffer(destFile, io.LimitReader(reader, iLength),
		buffer)
	if err != nil {
		return fmt.Errorf("error copying: %s", err)
	}
	if nCopied != iLength {
		return fmt.Errorf("expected length: %d, got: %d for: %s\n",
			length, nCopied, filename)
	}
	doClose = false
	return destFile.Close()
}

func writeInode(inode filesystem.GenericInode, filename string) error {
	switch inode := inode.(type) {
	case *filesystem.RegularInode:
		if inode.Size < 1 {
			if err := createEmptyFile(filename); err != nil {
				return err
			}
		}
		if err := inode.WriteMetadata(filename); err != nil {
			return err
		}
	case *filesystem.ComputedRegularInode:
		if err := createEmptyFile(filename); err != nil {
			return err
		}
		tmpInode := &filesystem.RegularInode{
			Mode: inode.Mode,
			Uid:  inode.Uid,
			Gid:  inode.Gid,
		}
		if err := tmpInode.WriteMetadata(filename); err != nil {
			return err
		}
	case *filesystem.SymlinkInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	case *filesystem.SpecialInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	case *filesystem.DirectoryInode:
		if err := inode.Write(filename); err != nil {
			return err
		}
	default:
		return errors.New("unsupported inode type")
	}
	return nil
}

func writeInodes(inodeTable filesystem.InodeTable, inodesDir string) error {
	for inodeNumber, inode := range inodeTable {
		filename := path.Join(inodesDir, fmt.Sprintf("%d", inodeNumber))
		if err := writeInode(inode, filename); err != nil {
			return err
		}
	}
	return nil
}

func buildTree(directory *filesystem.DirectoryInode,
	rootDir, mySubPathName, inodesDir string) error {
	for _, dirent := range directory.EntryList {
		oldPath := path.Join(inodesDir, fmt.Sprintf("%d", dirent.InodeNumber))
		newSubPath := path.Join(mySubPathName, dirent.Name)
		newFullPath := path.Join(rootDir, newSubPath)
		if inode := dirent.Inode(); inode == nil {
			panic("no inode pointer for: " + newSubPath)
		} else if dinode, ok := inode.(*filesystem.DirectoryInode); ok {
			if err := renameDir(oldPath, newFullPath, dinode); err != nil {
				return err
			}
			err := buildTree(dinode, rootDir, newSubPath, inodesDir)
			if err != nil {
				return err
			}
		} else {
			if err := link(oldPath, newFullPath, inode); err != nil {
				if !os.IsNotExist(err) {
					return err
				}
			}
		}
	}
	return nil
}

func link(oldname, newname string, inode filesystem.GenericInode) error {
	if err := os.Link(oldname, newname); err == nil {
		return nil
	}
	if finode, ok := inode.(*filesystem.RegularInode); ok {
		if finode.Size > 0 {
			reader, err := os.Open(oldname)
			if err != nil {
				return err
			}
			defer reader.Close()
			writer, err := os.Create(newname)
			if err != nil {
				return err
			}
			defer writer.Close()
			if _, err := io.Copy(writer, reader); err != nil {
				return err
			}
		}
	}
	if err := writeInode(inode, newname); err != nil {
		return err
	}
	return nil
}

func renameDir(oldpath, newpath string,
	inode *filesystem.DirectoryInode) error {
	if err := os.Rename(oldpath, newpath); err == nil {
		return nil
	}
	if oldFi, err := os.Lstat(oldpath); err != nil {
		return err
	} else {
		if !oldFi.IsDir() {
			return fmt.Errorf("%s is not a directory", oldpath)
		}
	}
	if newFi, err := os.Lstat(newpath); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		if err := inode.Write(newpath); err != nil {
			return err
		}
	} else {
		if !newFi.IsDir() {
			return fmt.Errorf("%s is not a directory", newpath)
		}
		if err := inode.WriteMetadata(newpath); err != nil {
			return err
		}
	}
	if err := os.Remove(oldpath); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package flow

import (
	"bytes"
	"fmt"
	"os"
	"os/signal"
	"path"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	pkgPath      = reflect.TypeOf(Flow{}).PkgPath()
	DefaultDebug = false
)

type debugInfo struct {
	Stack string
	Info  string
}

func (d *debugInfo) String() string {
	return d.Stack + " - " + d.Info
}

type Flow struct {
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32
	exited   int32
	onClose  []func()
	id       uintptr

	mutex   sync.Mutex
	debug   []debugInfo
	printed int32
}

func NewEx(n int) *Flow {
	f := &Flow{
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.appendDebug("init")
	return f
}

func New() *Flow {
	return NewEx(0)
}

func (f *Flow) WaitNotify(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	case <-f.IsClose():
		return false
	}
}

func (f *Flow) MarkExit() bool {
	return atomic.CompareAndSwapInt32(&f.exited, 0, 1)
}

func (f *Flow) IsExit() bool {
	return atomic.LoadInt32(&f.exited) == 1
}

func (f *Flow) printDebug() {
	buf := bytes.NewBuffer(nil)
	maxLength := 0
	for _, d := range f.debug {
		if maxLength < len(d.Stack) {
			maxLength = len(d.Stack)
		}
	}
	fill := func(a string, n int) string {
		return a + strings.Repeat(" ", n-len(a))
	}
	buf.WriteString("\n")
	for _, d := range f.debug {
		buf.WriteString(fmt.Sprint(&f) + " ")
		buf.WriteString(fill(d.Stack, maxLength) + " - " + d.Info + "\n")
	}
	print(buf.String())
}

func (f *Flow) appendDebug(info string) {
	pc, fp, line, _ := runtime.Caller(f.getCaller())
	name := runtime.FuncForPC(pc).Name()
	stack := fmt.Sprintf("%v:%v %v", path.Base(fp), line, path.Base(name))
	f.debug = append(f.debug, debugInfo{stack, info})
}

func (f *Flow) SetOnClose(exit func()) *Flow {
	f.onClose = []func(){exit}
	return f
}

func (f *Flow) AddOnClose(exit func()) *Flow {
	f.onClose = append(f.onClose, exit)
	return f
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) Tick(t *time.Ticker) bool {
	select {
	case <-t.C:
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) ForkTo(ref **Flow, exit func()) {
	*ref = f.Fork(0).AddOnClose(exit)
}

func (f *Flow) Fork(n int) *Flow {
	f2 := NewEx(n)
	f2.Parent = f
	// TODO(chzyer): test it !
	f2.errChan = f.errChan
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2
	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	f.appendDebug("close")
	f.close()
}

func (f *Flow) close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}
	f.appendDebug("stop")

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
	if len(f.onClose) > 0 {
		go func() {
			for _, f := range f.onClose {
				f()
			}
		}()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	atomic.AddInt32(f.ref, int32(n))
	f.appendDebug(fmt.Sprintf("add: %v, ref: %v", n, *f.ref))
	f.wg.Add(n)
}

func (f *Flow) getCaller() int {
	for i := 0; ; i++ {
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}
		f := runtime.FuncForPC(pc).Name()
		if !strings.HasPrefix(f, pkgPath) {
			return i - 1
		}
	}
	return 0
}

func (f *Flow) Done() {
	f.wg.Done()
	if atomic.AddInt32(f.ref, -1) == 0 {
		f.Stop()
	}
}

func (f *Flow) DoneAndClose() {
	f.Done()
	f.appendDebug(fmt.Sprintf("done and close, ref: %v", *f.ref))
	f.Stop()
}

func (f *Flow) wait() {
	f.appendDebug("wait")

	done := make(chan struct{})
	printed := int32(0)
	if DefaultDebug && atomic.CompareAndSwapInt32(&f.printed, 0, 1) {
		go func() {
			select {
			case <-done:
				return
			case <-time.After(1000 * time.Millisecond):
				f.printDebug()
				atomic.StoreInt32(&printed, 1)
			}
		}()
	}
	<-f.stopChan
	f.wg.Wait()
	close(done)
	if atomic.LoadInt32(&printed) == 1 {
		println(fmt.Sprint(&f) + " - exit")
	}

	if f.Parent != nil {
		f.Parent.Done()
		f.Parent = nil
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
		f.appendDebug("got closed")
	case <-signalChan:
		f.appendDebug("got signal")
		f.Stop()
	case err = <-f.errChan:
		f.appendDebug(fmt.Sprintf("got error: %v", err))

		if err != nil {
			f.Stop()
		}
	}

	go func() {
		<-signalChan
		// force close
		println("force close")
		os.Exit(1)
	}()

	f.wait()
	return err
}
<commit_msg>add GetDebug() []byte<commit_after>package flow

import (
	"bytes"
	"fmt"
	"os"
	"os/signal"
	"path"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

var (
	pkgPath      = reflect.TypeOf(Flow{}).PkgPath()
	DefaultDebug = false
)

type debugInfo struct {
	Stack string
	Info  string
}

func (d *debugInfo) String() string {
	return d.Stack + " - " + d.Info
}

type Flow struct {
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32
	exited   int32
	onClose  []func()
	id       uintptr

	mutex   sync.Mutex
	debug   []debugInfo
	printed int32
}

func NewEx(n int) *Flow {
	f := &Flow{
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.appendDebug("init")
	return f
}

func New() *Flow {
	return NewEx(0)
}

func (f *Flow) WaitNotify(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	case <-f.IsClose():
		return false
	}
}

func (f *Flow) MarkExit() bool {
	return atomic.CompareAndSwapInt32(&f.exited, 0, 1)
}

func (f *Flow) IsExit() bool {
	return atomic.LoadInt32(&f.exited) == 1
}

func (f *Flow) GetDebug() []byte {
	buf := bytes.NewBuffer(nil)
	maxLength := 0
	for _, d := range f.debug {
		if maxLength < len(d.Stack) {
			maxLength = len(d.Stack)
		}
	}
	fill := func(a string, n int) string {
		return a + strings.Repeat(" ", n-len(a))
	}
	buf.WriteString("\n")
	for _, d := range f.debug {
		buf.WriteString(fill(d.Stack, maxLength) + " - " + d.Info + "\n")
	}
	return buf.Bytes()
}

func (f *Flow) printDebug() {
	println(string(f.GetDebug()))
}

func (f *Flow) appendDebug(info string) {
	pc, fp, line, _ := runtime.Caller(f.getCaller())
	name := runtime.FuncForPC(pc).Name()
	stack := fmt.Sprintf("%v:%v %v", path.Base(fp), line, path.Base(name))
	f.debug = append(f.debug, debugInfo{stack, info})
}

func (f *Flow) SetOnClose(exit func()) *Flow {
	f.onClose = []func(){exit}
	return f
}

func (f *Flow) AddOnClose(exit func()) *Flow {
	f.onClose = append(f.onClose, exit)
	return f
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) Tick(t *time.Ticker) bool {
	select {
	case <-t.C:
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) ForkTo(ref **Flow, exit func()) {
	*ref = f.Fork(0).AddOnClose(exit)
}

func (f *Flow) Fork(n int) *Flow {
	f2 := NewEx(n)
	f2.Parent = f
	// TODO(chzyer): test it !
	f2.errChan = f.errChan
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2
	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	f.appendDebug("close")
	f.close()
}

func (f *Flow) close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}
	f.appendDebug("stop")

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
	if len(f.onClose) > 0 {
		go func() {
			for _, f := range f.onClose {
				f()
			}
		}()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	atomic.AddInt32(f.ref, int32(n))
	f.appendDebug(fmt.Sprintf("add: %v, ref: %v", n, *f.ref))
	f.wg.Add(n)
}

func (f *Flow) getCaller() int {
	for i := 0; ; i++ {
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}
		f := runtime.FuncForPC(pc).Name()
		if !strings.HasPrefix(f, pkgPath) {
			return i - 1
		}
	}
	return 0
}

func (f *Flow) Done() {
	f.wg.Done()
	if atomic.AddInt32(f.ref, -1) == 0 {
		f.Stop()
	}
}

func (f *Flow) DoneAndClose() {
	f.Done()
	f.appendDebug(fmt.Sprintf("done and close, ref: %v", *f.ref))
	f.Stop()
}

func (f *Flow) wait() {
	f.appendDebug("wait")

	done := make(chan struct{})
	printed := int32(0)
	if DefaultDebug && atomic.CompareAndSwapInt32(&f.printed, 0, 1) {
		go func() {
			select {
			case <-done:
				return
			case <-time.After(1000 * time.Millisecond):
				f.printDebug()
				atomic.StoreInt32(&printed, 1)
			}
		}()
	}
	<-f.stopChan
	f.wg.Wait()
	close(done)
	if atomic.LoadInt32(&printed) == 1 {
		println(fmt.Sprint(&f) + " - exit")
	}

	if f.Parent != nil {
		f.Parent.Done()
		f.Parent = nil
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
		f.appendDebug("got closed")
	case <-signalChan:
		f.appendDebug("got signal")
		f.Stop()
	case err = <-f.errChan:
		f.appendDebug(fmt.Sprintf("got error: %v", err))

		if err != nil {
			f.Stop()
		}
	}

	go func() {
		<-signalChan
		// force close
		println("force close")
		os.Exit(1)
	}()

	f.wait()
	return err
}
<|endoftext|>


<commit_before>// Package form provides an easy to use way to parse form values from an HTTP
// request into a struct
package form // import "vimagination.zapto.org/form"

import (
	"net/http"
	"reflect"
	"strings"
	"sync"
)

var interType = reflect.TypeOf((*formParser)(nil)).Elem()

type processorDetails struct {
	processor
	Post, Required bool
	Index          []int
}

type typeMap map[string]processorDetails

var (
	tmMu     sync.RWMutex
	typeMaps = make(map[reflect.Type]typeMap)
)

func getTypeMap(t reflect.Type) typeMap {
	tmMu.RLock()
	tm, ok := typeMaps[t]
	tmMu.RUnlock()
	if ok {
		return tm
	}
	tmMu.Lock()
	tm = createTypeMap(t)
	tmMu.Unlock()
	return tm
}

func basicTypeProcessor(t reflect.Type, tag reflect.StructTag) processor {
	switch t.Kind() {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return newInum(tag, t.Bits())
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return newUnum(tag, t.Bits())
	case reflect.Float32, reflect.Float64:
		return newFloat(tag, t.Bits())
	case reflect.String:
		return newString(tag)
	case reflect.Bool:
		return boolean{}
	}
	return nil
}

func createTypeMap(t reflect.Type) typeMap {
	tm, ok := typeMaps[t]
	if ok {
		return tm
	}
	tm = make(typeMap)
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if f.PkgPath != "" {
			continue
		}
		name := f.Name
		var required, post bool
		if n := f.Tag.Get("form"); n == "-" {
			continue
		} else if n != "" {
			p := strings.IndexByte(n, ',')
			if p >= 0 {
				if p > 0 {
					name = n[:p]
				}
				rest := n[p:]
				required = strings.Contains(rest, ",required,") || strings.HasSuffix(rest, ",required")
				post = strings.Contains(rest, ",post,") || strings.HasSuffix(rest, ",post")
			} else {
				name = n
			}
		}
		var p processor
		if f.Type.Implements(interType) {
			p = inter(false)
		} else if reflect.PtrTo(f.Type).Implements(interType) {
			p = inter(true)
		} else if k := f.Type.Kind(); k == reflect.Slice || k == reflect.Ptr {
			et := f.Type.Elem()
			s := basicTypeProcessor(et, f.Tag)
			if s == nil {
				continue
			}
			if k == reflect.Slice {
				p = slice{
					processor: s,
					typ:       reflect.SliceOf(et),
				}
			} else {
				p = pointer{
					processor: s,
					typ:       et,
				}
			}
		} else if k == reflect.Struct && f.Anonymous {
			for n, p := range createTypeMap(f.Type) {
				if _, ok := tm[n]; !ok {
					tm[n] = processorDetails{
						processor: p.processor,
						Required:  p.Required,
						Post:      p.Post,
						Index:     append(append(make([]int, 0, len(p.Index)+1), i), p.Index...),
					}
				}
			}
			continue
		} else {
			p = basicTypeProcessor(f.Type, f.Tag)
			if p == nil {
				continue
			}
		}
		tm[name] = processorDetails{
			processor: p,
			Required:  required,
			Post:      post,
			Index:     []int{i},
		}
	}
	typeMaps[t] = tm
	return tm
}

// Process parses the form data from the request into the passed value, which
// must be a pointer to a struct.
//
// Form keys are assumed to be the field names unless a 'form' tag is provided
// with an alternate name, for example, in the following struct, the int is
// parse with key 'A' and the bool is parsed with key 'C'.
//
// type Example struct {
//	A int
//	B bool `form:"C"`
// }
//
// Two options can be added to the form tag to modify the processing. The
// 'post' option forces the processer to parse a value from the PostForm field
// of the Request, and the 'required' option will have an error thrown if the
// key in not set.
//
// Number types can also have minimums and maximums checked during processing
// by setting the 'min' and 'max' tags accordingly.
//
// In a similar vein, string types can utilise the 'regex' tag to set a
// regular expression to be matched against.
//
// Lastly, a custom data processor can be specified by attaching a method to
// the field type with the following specification:
//
// ParseForm([]string) error
func Process(r *http.Request, fv interface{}) error {
	v := reflect.ValueOf(fv)
	if v.Kind() != reflect.Ptr {
		return ErrNeedPointer
	}
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return ErrNeedStruct
	}
	tm := getTypeMap(v.Type())
	if err := r.ParseForm(); err != nil {
		return err
	}
	var errors ErrorMap
	for key, pd := range tm {
		var (
			val []string
			ok  bool
		)
		if pd.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := pd.processor.process(v.FieldByIndex(pd.Index), val); err != nil {
				if errors == nil {
					errors = make(ErrorMap)
				}
				errors[key] = err
			}
		} else if pd.Required {
			if errors == nil {
				errors = make(ErrorMap)
			}
			errors[key] = ErrRequiredMissing
		}
	}
	if len(errors) > 0 {
		return errors
	}
	return nil
}
<commit_msg>added more detail for Process comment<commit_after>// Package form provides an easy to use way to parse form values from an HTTP
// request into a struct
package form // import "vimagination.zapto.org/form"

import (
	"net/http"
	"reflect"
	"strings"
	"sync"
)

var interType = reflect.TypeOf((*formParser)(nil)).Elem()

type processorDetails struct {
	processor
	Post, Required bool
	Index          []int
}

type typeMap map[string]processorDetails

var (
	tmMu     sync.RWMutex
	typeMaps = make(map[reflect.Type]typeMap)
)

func getTypeMap(t reflect.Type) typeMap {
	tmMu.RLock()
	tm, ok := typeMaps[t]
	tmMu.RUnlock()
	if ok {
		return tm
	}
	tmMu.Lock()
	tm = createTypeMap(t)
	tmMu.Unlock()
	return tm
}

func basicTypeProcessor(t reflect.Type, tag reflect.StructTag) processor {
	switch t.Kind() {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return newInum(tag, t.Bits())
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return newUnum(tag, t.Bits())
	case reflect.Float32, reflect.Float64:
		return newFloat(tag, t.Bits())
	case reflect.String:
		return newString(tag)
	case reflect.Bool:
		return boolean{}
	}
	return nil
}

func createTypeMap(t reflect.Type) typeMap {
	tm, ok := typeMaps[t]
	if ok {
		return tm
	}
	tm = make(typeMap)
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if f.PkgPath != "" {
			continue
		}
		name := f.Name
		var required, post bool
		if n := f.Tag.Get("form"); n == "-" {
			continue
		} else if n != "" {
			p := strings.IndexByte(n, ',')
			if p >= 0 {
				if p > 0 {
					name = n[:p]
				}
				rest := n[p:]
				required = strings.Contains(rest, ",required,") || strings.HasSuffix(rest, ",required")
				post = strings.Contains(rest, ",post,") || strings.HasSuffix(rest, ",post")
			} else {
				name = n
			}
		}
		var p processor
		if f.Type.Implements(interType) {
			p = inter(false)
		} else if reflect.PtrTo(f.Type).Implements(interType) {
			p = inter(true)
		} else if k := f.Type.Kind(); k == reflect.Slice || k == reflect.Ptr {
			et := f.Type.Elem()
			s := basicTypeProcessor(et, f.Tag)
			if s == nil {
				continue
			}
			if k == reflect.Slice {
				p = slice{
					processor: s,
					typ:       reflect.SliceOf(et),
				}
			} else {
				p = pointer{
					processor: s,
					typ:       et,
				}
			}
		} else if k == reflect.Struct && f.Anonymous {
			for n, p := range createTypeMap(f.Type) {
				if _, ok := tm[n]; !ok {
					tm[n] = processorDetails{
						processor: p.processor,
						Required:  p.Required,
						Post:      p.Post,
						Index:     append(append(make([]int, 0, len(p.Index)+1), i), p.Index...),
					}
				}
			}
			continue
		} else {
			p = basicTypeProcessor(f.Type, f.Tag)
			if p == nil {
				continue
			}
		}
		tm[name] = processorDetails{
			processor: p,
			Required:  required,
			Post:      post,
			Index:     []int{i},
		}
	}
	typeMaps[t] = tm
	return tm
}

// Process parses the form data from the request into the passed value, which
// must be a pointer to a struct.
//
// Form keys are assumed to be the field names unless a 'form' tag is provided
// with an alternate name, for example, in the following struct, the int is
// parse with key 'A' and the bool is parsed with key 'C'.
//
// type Example struct {
//	A int
//	B bool `form:"C"`
// }
//
// Two options can be added to the form tag to modify the processing. The
// 'post' option forces the processer to parse a value from the PostForm field
// of the Request, and the 'required' option will have an error thrown if the
// key in not set.
//
// Number types can also have minimums and maximums checked during processing
// by setting the 'min' and 'max' tags accordingly.
//
// In a similar vein, string types can utilise the 'regex' tag to set a
// regular expression to be matched against.
//
// Anonymous structs are traversed, but will not override more local fields.
//
// Slices of basic types can be processed, and errors returned from any such
// processing will be of the Errors type, which each indexed entry
// corresponding to the index of the processed data.
//
// Pointers to basic types can also be processed, with the type being allocated
// even if an error occurs.
//
// Lastly, a custom data processor can be specified by attaching a method to
// the field type with the following specification:
//
// ParseForm([]string) error
func Process(r *http.Request, fv interface{}) error {
	v := reflect.ValueOf(fv)
	if v.Kind() != reflect.Ptr {
		return ErrNeedPointer
	}
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return ErrNeedStruct
	}
	tm := getTypeMap(v.Type())
	if err := r.ParseForm(); err != nil {
		return err
	}
	var errors ErrorMap
	for key, pd := range tm {
		var (
			val []string
			ok  bool
		)
		if pd.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := pd.processor.process(v.FieldByIndex(pd.Index), val); err != nil {
				if errors == nil {
					errors = make(ErrorMap)
				}
				errors[key] = err
			}
		} else if pd.Required {
			if errors == nil {
				errors = make(ErrorMap)
			}
			errors[key] = ErrRequiredMissing
		}
	}
	if len(errors) > 0 {
		return errors
	}
	return nil
}
<|endoftext|>


<commit_before>// +build gofuzz
package amqp

import "bytes"

func Fuzz(data []byte) int {
	r := reader{bytes.NewReader(data)}
	frame, err := r.ReadFrame()
	if err != nil {
		if frame != nil {
			panic("frame is not nil")
		}
		return 0
	}
	return 1
}
<commit_msg>the +build tag isn't a doc comment<commit_after>// +build gofuzz

package amqp

import "bytes"

func Fuzz(data []byte) int {
	r := reader{bytes.NewReader(data)}
	frame, err := r.ReadFrame()
	if err != nil {
		if frame != nil {
			panic("frame is not nil")
		}
		return 0
	}
	return 1
}
<|endoftext|>


<commit_before>package main

import (
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/davecgh/go-spew/spew"
)

func TestItemAssembly(t *testing.T) {
	var tests = []testpair{
		{
			`>\C[14]…今は使用できません。`,
			`>\C[14]…今は使用できません。`,
		},
		{
			`【\C[14]\N[2]\C[0]】　\{アハァァーーーンッ！！`,
			`【\C[14]\N[2]\C[0]】　\{ アハァァーーーンッ！！`,
		},
		{
			`疾風苦無(消費1)　en(v[25] >= 1)`,
			`疾風苦無 (消費 1)　en(v[25] >= 1)`,
		},
		{
			`PT加入en(!s[484] and v[25] <2)`,
			`PT 加入 en(!s[484] and v[25] <2)`,
		},
		{
			`\i[21]メンタルキュア`,
			`\i[21] メンタルキュア`,
		},
		{
			`"0x#{text}"`,
			`"0x#{text}"`,
		},
		{
			`[レース10]`,
			`[レース 10]`,
		},
	}

	for _, pair := range tests {
		//pair.input = unescapeText(pair.input)
		items, err := parseText(pair.input)
		if err != nil {
			log.Errorf("%s\ntext: %q", err, pair.input)
			log.Error(spew.Sdump(items))
		} else {
			log.Debug(spew.Sdump(items))
		}

		r := assembleItems(items)

		if r != pair.output {
			t.Errorf("For input:\n%q\nexpected:\n%q\ngot:\n%q\n", pair.input, pair.output, r)
		}
	}
}
<commit_msg>Dump items on error<commit_after>package main

import (
	"testing"

	log "github.com/Sirupsen/logrus"
	"github.com/davecgh/go-spew/spew"
)

func TestItemAssembly(t *testing.T) {
	var tests = []testpair{
		{
			`>\C[14]…今は使用できません。`,
			`>\C[14]…今は使用できません。`,
		},
		{
			`【\C[14]\N[2]\C[0]】　\{アハァァーーーンッ！！`,
			`【\C[14]\N[2]\C[0]】　\{ アハァァーーーンッ！！`,
		},
		{
			`疾風苦無(消費1)　en(v[25] >= 1)`,
			`疾風苦無 (消費 1)　en(v[25] >= 1)`,
		},
		{
			`PT加入en(!s[484] and v[25] <2)`,
			`PT 加入 en(!s[484] and v[25] <2)`,
		},
		{
			`\i[21]メンタルキュア`,
			`\i[21] メンタルキュア`,
		},
		{
			`"0x#{text}"`,
			`"0x#{text}"`,
		},
		{
			`[レース10]`,
			`[レース 10]`,
		},
		{
			`%sの%sを %s 奪った`,
			`%s の %s を %s 奪った`,
		},
	}

	for _, pair := range tests {
		//pair.input = unescapeText(pair.input)
		items, err := parseText(pair.input)
		if err != nil {
			log.Errorf("%s\ntext: %q", err, pair.input)
			log.Error(spew.Sdump(items))
		} else {
			log.Debug(spew.Sdump(items))
		}

		r := assembleItems(items)

		if r != pair.output {
			t.Errorf("For input:\n%q\nexpected:\n%q\ngot:\n%q\nitems:\n%s", pair.input, pair.output, r, spew.Sdump(items))
		}
	}
}
<|endoftext|>


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

package tar

import (
	"bytes"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strings"
	"testing"
	"time"
)

func TestFileInfoHeader(t *testing.T) {
	fi, err := os.Stat("testdata/small.txt")
	if err != nil {
		t.Fatal(err)
	}
	h, err := FileInfoHeader(fi, "")
	if err != nil {
		t.Fatalf("FileInfoHeader: %v", err)
	}
	if g, e := h.Name, "small.txt"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e {
		t.Errorf("Mode = %#o; want %#o", g, e)
	}
	if g, e := h.Size, int64(5); g != e {
		t.Errorf("Size = %v; want %v", g, e)
	}
	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
		t.Errorf("ModTime = %v; want %v", g, e)
	}
}

func TestFileInfoHeaderDir(t *testing.T) {
	fi, err := os.Stat("testdata")
	if err != nil {
		t.Fatal(err)
	}
	h, err := FileInfoHeader(fi, "")
	if err != nil {
		t.Fatalf("FileInfoHeader: %v", err)
	}
	if g, e := h.Name, "testdata/"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	// Ignoring c_ISGID for golang.org/issue/4867
	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
		t.Errorf("Mode = %#o; want %#o", g, e)
	}
	if g, e := h.Size, int64(0); g != e {
		t.Errorf("Size = %v; want %v", g, e)
	}
	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
		t.Errorf("ModTime = %v; want %v", g, e)
	}
}

func TestFileInfoHeaderSymlink(t *testing.T) {
	h, err := FileInfoHeader(symlink{}, "some-target")
	if err != nil {
		t.Fatal(err)
	}
	if g, e := h.Name, "some-symlink"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	if g, e := h.Linkname, "some-target"; g != e {
		t.Errorf("Linkname = %q; want %q", g, e)
	}
}

type symlink struct{}

func (symlink) Name() string       { return "some-symlink" }
func (symlink) Size() int64        { return 0 }
func (symlink) Mode() os.FileMode  { return os.ModeSymlink }
func (symlink) ModTime() time.Time { return time.Time{} }
func (symlink) IsDir() bool        { return false }
func (symlink) Sys() interface{}   { return nil }

func TestRoundTrip(t *testing.T) {
	data := []byte("some file contents")

	var b bytes.Buffer
	tw := NewWriter(&b)
	hdr := &Header{
		Name:    "file.txt",
		Uid:     1 << 21, // too big for 8 octal digits
		Size:    int64(len(data)),
		ModTime: time.Now(),
	}
	// tar only supports second precision.
	hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond)
	if err := tw.WriteHeader(hdr); err != nil {
		t.Fatalf("tw.WriteHeader: %v", err)
	}
	if _, err := tw.Write(data); err != nil {
		t.Fatalf("tw.Write: %v", err)
	}
	if err := tw.Close(); err != nil {
		t.Fatalf("tw.Close: %v", err)
	}

	// Read it back.
	tr := NewReader(&b)
	rHdr, err := tr.Next()
	if err != nil {
		t.Fatalf("tr.Next: %v", err)
	}
	if !reflect.DeepEqual(rHdr, hdr) {
		t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
	}
	rData, err := ioutil.ReadAll(tr)
	if err != nil {
		t.Fatalf("Read: %v", err)
	}
	if !bytes.Equal(rData, data) {
		t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
	}
}

type headerRoundTripTest struct {
	h  *Header
	fm os.FileMode
}

func TestHeaderRoundTrip(t *testing.T) {
	golden := []headerRoundTripTest{
		// regular file.
		{
			h: &Header{
				Name:     "test.txt",
				Mode:     0644 | c_ISREG,
				Size:     12,
				ModTime:  time.Unix(1360600916, 0),
				Typeflag: TypeReg,
			},
			fm: 0644,
		},
		// hard link.
		{
			h: &Header{
				Name:     "hard.txt",
				Mode:     0644 | c_ISLNK,
				Size:     0,
				ModTime:  time.Unix(1360600916, 0),
				Typeflag: TypeLink,
			},
			fm: 0644 | os.ModeSymlink,
		},
		// symbolic link.
		{
			h: &Header{
				Name:     "link.txt",
				Mode:     0777 | c_ISLNK,
				Size:     0,
				ModTime:  time.Unix(1360600852, 0),
				Typeflag: TypeSymlink,
			},
			fm: 0777 | os.ModeSymlink,
		},
		// character device node.
		{
			h: &Header{
				Name:     "dev/null",
				Mode:     0666 | c_ISCHR,
				Size:     0,
				ModTime:  time.Unix(1360578951, 0),
				Typeflag: TypeChar,
			},
			fm: 0666 | os.ModeDevice | os.ModeCharDevice,
		},
		// block device node.
		{
			h: &Header{
				Name:     "dev/sda",
				Mode:     0660 | c_ISBLK,
				Size:     0,
				ModTime:  time.Unix(1360578954, 0),
				Typeflag: TypeBlock,
			},
			fm: 0660 | os.ModeDevice,
		},
		// directory.
		{
			h: &Header{
				Name:     "dir/",
				Mode:     0755 | c_ISDIR,
				Size:     0,
				ModTime:  time.Unix(1360601116, 0),
				Typeflag: TypeDir,
			},
			fm: 0755 | os.ModeDir,
		},
		// fifo node.
		{
			h: &Header{
				Name:     "dev/initctl",
				Mode:     0600 | c_ISFIFO,
				Size:     0,
				ModTime:  time.Unix(1360578949, 0),
				Typeflag: TypeFifo,
			},
			fm: 0600 | os.ModeNamedPipe,
		},
		// setuid.
		{
			h: &Header{
				Name:     "bin/su",
				Mode:     0755 | c_ISREG | c_ISUID,
				Size:     23232,
				ModTime:  time.Unix(1355405093, 0),
				Typeflag: TypeReg,
			},
			fm: 0755 | os.ModeSetuid,
		},
		// setguid.
		{
			h: &Header{
				Name:     "group.txt",
				Mode:     0750 | c_ISREG | c_ISGID,
				Size:     0,
				ModTime:  time.Unix(1360602346, 0),
				Typeflag: TypeReg,
			},
			fm: 0750 | os.ModeSetgid,
		},
		// sticky.
		{
			h: &Header{
				Name:     "sticky.txt",
				Mode:     0600 | c_ISREG | c_ISVTX,
				Size:     7,
				ModTime:  time.Unix(1360602540, 0),
				Typeflag: TypeReg,
			},
			fm: 0600 | os.ModeSticky,
		},
	}

	for i, g := range golden {
		fi := g.h.FileInfo()
		h2, err := FileInfoHeader(fi, "")
		if err != nil {
			t.Error(err)
			continue
		}
		if strings.Contains(fi.Name(), "/") {
			t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
		}
		name := path.Base(g.h.Name)
		if fi.IsDir() {
			name += "/"
		}
		if got, want := h2.Name, name; got != want {
			t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
		}
		if got, want := h2.Size, g.h.Size; got != want {
			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
		}
		if got, want := h2.Mode, g.h.Mode; got != want {
			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
		}
		if got, want := fi.Mode(), g.fm; got != want {
			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
		}
		if got, want := h2.ModTime, g.h.ModTime; got != want {
			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
		}
		if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
			t.Errorf("i=%d: Sys didn't return original *Header", i)
		}
	}
}
<commit_msg>archive/tar: add test case for passing nil to FileInfoHeader<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tar

import (
	"bytes"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strings"
	"testing"
	"time"
)

func TestFileInfoHeader(t *testing.T) {
	fi, err := os.Stat("testdata/small.txt")
	if err != nil {
		t.Fatal(err)
	}
	h, err := FileInfoHeader(fi, "")
	if err != nil {
		t.Fatalf("FileInfoHeader: %v", err)
	}
	if g, e := h.Name, "small.txt"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e {
		t.Errorf("Mode = %#o; want %#o", g, e)
	}
	if g, e := h.Size, int64(5); g != e {
		t.Errorf("Size = %v; want %v", g, e)
	}
	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
		t.Errorf("ModTime = %v; want %v", g, e)
	}
	// FileInfoHeader should error when passing nil FileInfo
	if _, err := FileInfoHeader(nil, ""); err == nil {
		t.Fatalf("Expected error when passing nil to FileInfoHeader")
	}
}

func TestFileInfoHeaderDir(t *testing.T) {
	fi, err := os.Stat("testdata")
	if err != nil {
		t.Fatal(err)
	}
	h, err := FileInfoHeader(fi, "")
	if err != nil {
		t.Fatalf("FileInfoHeader: %v", err)
	}
	if g, e := h.Name, "testdata/"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	// Ignoring c_ISGID for golang.org/issue/4867
	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
		t.Errorf("Mode = %#o; want %#o", g, e)
	}
	if g, e := h.Size, int64(0); g != e {
		t.Errorf("Size = %v; want %v", g, e)
	}
	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
		t.Errorf("ModTime = %v; want %v", g, e)
	}
}

func TestFileInfoHeaderSymlink(t *testing.T) {
	h, err := FileInfoHeader(symlink{}, "some-target")
	if err != nil {
		t.Fatal(err)
	}
	if g, e := h.Name, "some-symlink"; g != e {
		t.Errorf("Name = %q; want %q", g, e)
	}
	if g, e := h.Linkname, "some-target"; g != e {
		t.Errorf("Linkname = %q; want %q", g, e)
	}
}

type symlink struct{}

func (symlink) Name() string       { return "some-symlink" }
func (symlink) Size() int64        { return 0 }
func (symlink) Mode() os.FileMode  { return os.ModeSymlink }
func (symlink) ModTime() time.Time { return time.Time{} }
func (symlink) IsDir() bool        { return false }
func (symlink) Sys() interface{}   { return nil }

func TestRoundTrip(t *testing.T) {
	data := []byte("some file contents")

	var b bytes.Buffer
	tw := NewWriter(&b)
	hdr := &Header{
		Name:    "file.txt",
		Uid:     1 << 21, // too big for 8 octal digits
		Size:    int64(len(data)),
		ModTime: time.Now(),
	}
	// tar only supports second precision.
	hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond)
	if err := tw.WriteHeader(hdr); err != nil {
		t.Fatalf("tw.WriteHeader: %v", err)
	}
	if _, err := tw.Write(data); err != nil {
		t.Fatalf("tw.Write: %v", err)
	}
	if err := tw.Close(); err != nil {
		t.Fatalf("tw.Close: %v", err)
	}

	// Read it back.
	tr := NewReader(&b)
	rHdr, err := tr.Next()
	if err != nil {
		t.Fatalf("tr.Next: %v", err)
	}
	if !reflect.DeepEqual(rHdr, hdr) {
		t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
	}
	rData, err := ioutil.ReadAll(tr)
	if err != nil {
		t.Fatalf("Read: %v", err)
	}
	if !bytes.Equal(rData, data) {
		t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
	}
}

type headerRoundTripTest struct {
	h  *Header
	fm os.FileMode
}

func TestHeaderRoundTrip(t *testing.T) {
	golden := []headerRoundTripTest{
		// regular file.
		{
			h: &Header{
				Name:     "test.txt",
				Mode:     0644 | c_ISREG,
				Size:     12,
				ModTime:  time.Unix(1360600916, 0),
				Typeflag: TypeReg,
			},
			fm: 0644,
		},
		// hard link.
		{
			h: &Header{
				Name:     "hard.txt",
				Mode:     0644 | c_ISLNK,
				Size:     0,
				ModTime:  time.Unix(1360600916, 0),
				Typeflag: TypeLink,
			},
			fm: 0644 | os.ModeSymlink,
		},
		// symbolic link.
		{
			h: &Header{
				Name:     "link.txt",
				Mode:     0777 | c_ISLNK,
				Size:     0,
				ModTime:  time.Unix(1360600852, 0),
				Typeflag: TypeSymlink,
			},
			fm: 0777 | os.ModeSymlink,
		},
		// character device node.
		{
			h: &Header{
				Name:     "dev/null",
				Mode:     0666 | c_ISCHR,
				Size:     0,
				ModTime:  time.Unix(1360578951, 0),
				Typeflag: TypeChar,
			},
			fm: 0666 | os.ModeDevice | os.ModeCharDevice,
		},
		// block device node.
		{
			h: &Header{
				Name:     "dev/sda",
				Mode:     0660 | c_ISBLK,
				Size:     0,
				ModTime:  time.Unix(1360578954, 0),
				Typeflag: TypeBlock,
			},
			fm: 0660 | os.ModeDevice,
		},
		// directory.
		{
			h: &Header{
				Name:     "dir/",
				Mode:     0755 | c_ISDIR,
				Size:     0,
				ModTime:  time.Unix(1360601116, 0),
				Typeflag: TypeDir,
			},
			fm: 0755 | os.ModeDir,
		},
		// fifo node.
		{
			h: &Header{
				Name:     "dev/initctl",
				Mode:     0600 | c_ISFIFO,
				Size:     0,
				ModTime:  time.Unix(1360578949, 0),
				Typeflag: TypeFifo,
			},
			fm: 0600 | os.ModeNamedPipe,
		},
		// setuid.
		{
			h: &Header{
				Name:     "bin/su",
				Mode:     0755 | c_ISREG | c_ISUID,
				Size:     23232,
				ModTime:  time.Unix(1355405093, 0),
				Typeflag: TypeReg,
			},
			fm: 0755 | os.ModeSetuid,
		},
		// setguid.
		{
			h: &Header{
				Name:     "group.txt",
				Mode:     0750 | c_ISREG | c_ISGID,
				Size:     0,
				ModTime:  time.Unix(1360602346, 0),
				Typeflag: TypeReg,
			},
			fm: 0750 | os.ModeSetgid,
		},
		// sticky.
		{
			h: &Header{
				Name:     "sticky.txt",
				Mode:     0600 | c_ISREG | c_ISVTX,
				Size:     7,
				ModTime:  time.Unix(1360602540, 0),
				Typeflag: TypeReg,
			},
			fm: 0600 | os.ModeSticky,
		},
	}

	for i, g := range golden {
		fi := g.h.FileInfo()
		h2, err := FileInfoHeader(fi, "")
		if err != nil {
			t.Error(err)
			continue
		}
		if strings.Contains(fi.Name(), "/") {
			t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
		}
		name := path.Base(g.h.Name)
		if fi.IsDir() {
			name += "/"
		}
		if got, want := h2.Name, name; got != want {
			t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
		}
		if got, want := h2.Size, g.h.Size; got != want {
			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
		}
		if got, want := h2.Mode, g.h.Mode; got != want {
			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
		}
		if got, want := fi.Mode(), g.fm; got != want {
			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
		}
		if got, want := h2.ModTime, g.h.ModTime; got != want {
			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
		}
		if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
			t.Errorf("i=%d: Sys didn't return original *Header", i)
		}
	}
}
<|endoftext|>


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

package tls

import (
	"crypto/x509"
	"io/ioutil"
)

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt", // Linux etc
	"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
	"/etc/ssl/ca-bundle.pem",             // OpenSUSE
}

func initDefaultRoots() {
	roots := x509.NewCertPool()
	for _, file := range certFiles {
		data, err := ioutil.ReadFile(file)
		if err == nil {
			roots.AppendCertsFromPEM(data)
			break
		}
	}
	varDefaultRoots = roots
}
<commit_msg>crypto/tls: add openbsd root certificate location<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"crypto/x509"
	"io/ioutil"
)

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt", // Linux etc
	"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
	"/etc/ssl/ca-bundle.pem",             // OpenSUSE
	"/etc/ssl/cert.pem",                  // OpenBSD
}

func initDefaultRoots() {
	roots := x509.NewCertPool()
	for _, file := range certFiles {
		data, err := ioutil.ReadFile(file)
		if err == nil {
			roots.AppendCertsFromPEM(data)
			break
		}
	}
	varDefaultRoots = roots
}
<|endoftext|>


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

package runtime_test

import (
	. "runtime"
	"testing"
)

func TestMemmove(t *testing.T) {
	size := 256
	if testing.Short() {
		size = 128 + 16
	}
	src := make([]byte, size)
	dst := make([]byte, size)
	for i := 0; i < size; i++ {
		src[i] = byte(128 + (i & 127))
	}
	for i := 0; i < size; i++ {
		dst[i] = byte(i & 127)
	}
	for n := 0; n <= size; n++ {
		for x := 0; x <= size-n; x++ { // offset in src
			for y := 0; y <= size-n; y++ { // offset in dst
				copy(dst[y:y+n], src[x:x+n])
				for i := 0; i < y; i++ {
					if dst[i] != byte(i&127) {
						t.Fatalf("prefix dst[%d] = %d", i, dst[i])
					}
				}
				for i := y; i < y+n; i++ {
					if dst[i] != byte(128+((i-y+x)&127)) {
						t.Fatalf("copied dst[%d] = %d", i, dst[i])
					}
					dst[i] = byte(i & 127) // reset dst
				}
				for i := y + n; i < size; i++ {
					if dst[i] != byte(i&127) {
						t.Fatalf("suffix dst[%d] = %d", i, dst[i])
					}
				}
			}
		}
	}
}

func TestMemmoveAlias(t *testing.T) {
	size := 256
	if testing.Short() {
		size = 128 + 16
	}
	buf := make([]byte, size)
	for i := 0; i < size; i++ {
		buf[i] = byte(i)
	}
	for n := 0; n <= size; n++ {
		for x := 0; x <= size-n; x++ { // src offset
			for y := 0; y <= size-n; y++ { // dst offset
				copy(buf[y:y+n], buf[x:x+n])
				for i := 0; i < y; i++ {
					if buf[i] != byte(i) {
						t.Fatalf("prefix buf[%d] = %d", i, buf[i])
					}
				}
				for i := y; i < y+n; i++ {
					if buf[i] != byte(i-y+x) {
						t.Fatalf("copied buf[%d] = %d", i, buf[i])
					}
					buf[i] = byte(i) // reset buf
				}
				for i := y + n; i < size; i++ {
					if buf[i] != byte(i) {
						t.Fatalf("suffix buf[%d] = %d", i, buf[i])
					}
				}
			}
		}
	}
}

func bmMemmove(b *testing.B, n int) {
	x := make([]byte, n)
	y := make([]byte, n)
	b.SetBytes(int64(n))
	for i := 0; i < b.N; i++ {
		copy(x, y)
	}
}

func BenchmarkMemmove0(b *testing.B)    { bmMemmove(b, 0) }
func BenchmarkMemmove1(b *testing.B)    { bmMemmove(b, 1) }
func BenchmarkMemmove2(b *testing.B)    { bmMemmove(b, 2) }
func BenchmarkMemmove3(b *testing.B)    { bmMemmove(b, 3) }
func BenchmarkMemmove4(b *testing.B)    { bmMemmove(b, 4) }
func BenchmarkMemmove5(b *testing.B)    { bmMemmove(b, 5) }
func BenchmarkMemmove6(b *testing.B)    { bmMemmove(b, 6) }
func BenchmarkMemmove7(b *testing.B)    { bmMemmove(b, 7) }
func BenchmarkMemmove8(b *testing.B)    { bmMemmove(b, 8) }
func BenchmarkMemmove9(b *testing.B)    { bmMemmove(b, 9) }
func BenchmarkMemmove10(b *testing.B)   { bmMemmove(b, 10) }
func BenchmarkMemmove11(b *testing.B)   { bmMemmove(b, 11) }
func BenchmarkMemmove12(b *testing.B)   { bmMemmove(b, 12) }
func BenchmarkMemmove13(b *testing.B)   { bmMemmove(b, 13) }
func BenchmarkMemmove14(b *testing.B)   { bmMemmove(b, 14) }
func BenchmarkMemmove15(b *testing.B)   { bmMemmove(b, 15) }
func BenchmarkMemmove16(b *testing.B)   { bmMemmove(b, 16) }
func BenchmarkMemmove32(b *testing.B)   { bmMemmove(b, 32) }
func BenchmarkMemmove64(b *testing.B)   { bmMemmove(b, 64) }
func BenchmarkMemmove128(b *testing.B)  { bmMemmove(b, 128) }
func BenchmarkMemmove256(b *testing.B)  { bmMemmove(b, 256) }
func BenchmarkMemmove512(b *testing.B)  { bmMemmove(b, 512) }
func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }

func TestMemclr(t *testing.T) {
	size := 512
	if testing.Short() {
		size = 128 + 16
	}
	mem := make([]byte, size)
	for i := 0; i < size; i++ {
		mem[i] = 0xee
	}
	for n := 0; n < size; n++ {
		for x := 0; x <= size-n; x++ { // offset in mem
			MemclrBytes(mem[x : x+n])
			for i := 0; i < x; i++ {
				if mem[i] != 0xee {
					t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i])
				}
			}
			for i := x; i < x+n; i++ {
				if mem[i] != 0 {
					t.Fatalf("failed clear mem[%d] = %d", i, mem[i])
				}
				mem[i] = 0xee
			}
			for i := x + n; i < size; i++ {
				if mem[i] != 0xee {
					t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i])
				}
			}
		}
	}
}

func bmMemclr(b *testing.B, n int) {
	x := make([]byte, n)
	b.SetBytes(int64(n))
	for i := 0; i < b.N; i++ {
		MemclrBytes(x)
	}
}
func BenchmarkMemclr5(b *testing.B)     { bmMemclr(b, 5) }
func BenchmarkMemclr16(b *testing.B)    { bmMemclr(b, 16) }
func BenchmarkMemclr64(b *testing.B)    { bmMemclr(b, 64) }
func BenchmarkMemclr256(b *testing.B)   { bmMemclr(b, 256) }
func BenchmarkMemclr4096(b *testing.B)  { bmMemclr(b, 4096) }
func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }

func BenchmarkClearFat16(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [16 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat24(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [24 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat32(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [32 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [64 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat128(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [128 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat256(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [256 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat512(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [512 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat1024(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [1024 / 4]uint32
		_ = x
	}
}

func BenchmarkCopyFat16(b *testing.B) {
	var x [16 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat24(b *testing.B) {
	var x [24 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat32(b *testing.B) {
	var x [32 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat64(b *testing.B) {
	var x [64 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat128(b *testing.B) {
	var x [128 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat256(b *testing.B) {
	var x [256 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat512(b *testing.B) {
	var x [512 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat1024(b *testing.B) {
	var x [1024 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
<commit_msg>runtime: add Benchmark[Clear|Copy]Fat[8|12]<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	. "runtime"
	"testing"
)

func TestMemmove(t *testing.T) {
	size := 256
	if testing.Short() {
		size = 128 + 16
	}
	src := make([]byte, size)
	dst := make([]byte, size)
	for i := 0; i < size; i++ {
		src[i] = byte(128 + (i & 127))
	}
	for i := 0; i < size; i++ {
		dst[i] = byte(i & 127)
	}
	for n := 0; n <= size; n++ {
		for x := 0; x <= size-n; x++ { // offset in src
			for y := 0; y <= size-n; y++ { // offset in dst
				copy(dst[y:y+n], src[x:x+n])
				for i := 0; i < y; i++ {
					if dst[i] != byte(i&127) {
						t.Fatalf("prefix dst[%d] = %d", i, dst[i])
					}
				}
				for i := y; i < y+n; i++ {
					if dst[i] != byte(128+((i-y+x)&127)) {
						t.Fatalf("copied dst[%d] = %d", i, dst[i])
					}
					dst[i] = byte(i & 127) // reset dst
				}
				for i := y + n; i < size; i++ {
					if dst[i] != byte(i&127) {
						t.Fatalf("suffix dst[%d] = %d", i, dst[i])
					}
				}
			}
		}
	}
}

func TestMemmoveAlias(t *testing.T) {
	size := 256
	if testing.Short() {
		size = 128 + 16
	}
	buf := make([]byte, size)
	for i := 0; i < size; i++ {
		buf[i] = byte(i)
	}
	for n := 0; n <= size; n++ {
		for x := 0; x <= size-n; x++ { // src offset
			for y := 0; y <= size-n; y++ { // dst offset
				copy(buf[y:y+n], buf[x:x+n])
				for i := 0; i < y; i++ {
					if buf[i] != byte(i) {
						t.Fatalf("prefix buf[%d] = %d", i, buf[i])
					}
				}
				for i := y; i < y+n; i++ {
					if buf[i] != byte(i-y+x) {
						t.Fatalf("copied buf[%d] = %d", i, buf[i])
					}
					buf[i] = byte(i) // reset buf
				}
				for i := y + n; i < size; i++ {
					if buf[i] != byte(i) {
						t.Fatalf("suffix buf[%d] = %d", i, buf[i])
					}
				}
			}
		}
	}
}

func bmMemmove(b *testing.B, n int) {
	x := make([]byte, n)
	y := make([]byte, n)
	b.SetBytes(int64(n))
	for i := 0; i < b.N; i++ {
		copy(x, y)
	}
}

func BenchmarkMemmove0(b *testing.B)    { bmMemmove(b, 0) }
func BenchmarkMemmove1(b *testing.B)    { bmMemmove(b, 1) }
func BenchmarkMemmove2(b *testing.B)    { bmMemmove(b, 2) }
func BenchmarkMemmove3(b *testing.B)    { bmMemmove(b, 3) }
func BenchmarkMemmove4(b *testing.B)    { bmMemmove(b, 4) }
func BenchmarkMemmove5(b *testing.B)    { bmMemmove(b, 5) }
func BenchmarkMemmove6(b *testing.B)    { bmMemmove(b, 6) }
func BenchmarkMemmove7(b *testing.B)    { bmMemmove(b, 7) }
func BenchmarkMemmove8(b *testing.B)    { bmMemmove(b, 8) }
func BenchmarkMemmove9(b *testing.B)    { bmMemmove(b, 9) }
func BenchmarkMemmove10(b *testing.B)   { bmMemmove(b, 10) }
func BenchmarkMemmove11(b *testing.B)   { bmMemmove(b, 11) }
func BenchmarkMemmove12(b *testing.B)   { bmMemmove(b, 12) }
func BenchmarkMemmove13(b *testing.B)   { bmMemmove(b, 13) }
func BenchmarkMemmove14(b *testing.B)   { bmMemmove(b, 14) }
func BenchmarkMemmove15(b *testing.B)   { bmMemmove(b, 15) }
func BenchmarkMemmove16(b *testing.B)   { bmMemmove(b, 16) }
func BenchmarkMemmove32(b *testing.B)   { bmMemmove(b, 32) }
func BenchmarkMemmove64(b *testing.B)   { bmMemmove(b, 64) }
func BenchmarkMemmove128(b *testing.B)  { bmMemmove(b, 128) }
func BenchmarkMemmove256(b *testing.B)  { bmMemmove(b, 256) }
func BenchmarkMemmove512(b *testing.B)  { bmMemmove(b, 512) }
func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }

func TestMemclr(t *testing.T) {
	size := 512
	if testing.Short() {
		size = 128 + 16
	}
	mem := make([]byte, size)
	for i := 0; i < size; i++ {
		mem[i] = 0xee
	}
	for n := 0; n < size; n++ {
		for x := 0; x <= size-n; x++ { // offset in mem
			MemclrBytes(mem[x : x+n])
			for i := 0; i < x; i++ {
				if mem[i] != 0xee {
					t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i])
				}
			}
			for i := x; i < x+n; i++ {
				if mem[i] != 0 {
					t.Fatalf("failed clear mem[%d] = %d", i, mem[i])
				}
				mem[i] = 0xee
			}
			for i := x + n; i < size; i++ {
				if mem[i] != 0xee {
					t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i])
				}
			}
		}
	}
}

func bmMemclr(b *testing.B, n int) {
	x := make([]byte, n)
	b.SetBytes(int64(n))
	for i := 0; i < b.N; i++ {
		MemclrBytes(x)
	}
}
func BenchmarkMemclr5(b *testing.B)     { bmMemclr(b, 5) }
func BenchmarkMemclr16(b *testing.B)    { bmMemclr(b, 16) }
func BenchmarkMemclr64(b *testing.B)    { bmMemclr(b, 64) }
func BenchmarkMemclr256(b *testing.B)   { bmMemclr(b, 256) }
func BenchmarkMemclr4096(b *testing.B)  { bmMemclr(b, 4096) }
func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }

func BenchmarkClearFat8(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [8 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat12(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [12 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat16(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [16 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat24(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [24 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat32(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [32 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [64 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat128(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [128 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat256(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [256 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat512(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [512 / 4]uint32
		_ = x
	}
}
func BenchmarkClearFat1024(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var x [1024 / 4]uint32
		_ = x
	}
}

func BenchmarkCopyFat8(b *testing.B) {
	var x [8 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat12(b *testing.B) {
	var x [12 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat16(b *testing.B) {
	var x [16 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat24(b *testing.B) {
	var x [24 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat32(b *testing.B) {
	var x [32 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat64(b *testing.B) {
	var x [64 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat128(b *testing.B) {
	var x [128 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat256(b *testing.B) {
	var x [256 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat512(b *testing.B) {
	var x [512 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
func BenchmarkCopyFat1024(b *testing.B) {
	var x [1024 / 4]uint32
	for i := 0; i < b.N; i++ {
		y := x
		_ = y
	}
}
<|endoftext|>


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

package strings_test

import (
	"fmt"
	"strings"
	"unicode"
)

func ExampleFields() {
	fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
	// Output: Fields are: ["foo" "bar" "baz"]
}

func ExampleFieldsFunc() {
	f := func(c rune) bool {
		return !unicode.IsLetter(c) && !unicode.IsNumber(c)
	}
	fmt.Printf("Fields are: %q", strings.FieldsFunc("  foo1;bar2,baz3...", f))
	// Output: Fields are: ["foo1" "bar2" "baz3"]
}

func ExampleContains() {
	fmt.Println(strings.Contains("seafood", "foo"))
	fmt.Println(strings.Contains("seafood", "bar"))
	fmt.Println(strings.Contains("seafood", ""))
	fmt.Println(strings.Contains("", ""))
	// Output:
	// true
	// false
	// true
	// true
}

func ExampleContainsAny() {
	fmt.Println(strings.ContainsAny("team", "i"))
	fmt.Println(strings.ContainsAny("failure", "u & i"))
	fmt.Println(strings.ContainsAny("foo", ""))
	fmt.Println(strings.ContainsAny("", ""))
	// Output:
	// false
	// true
	// false
	// false
}

func ExampleCount() {
	fmt.Println(strings.Count("cheese", "e"))
	fmt.Println(strings.Count("five", "")) // before & after each rune
	// Output:
	// 3
	// 5
}

func ExampleEqualFold() {
	fmt.Println(strings.EqualFold("Go", "go"))
	// Output: true
}

func ExampleIndex() {
	fmt.Println(strings.Index("chicken", "ken"))
	fmt.Println(strings.Index("chicken", "dmr"))
	// Output:
	// 4
	// -1
}

func ExampleIndexFunc() {
	f := func(c rune) bool {
		return unicode.Is(unicode.Han, c)
	}
	fmt.Println(strings.IndexFunc("Hello, 世界", f))
	fmt.Println(strings.IndexFunc("Hello, world", f))
	// Output:
	// 7
	// -1
}

func ExampleIndexRune() {
	fmt.Println(strings.IndexRune("chicken", 'k'))
	fmt.Println(strings.IndexRune("chicken", 'd'))
	// Output:
	// 4
	// -1
}

func ExampleLastIndex() {
	fmt.Println(strings.Index("go gopher", "go"))
	fmt.Println(strings.LastIndex("go gopher", "go"))
	fmt.Println(strings.LastIndex("go gopher", "rodent"))
	// Output:
	// 0
	// 3
	// -1
}

func ExampleJoin() {
	s := []string{"foo", "bar", "baz"}
	fmt.Println(strings.Join(s, ", "))
	// Output: foo, bar, baz
}

func ExampleRepeat() {
	fmt.Println("ba" + strings.Repeat("na", 2))
	// Output: banana
}

func ExampleReplace() {
	fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
	fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
	// Output:
	// oinky oinky oink
	// moo moo moo
}

func ExampleSplit() {
	fmt.Printf("%q\n", strings.Split("a,b,c", ","))
	fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
	fmt.Printf("%q\n", strings.Split(" xyz ", ""))
	fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
	// Output:
	// ["a" "b" "c"]
	// ["" "man " "plan " "canal panama"]
	// [" " "x" "y" "z" " "]
	// [""]
}

func ExampleSplitN() {
	fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
	z := strings.SplitN("a,b,c", ",", 0)
	fmt.Printf("%q (nil = %v)\n", z, z == nil)
	// Output:
	// ["a" "b,c"]
	// [] (nil = true)
}

func ExampleSplitAfter() {
	fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
	// Output: ["a," "b," "c"]
}

func ExampleSplitAfterN() {
	fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
	// Output: ["a," "b,c"]
}

func ExampleTitle() {
	fmt.Println(strings.Title("her royal highness"))
	// Output: Her Royal Highness
}

func ExampleToTitle() {
	fmt.Println(strings.ToTitle("loud noises"))
	fmt.Println(strings.ToTitle("хлеб"))
	// Output:
	// LOUD NOISES
	// ХЛЕБ
}

func ExampleTrim() {
	fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
	// Output: ["Achtung! Achtung"]
}

func ExampleMap() {
	rot13 := func(r rune) rune {
		switch {
		case r >= 'A' && r <= 'Z':
			return 'A' + (r-'A'+13)%26
		case r >= 'a' && r <= 'z':
			return 'a' + (r-'a'+13)%26
		}
		return r
	}
	fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
	// Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
}

func ExampleTrimSpace() {
	fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
	// Output: a lone gopher
}

func ExampleNewReplacer() {
	r := strings.NewReplacer("<", "<", ">", ">")
	fmt.Println(r.Replace("This is HTML!"))
	// Output: This is <b>HTML</b>!
}

func ExampleToUpper() {
	fmt.Println(strings.ToUpper("Gopher"))
	// Output: GOPHER
}

func ExampleToLower() {
	fmt.Println(strings.ToLower("Gopher"))
	// Output: gopher
}

func ExampleTrimSuffix() {
	var s = "Hello, goodbye, etc!"
	s = strings.TrimSuffix(s, "goodbye, etc!")
	s = strings.TrimSuffix(s, "planet")
	fmt.Print(s, "world!")
	// Output: Hello, world!
}

func ExampleTrimPrefix() {
	var s = "Goodbye,, world!"
	s = strings.TrimPrefix(s, "Goodbye,")
	s = strings.TrimPrefix(s, "Howdy,")
	fmt.Print("Hello" + s)
	// Output: Hello, world!
}
<commit_msg>strings: Add example function for IndexAny<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package strings_test

import (
	"fmt"
	"strings"
	"unicode"
)

func ExampleFields() {
	fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
	// Output: Fields are: ["foo" "bar" "baz"]
}

func ExampleFieldsFunc() {
	f := func(c rune) bool {
		return !unicode.IsLetter(c) && !unicode.IsNumber(c)
	}
	fmt.Printf("Fields are: %q", strings.FieldsFunc("  foo1;bar2,baz3...", f))
	// Output: Fields are: ["foo1" "bar2" "baz3"]
}

func ExampleContains() {
	fmt.Println(strings.Contains("seafood", "foo"))
	fmt.Println(strings.Contains("seafood", "bar"))
	fmt.Println(strings.Contains("seafood", ""))
	fmt.Println(strings.Contains("", ""))
	// Output:
	// true
	// false
	// true
	// true
}

func ExampleContainsAny() {
	fmt.Println(strings.ContainsAny("team", "i"))
	fmt.Println(strings.ContainsAny("failure", "u & i"))
	fmt.Println(strings.ContainsAny("foo", ""))
	fmt.Println(strings.ContainsAny("", ""))
	// Output:
	// false
	// true
	// false
	// false
}

func ExampleCount() {
	fmt.Println(strings.Count("cheese", "e"))
	fmt.Println(strings.Count("five", "")) // before & after each rune
	// Output:
	// 3
	// 5
}

func ExampleEqualFold() {
	fmt.Println(strings.EqualFold("Go", "go"))
	// Output: true
}

func ExampleIndex() {
	fmt.Println(strings.Index("chicken", "ken"))
	fmt.Println(strings.Index("chicken", "dmr"))
	// Output:
	// 4
	// -1
}

func ExampleIndexFunc() {
	f := func(c rune) bool {
		return unicode.Is(unicode.Han, c)
	}
	fmt.Println(strings.IndexFunc("Hello, 世界", f))
	fmt.Println(strings.IndexFunc("Hello, world", f))
	// Output:
	// 7
	// -1
}

func ExampleIndexAny() {
	fmt.Println(strings.IndexAny("chicken", "aeiouy"))
	fmt.Println(strings.IndexAny("crwth", "aeiouy"))
	// Output:
	// 2
	// -1
}

func ExampleIndexRune() {
	fmt.Println(strings.IndexRune("chicken", 'k'))
	fmt.Println(strings.IndexRune("chicken", 'd'))
	// Output:
	// 4
	// -1
}

func ExampleLastIndex() {
	fmt.Println(strings.Index("go gopher", "go"))
	fmt.Println(strings.LastIndex("go gopher", "go"))
	fmt.Println(strings.LastIndex("go gopher", "rodent"))
	// Output:
	// 0
	// 3
	// -1
}

func ExampleJoin() {
	s := []string{"foo", "bar", "baz"}
	fmt.Println(strings.Join(s, ", "))
	// Output: foo, bar, baz
}

func ExampleRepeat() {
	fmt.Println("ba" + strings.Repeat("na", 2))
	// Output: banana
}

func ExampleReplace() {
	fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
	fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
	// Output:
	// oinky oinky oink
	// moo moo moo
}

func ExampleSplit() {
	fmt.Printf("%q\n", strings.Split("a,b,c", ","))
	fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
	fmt.Printf("%q\n", strings.Split(" xyz ", ""))
	fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
	// Output:
	// ["a" "b" "c"]
	// ["" "man " "plan " "canal panama"]
	// [" " "x" "y" "z" " "]
	// [""]
}

func ExampleSplitN() {
	fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
	z := strings.SplitN("a,b,c", ",", 0)
	fmt.Printf("%q (nil = %v)\n", z, z == nil)
	// Output:
	// ["a" "b,c"]
	// [] (nil = true)
}

func ExampleSplitAfter() {
	fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
	// Output: ["a," "b," "c"]
}

func ExampleSplitAfterN() {
	fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
	// Output: ["a," "b,c"]
}

func ExampleTitle() {
	fmt.Println(strings.Title("her royal highness"))
	// Output: Her Royal Highness
}

func ExampleToTitle() {
	fmt.Println(strings.ToTitle("loud noises"))
	fmt.Println(strings.ToTitle("хлеб"))
	// Output:
	// LOUD NOISES
	// ХЛЕБ
}

func ExampleTrim() {
	fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
	// Output: ["Achtung! Achtung"]
}

func ExampleMap() {
	rot13 := func(r rune) rune {
		switch {
		case r >= 'A' && r <= 'Z':
			return 'A' + (r-'A'+13)%26
		case r >= 'a' && r <= 'z':
			return 'a' + (r-'a'+13)%26
		}
		return r
	}
	fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
	// Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
}

func ExampleTrimSpace() {
	fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
	// Output: a lone gopher
}

func ExampleNewReplacer() {
	r := strings.NewReplacer("<", "<", ">", ">")
	fmt.Println(r.Replace("This is HTML!"))
	// Output: This is <b>HTML</b>!
}

func ExampleToUpper() {
	fmt.Println(strings.ToUpper("Gopher"))
	// Output: GOPHER
}

func ExampleToLower() {
	fmt.Println(strings.ToLower("Gopher"))
	// Output: gopher
}

func ExampleTrimSuffix() {
	var s = "Hello, goodbye, etc!"
	s = strings.TrimSuffix(s, "goodbye, etc!")
	s = strings.TrimSuffix(s, "planet")
	fmt.Print(s, "world!")
	// Output: Hello, world!
}

func ExampleTrimPrefix() {
	var s = "Goodbye,, world!"
	s = strings.TrimPrefix(s, "Goodbye,")
	s = strings.TrimPrefix(s, "Howdy,")
	fmt.Print("Hello" + s)
	// Output: Hello, world!
}
<|endoftext|>


<commit_before>package jobs

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/juju/errgo"

	"arvika.pulcy.com/pulcy/deployit/units"
)

var (
	taskNamePattern = regexp.MustCompile(`^([a-z0-9_]{2,30})$`)
)

type TaskName string

func (tn TaskName) String() string {
	return string(tn)
}

func (tn TaskName) Validate() error {
	if !taskNamePattern.MatchString(string(tn)) {
		return maskAny(errgo.WithCausef(nil, InvalidNameError, "task name must match '%s', got '%s'", taskNamePattern, tn))
	}
	return nil
}

type Task struct {
	Name   TaskName   `json:"name", maspstructure:"-"`
	group  *TaskGroup `json:"-", mapstructure:"-"`
	Count  uint       `json:"-"` // This value is used during parsing only
	Global bool       `json:"-"` // This value is used during parsing only

	Image       DockerImage       `json:"image"`
	VolumesFrom []TaskName        `json:"volumes-from,omitempty"`
	Volumes     []string          `json:"volumes,omitempty"`
	Args        []string          `json:"args,omitempty"`
	Environment map[string]string `json:"environment,omitempty"`
	Ports       []string          `json:"ports,omitempty"`
	FrontEnds   []FrontEnd        `json:"frontends,omitempty"`
}

type TaskList []*Task

// Check for errors
func (t *Task) Validate() error {
	if err := t.Name.Validate(); err != nil {
		return maskAny(err)
	}
	for _, name := range t.VolumesFrom {
		_, err := t.group.Task(name)
		if err != nil {
			return maskAny(err)
		}
	}

	return nil
}

// createUnits creates all units needed to run this task.
func (t *Task) createUnits(scalingGroup uint) ([]*units.Unit, error) {
	units := []*units.Unit{}
	main, err := t.createMainUnit(scalingGroup)
	if err != nil {
		return nil, maskAny(err)
	}
	units = append(units, main)

	return units, nil
}

// createMainUnit
func (t *Task) createMainUnit(scalingGroup uint) (*units.Unit, error) {
	name := t.containerName(scalingGroup)
	serviceName := t.serviceName()
	image := t.Image.String()
	execStart := []string{
		"/usr/bin/docker",
		"run",
		"--rm",
		fmt.Sprintf("--name %s", name),
	}
	if len(t.Ports) > 0 {
		for _, p := range t.Ports {
			execStart = append(execStart, fmt.Sprintf("-p %s", p))
		}
	} else {
		execStart = append(execStart, "-P")
	}
	for _, v := range t.Volumes {
		execStart = append(execStart, fmt.Sprintf("-v %s", v))
	}
	for _, name := range t.VolumesFrom {
		other, err := t.group.Task(name)
		if err != nil {
			return nil, maskAny(err)
		}
		execStart = append(execStart, fmt.Sprintf("--volumes-from %s", other.containerName(scalingGroup)))
	}
	for k, v := range t.Environment {
		execStart = append(execStart, "-e "+strconv.Quote(fmt.Sprintf("%s=%s", k, v)))
	}
	execStart = append(execStart, fmt.Sprintf("-e SERVICE_NAME=%s", serviceName)) // Support registrator
	execStart = append(execStart, image)
	execStart = append(execStart, t.Args...)
	main := &units.Unit{
		Name:         t.unitName(scalingGroup),
		FullName:     t.unitName(scalingGroup) + ".service",
		Description:  fmt.Sprintf("Main unit for %s slice %v", t.fullName(), scalingGroup),
		Type:         "service",
		Scalable:     t.group.IsScalable(),
		ScalingGroup: scalingGroup,
		ExecOptions:  units.NewExecOptions(execStart...),
		FleetOptions: units.NewFleetOptions(),
	}
	//main.FleetOptions.IsGlobal = ds.global
	main.ExecOptions.ExecStartPre = []string{
		fmt.Sprintf("/usr/bin/docker pull %s", image),
		fmt.Sprintf("-/usr/bin/docker stop -t %v %s", main.ExecOptions.ContainerTimeoutStopSec, name),
		fmt.Sprintf("-/usr/bin/docker rm -f %s", name),
	}
	main.ExecOptions.ExecStop = fmt.Sprintf("-/usr/bin/docker stop -t %v %s", main.ExecOptions.ContainerTimeoutStopSec, name)
	main.ExecOptions.ExecStopPost = []string{
		fmt.Sprintf("-/usr/bin/docker rm -f %s", name),
	}
	main.FleetOptions.IsGlobal = t.group.Global

	if err := t.addFrontEndRegistration(main); err != nil {
		return nil, maskAny(err)
	}

	return main, nil
}

// Gets the full name of this task: job/taskgroup/task
func (t *Task) fullName() string {
	return fmt.Sprintf("%s/%s", t.group.fullName(), t.Name)
}

// unitName returns the name of the systemd unit for this task.
func (t *Task) unitName(scalingGroup uint) string {
	base := strings.Replace(t.fullName(), "/", "-", -1)
	if !t.group.IsScalable() {
		return base
	}
	return fmt.Sprintf("%s@%v", base, scalingGroup)
}

// containerName returns the name of the docker contained used for this task.
func (t *Task) containerName(scalingGroup uint) string {
	base := strings.Replace(t.fullName(), "/", "-", -1)
	return fmt.Sprintf("%s-%v", base, scalingGroup)
}

// serviceName returns the name used to register this service.
func (t *Task) serviceName() string {
	return strings.Replace(t.fullName(), "/", "-", -1)
}

type frontendRecord struct {
	Selectors []frontendSelectorRecord `json:"selectors"`
	Service   string                   `json:"service,omitempty"`
}

type frontendSelectorRecord struct {
	Domain     string `json:"domain,omitempty"`
	PathPrefix string `json:"path-prefix,omitempty"`
}

// addFrontEndRegistration adds registration code for frontends to the given units
func (t *Task) addFrontEndRegistration(main *units.Unit) error {
	if len(t.FrontEnds) == 0 {
		return nil
	}
	key := "/pulcy/frontend/" + t.serviceName()
	record := frontendRecord{
		Service: t.serviceName(),
	}
	for _, fr := range t.FrontEnds {
		record.Selectors = append(record.Selectors, frontendSelectorRecord{
			Domain:     fr.Domain,
			PathPrefix: fr.PathPrefix,
		})
	}
	json, err := json.Marshal(&record)
	if err != nil {
		return maskAny(err)
	}
	main.ExecOptions.ExecStartPost = append(main.ExecOptions.ExecStartPost,
		fmt.Sprintf("/bin/sh -c 'echo %s | base64 -d | /usr/bin/etcdctl set %s'", base64.StdEncoding.EncodeToString(json), key),
	)
	return nil
}

func (l TaskList) Len() int {
	return len(l)
}

func (l TaskList) Less(i, j int) bool {
	return bytes.Compare([]byte(l[i].Name.String()), []byte(l[j].Name.String())) < 0
}

func (l TaskList) Swap(i, j int) {
	tmp := l[i]
	l[i] = l[j]
	l[j] = tmp
}
<commit_msg>Added Conflicts rule<commit_after>package jobs

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/juju/errgo"

	"arvika.pulcy.com/pulcy/deployit/units"
)

var (
	taskNamePattern = regexp.MustCompile(`^([a-z0-9_]{2,30})$`)
)

type TaskName string

func (tn TaskName) String() string {
	return string(tn)
}

func (tn TaskName) Validate() error {
	if !taskNamePattern.MatchString(string(tn)) {
		return maskAny(errgo.WithCausef(nil, InvalidNameError, "task name must match '%s', got '%s'", taskNamePattern, tn))
	}
	return nil
}

type Task struct {
	Name   TaskName   `json:"name", maspstructure:"-"`
	group  *TaskGroup `json:"-", mapstructure:"-"`
	Count  uint       `json:"-"` // This value is used during parsing only
	Global bool       `json:"-"` // This value is used during parsing only

	Image       DockerImage       `json:"image"`
	VolumesFrom []TaskName        `json:"volumes-from,omitempty"`
	Volumes     []string          `json:"volumes,omitempty"`
	Args        []string          `json:"args,omitempty"`
	Environment map[string]string `json:"environment,omitempty"`
	Ports       []string          `json:"ports,omitempty"`
	FrontEnds   []FrontEnd        `json:"frontends,omitempty"`
}

type TaskList []*Task

// Check for errors
func (t *Task) Validate() error {
	if err := t.Name.Validate(); err != nil {
		return maskAny(err)
	}
	for _, name := range t.VolumesFrom {
		_, err := t.group.Task(name)
		if err != nil {
			return maskAny(err)
		}
	}

	return nil
}

// createUnits creates all units needed to run this task.
func (t *Task) createUnits(scalingGroup uint) ([]*units.Unit, error) {
	units := []*units.Unit{}
	main, err := t.createMainUnit(scalingGroup)
	if err != nil {
		return nil, maskAny(err)
	}
	units = append(units, main)

	return units, nil
}

// createMainUnit
func (t *Task) createMainUnit(scalingGroup uint) (*units.Unit, error) {
	name := t.containerName(scalingGroup)
	serviceName := t.serviceName()
	image := t.Image.String()
	execStart := []string{
		"/usr/bin/docker",
		"run",
		"--rm",
		fmt.Sprintf("--name %s", name),
	}
	if len(t.Ports) > 0 {
		for _, p := range t.Ports {
			execStart = append(execStart, fmt.Sprintf("-p %s", p))
		}
	} else {
		execStart = append(execStart, "-P")
	}
	for _, v := range t.Volumes {
		execStart = append(execStart, fmt.Sprintf("-v %s", v))
	}
	for _, name := range t.VolumesFrom {
		other, err := t.group.Task(name)
		if err != nil {
			return nil, maskAny(err)
		}
		execStart = append(execStart, fmt.Sprintf("--volumes-from %s", other.containerName(scalingGroup)))
	}
	for k, v := range t.Environment {
		execStart = append(execStart, "-e "+strconv.Quote(fmt.Sprintf("%s=%s", k, v)))
	}
	execStart = append(execStart, fmt.Sprintf("-e SERVICE_NAME=%s", serviceName)) // Support registrator
	execStart = append(execStart, image)
	execStart = append(execStart, t.Args...)
	main := &units.Unit{
		Name:         t.unitName(strconv.Itoa(int(scalingGroup))),
		FullName:     t.unitName(strconv.Itoa(int(scalingGroup))) + ".service",
		Description:  fmt.Sprintf("Main unit for %s slice %v", t.fullName(), scalingGroup),
		Type:         "service",
		Scalable:     t.group.IsScalable(),
		ScalingGroup: scalingGroup,
		ExecOptions:  units.NewExecOptions(execStart...),
		FleetOptions: units.NewFleetOptions(),
	}
	//main.FleetOptions.IsGlobal = ds.global
	main.ExecOptions.ExecStartPre = []string{
		fmt.Sprintf("/usr/bin/docker pull %s", image),
		fmt.Sprintf("-/usr/bin/docker stop -t %v %s", main.ExecOptions.ContainerTimeoutStopSec, name),
		fmt.Sprintf("-/usr/bin/docker rm -f %s", name),
	}
	main.ExecOptions.ExecStop = fmt.Sprintf("-/usr/bin/docker stop -t %v %s", main.ExecOptions.ContainerTimeoutStopSec, name)
	main.ExecOptions.ExecStopPost = []string{
		fmt.Sprintf("-/usr/bin/docker rm -f %s", name),
	}
	main.FleetOptions.IsGlobal = t.group.Global
	if t.group.IsScalable() {
		main.FleetOptions.Conflicts(t.unitName("*") + ".service")
	}

	if err := t.addFrontEndRegistration(main); err != nil {
		return nil, maskAny(err)
	}

	return main, nil
}

// Gets the full name of this task: job/taskgroup/task
func (t *Task) fullName() string {
	return fmt.Sprintf("%s/%s", t.group.fullName(), t.Name)
}

// unitName returns the name of the systemd unit for this task.
func (t *Task) unitName(scalingGroup string) string {
	base := strings.Replace(t.fullName(), "/", "-", -1)
	if !t.group.IsScalable() {
		return base
	}
	return fmt.Sprintf("%s@%s", base, scalingGroup)
}

// containerName returns the name of the docker contained used for this task.
func (t *Task) containerName(scalingGroup uint) string {
	base := strings.Replace(t.fullName(), "/", "-", -1)
	if !t.group.IsScalable() {
		return base
	}
	return fmt.Sprintf("%s-%v", base, scalingGroup)
}

// serviceName returns the name used to register this service.
func (t *Task) serviceName() string {
	return strings.Replace(t.fullName(), "/", "-", -1)
}

type frontendRecord struct {
	Selectors []frontendSelectorRecord `json:"selectors"`
	Service   string                   `json:"service,omitempty"`
}

type frontendSelectorRecord struct {
	Domain     string `json:"domain,omitempty"`
	PathPrefix string `json:"path-prefix,omitempty"`
}

// addFrontEndRegistration adds registration code for frontends to the given units
func (t *Task) addFrontEndRegistration(main *units.Unit) error {
	if len(t.FrontEnds) == 0 {
		return nil
	}
	key := "/pulcy/frontend/" + t.serviceName()
	record := frontendRecord{
		Service: t.serviceName(),
	}
	for _, fr := range t.FrontEnds {
		record.Selectors = append(record.Selectors, frontendSelectorRecord{
			Domain:     fr.Domain,
			PathPrefix: fr.PathPrefix,
		})
	}
	json, err := json.Marshal(&record)
	if err != nil {
		return maskAny(err)
	}
	main.ExecOptions.ExecStartPost = append(main.ExecOptions.ExecStartPost,
		fmt.Sprintf("/bin/sh -c 'echo %s | base64 -d | /usr/bin/etcdctl set %s'", base64.StdEncoding.EncodeToString(json), key),
	)
	return nil
}

func (l TaskList) Len() int {
	return len(l)
}

func (l TaskList) Less(i, j int) bool {
	return bytes.Compare([]byte(l[i].Name.String()), []byte(l[j].Name.String())) < 0
}

func (l TaskList) Swap(i, j int) {
	tmp := l[i]
	l[i] = l[j]
	l[j] = tmp
}
<|endoftext|>