<commit_before>package torrent

import (
	"strings"

	"github.com/anacrolix/torrent/metainfo"
	pwp "github.com/anacrolix/torrent/peer_protocol"
)

// Provides access to regions of torrent data that correspond to its files.
type File struct {
	t      *Torrent
	path   string
	offset int64
	length int64
	fi     metainfo.FileInfo
	prio   piecePriority
}

func (f *File) Torrent() *Torrent {
	return f.t
}

// Data for this file begins this many bytes into the Torrent.
func (f *File) Offset() int64 {
	return f.offset
}

// The FileInfo from the metainfo.Info to which this file corresponds.
func (f File) FileInfo() metainfo.FileInfo {
	return f.fi
}

// The file's path components joined by '/'.
func (f File) Path() string {
	return f.path
}

// The file's length in bytes.
func (f *File) Length() int64 {
	return f.length
}

// The relative file path for a multi-file torrent, and the torrent name for a
// single-file torrent.
func (f *File) DisplayPath() string {
	fip := f.FileInfo().Path
	if len(fip) == 0 {
		return f.t.Info().Name
	}
	return strings.Join(fip, "/")

}

// The download status of a piece that comprises part of a File.
type FilePieceState struct {
	Bytes int64 // Bytes within the piece that are part of this File.
	PieceState
}

// Returns the state of pieces in this file.
func (f *File) State() (ret []FilePieceState) {
	f.t.cl.mu.RLock()
	defer f.t.cl.mu.RUnlock()
	pieceSize := int64(f.t.usualPieceSize())
	off := f.offset % pieceSize
	remaining := f.length
	for i := int(f.offset / pieceSize); ; i++ {
		if remaining == 0 {
			break
		}
		len1 := pieceSize - off
		if len1 > remaining {
			len1 = remaining
		}
		ps := f.t.pieceState(i)
		ret = append(ret, FilePieceState{len1, ps})
		off = 0
		remaining -= len1
	}
	return
}

// Requests that all pieces containing data in the file be downloaded.
func (f *File) Download() {
	f.SetPriority(PiecePriorityNormal)
}

func byteRegionExclusivePieces(off, size, pieceSize int64) (begin, end int) {
	begin = int((off + pieceSize - 1) / pieceSize)
	end = int((off + size) / pieceSize)
	return
}

func (f *File) exclusivePieces() (begin, end int) {
	return byteRegionExclusivePieces(f.offset, f.length, int64(f.t.usualPieceSize()))
}

// Deprecated: Use File.SetPriority.
func (f *File) Cancel() {
	f.SetPriority(PiecePriorityNone)
}

func (f *File) NewReader() Reader {
	tr := reader{
		mu:        &f.t.cl.mu,
		t:         f.t,
		readahead: 5 * 1024 * 1024,
		offset:    f.Offset(),
		length:    f.Length(),
	}
	f.t.addReader(&tr)
	return &tr
}

// Sets the minimum priority for pieces in the File.
func (f *File) SetPriority(prio piecePriority) {
	f.t.cl.mu.Lock()
	defer f.t.cl.mu.Unlock()
	if prio == f.prio {
		return
	}
	f.prio = prio
	f.t.updatePiecePriorities(f.firstPieceIndex().Int(), f.lastPieceIndex().Int()+1)
}

// Returns the priority per File.SetPriority.
func (f *File) Priority() piecePriority {
	f.t.cl.mu.Lock()
	defer f.t.cl.mu.Unlock()
	return f.prio
}

func (f *File) firstPieceIndex() pwp.Integer {
	return pwp.Integer(f.offset / int64(f.t.usualPieceSize()))
}

func (f *File) lastPieceIndex() pwp.Integer {
	return pwp.Integer((f.offset + f.length) / int64(f.t.usualPieceSize()))
}
<commit_msg>Don't lock Client in File.DisplayPath<commit_after>package torrent

import (
	"strings"

	"github.com/anacrolix/torrent/metainfo"
	pwp "github.com/anacrolix/torrent/peer_protocol"
)

// Provides access to regions of torrent data that correspond to its files.
type File struct {
	t      *Torrent
	path   string
	offset int64
	length int64
	fi     metainfo.FileInfo
	prio   piecePriority
}

func (f *File) Torrent() *Torrent {
	return f.t
}

// Data for this file begins this many bytes into the Torrent.
func (f *File) Offset() int64 {
	return f.offset
}

// The FileInfo from the metainfo.Info to which this file corresponds.
func (f File) FileInfo() metainfo.FileInfo {
	return f.fi
}

// The file's path components joined by '/'.
func (f File) Path() string {
	return f.path
}

// The file's length in bytes.
func (f *File) Length() int64 {
	return f.length
}

// The relative file path for a multi-file torrent, and the torrent name for a
// single-file torrent.
func (f *File) DisplayPath() string {
	fip := f.FileInfo().Path
	if len(fip) == 0 {
		return f.t.info.Name
	}
	return strings.Join(fip, "/")

}

// The download status of a piece that comprises part of a File.
type FilePieceState struct {
	Bytes int64 // Bytes within the piece that are part of this File.
	PieceState
}

// Returns the state of pieces in this file.
func (f *File) State() (ret []FilePieceState) {
	f.t.cl.mu.RLock()
	defer f.t.cl.mu.RUnlock()
	pieceSize := int64(f.t.usualPieceSize())
	off := f.offset % pieceSize
	remaining := f.length
	for i := int(f.offset / pieceSize); ; i++ {
		if remaining == 0 {
			break
		}
		len1 := pieceSize - off
		if len1 > remaining {
			len1 = remaining
		}
		ps := f.t.pieceState(i)
		ret = append(ret, FilePieceState{len1, ps})
		off = 0
		remaining -= len1
	}
	return
}

// Requests that all pieces containing data in the file be downloaded.
func (f *File) Download() {
	f.SetPriority(PiecePriorityNormal)
}

func byteRegionExclusivePieces(off, size, pieceSize int64) (begin, end int) {
	begin = int((off + pieceSize - 1) / pieceSize)
	end = int((off + size) / pieceSize)
	return
}

func (f *File) exclusivePieces() (begin, end int) {
	return byteRegionExclusivePieces(f.offset, f.length, int64(f.t.usualPieceSize()))
}

// Deprecated: Use File.SetPriority.
func (f *File) Cancel() {
	f.SetPriority(PiecePriorityNone)
}

func (f *File) NewReader() Reader {
	tr := reader{
		mu:        &f.t.cl.mu,
		t:         f.t,
		readahead: 5 * 1024 * 1024,
		offset:    f.Offset(),
		length:    f.Length(),
	}
	f.t.addReader(&tr)
	return &tr
}

// Sets the minimum priority for pieces in the File.
func (f *File) SetPriority(prio piecePriority) {
	f.t.cl.mu.Lock()
	defer f.t.cl.mu.Unlock()
	if prio == f.prio {
		return
	}
	f.prio = prio
	f.t.updatePiecePriorities(f.firstPieceIndex().Int(), f.lastPieceIndex().Int()+1)
}

// Returns the priority per File.SetPriority.
func (f *File) Priority() piecePriority {
	f.t.cl.mu.Lock()
	defer f.t.cl.mu.Unlock()
	return f.prio
}

func (f *File) firstPieceIndex() pwp.Integer {
	return pwp.Integer(f.offset / int64(f.t.usualPieceSize()))
}

func (f *File) lastPieceIndex() pwp.Integer {
	return pwp.Integer((f.offset + f.length) / int64(f.t.usualPieceSize()))
}
<|endoftext|>


<commit_before>package file

import (
	"os"
	"time"
)

// Limit of the waiting time in seconds to wait for files to be released.
var WaitTimeout float64 = 30.0

// Interval to retry file locking.
var RetryInterval time.Duration = 50 * time.Millisecond

// Types of Locks
type LockType int

const (
	// Shared Lock
	SHARED_LOCK LockType = iota
	// Exclusive Lock
	EXCLUSIVE_LOCK
)

// Open the file with locking. OpenToRead is the same as Open(path, os.O_RDONLY, 0400, SHARED_LOCK)
func OpenToRead(path string) (*os.File, error) {
	return Open(path, os.O_RDONLY, 0400, SHARED_LOCK)
}

// Open the file with locking. OpenToRead is the same as Open(path, os.O_WRONLY|O_TRUNC, 0600, EXCLUSIVE_LOCK)
func OpenToUpdate(path string) (*os.File, error) {
	return Open(path, os.O_WRONLY|os.O_TRUNC, 0600, EXCLUSIVE_LOCK)
}

// Open the file with locking. Create is the same as Open(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600, EXCLUSIVE_LOCK)
func Create(path string) (*os.File, error) {
	return Open(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600, EXCLUSIVE_LOCK)
}

// Open the file with locking. OpenToReadWithTimeout is the same as OpenWithTimeout(path, os.O_RDONLY, 0400, SHARED_LOCK)
func OpenToReadWithTimeout(path string) (*os.File, error) {
	return OpenWithTimeout(path, os.O_RDONLY, 0400, SHARED_LOCK)
}

// Open the file with locking. OpenToUpdateWithTimeout is the same as OpenWithTimeout(path, os.O_WRONLY|O_TRUNC, 0600, EXCLUSIVE_LOCK)
func OpenToUpdateWithTimeout(path string) (*os.File, error) {
	return OpenWithTimeout(path, os.O_WRONLY|os.O_TRUNC, 0600, EXCLUSIVE_LOCK)
}

// Open the file with file locking. If the file is already locked, waits until the file is released.
func Open(path string, flag int, perm os.FileMode, lockType LockType) (*os.File, error) {
	fp, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, NewIOError(err.Error())
	}

	err = Lock(fp, lockType)
	if err != nil {
		fp.Close()
		return nil, err
	}
	return fp, nil
}

// Open the file with file locking. If the file is already locked, waits for up to WaitTimeout seconds.
func OpenWithTimeout(path string, flag int, perm os.FileMode, lockType LockType) (*os.File, error) {
	fp, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, NewIOError(err.Error())
	}

	err = LockWithTimeout(fp, lockType)

	if err != nil {
		fp.Close()
		return nil, err
	}

	return fp, nil
}

// Places a lock on the file. If the file is already locked, waits until the file is released.
func Lock(fp *os.File, lockType LockType) error {
	var err error
	switch lockType {
	case EXCLUSIVE_LOCK:
		err = LockEX(fp)
	default:
		err = LockSH(fp)
	}

	if err != nil {
		return NewLockError(err.Error())
	}
	return nil
}

// Places a lock on the file. If the file is already locked, returns an error immediately.
func TryLock(fp *os.File, lockType LockType) error {
	var err error
	switch lockType {
	case EXCLUSIVE_LOCK:
		err = TryLockEX(fp)
	default:
		err = TryLockSH(fp)
	}

	if err != nil {
		return NewLockError(err.Error())
	}
	return nil
}

// Places a lock on the file. If the file is already locked, waits for up to WaitTimeout seconds.
func LockWithTimeout(fp *os.File, lockType LockType) error {
	start := time.Now()

	err := TryLock(fp, lockType)
	if err == nil {
		return nil
	}

	if 0 < WaitTimeout {
		for {
			if time.Since(start).Seconds() > WaitTimeout {
				err = NewTimeoutError(fp.Name())
				break
			}
			time.Sleep(RetryInterval)

			if err = TryLock(fp, lockType); err == nil {
				break
			}
		}
	}

	return err
}

// Unlocks and closes the file
func Close(fp *os.File) error {
	defer func() {
		fp.Close()
	}()

	if err := Unlock(fp); err != nil {
		return NewLockError(err.Error())
	}
	return nil
}
<commit_msg>Change the behavior of the OpenToUpdate function.<commit_after>package file

import (
	"os"
	"time"
)

// Limit of the waiting time in seconds to wait for files to be released.
var WaitTimeout float64 = 30.0

// Interval to retry file locking.
var RetryInterval time.Duration = 50 * time.Millisecond

// Types of Locks
type LockType int

const (
	// Shared Lock
	SHARED_LOCK LockType = iota
	// Exclusive Lock
	EXCLUSIVE_LOCK
)

// Open the file with locking. OpenToRead is the same as Open(path, os.O_RDONLY, 0400, SHARED_LOCK)
func OpenToRead(path string) (*os.File, error) {
	return Open(path, os.O_RDONLY, 0400, SHARED_LOCK)
}

// Open the file with locking. OpenToRead is the same as Open(path, os.O_RDWR, 0600, EXCLUSIVE_LOCK)
func OpenToUpdate(path string) (*os.File, error) {
	return Open(path, os.O_RDWR, 0600, EXCLUSIVE_LOCK)
}

// Open the file with locking. Create is the same as Open(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600, EXCLUSIVE_LOCK)
func Create(path string) (*os.File, error) {
	return Open(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600, EXCLUSIVE_LOCK)
}

// Open the file with locking. OpenToReadWithTimeout is the same as OpenWithTimeout(path, os.O_RDONLY, 0400, SHARED_LOCK)
func OpenToReadWithTimeout(path string) (*os.File, error) {
	return OpenWithTimeout(path, os.O_RDONLY, 0400, SHARED_LOCK)
}

// Open the file with locking. OpenToUpdateWithTimeout is the same as OpenWithTimeout(path, os.O_RDWR, 0600, EXCLUSIVE_LOCK)
func OpenToUpdateWithTimeout(path string) (*os.File, error) {
	return OpenWithTimeout(path, os.O_RDWR, 0600, EXCLUSIVE_LOCK)
}

// Open the file with file locking. If the file is already locked, waits until the file is released.
func Open(path string, flag int, perm os.FileMode, lockType LockType) (*os.File, error) {
	fp, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, NewIOError(err.Error())
	}

	err = Lock(fp, lockType)
	if err != nil {
		fp.Close()
		return nil, err
	}
	return fp, nil
}

// Open the file with file locking. If the file is already locked, waits for up to WaitTimeout seconds.
func OpenWithTimeout(path string, flag int, perm os.FileMode, lockType LockType) (*os.File, error) {
	fp, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, NewIOError(err.Error())
	}

	err = LockWithTimeout(fp, lockType)

	if err != nil {
		fp.Close()
		return nil, err
	}

	return fp, nil
}

// Places a lock on the file. If the file is already locked, waits until the file is released.
func Lock(fp *os.File, lockType LockType) error {
	var err error
	switch lockType {
	case EXCLUSIVE_LOCK:
		err = LockEX(fp)
	default:
		err = LockSH(fp)
	}

	if err != nil {
		return NewLockError(err.Error())
	}
	return nil
}

// Places a lock on the file. If the file is already locked, returns an error immediately.
func TryLock(fp *os.File, lockType LockType) error {
	var err error
	switch lockType {
	case EXCLUSIVE_LOCK:
		err = TryLockEX(fp)
	default:
		err = TryLockSH(fp)
	}

	if err != nil {
		return NewLockError(err.Error())
	}
	return nil
}

// Places a lock on the file. If the file is already locked, waits for up to WaitTimeout seconds.
func LockWithTimeout(fp *os.File, lockType LockType) error {
	start := time.Now()

	err := TryLock(fp, lockType)
	if err == nil {
		return nil
	}

	if 0 < WaitTimeout {
		for {
			if time.Since(start).Seconds() > WaitTimeout {
				err = NewTimeoutError(fp.Name())
				break
			}
			time.Sleep(RetryInterval)

			if err = TryLock(fp, lockType); err == nil {
				break
			}
		}
	}

	return err
}

// Unlocks and closes the file
func Close(fp *os.File) error {
	defer func() {
		fp.Close()
	}()

	if err := Unlock(fp); err != nil {
		return NewLockError(err.Error())
	}
	return nil
}
<|endoftext|>


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

package redux

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

	"github.com/gyepisam/fileutils"
)

// File represents a source or target file..
type File struct {
	Target string // file name argument to redo, redo-ifchange, redo-ifcreate, etc

	RootDir string // contains .redo directory
	Path    string // Relative to RootDir

	Dir      string
	Name     string
	Basename string
	Ext      string // File extension. Could be empty. Includes preceeding dot.

	PathHash     Hash   // SHA1 hash of Path. Used as database key.
	FullPathHash Hash   //SHA1 hash of RootDir/Path. Used for loop detection.
	DoFile       string // Do script used to generate target output.

	Config     Config
	db         DB
	IsTaskFlag bool // If true, target is a task and run for side effects
}

// IsTask denotes when the current target is a task script, either
// implicitly (name begins with @) or explicitly (-task argument to redo).
func (f *File) IsTask() bool {
	return f.IsTaskFlag ||
		strings.HasPrefix(TASK_PREFIX+DEFAULT_TARGET, f.Name) ||
		strings.HasPrefix(DEFAULT_TARGET, f.Name)
}

func splitpath(path string) (string, string) {
	return filepath.Dir(path), filepath.Base(path)
}

// NewFile creates and returns a File instance for the given path.
// If the path is not fully qualified, it is made relative to dir.
// The newly created instance is initialized with the database specified by
// the configuration file found in its root directory or the default database.
// If a file does not have a root directory, it is initialized with a NullDb
// and HasNullDb will return true.
func NewFile(dir, path string) (f *File, err error) {

	if path == "" {
		return nil, errors.New("target path cannot be empty")
	}

	var targetPath string

	if filepath.IsAbs(path) {
		targetPath = path
	} else {
		targetPath = filepath.Clean(filepath.Join(dir, path))
	}

	if isdir, err := fileutils.IsDir(targetPath); err != nil {
		return nil, err
	} else if isdir {
		return nil, fmt.Errorf("target %s is a directory", targetPath)
	}

	f = new(File)

	f.Target = path

	rootDir, filename := splitpath(targetPath)
	relPath := &RelPath{}
	relPath.Add(filename)

	hasRoot := false

	for {
		exists, err := fileutils.DirExists(filepath.Join(rootDir, REDO_DIR))
		if err != nil {
			return nil, err
		}
		if exists {
			hasRoot = true
			break
		}
		if rootDir == "/" || rootDir == "." {
			break
		}
		rootDir, filename = splitpath(rootDir)
		relPath.Add(filename)
	}

	f.RootDir = rootDir

	f.Path = relPath.Join()

	f.PathHash = MakeHash(f.Path)
	f.FullPathHash = MakeHash(filepath.Join(f.RootDir, f.Path))

	f.Debug("@Hash %s: %s -> %s\n", f.RootDir, f.Path, f.PathHash)

	f.Dir, f.Name = splitpath(f.Fullpath())
	f.Ext = filepath.Ext(f.Name)

	if hasRoot {
		// TODO(gsam): Read config file in rootDir to determine DB type, if any.
		// Default to FileDB if not specified.
		// f.Config = Config{DBType: "file"}
		f.db, err = FileDbOpen(f.RootDir)
		if err != nil {
			return nil, err
		}

		err := os.Mkdir(f.tempDir(), 0755)
		if err != nil && !os.IsExist(err) {
			return nil, err
		}

	} else {
		f.Config = Config{DBType: "null"}
		f.db, err = NullDbOpen("")
		if err != nil {
			return nil, err
		}
		f.Debug("@NullDb\n")
	}

	return
}

// HasNullDb specifies whether the File receiver uses a NullDb.
func (f *File) HasNullDb() bool {
	return f.db.IsNull()
}

// Fullpath returns the fully qualified path to the target file.
func (f *File) Fullpath() string {
	return filepath.Join(f.RootDir, f.Path)
}

// Rel makes path relative to f.RootDir.
func (f *File) Rel(path string) string {
	relpath, err := filepath.Rel(f.RootDir, path)
	if err != nil {
		panic(err)
	}
	return filepath.Clean(relpath)
}

// Abs returns a cleaned up fullpath by joining f.RootDir to path.
func (f *File) Abs(path string) string {
	if filepath.IsAbs(path) {
		return path
	}
	return filepath.Clean(filepath.Join(f.RootDir, path))
}

// Exist verifies that the file exists on disk.
func (f *File) Exists() (bool, error) {
	return fileutils.FileExists(f.Fullpath())
}

// HasDoFile returns true if the receiver has been assigned a .do script.
func (f *File) HasDoFile() bool {
	return len(f.DoFile) > 0
}

// IsCurrent returns a boolean denoting whether the target is up to date.

// A target is up to date if the following conditions hold:
//   The file exists
//   The file has not been flagged to be rebuilt
//   The file has not changed since creation. That is; the file has a metadata record
//   	and that record matches the actual file metadata.
//   All the file's prerequisites are also current.

func (f *File) IsCurrent() (bool, error) {
	return f.isCurrent()
}

func (f *File) isCurrent() (bool, error) {

	reason := func(msg string) (bool, error) {
		f.Debug("@Outdated because %s\n", msg)
		return false, nil
	}

	if f.MustRebuild() {
		return reason("REBUILD")
	}

	storedMeta, found, err := f.GetMetadata()
	if err != nil {
		return false, err
	} else if !found {
		return reason("no record metadata")
	}

	fileMeta, err := f.NewMetadata()
	if err != nil {
		return false, err
	} else if fileMeta == nil {
		return reason("no file metadata")
	}

	if !storedMeta.Equal(fileMeta) {
		return reason("record metadata != file metadata")
	}

	// redo-ifcreate dependencies
	created, err := f.PrerequisiteFiles(IFCREATE, AUTO_IFCREATE)
	if err != nil {
		return false, err
	}

	for _, prerequisite := range created {
		if exists, err := prerequisite.Exists(); err != nil {
			return false, err
		} else if exists {
			return reason("ifcreate dependency target exists")
		}
	}

	// redo-ifchange dependencies
	changed, err := f.Prerequisites(IFCHANGE, AUTO_IFCHANGE)
	if err != nil {
		return false, err
	}

	for _, prerequisite := range changed {
		if isCurrent, err := prerequisite.IsCurrent(f.RootDir); err != nil || !isCurrent {
			return isCurrent, err
		}
	}

	return true, nil
}

// NewMetadata computes and returns the file metadata.
func (f *File) NewMetadata() (m *Metadata, err error) {

	m, err = NewMetadata(f.Fullpath(), f.Path)
	if m == nil || err == nil {
		return
	}

	if len(f.DoFile) > 0 {
		if path, err := filepath.Rel(f.RootDir, f.DoFile); err != nil {
			m.DoFile = f.DoFile
		} else {
			m.DoFile = path
		}
	}

	return
}

// ContentHash returns a cryptographic hash of the file contents.
func (f *File) ContentHash() (Hash, error) {
	return ContentHash(f.Fullpath())
}

// Log prints out messages to stderr when the verbosity is greater than N.
func (f *File) Log(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
}

// Debug prints out messages to stderr when the debug flag is enabled.
func (f *File) Debug(format string, args ...interface{}) {
	if Debug {
		for i, value := range args {
			if value == nil {
				args[i] = "<nil>"
			}
		}
		fmt.Fprintf(os.Stderr, "%s %s: ", os.Args[0], f.Target)
		fmt.Fprintf(os.Stderr, format, args...)
	}
}

func (f *File) GenerateNotifications(oldMeta, newMeta *Metadata) error {

	if oldMeta == nil {
		if err := f.NotifyDependents(IFCREATE); err != nil {
			return err
		}
	}

	if !newMeta.Equal(oldMeta) {
		if err := f.NotifyDependents(IFCHANGE); err != nil {
			return err
		}
	}

	return nil
}

// RedoDir returns the path to the .redo directory.
func (f *File) RedoDir() string {
	return filepath.Join(f.RootDir, REDO_DIR)
}

func (f *File) tempDir() string {
	if s := os.Getenv("REDO_TMP_DIR"); len(s) > 0 {
		return s
	}
	return filepath.Join(f.RedoDir(), "tmp")
}

func (f *File) tempFile() (*os.File, error) {
	return ioutil.TempFile(f.tempDir(), strings.Replace(f.Name, ".", "-", -1)+"-redo-tmp-")
}

// DoInfoCandidates generates a list of possible do filenames for this file
func (f *File) DoInfoCandidates() []*DoInfo {

	const sep = `.`
	parts := strings.Split(f.Name, sep)
	n := len(parts)
	if n == 0 {
		return nil
	}

	// +1 for default.do
	out := make([]*DoInfo, n+1)

	add := func(index int, basename string, exts, arg2 []string) {
		a := make([]string, len(exts)+2)
		a[0] = basename
		copy(a[1:], exts)
		a[len(a)-1] = DO_EXT
		out[index] = &DoInfo{Name: strings.Join(a, sep), Arg2: strings.Join(arg2, sep)}
	}

	add(0, parts[0], parts[1:n], parts[0:n]) // target.(ext\.)*do

	for i := 1; i < len(out); i++ {
		add(i, DO_BASENAME, parts[i:n], parts[0:i])
	}

	return out
}

// NewOutput returns an initialized Output
func (f *File) NewOutput(isArg3 bool) (*Output, error) {
	tmp, err := f.tempFile()
	if err != nil {
		return nil, err
	}
	return NewOutput(tmp, isArg3)
}
<commit_msg>Removed unused struct member<commit_after>// Copyright 2014 Gyepi Sam. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package redux

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

	"github.com/gyepisam/fileutils"
)

// File represents a source or target file..
type File struct {
	Target string // file name argument to redo, redo-ifchange, redo-ifcreate, etc

	RootDir string // contains .redo directory
	Path    string // Relative to RootDir

	Dir  string
	Name string
	Ext  string // File extension. Could be empty. Includes preceding dot.

	PathHash     Hash   // SHA1 hash of Path. Used as database key.
	FullPathHash Hash   //SHA1 hash of RootDir/Path. Used for loop detection.
	DoFile       string // Do script used to generate target output.

	Config     Config
	db         DB
	IsTaskFlag bool // If true, target is a task and run for side effects
}

// IsTask denotes when the current target is a task script, either
// implicitly (name begins with @) or explicitly (-task argument to redo).
func (f *File) IsTask() bool {
	return f.IsTaskFlag ||
		strings.HasPrefix(TASK_PREFIX+DEFAULT_TARGET, f.Name) ||
		strings.HasPrefix(DEFAULT_TARGET, f.Name)
}

func splitpath(path string) (string, string) {
	return filepath.Dir(path), filepath.Base(path)
}

// NewFile creates and returns a File instance for the given path.
// If the path is not fully qualified, it is made relative to dir.
// The newly created instance is initialized with the database specified by
// the configuration file found in its root directory or the default database.
// If a file does not have a root directory, it is initialized with a NullDb
// and HasNullDb will return true.
func NewFile(dir, path string) (f *File, err error) {

	if path == "" {
		return nil, errors.New("target path cannot be empty")
	}

	var targetPath string

	if filepath.IsAbs(path) {
		targetPath = path
	} else {
		targetPath = filepath.Clean(filepath.Join(dir, path))
	}

	if isdir, err := fileutils.IsDir(targetPath); err != nil {
		return nil, err
	} else if isdir {
		return nil, fmt.Errorf("target %s is a directory", targetPath)
	}

	f = new(File)

	f.Target = path

	rootDir, filename := splitpath(targetPath)
	relPath := &RelPath{}
	relPath.Add(filename)

	hasRoot := false

	for {
		exists, err := fileutils.DirExists(filepath.Join(rootDir, REDO_DIR))
		if err != nil {
			return nil, err
		}
		if exists {
			hasRoot = true
			break
		}
		if rootDir == "/" || rootDir == "." {
			break
		}
		rootDir, filename = splitpath(rootDir)
		relPath.Add(filename)
	}

	f.RootDir = rootDir

	f.Path = relPath.Join()

	f.PathHash = MakeHash(f.Path)
	f.FullPathHash = MakeHash(filepath.Join(f.RootDir, f.Path))

	f.Debug("@Hash %s: %s -> %s\n", f.RootDir, f.Path, f.PathHash)

	f.Dir, f.Name = splitpath(f.Fullpath())
	f.Ext = filepath.Ext(f.Name)

	if hasRoot {
		// TODO(gsam): Read config file in rootDir to determine DB type, if any.
		// Default to FileDB if not specified.
		// f.Config = Config{DBType: "file"}
		f.db, err = FileDbOpen(f.RootDir)
		if err != nil {
			return nil, err
		}

		err := os.Mkdir(f.tempDir(), 0755)
		if err != nil && !os.IsExist(err) {
			return nil, err
		}

	} else {
		f.Config = Config{DBType: "null"}
		f.db, err = NullDbOpen("")
		if err != nil {
			return nil, err
		}
		f.Debug("@NullDb\n")
	}

	return
}

// HasNullDb specifies whether the File receiver uses a NullDb.
func (f *File) HasNullDb() bool {
	return f.db.IsNull()
}

// Fullpath returns the fully qualified path to the target file.
func (f *File) Fullpath() string {
	return filepath.Join(f.RootDir, f.Path)
}

// Rel makes path relative to f.RootDir.
func (f *File) Rel(path string) string {
	relpath, err := filepath.Rel(f.RootDir, path)
	if err != nil {
		panic(err)
	}
	return filepath.Clean(relpath)
}

// Abs returns a cleaned up fullpath by joining f.RootDir to path.
func (f *File) Abs(path string) string {
	if filepath.IsAbs(path) {
		return path
	}
	return filepath.Clean(filepath.Join(f.RootDir, path))
}

// Exist verifies that the file exists on disk.
func (f *File) Exists() (bool, error) {
	return fileutils.FileExists(f.Fullpath())
}

// HasDoFile returns true if the receiver has been assigned a .do script.
func (f *File) HasDoFile() bool {
	return len(f.DoFile) > 0
}

// IsCurrent returns a boolean denoting whether the target is up to date.

// A target is up to date if the following conditions hold:
//   The file exists
//   The file has not been flagged to be rebuilt
//   The file has not changed since creation. That is; the file has a metadata record
//   	and that record matches the actual file metadata.
//   All the file's prerequisites are also current.

func (f *File) IsCurrent() (bool, error) {
	return f.isCurrent()
}

func (f *File) isCurrent() (bool, error) {

	reason := func(msg string) (bool, error) {
		f.Debug("@Outdated because %s\n", msg)
		return false, nil
	}

	if f.MustRebuild() {
		return reason("REBUILD")
	}

	storedMeta, found, err := f.GetMetadata()
	if err != nil {
		return false, err
	} else if !found {
		return reason("no record metadata")
	}

	fileMeta, err := f.NewMetadata()
	if err != nil {
		return false, err
	} else if fileMeta == nil {
		return reason("no file metadata")
	}

	if !storedMeta.Equal(fileMeta) {
		return reason("record metadata != file metadata")
	}

	// redo-ifcreate dependencies
	created, err := f.PrerequisiteFiles(IFCREATE, AUTO_IFCREATE)
	if err != nil {
		return false, err
	}

	for _, prerequisite := range created {
		if exists, err := prerequisite.Exists(); err != nil {
			return false, err
		} else if exists {
			return reason("ifcreate dependency target exists")
		}
	}

	// redo-ifchange dependencies
	changed, err := f.Prerequisites(IFCHANGE, AUTO_IFCHANGE)
	if err != nil {
		return false, err
	}

	for _, prerequisite := range changed {
		if isCurrent, err := prerequisite.IsCurrent(f.RootDir); err != nil || !isCurrent {
			return isCurrent, err
		}
	}

	return true, nil
}

// NewMetadata computes and returns the file metadata.
func (f *File) NewMetadata() (m *Metadata, err error) {

	m, err = NewMetadata(f.Fullpath(), f.Path)
	if m == nil || err == nil {
		return
	}

	if len(f.DoFile) > 0 {
		if path, err := filepath.Rel(f.RootDir, f.DoFile); err != nil {
			m.DoFile = f.DoFile
		} else {
			m.DoFile = path
		}
	}

	return
}

// ContentHash returns a cryptographic hash of the file contents.
func (f *File) ContentHash() (Hash, error) {
	return ContentHash(f.Fullpath())
}

// Log prints out messages to stderr when the verbosity is greater than N.
func (f *File) Log(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
}

// Debug prints out messages to stderr when the debug flag is enabled.
func (f *File) Debug(format string, args ...interface{}) {
	if Debug {
		for i, value := range args {
			if value == nil {
				args[i] = "<nil>"
			}
		}
		fmt.Fprintf(os.Stderr, "%s %s: ", os.Args[0], f.Target)
		fmt.Fprintf(os.Stderr, format, args...)
	}
}

func (f *File) GenerateNotifications(oldMeta, newMeta *Metadata) error {

	if oldMeta == nil {
		if err := f.NotifyDependents(IFCREATE); err != nil {
			return err
		}
	}

	if !newMeta.Equal(oldMeta) {
		if err := f.NotifyDependents(IFCHANGE); err != nil {
			return err
		}
	}

	return nil
}

// RedoDir returns the path to the .redo directory.
func (f *File) RedoDir() string {
	return filepath.Join(f.RootDir, REDO_DIR)
}

func (f *File) tempDir() string {
	if s := os.Getenv("REDO_TMP_DIR"); len(s) > 0 {
		return s
	}
	return filepath.Join(f.RedoDir(), "tmp")
}

func (f *File) tempFile() (*os.File, error) {
	return ioutil.TempFile(f.tempDir(), strings.Replace(f.Name, ".", "-", -1)+"-redo-tmp-")
}

// DoInfoCandidates generates a list of possible do filenames for this file
func (f *File) DoInfoCandidates() []*DoInfo {

	const sep = `.`
	parts := strings.Split(f.Name, sep)
	n := len(parts)
	if n == 0 {
		return nil
	}

	// +1 for default.do
	out := make([]*DoInfo, n+1)

	add := func(index int, basename string, exts, arg2 []string) {
		a := make([]string, len(exts)+2)
		a[0] = basename
		copy(a[1:], exts)
		a[len(a)-1] = DO_EXT
		out[index] = &DoInfo{Name: strings.Join(a, sep), Arg2: strings.Join(arg2, sep)}
	}

	add(0, parts[0], parts[1:n], parts[0:n]) // target.(ext\.)*do

	for i := 1; i < len(out); i++ {
		add(i, DO_BASENAME, parts[i:n], parts[0:i])
	}

	return out
}

// NewOutput returns an initialized Output
func (f *File) NewOutput(isArg3 bool) (*Output, error) {
	tmp, err := f.tempFile()
	if err != nil {
		return nil, err
	}
	return NewOutput(tmp, isArg3)
}
<|endoftext|>


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

import (
	"errors"
	"net/http"
	"reflect"
)

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

func (p processor) process(v reflect.Value, data []string) error {
	return nil
}

type typeMap map[string]processor

func createTypeMap(t reflect.Type) typeMap {
	return nil
}

func ProcessForm(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 := createTypeMap(v.Type())
	if err := r.ParseForm(); err != nil {
		return err
	}
	for key, processor := range tm {
		var (
			val []string
			ok  bool
		)
		if processor.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := processor.process(v.FieldByIndex(processor.Index), val); err != nil {

			}
		} else if processor.Required {

		}
	}
	return nil
}

var (
	ErrNeedPointer = errors.New("need pointer to type")
	ErrNeedStruct  = errors.New("need struct type")
)
<commit_msg>added typeMap caching<commit_after>// Package form provides an easy to use way to parse form values from an HTTP
// request into a struct or other data object
package form // import "vimagination.zapto.org/form"

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

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

func (p processor) process(v reflect.Value, data []string) error {
	return nil
}

type typeMap map[string]processor

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 createTypeMap(t reflect.Type) typeMap {
	tm, ok = typeMaps[t]
	if ok {
		return tm
	}
	tm = make(typeMap)
	typeMaps[t] = tm
	return tm
}

func ProcessForm(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
	}
	for key, processor := range tm {
		var (
			val []string
			ok  bool
		)
		if processor.Post {
			val, ok = r.PostForm[key]
		} else {
			val, ok = r.Form[key]
		}
		if ok {
			if err := processor.process(v.FieldByIndex(processor.Index), val); err != nil {

			}
		} else if processor.Required {

		}
	}
	return nil
}

var (
	ErrNeedPointer = errors.New("need pointer to type")
	ErrNeedStruct  = errors.New("need struct type")
)
<|endoftext|>


<commit_before>package registry // import "github.com/docker/docker/registry"

import (
	"github.com/docker/distribution/reference"
	registrytypes "github.com/docker/docker/api/types/registry"
)

// RepositoryData tracks the image list, list of endpoints for a repository
type RepositoryData struct {
	// ImgList is a list of images in the repository
	ImgList map[string]*ImgData
	// Endpoints is a list of endpoints returned in X-Docker-Endpoints
	Endpoints []string
}

// ImgData is used to transfer image checksums to and from the registry
type ImgData struct {
	// ID is an opaque string that identifies the image
	ID              string `json:"id"`
	Checksum        string `json:"checksum,omitempty"`
	ChecksumPayload string `json:"-"`
	Tag             string `json:",omitempty"`
}

// PingResult contains the information returned when pinging a registry. It
// indicates the registry's version and whether the registry claims to be a
// standalone registry.
type PingResult struct {
	// Version is the registry version supplied by the registry in an HTTP
	// header
	Version string `json:"version"`
	// Standalone is set to true if the registry indicates it is a
	// standalone registry in the X-Docker-Registry-Standalone
	// header
	Standalone bool `json:"standalone"`
}

// APIVersion is an integral representation of an API version (presently
// either 1 or 2)
type APIVersion int

func (av APIVersion) String() string {
	return apiVersions[av]
}

// API Version identifiers.
const (
	_                      = iota
	APIVersion1 APIVersion = iota
	APIVersion2
)

var apiVersions = map[APIVersion]string{
	APIVersion1: "v1",
	APIVersion2: "v2",
}

// RepositoryInfo describes a repository
type RepositoryInfo struct {
	Name reference.Named
	// Index points to registry information
	Index *registrytypes.IndexInfo
	// Official indicates whether the repository is considered official.
	// If the registry is official, and the normalized name does not
	// contain a '/' (e.g. "foo"), then it is considered an official repo.
	Official bool
	// Class represents the class of the repository, such as "plugin"
	// or "image".
	Class string
}
<commit_msg>registry: remove use of iota for consts<commit_after>package registry // import "github.com/docker/docker/registry"

import (
	"github.com/docker/distribution/reference"
	registrytypes "github.com/docker/docker/api/types/registry"
)

// RepositoryData tracks the image list, list of endpoints for a repository
type RepositoryData struct {
	// ImgList is a list of images in the repository
	ImgList map[string]*ImgData
	// Endpoints is a list of endpoints returned in X-Docker-Endpoints
	Endpoints []string
}

// ImgData is used to transfer image checksums to and from the registry
type ImgData struct {
	// ID is an opaque string that identifies the image
	ID              string `json:"id"`
	Checksum        string `json:"checksum,omitempty"`
	ChecksumPayload string `json:"-"`
	Tag             string `json:",omitempty"`
}

// PingResult contains the information returned when pinging a registry. It
// indicates the registry's version and whether the registry claims to be a
// standalone registry.
type PingResult struct {
	// Version is the registry version supplied by the registry in an HTTP
	// header
	Version string `json:"version"`
	// Standalone is set to true if the registry indicates it is a
	// standalone registry in the X-Docker-Registry-Standalone
	// header
	Standalone bool `json:"standalone"`
}

// APIVersion is an integral representation of an API version (presently
// either 1 or 2)
type APIVersion int

func (av APIVersion) String() string {
	return apiVersions[av]
}

// API Version identifiers.
const (
	APIVersion1 APIVersion = 1
	APIVersion2 APIVersion = 2
)

var apiVersions = map[APIVersion]string{
	APIVersion1: "v1",
	APIVersion2: "v2",
}

// RepositoryInfo describes a repository
type RepositoryInfo struct {
	Name reference.Named
	// Index points to registry information
	Index *registrytypes.IndexInfo
	// Official indicates whether the repository is considered official.
	// If the registry is official, and the normalized name does not
	// contain a '/' (e.g. "foo"), then it is considered an official repo.
	Official bool
	// Class represents the class of the repository, such as "plugin"
	// or "image".
	Class string
}
<|endoftext|>


<commit_before>package of10

import (
	"net"

	. "github.com/oshothebig/goflow/openflow"
)

type FeaturesRequest struct {
	Header
}

type FeaturesReply struct {
	Header
	DatapathId   DatapathId
	Buffers      uint32
	Tables       uint8
	pad          [3]uint8
	Capabilities Capability
	Actions      ActionType
	Ports        []PhysicalPort
}

type DatapathId uint64
type Capability uint32

const (
	OFPC_FLOW_STATS Capability = 1 << iota
	OFPC_TABLE_STATS
	OFPC_PORT_STATS
	OFPC_STP
	OFPC_RESERVED
	OFPC_IP_REASM
	OFPC_QUEUE_STATS
	OFPC_ARP_MATCH_IP
)

var Capabilities = struct {
	FlowStats    Capability
	TableStats   Capability
	PortStats    Capability
	Stp          Capability
	Reserved     Capability
	IpReassemble Capability
	QueueStats   Capability
	ArpMatchIp   Capability
}{
	OFPC_FLOW_STATS,
	OFPC_TABLE_STATS,
	OFPC_PORT_STATS,
	OFPC_STP,
	OFPC_RESERVED,
	OFPC_IP_REASM,
	OFPC_QUEUE_STATS,
	OFPC_ARP_MATCH_IP,
}

type SwitchConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type ConfigFlag uint16

const (
	OFPC_FRAG_NORMAL ConfigFlag = iota
	OFPC_FRAG_DROP
	OFPC_FRAG_REASM
	OFPC_FRAG_MASK
)

var ConfigFlags = struct {
	FragmentNormal     ConfigFlag
	FragmentDrop       ConfigFlag
	FragmentReassemble ConfigFlag
	FragmentMask       ConfigFlag
}{
	OFPC_FRAG_NORMAL,
	OFPC_FRAG_DROP,
	OFPC_FRAG_REASM,
	OFPC_FRAG_MASK,
}

type FlowMod struct {
	Header
	Match       Match
	Cookie      Cookie
	Command     FlowModCommand
	IdleTimeout uint16
	HardTimeout uint16
	Priority    uint16
	BufferId    BufferId
	OutPort     PortNumber
	Flags       FlowModFlag
	Actions     []Action
}

type Cookie uint64
type FlowModCommand uint16
type BufferId uint32
type FlowModFlag uint16

const (
	OFPFC_ADD FlowModCommand = iota
	OFPFC_MODIFY
	OFPFC_MODIFY_STRICT
	OFPFC_DELETE
	OFPFC_DELETE_STRICT
)

var FlowModCommands = struct {
	Add          FlowModCommand
	Modify       FlowModCommand
	ModifyStrict FlowModCommand
	Delete       FlowModCommand
	DeleteStrict FlowModCommand
}{
	OFPFC_ADD,
	OFPFC_MODIFY,
	OFPFC_MODIFY_STRICT,
	OFPFC_DELETE,
	OFPFC_DELETE_STRICT,
}

const (
	OFPFF_SEND_FLOW_REM FlowModFlag = 1 << iota
	OFPFF_CHECK_OVERLAP
	OFPFF_EMERG
)

var FlowModFlags = struct {
	SendFlowRemoved FlowModFlag
	CheckOverlap    FlowModFlag
	Emergency       FlowModFlag
}{
	OFPFF_SEND_FLOW_REM,
	OFPFF_CHECK_OVERLAP,
	OFPFF_EMERG,
}

type PortMod struct {
	Header
	PortNumber      PortNumber
	HardwareAddress net.HardwareAddr
	Config          PortConfig
	Mask            PortConfig
	Advertise       PortFeature
	pad             [4]uint8
}

type QueueGetConfigRequest struct {
	Header
	Port PortNumber
	pad  [2]uint8
}

type QueueGetConfigReply struct {
	Header
	Port   PortNumber
	pad    [6]uint8
	Queues []PacketQueue
}
<commit_msg>Define structs related to Stats messages<commit_after>package of10

import (
	"net"

	. "github.com/oshothebig/goflow/openflow"
)

type FeaturesRequest struct {
	Header
}

type FeaturesReply struct {
	Header
	DatapathId   DatapathId
	Buffers      uint32
	Tables       uint8
	pad          [3]uint8
	Capabilities Capability
	Actions      ActionType
	Ports        []PhysicalPort
}

type DatapathId uint64
type Capability uint32

const (
	OFPC_FLOW_STATS Capability = 1 << iota
	OFPC_TABLE_STATS
	OFPC_PORT_STATS
	OFPC_STP
	OFPC_RESERVED
	OFPC_IP_REASM
	OFPC_QUEUE_STATS
	OFPC_ARP_MATCH_IP
)

var Capabilities = struct {
	FlowStats    Capability
	TableStats   Capability
	PortStats    Capability
	Stp          Capability
	Reserved     Capability
	IpReassemble Capability
	QueueStats   Capability
	ArpMatchIp   Capability
}{
	OFPC_FLOW_STATS,
	OFPC_TABLE_STATS,
	OFPC_PORT_STATS,
	OFPC_STP,
	OFPC_RESERVED,
	OFPC_IP_REASM,
	OFPC_QUEUE_STATS,
	OFPC_ARP_MATCH_IP,
}

type SwitchConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type ConfigFlag uint16

const (
	OFPC_FRAG_NORMAL ConfigFlag = iota
	OFPC_FRAG_DROP
	OFPC_FRAG_REASM
	OFPC_FRAG_MASK
)

var ConfigFlags = struct {
	FragmentNormal     ConfigFlag
	FragmentDrop       ConfigFlag
	FragmentReassemble ConfigFlag
	FragmentMask       ConfigFlag
}{
	OFPC_FRAG_NORMAL,
	OFPC_FRAG_DROP,
	OFPC_FRAG_REASM,
	OFPC_FRAG_MASK,
}

type FlowMod struct {
	Header
	Match       Match
	Cookie      Cookie
	Command     FlowModCommand
	IdleTimeout uint16
	HardTimeout uint16
	Priority    uint16
	BufferId    BufferId
	OutPort     PortNumber
	Flags       FlowModFlag
	Actions     []Action
}

type Cookie uint64
type FlowModCommand uint16
type BufferId uint32
type FlowModFlag uint16

const (
	OFPFC_ADD FlowModCommand = iota
	OFPFC_MODIFY
	OFPFC_MODIFY_STRICT
	OFPFC_DELETE
	OFPFC_DELETE_STRICT
)

var FlowModCommands = struct {
	Add          FlowModCommand
	Modify       FlowModCommand
	ModifyStrict FlowModCommand
	Delete       FlowModCommand
	DeleteStrict FlowModCommand
}{
	OFPFC_ADD,
	OFPFC_MODIFY,
	OFPFC_MODIFY_STRICT,
	OFPFC_DELETE,
	OFPFC_DELETE_STRICT,
}

const (
	OFPFF_SEND_FLOW_REM FlowModFlag = 1 << iota
	OFPFF_CHECK_OVERLAP
	OFPFF_EMERG
)

var FlowModFlags = struct {
	SendFlowRemoved FlowModFlag
	CheckOverlap    FlowModFlag
	Emergency       FlowModFlag
}{
	OFPFF_SEND_FLOW_REM,
	OFPFF_CHECK_OVERLAP,
	OFPFF_EMERG,
}

type PortMod struct {
	Header
	PortNumber      PortNumber
	HardwareAddress net.HardwareAddr
	Config          PortConfig
	Mask            PortConfig
	Advertise       PortFeature
	pad             [4]uint8
}

type QueueGetConfigRequest struct {
	Header
	Port PortNumber
	pad  [2]uint8
}

type QueueGetConfigReply struct {
	Header
	Port   PortNumber
	pad    [6]uint8
	Queues []PacketQueue
}

type StatsRequest struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsReply struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsType uint16

const (
	OFPST_DESC StatsType = iota
	OFPST_FLOW
	OFPST_AGGREGATE
	OFPST_TABLE
	OFPST_PORT
	OFPST_QUEUE
	OFPST_VENDOR StatsType = 0xffff
)

var StatsTypes = struct {
	Description StatsType
	Flow        StatsType
	Aggregate   StatsType
	Table       StatsType
	Port        StatsType
	Queue       StatsType
	Vendor      StatsType
}{
	OFPST_DESC,
	OFPST_FLOW,
	OFPST_AGGREGATE,
	OFPST_TABLE,
	OFPST_PORT,
	OFPST_QUEUE,
	OFPST_VENDOR,
}
<|endoftext|>


<commit_before>package process

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	"kego.io/process/parser"

	"fmt"

	"kego.io/context/envctx"
	"kego.io/kerr"
	"kego.io/kerr/assert"
	"kego.io/process/tests"
)

func TestRun(t *testing.T) {

	cb := tests.NewContextBuilder().RealGopath()
	defer cb.Cleanup()

	path, dir := cb.TempPackage("d", map[string]string{
		"a.yaml": `
			type: system:type
			id: a
			fields:
				b:
					type: system:@string
					maxLength: 5`,
		"d.go": `package d`,
	})

	cb.Path(path).Dir(dir).Jauto().Wg().Sauto(parser.Parse)

	env := envctx.FromContext(cb.Ctx())

	err := Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	b, err := ioutil.ReadFile(filepath.Join(dir, "generated.go"))
	assert.NoError(t, err)
	assert.Contains(t, string(b), "pkg.InitType(\"a\", reflect.TypeOf((*A)(nil)), reflect.TypeOf((*ARule)(nil)), reflect.TypeOf((*AInterface)(nil)).Elem())")
	assert.Contains(t, string(b), fmt.Sprintf("%v", env.Hash))

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	file1, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time1 := file1.ModTime()

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	cb.TempFile("c.yaml", `
		type: a
		id: c
		b: foo`)

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	// should not rebuild validate command
	file2, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time2 := file2.ModTime()
	assert.Equal(t, time1, time2)

	cb.TempFile("e.yaml", `
		type: a
		id: e
		b: tooolong`)

	err = RunValidateCommand(cb.Ctx())
	assert.IsError(t, err, "KFNIOHWCBT")
	assert.HasError(t, err, "ETWHPXTUVB")

	cb.TempFile("f.yaml", `
		type: system:type
		id: f`)

	// This loads the new system.Type into the system cache
	cb.Sauto(parser.Parse)
	// This generates a new generated.go
	err = Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	// This will re-run the build, but still return the validation error
	err = RunValidateCommand(cb.Ctx())
	assert.IsError(t, err, "KFNIOHWCBT")
	assert.HasError(t, err, "ETWHPXTUVB")

	cb.RemoveTempFile("e.yaml")

	cb.TempFile("h.yaml", `
		type: system:type
		id: h`)

	// This loads the new system.Type into the system cache
	cb.Sauto(parser.Parse)
	// This generates a new generated.go
	err = Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	// This will re-run the build, but not return the validation error
	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	// should rebuild validate command
	file3, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time3 := file3.ModTime()
	assert.NotEqual(t, time1, time3)

	cb.TempFile("g.yaml", `
		type: system:type
		id: g`)

	// We add a new type, but we haven't generated the struct, so it will fail with hash changed
	err = runValidateCommand(cb.Ctx(), false, false)
	assert.IsError(t, err, "DTTHRRJSSF")

	err = os.Remove(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)

	_, err = os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.True(t, os.IsNotExist(err))

	err = runValidateCommand(cb.Ctx(), false, false)
	assert.IsError(t, err, "DTTHRRJSSF")
	_, ok := kerr.Source(err).(*os.PathError)
	assert.True(t, ok)

}
<commit_msg>TestLogger, TestMultiWriter<commit_after>package process

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	"kego.io/process/parser"

	"fmt"

	"bytes"

	"kego.io/context/envctx"
	"kego.io/kerr"
	"kego.io/kerr/assert"
	"kego.io/process/tests"
)

func TestMultiWriter(t *testing.T) {
	var p, w1, w2 []byte
	pb := bytes.NewBuffer(p)
	w1b := bytes.NewBuffer(w1)
	w2b := bytes.NewBuffer(w2)
	mw := MultiWriter(pb, w1b, w2b)
	mw.Write([]byte("a"))
	mw.Write([]byte("b"))
	assert.Equal(t, "ab", pb.String())
	assert.Equal(t, "ab", w1b.String())
	assert.Equal(t, "ab", w2b.String())
}

func TestLogger(t *testing.T) {
	_, o, e := logger(false)
	_, ok := o.(*bytes.Buffer)
	assert.True(t, ok)
	_, ok = e.(*bytes.Buffer)
	assert.True(t, ok)

	_, o, e = logger(true)
	_, ok = o.(*multiWriter)
	assert.True(t, ok)
	_, ok = e.(*multiWriter)
	assert.True(t, ok)
}

func TestRun(t *testing.T) {

	cb := tests.NewContextBuilder().RealGopath()
	defer cb.Cleanup()

	path, dir := cb.TempPackage("d", map[string]string{
		"a.yaml": `
			type: system:type
			id: a
			fields:
				b:
					type: system:@string
					maxLength: 5`,
		"d.go": `package d`,
	})

	cb.Path(path).Dir(dir).Jauto().Wg().Sauto(parser.Parse)

	env := envctx.FromContext(cb.Ctx())

	err := Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	b, err := ioutil.ReadFile(filepath.Join(dir, "generated.go"))
	assert.NoError(t, err)
	assert.Contains(t, string(b), "pkg.InitType(\"a\", reflect.TypeOf((*A)(nil)), reflect.TypeOf((*ARule)(nil)), reflect.TypeOf((*AInterface)(nil)).Elem())")
	assert.Contains(t, string(b), fmt.Sprintf("%v", env.Hash))

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	file1, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time1 := file1.ModTime()

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	cb.TempFile("c.yaml", `
		type: a
		id: c
		b: foo`)

	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	// should not rebuild validate command
	file2, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time2 := file2.ModTime()
	assert.Equal(t, time1, time2)

	cb.TempFile("e.yaml", `
		type: a
		id: e
		b: tooolong`)

	err = RunValidateCommand(cb.Ctx())
	assert.IsError(t, err, "KFNIOHWCBT")
	assert.HasError(t, err, "ETWHPXTUVB")

	cb.TempFile("f.yaml", `
		type: system:type
		id: f`)

	// This loads the new system.Type into the system cache
	cb.Sauto(parser.Parse)
	// This generates a new generated.go
	err = Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	// This will re-run the build, but still return the validation error
	err = RunValidateCommand(cb.Ctx())
	assert.IsError(t, err, "KFNIOHWCBT")
	assert.HasError(t, err, "ETWHPXTUVB")

	cb.RemoveTempFile("e.yaml")

	cb.TempFile("h.yaml", `
		type: system:type
		id: h`)

	// This loads the new system.Type into the system cache
	cb.Sauto(parser.Parse)
	// This generates a new generated.go
	err = Generate(cb.Ctx(), env)
	assert.NoError(t, err)

	// This will re-run the build, but not return the validation error
	err = RunValidateCommand(cb.Ctx())
	assert.NoError(t, err)

	// should rebuild validate command
	file3, err := os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)
	time3 := file3.ModTime()
	assert.NotEqual(t, time1, time3)

	cb.TempFile("g.yaml", `
		type: system:type
		id: g`)

	// We add a new type, but we haven't generated the struct, so it will fail with hash changed
	err = runValidateCommand(cb.Ctx(), false, false)
	assert.IsError(t, err, "DTTHRRJSSF")

	err = os.Remove(filepath.Join(dir, ".localke", "validate"))
	assert.NoError(t, err)

	_, err = os.Stat(filepath.Join(dir, ".localke", "validate"))
	assert.True(t, os.IsNotExist(err))

	err = runValidateCommand(cb.Ctx(), false, false)
	assert.IsError(t, err, "DTTHRRJSSF")
	_, ok := kerr.Source(err).(*os.PathError)
	assert.True(t, ok)

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"text/template"

	"github.com/gorilla/mux"
	. "github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/mesh"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

var rootTemplate = template.New("root").Funcs(map[string]interface{}{
	"countDNSEntries": func(entries []nameserver.EntryStatus) int {
		count := 0
		for _, entry := range entries {
			if entry.Tombstone == 0 {
				count++
			}
		}
		return count
	},
	"upstreamServers": func(servers []string) string {
		if len(servers) == 0 {
			return "none"
		}
		return strings.Join(servers, ", ")
	},
	"printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string {
		var buffer bytes.Buffer

		type stats struct {
			ips       uint32
			nickname  string
			reachable bool
		}

		peerStats := make(map[string]*stats)

		for _, entry := range status.Entries {
			s, found := peerStats[entry.Peer]
			if !found {
				s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
				peerStats[entry.Peer] = s
			}
			s.ips += entry.Size
		}

		printOwned := func(name string, nickName string, reachable bool, ips uint32) {
			reachableStr := ""
			if !reachable {
				reachableStr = "- unreachable!"
			}
			percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs)

			displayName := name + " (" + nickName + "):"
			fmt.Fprintf(&buffer, "%-32s %8d IPs (%04.1f%% of total) %s\n",
				displayName, ips, percentageRanges, reachableStr)
		}

		// print the local info first
		if ourStats := peerStats[router.Name]; ourStats != nil {
			printOwned(router.Name, ourStats.nickname, true, ourStats.ips)
		}

		// and then the rest
		for peer, stats := range peerStats {
			if peer != router.Name {
				printOwned(peer, stats.nickname, stats.reachable, stats.ips)
			}
		}

		return buffer.String()
	},
	"allIPAMOwnersUnreachable": func(status ipam.Status) bool {
		for _, entry := range status.Entries {
			if entry.Size > 0 && entry.IsKnownPeer {
				return false
			}
		}
		return true
	},
	"printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string {
		counts := make(map[string]int)
		for _, conn := range conns {
			counts[conn.State]++
		}
		return printCounts(counts, []string{"established", "pending", "retrying", "failed", "connecting"})
	},
	"printPeerConnectionCounts": func(peers []mesh.PeerStatus) string {
		counts := make(map[string]int)
		for _, peer := range peers {
			for _, conn := range peer.Connections {
				if conn.Established {
					counts["established"]++
				} else {
					counts["pending"]++
				}
			}
		}
		return printCounts(counts, []string{"established", "pending"})
	},
	"printState": func(enabled bool) string {
		if enabled {
			return "enabled"
		}
		return "disabled"
	},
	"trimSuffix": strings.TrimSuffix,
})

// Print counts in a specified order
func printCounts(counts map[string]int, keys []string) string {
	var stringCounts []string
	for _, key := range keys {
		if count, ok := counts[key]; ok {
			stringCounts = append(stringCounts, fmt.Sprintf("%d %s", count, key))
		}
	}
	return strings.Join(stringCounts, ", ")
}

// Strip escaped newlines from template
func escape(template string) string {
	return strings.Replace(template, "\\\n", "", -1)
}

// Define a named template panicking on error
func defTemplate(name string, text string) *template.Template {
	return template.Must(rootTemplate.New(name).Parse(escape(text)))
}

var statusTemplate = defTemplate("status", `\
       Version: {{.Version}}

       Service: router
      Protocol: {{.Router.Protocol}} \
{{if eq .Router.ProtocolMinVersion .Router.ProtocolMaxVersion}}\
{{.Router.ProtocolMaxVersion}}\
{{else}}\
{{.Router.ProtocolMinVersion}}..{{.Router.ProtocolMaxVersion}}\
{{end}}
          Name: {{.Router.Name}}({{.Router.NickName}})
    Encryption: {{printState .Router.Encryption}}
 PeerDiscovery: {{printState .Router.PeerDiscovery}}
       Targets: {{len .Router.Targets}}
   Connections: {{len .Router.Connections}}{{with printConnectionCounts .Router.Connections}} ({{.}}){{end}}
         Peers: {{len .Router.Peers}}{{with printPeerConnectionCounts .Router.Peers}} (with {{.}} connections){{end}}
{{if .IPAM}}\

       Service: ipam
{{if .IPAM.Entries}}\
{{if allIPAMOwnersUnreachable .IPAM}}\
        Status: all IP ranges owned by unreachable peers - use 'rmpeer' if they are dead
{{else if len .IPAM.PendingAllocates}}\
        Status: waiting for IP range grant from peers
{{else}}\
        Status: ready
{{end}}\
{{else if .IPAM.Paxos}}\
        Status: awaiting consensus (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}})
{{else}}\
        Status: idle
{{end}}\
         Range: {{.IPAM.Range}}
 DefaultSubnet: {{.IPAM.DefaultSubnet}}
{{end}}\
{{if .DNS}}\

       Service: dns
        Domain: {{.DNS.Domain}}
      Upstream: {{upstreamServers .DNS.Upstream}}
           TTL: {{.DNS.TTL}}
       Entries: {{countDNSEntries .DNS.Entries}}
{{end}}\
`)

var targetsTemplate = defTemplate("targetsTemplate", `\
{{range .Router.Targets}}{{.}}
{{end}}\
`)

var connectionsTemplate = defTemplate("connectionsTemplate", `\
{{range .Router.Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}}
{{end}}\
`)

var peersTemplate = defTemplate("peers", `\
{{range .Router.Peers}}\
{{.Name}}({{.NickName}})
{{range .Connections}}\
   {{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \
{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-32v" $nameNickName}} \
{{if .Established}}established{{else}}pending{{end}}
{{end}}\
{{end}}\
`)

var dnsEntriesTemplate = defTemplate("dnsEntries", `\
{{$domain := printf ".%v" .DNS.Domain}}\
{{range .DNS.Entries}}\
{{if eq .Tombstone 0}}\
{{$hostname := trimSuffix .Hostname $domain}}\
{{printf "%-12v" $hostname}} {{printf "%-15v" .Address}} {{printf "%12.12v" .ContainerID}} {{.Origin}}
{{end}}\
{{end}}\
`)

var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`)

type WeaveStatus struct {
	Version string
	Router  *weave.NetworkRouterStatus `json:"Router,omitempty"`
	IPAM    *ipam.Status               `json:"IPAM,omitempty"`
	DNS     *nameserver.Status         `json:"DNS,omitempty"`
}

func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
	status := func() WeaveStatus {
		return WeaveStatus{
			version,
			weave.NewNetworkRouterStatus(router),
			ipam.NewStatus(allocator, defaultSubnet),
			nameserver.NewStatus(ns, dnsserver)}
	}
	muxRouter.Methods("GET").Path("/report").Headers("Accept", "application/json").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			json, err := json.MarshalIndent(status(), "", "    ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				Log.Error("Error during report marshalling: ", err)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(json)
		})

	muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			formatTemplate, err := template.New("format").Parse(mux.Vars(r)["format"])
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if err := formatTemplate.Execute(w, status()); err != nil {
				http.Error(w, "error during template execution", http.StatusInternalServerError)
				Log.Error(err)
			}
		})

	defHandler := func(path string, template *template.Template) {
		muxRouter.Methods("GET").Path(path).HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				if err := template.Execute(w, status()); err != nil {
					http.Error(w, "error during template execution", http.StatusInternalServerError)
					Log.Error(err)
				}
			})
	}

	defHandler("/status", statusTemplate)
	defHandler("/status/targets", targetsTemplate)
	defHandler("/status/connections", connectionsTemplate)
	defHandler("/status/peers", peersTemplate)
	defHandler("/status/dns", dnsEntriesTemplate)
	defHandler("/status/ipam", ipamTemplate)

}
<commit_msg>Adjust formatting after review feedback; hostnames up to 14 chars will now align<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"text/template"

	"github.com/gorilla/mux"
	. "github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/mesh"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

var rootTemplate = template.New("root").Funcs(map[string]interface{}{
	"countDNSEntries": func(entries []nameserver.EntryStatus) int {
		count := 0
		for _, entry := range entries {
			if entry.Tombstone == 0 {
				count++
			}
		}
		return count
	},
	"upstreamServers": func(servers []string) string {
		if len(servers) == 0 {
			return "none"
		}
		return strings.Join(servers, ", ")
	},
	"printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string {
		var buffer bytes.Buffer

		type stats struct {
			ips       uint32
			nickname  string
			reachable bool
		}

		peerStats := make(map[string]*stats)

		for _, entry := range status.Entries {
			s, found := peerStats[entry.Peer]
			if !found {
				s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
				peerStats[entry.Peer] = s
			}
			s.ips += entry.Size
		}

		printOwned := func(name string, nickName string, reachable bool, ips uint32) {
			reachableStr := ""
			if !reachable {
				reachableStr = "- unreachable!"
			}
			percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs)

			displayName := name + "(" + nickName + ")"
			fmt.Fprintf(&buffer, "%-37v %8d IPs (%04.1f%% of total) %s\n",
				displayName, ips, percentageRanges, reachableStr)
		}

		// print the local info first
		if ourStats := peerStats[router.Name]; ourStats != nil {
			printOwned(router.Name, ourStats.nickname, true, ourStats.ips)
		}

		// and then the rest
		for peer, stats := range peerStats {
			if peer != router.Name {
				printOwned(peer, stats.nickname, stats.reachable, stats.ips)
			}
		}

		return buffer.String()
	},
	"allIPAMOwnersUnreachable": func(status ipam.Status) bool {
		for _, entry := range status.Entries {
			if entry.Size > 0 && entry.IsKnownPeer {
				return false
			}
		}
		return true
	},
	"printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string {
		counts := make(map[string]int)
		for _, conn := range conns {
			counts[conn.State]++
		}
		return printCounts(counts, []string{"established", "pending", "retrying", "failed", "connecting"})
	},
	"printPeerConnectionCounts": func(peers []mesh.PeerStatus) string {
		counts := make(map[string]int)
		for _, peer := range peers {
			for _, conn := range peer.Connections {
				if conn.Established {
					counts["established"]++
				} else {
					counts["pending"]++
				}
			}
		}
		return printCounts(counts, []string{"established", "pending"})
	},
	"printState": func(enabled bool) string {
		if enabled {
			return "enabled"
		}
		return "disabled"
	},
	"trimSuffix": strings.TrimSuffix,
})

// Print counts in a specified order
func printCounts(counts map[string]int, keys []string) string {
	var stringCounts []string
	for _, key := range keys {
		if count, ok := counts[key]; ok {
			stringCounts = append(stringCounts, fmt.Sprintf("%d %s", count, key))
		}
	}
	return strings.Join(stringCounts, ", ")
}

// Strip escaped newlines from template
func escape(template string) string {
	return strings.Replace(template, "\\\n", "", -1)
}

// Define a named template panicking on error
func defTemplate(name string, text string) *template.Template {
	return template.Must(rootTemplate.New(name).Parse(escape(text)))
}

var statusTemplate = defTemplate("status", `\
       Version: {{.Version}}

       Service: router
      Protocol: {{.Router.Protocol}} \
{{if eq .Router.ProtocolMinVersion .Router.ProtocolMaxVersion}}\
{{.Router.ProtocolMaxVersion}}\
{{else}}\
{{.Router.ProtocolMinVersion}}..{{.Router.ProtocolMaxVersion}}\
{{end}}
          Name: {{.Router.Name}}({{.Router.NickName}})
    Encryption: {{printState .Router.Encryption}}
 PeerDiscovery: {{printState .Router.PeerDiscovery}}
       Targets: {{len .Router.Targets}}
   Connections: {{len .Router.Connections}}{{with printConnectionCounts .Router.Connections}} ({{.}}){{end}}
         Peers: {{len .Router.Peers}}{{with printPeerConnectionCounts .Router.Peers}} (with {{.}} connections){{end}}
{{if .IPAM}}\

       Service: ipam
{{if .IPAM.Entries}}\
{{if allIPAMOwnersUnreachable .IPAM}}\
        Status: all IP ranges owned by unreachable peers - use 'rmpeer' if they are dead
{{else if len .IPAM.PendingAllocates}}\
        Status: waiting for IP range grant from peers
{{else}}\
        Status: ready
{{end}}\
{{else if .IPAM.Paxos}}\
        Status: awaiting consensus (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}})
{{else}}\
        Status: idle
{{end}}\
         Range: {{.IPAM.Range}}
 DefaultSubnet: {{.IPAM.DefaultSubnet}}
{{end}}\
{{if .DNS}}\

       Service: dns
        Domain: {{.DNS.Domain}}
      Upstream: {{upstreamServers .DNS.Upstream}}
           TTL: {{.DNS.TTL}}
       Entries: {{countDNSEntries .DNS.Entries}}
{{end}}\
`)

var targetsTemplate = defTemplate("targetsTemplate", `\
{{range .Router.Targets}}{{.}}
{{end}}\
`)

var connectionsTemplate = defTemplate("connectionsTemplate", `\
{{range .Router.Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}}
{{end}}\
`)

var peersTemplate = defTemplate("peers", `\
{{range .Router.Peers}}\
{{.Name}}({{.NickName}})
{{range .Connections}}\
   {{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \
{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-37v" $nameNickName}} \
{{if .Established}}established{{else}}pending{{end}}
{{end}}\
{{end}}\
`)

var dnsEntriesTemplate = defTemplate("dnsEntries", `\
{{$domain := printf ".%v" .DNS.Domain}}\
{{range .DNS.Entries}}\
{{if eq .Tombstone 0}}\
{{$hostname := trimSuffix .Hostname $domain}}\
{{printf "%-12v" $hostname}} {{printf "%-15v" .Address}} {{printf "%12.12v" .ContainerID}} {{.Origin}}
{{end}}\
{{end}}\
`)

var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`)

type WeaveStatus struct {
	Version string
	Router  *weave.NetworkRouterStatus `json:"Router,omitempty"`
	IPAM    *ipam.Status               `json:"IPAM,omitempty"`
	DNS     *nameserver.Status         `json:"DNS,omitempty"`
}

func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
	status := func() WeaveStatus {
		return WeaveStatus{
			version,
			weave.NewNetworkRouterStatus(router),
			ipam.NewStatus(allocator, defaultSubnet),
			nameserver.NewStatus(ns, dnsserver)}
	}
	muxRouter.Methods("GET").Path("/report").Headers("Accept", "application/json").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			json, err := json.MarshalIndent(status(), "", "    ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				Log.Error("Error during report marshalling: ", err)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(json)
		})

	muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			formatTemplate, err := template.New("format").Parse(mux.Vars(r)["format"])
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if err := formatTemplate.Execute(w, status()); err != nil {
				http.Error(w, "error during template execution", http.StatusInternalServerError)
				Log.Error(err)
			}
		})

	defHandler := func(path string, template *template.Template) {
		muxRouter.Methods("GET").Path(path).HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				if err := template.Execute(w, status()); err != nil {
					http.Error(w, "error during template execution", http.StatusInternalServerError)
					Log.Error(err)
				}
			})
	}

	defHandler("/status", statusTemplate)
	defHandler("/status/targets", targetsTemplate)
	defHandler("/status/connections", connectionsTemplate)
	defHandler("/status/peers", peersTemplate)
	defHandler("/status/dns", dnsEntriesTemplate)
	defHandler("/status/ipam", ipamTemplate)

}
<|endoftext|>


<commit_before>package projects

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	log "github.com/Sirupsen/logrus"
	"github.com/citruspi/milou/configuration"
	"github.com/citruspi/milou/notifications"
)

type Project struct {
	Owner      string `json:"owner"`
	Repository string `json:"repository"`
	Version    struct {
		Type  string `json:"type"`
		Value string `json:"value"`
		Regex bool   `json:"regex"`
	} `json:"version"`
	Identifier string `json:"identifier"`
	Path       string `json:"path"`
}

var (
	conf configuration.Configuration
	list []Project
)

func init() {
	conf = configuration.Load()

	files, err := ioutil.ReadDir(conf.Projects)

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

	for _, file := range files {
		var project Project

		source, err := ioutil.ReadFile(conf.Projects + file.Name())

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

		err = json.Unmarshal(source, &project)

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

		list = append(list, project)
	}

	if conf.Mode == "standalone" || conf.Mode == "client" {
		DeployAll()
	}
}

func (p Project) BasePath() string {
	buffer := new(bytes.Buffer)

	t, _ := template.New("basepath").Parse(p.Path)
	t.Execute(buffer, p)

	return string(buffer.Bytes())
}

func (p Project) ArchivePath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) TemporaryPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.BasePath()[:len(p.BasePath())-1])
	buffer.WriteString(".milou/")

	return string(buffer.Bytes())
}

func (p Project) ExtractPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Repository)

	return string(buffer.Bytes())
}

func (p Project) ArchiveLocation() string {
	var buffer bytes.Buffer

	buffer.WriteString("https://s3.amazonaws.com/")
	buffer.WriteString(p.Identifier)
	buffer.WriteString("/")
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) Extract() error {
	err := os.MkdirAll(p.ExtractPath(), 0700)

	if err != nil {
		return err
	}

	r, err := zip.OpenReader(p.ArchivePath())
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(p.ExtractPath(), f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, f.Mode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, f.Mode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (p Project) Download() {
	response, err := http.Get(p.ArchiveLocation())
	defer response.Body.Close()

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

	archive, err := os.Create(p.ArchivePath())
	defer archive.Close()

	_, err = io.Copy(archive, response.Body)

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

func (p Project) Place() {
	err := os.RemoveAll(p.BasePath())

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

	err = os.Rename(p.ExtractPath(), p.BasePath())

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

func (p Project) Prepare() {
	if _, err := os.Stat(p.TemporaryPath()); os.IsNotExist(err) {
		err = os.MkdirAll(p.TemporaryPath(), 0700)

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

func (p Project) CleanUp() {
	err := os.RemoveAll(p.TemporaryPath())

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

func (p Project) Deploy() {
	p.Prepare()
	p.Download()
	p.Extract()
	p.Place()
	p.CleanUp()
}

func DeployAll() {
	for _, project := range list {
		project.Deploy()
	}
}

func Process(n notifications.Notification) {
	for _, project := range list {
		if project.Repository != n.Repository {
			continue
		}

		if project.Owner != n.Owner {
			continue
		}

		if project.Version.Type == "commit" {
			if project.Version.Value == n.Commit {
				project.Deploy()
				continue
			}
		}

		if project.Version.Type == "branch" {
			if project.Version.Regex {
				match, _ := regexp.MatchString(project.Version.Value, n.Branch)

				if match {
					project.Deploy()
				}
			} else if project.Version.Value == n.Branch {
				project.Deploy()
			}
		}
	}
}
<commit_msg>Added an option to set the FileMode for projects<commit_after>package projects

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"text/template"

	log "github.com/Sirupsen/logrus"
	"github.com/citruspi/milou/configuration"
	"github.com/citruspi/milou/notifications"
)

type Project struct {
	Owner      string `json:"owner"`
	Repository string `json:"repository"`
	Version    struct {
		Type  string `json:"type"`
		Value string `json:"value"`
		Regex bool   `json:"regex"`
	} `json:"version"`
	Identifier string `json:"identifier"`
	Path       string `json:"path"`
	Mode       string `json:"file_mode"`
}

var (
	conf configuration.Configuration
	list []Project
)

func init() {
	conf = configuration.Load()

	files, err := ioutil.ReadDir(conf.Projects)

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

	for _, file := range files {
		var project Project

		source, err := ioutil.ReadFile(conf.Projects + file.Name())

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

		err = json.Unmarshal(source, &project)

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

		list = append(list, project)
	}

	if conf.Mode == "standalone" || conf.Mode == "client" {
		DeployAll()
	}
}

func (p Project) BasePath() string {
	buffer := new(bytes.Buffer)

	t, _ := template.New("basepath").Parse(p.Path)
	t.Execute(buffer, p)

	return string(buffer.Bytes())
}

func (p Project) ArchivePath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) TemporaryPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.BasePath()[:len(p.BasePath())-1])
	buffer.WriteString(".milou/")

	return string(buffer.Bytes())
}

func (p Project) ExtractPath() string {
	var buffer bytes.Buffer

	buffer.WriteString(p.TemporaryPath())
	buffer.WriteString(p.Repository)

	return string(buffer.Bytes())
}

func (p Project) ArchiveLocation() string {
	var buffer bytes.Buffer

	buffer.WriteString("https://s3.amazonaws.com/")
	buffer.WriteString(p.Identifier)
	buffer.WriteString("/")
	buffer.WriteString(p.Version.Value)
	buffer.WriteString(".zip")

	return string(buffer.Bytes())
}

func (p Project) FileMode() os.FileMode {
	file_mode := os.FileMode(0700)

	log.Info(p.Mode)

	if p.Mode != "" {
		file_mode_int, err := strconv.ParseInt(p.Mode, 8, 32)

		if err == nil {
			file_mode = os.FileMode(file_mode_int)
		}
	}

	return file_mode
}

func (p Project) Extract() error {
	var err error

	err = os.MkdirAll(p.ExtractPath(), p.FileMode())

	if err != nil {
		return err
	}

	r, err := zip.OpenReader(p.ArchivePath())
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(p.ExtractPath(), f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, p.FileMode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, p.FileMode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, p.FileMode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (p Project) Download() {
	response, err := http.Get(p.ArchiveLocation())
	defer response.Body.Close()

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

	archive, err := os.Create(p.ArchivePath())
	defer archive.Close()

	_, err = io.Copy(archive, response.Body)

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

func (p Project) Place() {
	err := os.RemoveAll(p.BasePath())

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

	err = os.Rename(p.ExtractPath(), p.BasePath())

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

func (p Project) Prepare() {
	if _, err := os.Stat(p.TemporaryPath()); os.IsNotExist(err) {
		err = os.MkdirAll(p.TemporaryPath(), 0700)

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

func (p Project) CleanUp() {
	err := os.RemoveAll(p.TemporaryPath())

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

func (p Project) Deploy() {
	p.Prepare()
	p.Download()
	p.Extract()
	p.Place()
	p.CleanUp()
}

func DeployAll() {
	for _, project := range list {
		project.Deploy()
	}
}

func Process(n notifications.Notification) {
	for _, project := range list {
		if project.Repository != n.Repository {
			continue
		}

		if project.Owner != n.Owner {
			continue
		}

		if project.Version.Type == "commit" {
			if project.Version.Value == n.Commit {
				project.Deploy()
				continue
			}
		}

		if project.Version.Type == "branch" {
			if project.Version.Regex {
				match, _ := regexp.MatchString(project.Version.Value, n.Branch)

				if match {
					project.Deploy()
				}
			} else if project.Version.Value == n.Branch {
				project.Deploy()
			}
		}
	}
}
<|endoftext|>


<commit_before>package proto

import (
	"fmt"
	"testing"
)

func TestKeyID(t *testing.T) {

	pk := []byte{108, 121, 82, 46, 112, 133, 74, 243, 72, 208, 82, 162, 56, 223, 221, 115, 5, 228, 171, 34, 69, 211, 87, 96, 159, 119, 223, 186, 41, 220, 44, 62}
	ppk := &PublicKey{
		PubkeyType: &PublicKey_Ed25519{Ed25519: pk[:]},
	}
	id := KeyID(ppk)
	if got, want := id, uint64(15615436926645791512); got != want {
		t.Fatalf("KeyID() got %v, wanted %v", got, want)
	}
}
<commit_msg>fix typo<commit_after>package proto

import "testing"

func TestKeyID(t *testing.T) {

	pk := []byte{108, 121, 82, 46, 112, 133, 74, 243, 72, 208, 82, 162, 56, 223, 221, 115, 5, 228, 171, 34, 69, 211, 87, 96, 159, 119, 223, 186, 41, 220, 44, 62}
	ppk := &PublicKey{
		PubkeyType: &PublicKey_Ed25519{Ed25519: pk[:]},
	}
	id := KeyID(ppk)
	if got, want := id, uint64(15615436926645791512); got != want {
		t.Fatalf("KeyID() got %v, wanted %v", got, want)
	}
}
<|endoftext|>


<commit_before>package provider

import (
	"errors"
	"github.com/GehirnInc/GOpenID"
	"github.com/GehirnInc/GOpenID/dh"
	"math/big"
)

var (
	ErrUnknownMode                       = errors.New("Unknown mode")
	ErrInvalidCheckIDRequest             = errors.New("invalid checkid_* request")
	ErrInvalidCheckAuthenticationRequest = errors.New("invalid checkid_authentication request")
	ErrInvalidAssociateRequest           = errors.New("invalid associate request")
)

type Request interface {
	GetMode() string
	GetNamespace() gopenid.NamespaceURI
	GetMessage() gopenid.Message
}

func RequestFromMessage(msg gopenid.Message) (Request, error) {
	mode, _ := msg.GetArg(gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "mode"))
	switch mode {
	case "checkid_immediate":
		return CheckIDRequestFromMessage(msg)
	case "checkid_setup":
		return CheckIDRequestFromMessage(msg)
	case "associate":
		return AssociateRequestFromMessage(msg)
	case "check_authentication":
		return CheckAuthenticationRequestFromMessage(msg)
	default:
		return nil, ErrUnknownMode
	}

}

type CheckIDRequest struct {
	message gopenid.Message

	mode        gopenid.MessageValue
	claimedId   gopenid.MessageValue
	identity    gopenid.MessageValue
	assocHandle gopenid.MessageValue
	returnTo    gopenid.MessageValue
	realm       gopenid.MessageValue
}

func CheckIDRequestFromMessage(msg gopenid.Message) (req *CheckIDRequest, err error) {
	ns := msg.GetOpenIDNamespace()
	mode, _ := msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	claimedId, _ := msg.GetArg(gopenid.NewMessageKey(ns, "claimed_id"))
	identity, _ := msg.GetArg(gopenid.NewMessageKey(ns, "identity"))
	if (claimedId == "" && identity != "") || (claimedId != "" && identity == "") {
		// openid.claimed_id" and "openid.identity" SHALL be either both present or both absent
		err = ErrInvalidCheckIDRequest
		return
	}

	assocHandle, _ := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_handle"))

	returnTo, _ := msg.GetArg(gopenid.NewMessageKey(ns, "return_to"))
	if returnTo != "" {
		_, err = ParseRealm(returnTo.String())
		if err != nil {
			return
		}
	}

	realm, _ := msg.GetArg(gopenid.NewMessageKey(ns, "realm"))
	if realm == "" && returnTo == "" {
		// openid.realm MUST be sent if openid.return_to is omitted
		err = ErrInvalidCheckIDRequest
		return
	} else if realm != "" {
		var parsed Realm
		parsed, err = ParseRealm(realm.String())
		if err != nil {
			return
		}

		if returnTo != "" && !parsed.Validate(returnTo.String()) {
			err = ErrInvalidCheckIDRequest
			return
		}
	} else {
		realm = returnTo
	}

	req = &CheckIDRequest{
		message:     msg,
		mode:        mode,
		claimedId:   claimedId,
		identity:    identity,
		assocHandle: assocHandle,
		returnTo:    returnTo,
		realm:       realm,
	}
	return
}

func (req *CheckIDRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *CheckIDRequest) GetMode() string {
	return req.mode.String()
}

func (req *CheckIDRequest) GetMessage() gopenid.Message {
	return req.message
}

type CheckAuthenticationRequest struct {
	message gopenid.Message

	mode          gopenid.MessageValue
	assocHandle   gopenid.MessageValue
	signed        gopenid.MessageValue
	sig           gopenid.MessageValue
	responseNonce gopenid.MessageValue
}

func CheckAuthenticationRequestFromMessage(msg gopenid.Message) (req *CheckAuthenticationRequest, err error) {
	ns := msg.GetOpenIDNamespace()

	if ns != gopenid.NsOpenID20 {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	mode, _ := msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	assocHandle, ok := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_handle"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	signed, ok := msg.GetArg(gopenid.NewMessageKey(ns, "signed"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	sig, ok := msg.GetArg(gopenid.NewMessageKey(ns, "sig"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	responseNonce, ok := msg.GetArg(gopenid.NewMessageKey(ns, "response_nonce"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	req = &CheckAuthenticationRequest{
		message: msg,

		mode:          mode,
		assocHandle:   assocHandle,
		signed:        signed,
		sig:           sig,
		responseNonce: responseNonce,
	}
	return
}

func (req *CheckAuthenticationRequest) GetMode() string {
	return req.mode.String()
}

func (req *CheckAuthenticationRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *CheckAuthenticationRequest) GetMessage() gopenid.Message {
	return req.message
}

type AssociateRequest struct {
	message gopenid.Message
	err     error

	mode        gopenid.MessageValue
	assocType   gopenid.AssocType
	sessionType gopenid.SessionType

	dhParams         dh.Params
	dhConsumerPublic dh.PublicKey
}

func AssociateRequestFromMessage(msg gopenid.Message) (req *AssociateRequest, err error) {
	ns := msg.GetOpenIDNamespace()
	req = &AssociateRequest{
		message: msg,
	}

	req.mode, _ = msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	assocTypeName, _ := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_type"))
	req.assocType, err = gopenid.GetAssocTypeByName(assocTypeName.String())
	if err != nil {
		req.err = err
	}

	sessionTypeName, _ := msg.GetArg(gopenid.NewMessageKey(ns, "session_type"))
	req.sessionType, err = gopenid.GetSessionTypeByName(sessionTypeName.String())
	if err != nil {
		req.err = err
	}

	if req.sessionType.Name() != gopenid.SESSION_NO_ENCRYPTION.Name() {
		var (
			P *big.Int
			G *big.Int
		)
		PBase64, ok := msg.GetArg(gopenid.NewMessageKey(ns, "dh_modulus"))
		if !ok {
			err = ErrInvalidAssociateRequest
			return
		}
		P, err = gopenid.Base64ToInt(PBase64.Bytes())
		if err != nil {
			err = ErrInvalidAssociateRequest
			return
		}

		GBase64, _ := msg.GetArg(gopenid.NewMessageKey(ns, "dh_gen"))
		G, err = gopenid.Base64ToInt(GBase64.Bytes())
		if err != nil {
			err = ErrInvalidAssociateRequest
			return
		}
		req.dhParams = dh.Params{
			P: P,
			G: G,
		}

		var (
			Y *big.Int
		)
		YBase64, _ := msg.GetArg(gopenid.NewMessageKey(ns, "dh_consumer_public"))
		Y, err = gopenid.Base64ToInt(YBase64.Bytes())
		if err != nil {
			err = ErrInvalidAssociateRequest
			return
		}
		req.dhConsumerPublic = dh.PublicKey{
			Y: Y,
		}
	}

	return
}

func (req *AssociateRequest) GetMode() string {
	return req.mode.String()
}

func (req *AssociateRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *AssociateRequest) GetMessage() gopenid.Message {
	return req.message
}
<commit_msg>dh_gen, dh_modulus use the default value if request does not contains these value<commit_after>package provider

import (
	"errors"
	"github.com/GehirnInc/GOpenID"
	"github.com/GehirnInc/GOpenID/dh"
	"math/big"
)

var (
	ErrUnknownMode                       = errors.New("Unknown mode")
	ErrInvalidCheckIDRequest             = errors.New("invalid checkid_* request")
	ErrInvalidCheckAuthenticationRequest = errors.New("invalid checkid_authentication request")
	ErrInvalidAssociateRequest           = errors.New("invalid associate request")

	DEFAULT_DH_GEN     = big.NewInt(2)
	DEFAULT_DH_MODULUS = new(big.Int).SetBytes([]byte{
		0xdc, 0xf9, 0x3a, 0x0b, 0x88, 0x39, 0x72, 0xec, 0x0e, 0x19,
		0x98, 0x9a, 0xc5, 0xa2, 0xce, 0x31, 0x0e, 0x1d, 0x37, 0x71,
		0x7e, 0x8d, 0x95, 0x71, 0xbb, 0x76, 0x23, 0x73, 0x18, 0x66,
		0xe6, 0x1e, 0xf7, 0x5a, 0x2e, 0x27, 0x89, 0x8b, 0x05, 0x7f,
		0x98, 0x91, 0xc2, 0xe2, 0x7a, 0x63, 0x9c, 0x3f, 0x29, 0xb6,
		0x08, 0x14, 0x58, 0x1c, 0xd3, 0xb2, 0xca, 0x39, 0x86, 0xd2,
		0x68, 0x37, 0x05, 0x57, 0x7d, 0x45, 0xc2, 0xe7, 0xe5, 0x2d,
		0xc8, 0x1c, 0x7a, 0x17, 0x18, 0x76, 0xe5, 0xce, 0xa7, 0x4b,
		0x14, 0x48, 0xbf, 0xdf, 0xaf, 0x18, 0x82, 0x8e, 0xfd, 0x25,
		0x19, 0xf1, 0x4e, 0x45, 0xe3, 0x82, 0x66, 0x34, 0xaf, 0x19,
		0x49, 0xe5, 0xb5, 0x35, 0xcc, 0x82, 0x9a, 0x48, 0x3b, 0x8a,
		0x76, 0x22, 0x3e, 0x5d, 0x49, 0x0a, 0x25, 0x7f, 0x05, 0xbd,
		0xff, 0x16, 0xf2, 0xfb, 0x22, 0xc5, 0x83, 0xab,
	})
)

type Request interface {
	GetMode() string
	GetNamespace() gopenid.NamespaceURI
	GetMessage() gopenid.Message
}

func RequestFromMessage(msg gopenid.Message) (Request, error) {
	mode, _ := msg.GetArg(gopenid.NewMessageKey(msg.GetOpenIDNamespace(), "mode"))
	switch mode {
	case "checkid_immediate":
		return CheckIDRequestFromMessage(msg)
	case "checkid_setup":
		return CheckIDRequestFromMessage(msg)
	case "associate":
		return AssociateRequestFromMessage(msg)
	case "check_authentication":
		return CheckAuthenticationRequestFromMessage(msg)
	default:
		return nil, ErrUnknownMode
	}

}

type CheckIDRequest struct {
	message gopenid.Message

	mode        gopenid.MessageValue
	claimedId   gopenid.MessageValue
	identity    gopenid.MessageValue
	assocHandle gopenid.MessageValue
	returnTo    gopenid.MessageValue
	realm       gopenid.MessageValue
}

func CheckIDRequestFromMessage(msg gopenid.Message) (req *CheckIDRequest, err error) {
	ns := msg.GetOpenIDNamespace()
	mode, _ := msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	claimedId, _ := msg.GetArg(gopenid.NewMessageKey(ns, "claimed_id"))
	identity, _ := msg.GetArg(gopenid.NewMessageKey(ns, "identity"))
	if (claimedId == "" && identity != "") || (claimedId != "" && identity == "") {
		// openid.claimed_id" and "openid.identity" SHALL be either both present or both absent
		err = ErrInvalidCheckIDRequest
		return
	}

	assocHandle, _ := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_handle"))

	returnTo, _ := msg.GetArg(gopenid.NewMessageKey(ns, "return_to"))
	if returnTo != "" {
		_, err = ParseRealm(returnTo.String())
		if err != nil {
			return
		}
	}

	realm, _ := msg.GetArg(gopenid.NewMessageKey(ns, "realm"))
	if realm == "" && returnTo == "" {
		// openid.realm MUST be sent if openid.return_to is omitted
		err = ErrInvalidCheckIDRequest
		return
	} else if realm != "" {
		var parsed Realm
		parsed, err = ParseRealm(realm.String())
		if err != nil {
			return
		}

		if returnTo != "" && !parsed.Validate(returnTo.String()) {
			err = ErrInvalidCheckIDRequest
			return
		}
	} else {
		realm = returnTo
	}

	req = &CheckIDRequest{
		message:     msg,
		mode:        mode,
		claimedId:   claimedId,
		identity:    identity,
		assocHandle: assocHandle,
		returnTo:    returnTo,
		realm:       realm,
	}
	return
}

func (req *CheckIDRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *CheckIDRequest) GetMode() string {
	return req.mode.String()
}

func (req *CheckIDRequest) GetMessage() gopenid.Message {
	return req.message
}

type CheckAuthenticationRequest struct {
	message gopenid.Message

	mode          gopenid.MessageValue
	assocHandle   gopenid.MessageValue
	signed        gopenid.MessageValue
	sig           gopenid.MessageValue
	responseNonce gopenid.MessageValue
}

func CheckAuthenticationRequestFromMessage(msg gopenid.Message) (req *CheckAuthenticationRequest, err error) {
	ns := msg.GetOpenIDNamespace()

	if ns != gopenid.NsOpenID20 {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	mode, _ := msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	assocHandle, ok := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_handle"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	signed, ok := msg.GetArg(gopenid.NewMessageKey(ns, "signed"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	sig, ok := msg.GetArg(gopenid.NewMessageKey(ns, "sig"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	responseNonce, ok := msg.GetArg(gopenid.NewMessageKey(ns, "response_nonce"))
	if !ok {
		err = ErrInvalidCheckAuthenticationRequest
		return
	}

	req = &CheckAuthenticationRequest{
		message: msg,

		mode:          mode,
		assocHandle:   assocHandle,
		signed:        signed,
		sig:           sig,
		responseNonce: responseNonce,
	}
	return
}

func (req *CheckAuthenticationRequest) GetMode() string {
	return req.mode.String()
}

func (req *CheckAuthenticationRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *CheckAuthenticationRequest) GetMessage() gopenid.Message {
	return req.message
}

type AssociateRequest struct {
	message gopenid.Message
	err     error

	mode        gopenid.MessageValue
	assocType   gopenid.AssocType
	sessionType gopenid.SessionType

	dhParams         dh.Params
	dhConsumerPublic dh.PublicKey
}

func AssociateRequestFromMessage(msg gopenid.Message) (req *AssociateRequest, err error) {
	ns := msg.GetOpenIDNamespace()
	req = &AssociateRequest{
		message: msg,
	}

	req.mode, _ = msg.GetArg(gopenid.NewMessageKey(ns, "mode"))

	assocTypeName, _ := msg.GetArg(gopenid.NewMessageKey(ns, "assoc_type"))
	req.assocType, err = gopenid.GetAssocTypeByName(assocTypeName.String())
	if err != nil {
		req.err = err
	}

	sessionTypeName, _ := msg.GetArg(gopenid.NewMessageKey(ns, "session_type"))
	req.sessionType, err = gopenid.GetSessionTypeByName(sessionTypeName.String())
	if err != nil {
		req.err = err
	}

	if req.sessionType.Name() != gopenid.SESSION_NO_ENCRYPTION.Name() {
		var (
			P *big.Int
			G *big.Int
		)
		PBase64, _ := msg.GetArg(gopenid.NewMessageKey(ns, "dh_modulus"))
		if PBase64 != "" {
			P, err = gopenid.Base64ToInt(PBase64.Bytes())
			if err != nil {
				err = ErrInvalidAssociateRequest
				return
			}
		} else {
			P = DEFAULT_DH_MODULUS
		}

		GBase64, _ := msg.GetArg(gopenid.NewMessageKey(ns, "dh_gen"))
		if GBase64 != "" {
			G, err = gopenid.Base64ToInt(GBase64.Bytes())
			if err != nil {
				err = ErrInvalidAssociateRequest
				return
			}
		} else {
			G = DEFAULT_DH_GEN
		}
		req.dhParams = dh.Params{
			P: P,
			G: G,
		}

		var (
			Y *big.Int
		)
		YBase64, _ := msg.GetArg(gopenid.NewMessageKey(ns, "dh_consumer_public"))
		Y, err = gopenid.Base64ToInt(YBase64.Bytes())
		if err != nil {
			err = ErrInvalidAssociateRequest
			return
		}
		req.dhConsumerPublic = dh.PublicKey{
			Y: Y,
		}
	}

	return
}

func (req *AssociateRequest) GetMode() string {
	return req.mode.String()
}

func (req *AssociateRequest) GetNamespace() gopenid.NamespaceURI {
	return req.message.GetOpenIDNamespace()
}

func (req *AssociateRequest) GetMessage() gopenid.Message {
	return req.message
}
<|endoftext|>


<commit_before>package providers

import (
	"log"
	"net/http"
	"net/url"

	"github.com/bitly/oauth2_proxy/api"
)

type GitLabProvider struct {
	*ProviderData
	Group string
}

func NewGitLabProvider(p *ProviderData) *GitLabProvider {
	p.ProviderName = "GitLab"
	if p.LoginURL == nil || p.LoginURL.String() == "" {
		p.LoginURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/oauth/authorize",
		}
	}
	if p.RedeemURL == nil || p.RedeemURL.String() == "" {
		p.RedeemURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/oauth/token",
		}
	}
	if p.ValidateURL == nil || p.ValidateURL.String() == "" {
		p.ValidateURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/api/v3/user",
		}
	}
	if p.Scope == "" {
		p.Scope = "api"
	}
	return &GitLabProvider{ProviderData: p}
}

func (p *GitLabProvider) SetGroup(group string) {
	p.Group = group
}

func (p *GitLabProvider) GetEmailAddress(s *SessionState) (string, error) {

	req, err := http.NewRequest("GET",
		p.ValidateURL.String()+"?access_token="+s.AccessToken, nil)
	if err != nil {
		log.Printf("failed building request %s", err)
		return "", err
	}
	json, err := api.Request(req)
	if err != nil {
		log.Printf("failed making request %s", err)
		return "", err
	}
	return json.Get("email").String()
}
<commit_msg>Respect gitlab-group in provider<commit_after>package providers

import (
	"log"
	"net/http"
	"net/url"

	"github.com/bitly/oauth2_proxy/api"
	"fmt"
	"io/ioutil"
	"encoding/json"
)

type GitLabProvider struct {
	*ProviderData
	Group string
}

func NewGitLabProvider(p *ProviderData) *GitLabProvider {
	p.ProviderName = "GitLab"
	if p.LoginURL == nil || p.LoginURL.String() == "" {
		p.LoginURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/oauth/authorize",
		}
	}
	if p.RedeemURL == nil || p.RedeemURL.String() == "" {
		p.RedeemURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/oauth/token",
		}
	}
	if p.ValidateURL == nil || p.ValidateURL.String() == "" {
		p.ValidateURL = &url.URL{
			Scheme: "https",
			Host:   "gitlab.com",
			Path:   "/api/v3/user",
		}
	}
	if p.Scope == "" {
		p.Scope = "api"
	}
	return &GitLabProvider{ProviderData: p}
}

func (p *GitLabProvider) SetGroup(group string) {
	p.Group = group
}

func (p *GitLabProvider) hasGroup(accessToken string) (bool, error) {

	var groups []struct {
		Group string `json:"name"`
	}

	endpoint := p.ValidateURL.Scheme + "://" + p.ValidateURL.Host + "/api/v3/groups?access_token="+accessToken
	req, _ := http.NewRequest("GET", endpoint, nil)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return false, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return false, err
	}
	if resp.StatusCode != 200 {
		return false, fmt.Errorf("got %d from %q %s", resp.StatusCode, endpoint, body)
	}

	if err := json.Unmarshal(body, &groups); err != nil {
		return false, err
	}

	for _, group := range groups {
		if( p.Group == group.Group) {
			// Found the group
			return true, nil
		}
	}

	log.Printf("Group %s not found in %s", p.Group, groups)
	return false, nil
}

func (p *GitLabProvider) GetEmailAddress(s *SessionState) (string, error) {

	// if we require a group, check that first
	if p.Group != "" {
		if ok, err := p.hasGroup(s.AccessToken); err != nil || !ok {
			return "", err
		}
	}

	req, err := http.NewRequest("GET",
		p.ValidateURL.String()+"?access_token="+s.AccessToken, nil)
	if err != nil {
		log.Printf("failed building request %s", err)
		return "", err
	}
	json, err := api.Request(req)
	if err != nil {
		log.Printf("failed making request %s", err)
		return "", err
	}
	return json.Get("email").String()
}
<|endoftext|>