<commit_before>package chromedp

import (
	"context"
	"encoding/json"
	"errors"
	"sync"
	"sync/atomic"

	"github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/dom"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/cdproto/target"
)

// Target manages a Chrome DevTools Protocol target.
type Target struct {
	browser   *Browser
	SessionID target.SessionID
	TargetID  target.ID

	listenersMu sync.Mutex
	listeners   []cancelableListener

	messageQueue chan *cdproto.Message

	// frameMu protects both frames and cur.
	frameMu sync.RWMutex
	// frames is the set of encountered frames.
	frames       map[cdp.FrameID]*cdp.Frame
	execContexts map[cdp.FrameID]runtime.ExecutionContextID
	// cur is the current top level frame.
	cur cdp.FrameID

	// logging funcs
	logf, errf func(string, ...interface{})

	// Indicates if the target is a worker target.
	isWorker bool
}

func (t *Target) enclosingFrame(node *cdp.Node) cdp.FrameID {
	t.frameMu.RLock()
	top := t.frames[t.cur]
	t.frameMu.RUnlock()
	for {
		if node == nil {
			// Avoid crashing. This can happen if we're using an old
			// node that has been replaced, for example.
			return ""
		}
		if node.FrameID != "" {
			break
		}
		node = top.Nodes[node.ParentID]
	}
	return node.FrameID
}

func (t *Target) run(ctx context.Context) {
	type eventValue struct {
		method cdproto.MethodType
		value  interface{}
	}
	// syncEventQueue is used to handle events synchronously within Target.
	// TODO: If this queue gets full, the goroutine below could get stuck on
	// a send, and response callbacks would never run, resulting in a
	// deadlock. Can we fix this without potentially using lots of memory?
	syncEventQueue := make(chan eventValue, 4096)

	// This goroutine receives events from the browser, calls listeners, and
	// then passes the events onto the main goroutine for the target handler
	// to update itself.
	go func() {
		for {
			select {
			case <-ctx.Done():
				return

			case msg := <-t.messageQueue:
				if msg.ID != 0 {
					t.listenersMu.Lock()
					t.listeners = runListeners(t.listeners, msg)
					t.listenersMu.Unlock()
					continue
				}
				ev, err := cdproto.UnmarshalMessage(msg)
				if err != nil {
					if _, ok := err.(cdp.ErrUnknownCommandOrEvent); ok {
						// This is most likely an event received from an older
						// Chrome which a newer cdproto doesn't have, as it is
						// deprecated. Ignore that error.
						continue
					}
					t.errf("could not unmarshal event: %v", err)
					continue
				}
				t.listenersMu.Lock()
				t.listeners = runListeners(t.listeners, ev)
				t.listenersMu.Unlock()

				switch msg.Method.Domain() {
				case "Runtime", "Page", "DOM":
					select {
					case <-ctx.Done():
						return
					case syncEventQueue <- eventValue{msg.Method, ev}:
					}
				}
			}
		}
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case ev := <-syncEventQueue:
			switch ev.method.Domain() {
			case "Runtime":
				t.runtimeEvent(ev.value)
			case "Page":
				t.pageEvent(ev.value)
			case "DOM":
				t.domEvent(ctx, ev.value)
			}
		}
	}
}

func (t *Target) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	if method == target.CommandCloseTarget {
		return errors.New("to close the target, cancel its context or use chromedp.Cancel")
	}

	id := atomic.AddInt64(&t.browser.next, 1)
	lctx, cancel := context.WithCancel(ctx)
	ch := make(chan *cdproto.Message, 1)
	fn := func(ev interface{}) {
		if msg, ok := ev.(*cdproto.Message); ok && msg.ID == id {
			select {
			case <-ctx.Done():
			case ch <- msg:
			}
			cancel()
		}
	}
	t.listenersMu.Lock()
	t.listeners = append(t.listeners, cancelableListener{lctx, fn})
	t.listenersMu.Unlock()

	// send command
	var buf []byte
	if params != nil {
		var err error
		buf, err = easyjson.Marshal(params)
		if err != nil {
			return err
		}
	}
	cmd := &cdproto.Message{
		ID:        id,
		SessionID: t.SessionID,
		Method:    cdproto.MethodType(method),
		Params:    buf,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case t.browser.cmdQueue <- cmd:
	}

	// wait for result
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

// runtimeEvent handles incoming runtime events.
func (t *Target) runtimeEvent(ev interface{}) {
	switch ev := ev.(type) {
	case *runtime.EventExecutionContextCreated:
		var aux struct {
			FrameID cdp.FrameID
		}
		if len(ev.Context.AuxData) == 0 {
			break
		}
		if err := json.Unmarshal(ev.Context.AuxData, &aux); err != nil {
			t.errf("could not decode executionContextCreated auxData %q: %v", ev.Context.AuxData, err)
			break
		}
		if aux.FrameID != "" {
			t.frameMu.Lock()
			t.execContexts[aux.FrameID] = ev.Context.ID
			t.frameMu.Unlock()
		}
	case *runtime.EventExecutionContextDestroyed:
		t.frameMu.Lock()
		for frameID, ctxID := range t.execContexts {
			if ctxID == ev.ExecutionContextID {
				delete(t.execContexts, frameID)
			}
		}
		t.frameMu.Unlock()
	case *runtime.EventExecutionContextsCleared:
		t.frameMu.Lock()
		for frameID := range t.execContexts {
			delete(t.execContexts, frameID)
		}
		t.frameMu.Unlock()
	}
}

// documentUpdated handles the document updated event, retrieving the document
// root for the root frame.
func (t *Target) documentUpdated(ctx context.Context) {
	t.frameMu.RLock()
	f := t.frames[t.cur]
	t.frameMu.RUnlock()
	if f == nil {
		// TODO: This seems to happen on CI, when running the tests
		// under the headless-shell Docker image. Figure out why.
		t.errf("received DOM.documentUpdated when there's no top-level frame")
		return
	}
	f.Lock()
	defer f.Unlock()

	// invalidate nodes
	if f.Root != nil {
		close(f.Root.Invalidated)
	}

	f.Nodes = make(map[cdp.NodeID]*cdp.Node)
	var err error
	f.Root, err = dom.GetDocument().Do(cdp.WithExecutor(ctx, t))
	if err == context.Canceled {
		return // TODO: perhaps not necessary, but useful to keep the tests less noisy
	}
	if err != nil {
		t.errf("could not retrieve document root for %s: %v", f.ID, err)
		return
	}
	f.Root.Invalidated = make(chan struct{})
	walk(f.Nodes, f.Root)
}

// pageEvent handles incoming page events.
func (t *Target) pageEvent(ev interface{}) {
	var id cdp.FrameID
	var op frameOp

	switch e := ev.(type) {
	case *page.EventFrameNavigated:
		t.frameMu.Lock()
		t.frames[e.Frame.ID] = e.Frame
		if e.Frame.ParentID == "" {
			// This frame is only the new top-level frame if it has
			// no parent.
			t.cur = e.Frame.ID
		}
		t.frameMu.Unlock()
		return

	case *page.EventFrameAttached:
		id, op = e.FrameID, frameAttached(e.ParentFrameID)

	case *page.EventFrameDetached:
		id, op = e.FrameID, frameDetached

	case *page.EventFrameStartedLoading:
		id, op = e.FrameID, frameStartedLoading

	case *page.EventFrameStoppedLoading:
		id, op = e.FrameID, frameStoppedLoading

		// ignored events
	case *page.EventFrameRequestedNavigation:
		return
	case *page.EventDomContentEventFired:
		return
	case *page.EventLoadEventFired:
		return
	case *page.EventFrameResized:
		return
	case *page.EventLifecycleEvent:
		return
	case *page.EventNavigatedWithinDocument:
		return
	case *page.EventJavascriptDialogOpening:
		return
	case *page.EventJavascriptDialogClosed:
		return
	case *page.EventWindowOpen:
		return
	case *page.EventDownloadWillBegin:
		return
	case *page.EventDownloadProgress:
		return

	default:
		t.errf("unhandled page event %T", ev)
		return
	}

	t.frameMu.Lock()
	f := t.frames[id]
	if f == nil {
		// This can happen if a frame is attached or starts loading
		// before it's ever navigated to. We won't have all the frame
		// details just yet, but that's okay.
		f = &cdp.Frame{ID: id}
		t.frames[id] = f
	}
	t.frameMu.Unlock()

	f.Lock()
	op(f)
	f.Unlock()
}

// domEvent handles incoming DOM events.
func (t *Target) domEvent(ctx context.Context, ev interface{}) {
	f := t.frames[t.cur]
	var id cdp.NodeID
	var op nodeOp

	switch e := ev.(type) {
	case *dom.EventDocumentUpdated:
		t.documentUpdated(ctx)
		return

	case *dom.EventSetChildNodes:
		id, op = e.ParentID, setChildNodes(f.Nodes, e.Nodes)

	case *dom.EventAttributeModified:
		id, op = e.NodeID, attributeModified(e.Name, e.Value)

	case *dom.EventAttributeRemoved:
		id, op = e.NodeID, attributeRemoved(e.Name)

	case *dom.EventInlineStyleInvalidated:
		if len(e.NodeIds) == 0 {
			return
		}

		id, op = e.NodeIds[0], inlineStyleInvalidated(e.NodeIds[1:])

	case *dom.EventCharacterDataModified:
		id, op = e.NodeID, characterDataModified(e.CharacterData)

	case *dom.EventChildNodeCountUpdated:
		id, op = e.NodeID, childNodeCountUpdated(e.ChildNodeCount)

	case *dom.EventChildNodeInserted:
		id, op = e.ParentNodeID, childNodeInserted(f.Nodes, e.PreviousNodeID, e.Node)

	case *dom.EventChildNodeRemoved:
		id, op = e.ParentNodeID, childNodeRemoved(f.Nodes, e.NodeID)

	case *dom.EventShadowRootPushed:
		id, op = e.HostID, shadowRootPushed(f.Nodes, e.Root)

	case *dom.EventShadowRootPopped:
		id, op = e.HostID, shadowRootPopped(f.Nodes, e.RootID)

	case *dom.EventPseudoElementAdded:
		id, op = e.ParentID, pseudoElementAdded(f.Nodes, e.PseudoElement)

	case *dom.EventPseudoElementRemoved:
		id, op = e.ParentID, pseudoElementRemoved(f.Nodes, e.PseudoElementID)

	case *dom.EventDistributedNodesUpdated:
		id, op = e.InsertionPointID, distributedNodesUpdated(e.DistributedNodes)

	default:
		t.errf("unhandled node event %T", ev)
		return
	}

	n, ok := f.Nodes[id]
	if !ok {
		// Node ID has been invalidated. Nothing to do.
		return
	}

	f.Lock()
	op(n)
	f.Unlock()
}
<commit_msg>Fix data race when finding enclosing frame.<commit_after>package chromedp

import (
	"context"
	"encoding/json"
	"errors"
	"sync"
	"sync/atomic"

	"github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/dom"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/cdproto/target"
)

// Target manages a Chrome DevTools Protocol target.
type Target struct {
	browser   *Browser
	SessionID target.SessionID
	TargetID  target.ID

	listenersMu sync.Mutex
	listeners   []cancelableListener

	messageQueue chan *cdproto.Message

	// frameMu protects both frames and cur.
	frameMu sync.RWMutex
	// frames is the set of encountered frames.
	frames       map[cdp.FrameID]*cdp.Frame
	execContexts map[cdp.FrameID]runtime.ExecutionContextID
	// cur is the current top level frame.
	cur cdp.FrameID

	// logging funcs
	logf, errf func(string, ...interface{})

	// Indicates if the target is a worker target.
	isWorker bool
}

func (t *Target) enclosingFrame(node *cdp.Node) cdp.FrameID {
	t.frameMu.RLock()
	top := t.frames[t.cur]
	t.frameMu.RUnlock()
	top.RLock()
	defer top.RUnlock()
	for {
		if node == nil {
			// Avoid crashing. This can happen if we're using an old
			// node that has been replaced, for example.
			return ""
		}
		if node.FrameID != "" {
			break
		}
		node = top.Nodes[node.ParentID]
	}
	return node.FrameID
}

func (t *Target) run(ctx context.Context) {
	type eventValue struct {
		method cdproto.MethodType
		value  interface{}
	}
	// syncEventQueue is used to handle events synchronously within Target.
	// TODO: If this queue gets full, the goroutine below could get stuck on
	// a send, and response callbacks would never run, resulting in a
	// deadlock. Can we fix this without potentially using lots of memory?
	syncEventQueue := make(chan eventValue, 4096)

	// This goroutine receives events from the browser, calls listeners, and
	// then passes the events onto the main goroutine for the target handler
	// to update itself.
	go func() {
		for {
			select {
			case <-ctx.Done():
				return

			case msg := <-t.messageQueue:
				if msg.ID != 0 {
					t.listenersMu.Lock()
					t.listeners = runListeners(t.listeners, msg)
					t.listenersMu.Unlock()
					continue
				}
				ev, err := cdproto.UnmarshalMessage(msg)
				if err != nil {
					if _, ok := err.(cdp.ErrUnknownCommandOrEvent); ok {
						// This is most likely an event received from an older
						// Chrome which a newer cdproto doesn't have, as it is
						// deprecated. Ignore that error.
						continue
					}
					t.errf("could not unmarshal event: %v", err)
					continue
				}
				t.listenersMu.Lock()
				t.listeners = runListeners(t.listeners, ev)
				t.listenersMu.Unlock()

				switch msg.Method.Domain() {
				case "Runtime", "Page", "DOM":
					select {
					case <-ctx.Done():
						return
					case syncEventQueue <- eventValue{msg.Method, ev}:
					}
				}
			}
		}
	}()

	for {
		select {
		case <-ctx.Done():
			return
		case ev := <-syncEventQueue:
			switch ev.method.Domain() {
			case "Runtime":
				t.runtimeEvent(ev.value)
			case "Page":
				t.pageEvent(ev.value)
			case "DOM":
				t.domEvent(ctx, ev.value)
			}
		}
	}
}

func (t *Target) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	if method == target.CommandCloseTarget {
		return errors.New("to close the target, cancel its context or use chromedp.Cancel")
	}

	id := atomic.AddInt64(&t.browser.next, 1)
	lctx, cancel := context.WithCancel(ctx)
	ch := make(chan *cdproto.Message, 1)
	fn := func(ev interface{}) {
		if msg, ok := ev.(*cdproto.Message); ok && msg.ID == id {
			select {
			case <-ctx.Done():
			case ch <- msg:
			}
			cancel()
		}
	}
	t.listenersMu.Lock()
	t.listeners = append(t.listeners, cancelableListener{lctx, fn})
	t.listenersMu.Unlock()

	// send command
	var buf []byte
	if params != nil {
		var err error
		buf, err = easyjson.Marshal(params)
		if err != nil {
			return err
		}
	}
	cmd := &cdproto.Message{
		ID:        id,
		SessionID: t.SessionID,
		Method:    cdproto.MethodType(method),
		Params:    buf,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case t.browser.cmdQueue <- cmd:
	}

	// wait for result
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

// runtimeEvent handles incoming runtime events.
func (t *Target) runtimeEvent(ev interface{}) {
	switch ev := ev.(type) {
	case *runtime.EventExecutionContextCreated:
		var aux struct {
			FrameID cdp.FrameID
		}
		if len(ev.Context.AuxData) == 0 {
			break
		}
		if err := json.Unmarshal(ev.Context.AuxData, &aux); err != nil {
			t.errf("could not decode executionContextCreated auxData %q: %v", ev.Context.AuxData, err)
			break
		}
		if aux.FrameID != "" {
			t.frameMu.Lock()
			t.execContexts[aux.FrameID] = ev.Context.ID
			t.frameMu.Unlock()
		}
	case *runtime.EventExecutionContextDestroyed:
		t.frameMu.Lock()
		for frameID, ctxID := range t.execContexts {
			if ctxID == ev.ExecutionContextID {
				delete(t.execContexts, frameID)
			}
		}
		t.frameMu.Unlock()
	case *runtime.EventExecutionContextsCleared:
		t.frameMu.Lock()
		for frameID := range t.execContexts {
			delete(t.execContexts, frameID)
		}
		t.frameMu.Unlock()
	}
}

// documentUpdated handles the document updated event, retrieving the document
// root for the root frame.
func (t *Target) documentUpdated(ctx context.Context) {
	t.frameMu.RLock()
	f := t.frames[t.cur]
	t.frameMu.RUnlock()
	if f == nil {
		// TODO: This seems to happen on CI, when running the tests
		// under the headless-shell Docker image. Figure out why.
		t.errf("received DOM.documentUpdated when there's no top-level frame")
		return
	}
	f.Lock()
	defer f.Unlock()

	// invalidate nodes
	if f.Root != nil {
		close(f.Root.Invalidated)
	}

	f.Nodes = make(map[cdp.NodeID]*cdp.Node)
	var err error
	f.Root, err = dom.GetDocument().Do(cdp.WithExecutor(ctx, t))
	if err == context.Canceled {
		return // TODO: perhaps not necessary, but useful to keep the tests less noisy
	}
	if err != nil {
		t.errf("could not retrieve document root for %s: %v", f.ID, err)
		return
	}
	f.Root.Invalidated = make(chan struct{})
	walk(f.Nodes, f.Root)
}

// pageEvent handles incoming page events.
func (t *Target) pageEvent(ev interface{}) {
	var id cdp.FrameID
	var op frameOp

	switch e := ev.(type) {
	case *page.EventFrameNavigated:
		t.frameMu.Lock()
		t.frames[e.Frame.ID] = e.Frame
		if e.Frame.ParentID == "" {
			// This frame is only the new top-level frame if it has
			// no parent.
			t.cur = e.Frame.ID
		}
		t.frameMu.Unlock()
		return

	case *page.EventFrameAttached:
		id, op = e.FrameID, frameAttached(e.ParentFrameID)

	case *page.EventFrameDetached:
		id, op = e.FrameID, frameDetached

	case *page.EventFrameStartedLoading:
		id, op = e.FrameID, frameStartedLoading

	case *page.EventFrameStoppedLoading:
		id, op = e.FrameID, frameStoppedLoading

		// ignored events
	case *page.EventFrameRequestedNavigation:
		return
	case *page.EventDomContentEventFired:
		return
	case *page.EventLoadEventFired:
		return
	case *page.EventFrameResized:
		return
	case *page.EventLifecycleEvent:
		return
	case *page.EventNavigatedWithinDocument:
		return
	case *page.EventJavascriptDialogOpening:
		return
	case *page.EventJavascriptDialogClosed:
		return
	case *page.EventWindowOpen:
		return
	case *page.EventDownloadWillBegin:
		return
	case *page.EventDownloadProgress:
		return

	default:
		t.errf("unhandled page event %T", ev)
		return
	}

	t.frameMu.Lock()
	f := t.frames[id]
	if f == nil {
		// This can happen if a frame is attached or starts loading
		// before it's ever navigated to. We won't have all the frame
		// details just yet, but that's okay.
		f = &cdp.Frame{ID: id}
		t.frames[id] = f
	}
	t.frameMu.Unlock()

	f.Lock()
	op(f)
	f.Unlock()
}

// domEvent handles incoming DOM events.
func (t *Target) domEvent(ctx context.Context, ev interface{}) {
	f := t.frames[t.cur]
	var id cdp.NodeID
	var op nodeOp

	switch e := ev.(type) {
	case *dom.EventDocumentUpdated:
		t.documentUpdated(ctx)
		return

	case *dom.EventSetChildNodes:
		id, op = e.ParentID, setChildNodes(f.Nodes, e.Nodes)

	case *dom.EventAttributeModified:
		id, op = e.NodeID, attributeModified(e.Name, e.Value)

	case *dom.EventAttributeRemoved:
		id, op = e.NodeID, attributeRemoved(e.Name)

	case *dom.EventInlineStyleInvalidated:
		if len(e.NodeIds) == 0 {
			return
		}

		id, op = e.NodeIds[0], inlineStyleInvalidated(e.NodeIds[1:])

	case *dom.EventCharacterDataModified:
		id, op = e.NodeID, characterDataModified(e.CharacterData)

	case *dom.EventChildNodeCountUpdated:
		id, op = e.NodeID, childNodeCountUpdated(e.ChildNodeCount)

	case *dom.EventChildNodeInserted:
		id, op = e.ParentNodeID, childNodeInserted(f.Nodes, e.PreviousNodeID, e.Node)

	case *dom.EventChildNodeRemoved:
		id, op = e.ParentNodeID, childNodeRemoved(f.Nodes, e.NodeID)

	case *dom.EventShadowRootPushed:
		id, op = e.HostID, shadowRootPushed(f.Nodes, e.Root)

	case *dom.EventShadowRootPopped:
		id, op = e.HostID, shadowRootPopped(f.Nodes, e.RootID)

	case *dom.EventPseudoElementAdded:
		id, op = e.ParentID, pseudoElementAdded(f.Nodes, e.PseudoElement)

	case *dom.EventPseudoElementRemoved:
		id, op = e.ParentID, pseudoElementRemoved(f.Nodes, e.PseudoElementID)

	case *dom.EventDistributedNodesUpdated:
		id, op = e.InsertionPointID, distributedNodesUpdated(e.DistributedNodes)

	default:
		t.errf("unhandled node event %T", ev)
		return
	}

	n, ok := f.Nodes[id]
	if !ok {
		// Node ID has been invalidated. Nothing to do.
		return
	}

	f.Lock()
	op(n)
	f.Unlock()
}
<|endoftext|>


<commit_before><commit_msg>refactoring mutex handling<commit_after><|endoftext|>


<commit_before>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package oci

import (
	"context"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/pkg/cap"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

// WithHostDevices adds all the hosts device nodes to the container's spec
func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
	setLinux(s)

	devs, err := HostDevices()
	if err != nil {
		return err
	}
	s.Linux.Devices = append(s.Linux.Devices, devs...)
	return nil
}

// WithDevices recursively adds devices from the passed in path and associated cgroup rules for that device.
// If devicePath is a dir it traverses the dir to add all devices in that dir.
// If devicePath is not a dir, it attempts to add the single device.
// If containerPath is not set then the device path is used for the container path.
func WithDevices(devicePath, containerPath, permissions string) SpecOpts {
	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
		devs, err := getDevices(devicePath, containerPath)
		if err != nil {
			return err
		}
		for _, dev := range devs {
			s.Linux.Devices = append(s.Linux.Devices, dev)
			s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{
				Allow:  true,
				Type:   dev.Type,
				Major:  &dev.Major,
				Minor:  &dev.Minor,
				Access: permissions,
			})
		}
		return nil
	}
}

// WithMemorySwap sets the container's swap in bytes
func WithMemorySwap(swap int64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setResources(s)
		if s.Linux.Resources.Memory == nil {
			s.Linux.Resources.Memory = &specs.LinuxMemory{}
		}
		s.Linux.Resources.Memory.Swap = &swap
		return nil
	}
}

// WithPidsLimit sets the container's pid limit or maximum
func WithPidsLimit(limit int64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setResources(s)
		if s.Linux.Resources.Pids == nil {
			s.Linux.Resources.Pids = &specs.LinuxPids{}
		}
		s.Linux.Resources.Pids.Limit = limit
		return nil
	}
}

// WithCPUShares sets the container's cpu shares
func WithCPUShares(shares uint64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Shares = &shares
		return nil
	}
}

// WithCPUs sets the container's cpus/cores for use by the container
func WithCPUs(cpus string) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Cpus = cpus
		return nil
	}
}

// WithCPUsMems sets the container's cpu mems for use by the container
func WithCPUsMems(mems string) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Mems = mems
		return nil
	}
}

// WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period
func WithCPUCFS(quota int64, period uint64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Quota = &quota
		s.Linux.Resources.CPU.Period = &period
		return nil
	}
}

// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
// The capability set may differ from WithAllKnownCapabilities when running in a container.
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	caps, err := cap.Current()
	if err != nil {
		return err
	}
	return WithCapabilities(caps)(ctx, client, c, s)
}

// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	caps := cap.Known()
	return WithCapabilities(caps)(ctx, client, c, s)
}

// WithoutRunMount removes the `/run` inside the spec
func WithoutRunMount(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	return WithoutMounts("/run")(ctx, client, c, s)
}
<commit_msg>Fix dir support for devices V3 (#4847)<commit_after>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package oci

import (
	"context"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/pkg/cap"
	specs "github.com/opencontainers/runtime-spec/specs-go"
)

// WithHostDevices adds all the hosts device nodes to the container's spec
func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
	setLinux(s)

	devs, err := HostDevices()
	if err != nil {
		return err
	}
	s.Linux.Devices = append(s.Linux.Devices, devs...)
	return nil
}

// WithDevices recursively adds devices from the passed in path and associated cgroup rules for that device.
// If devicePath is a dir it traverses the dir to add all devices in that dir.
// If devicePath is not a dir, it attempts to add the single device.
// If containerPath is not set then the device path is used for the container path.
func WithDevices(devicePath, containerPath, permissions string) SpecOpts {
	return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
		devs, err := getDevices(devicePath, containerPath)
		if err != nil {
			return err
		}
		for i := range devs {
			s.Linux.Devices = append(s.Linux.Devices, devs[i])
			s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{
				Allow:  true,
				Type:   devs[i].Type,
				Major:  &devs[i].Major,
				Minor:  &devs[i].Minor,
				Access: permissions,
			})
		}
		return nil
	}
}

// WithMemorySwap sets the container's swap in bytes
func WithMemorySwap(swap int64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setResources(s)
		if s.Linux.Resources.Memory == nil {
			s.Linux.Resources.Memory = &specs.LinuxMemory{}
		}
		s.Linux.Resources.Memory.Swap = &swap
		return nil
	}
}

// WithPidsLimit sets the container's pid limit or maximum
func WithPidsLimit(limit int64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setResources(s)
		if s.Linux.Resources.Pids == nil {
			s.Linux.Resources.Pids = &specs.LinuxPids{}
		}
		s.Linux.Resources.Pids.Limit = limit
		return nil
	}
}

// WithCPUShares sets the container's cpu shares
func WithCPUShares(shares uint64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Shares = &shares
		return nil
	}
}

// WithCPUs sets the container's cpus/cores for use by the container
func WithCPUs(cpus string) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Cpus = cpus
		return nil
	}
}

// WithCPUsMems sets the container's cpu mems for use by the container
func WithCPUsMems(mems string) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Mems = mems
		return nil
	}
}

// WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period
func WithCPUCFS(quota int64, period uint64) SpecOpts {
	return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error {
		setCPU(s)
		s.Linux.Resources.CPU.Quota = &quota
		s.Linux.Resources.CPU.Period = &period
		return nil
	}
}

// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
// The capability set may differ from WithAllKnownCapabilities when running in a container.
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	caps, err := cap.Current()
	if err != nil {
		return err
	}
	return WithCapabilities(caps)(ctx, client, c, s)
}

// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	caps := cap.Known()
	return WithCapabilities(caps)(ctx, client, c, s)
}

// WithoutRunMount removes the `/run` inside the spec
func WithoutRunMount(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
	return WithoutMounts("/run")(ctx, client, c, s)
}
<|endoftext|>


<commit_before>// This file defines a Source that goes to and completes paths
// provided by a file.

package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// NewFileSource returns a Source that goes to and completes path
// given by the file. The file format is given in the `doc.go` file.
func NewFileSource(file string) Source {
	contents, err := ioutil.ReadFile(file)
	if err != nil {
		return &fileSource{}
	}

	shortcuts := make(map[string]string)
	for i, line := range strings.Split(string(contents), "\n") {
		if strings.HasPrefix(line, "#") || strings.Trim(line, whitespace) == "" {
			continue
		}
		fields := strings.Fields(strings.Trim(line, whitespace))
		if len(fields) != 2 {
			log.Fatalf(".goto has more than two fields on line %d", i)
		}
		if strings.HasPrefix(fields[1], "~"+string(os.PathSeparator)) {
			fields[1] = os.Getenv("HOME") + strings.TrimPrefix(fields[1], "~")
		}
		shortcuts[fields[0]] = fields[1]
	}
	return &fileSource{shortcuts}
}

type fileSource struct {
	shortcuts map[string]string
}

// Goto goes to the expanded destination if it exists on the filesystem.
func (s *fileSource) Goto(dest string) (string, error) {
	dir, err := s.expand(dest)
	if err != nil {
		return "", errors.New(fmt.Sprintf("No such shortcut %s", dest))
	}
	return dir, nil
}

// Complete returns recursive completion of all (sub)+directories of
// the expanded prefix.
func (s *fileSource) Complete(prefix string) []string {
	var completions []string
	for key := range s.shortcuts {
		if strings.HasPrefix(key, prefix) {
			completions = append(completions, key+string(os.PathSeparator))
		} else if strings.HasPrefix(prefix, key) {
			val, err := s.expand(prefix)
			n := strings.LastIndex(val, string(os.PathSeparator))
			m := strings.LastIndex(prefix, string(os.PathSeparator))
			if err != nil || n == -1 || m == -1 {
				continue
			}
			for _, completion := range completionsForDir(val[:n], val[n+1:]) {
				completions = append(completions, prefix[:m+1]+completion)
			}
		}
	}
	return completions
}

func (s *fileSource) expand(str string) (string, error) {
	for key := range s.shortcuts {
		if strings.HasPrefix(str, key) {
			return s.shortcuts[key] + string(os.PathSeparator) + strings.TrimPrefix(str, key), nil
		}
	}
	return "", errors.New(fmt.Sprintf("can't", str))
}

const whitespace = " \t"
<commit_msg>Improved handling, so that the longest key that fits is expanded.<commit_after>// This file defines a Source that goes to and completes paths
// provided by a file.

package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// NewFileSource returns a Source that goes to and completes path
// given by the file. The file format is given in the `doc.go` file.
func NewFileSource(file string) Source {
	contents, err := ioutil.ReadFile(file)
	if err != nil {
		return &fileSource{}
	}

	shortcuts := make(map[string]string)
	for i, line := range strings.Split(string(contents), "\n") {
		if strings.HasPrefix(line, "#") || strings.Trim(line, whitespace) == "" {
			continue
		}
		fields := strings.Fields(strings.Trim(line, whitespace))
		if len(fields) != 2 {
			log.Fatalf(".goto has more than two fields on line %d", i)
		}
		if strings.HasPrefix(fields[1], "~"+string(os.PathSeparator)) {
			fields[1] = os.Getenv("HOME") + strings.TrimPrefix(fields[1], "~")
		}
		shortcuts[fields[0]] = fields[1]
	}
	return &fileSource{shortcuts}
}

type fileSource struct {
	shortcuts map[string]string
}

// Goto goes to the expanded destination if it exists on the filesystem.
func (s *fileSource) Goto(dest string) (string, error) {
	dir, err := s.expand(dest)
	if err != nil {
		return "", errors.New(fmt.Sprintf("No such shortcut %s", dest))
	}
	return dir, nil
}

// Complete returns recursive completion of all (sub)+directories of
// the expanded prefix.
func (s *fileSource) Complete(prefix string) []string {
	var completions []string
	for key := range s.shortcuts {
		if strings.HasPrefix(key, prefix) {
			completions = append(completions, key+string(os.PathSeparator))
		} else if strings.HasPrefix(prefix, key) {
			val, err := s.expand(prefix)
			n := strings.LastIndex(val, string(os.PathSeparator))
			m := strings.LastIndex(prefix, string(os.PathSeparator))
			if err != nil || n == -1 || m == -1 {
				continue
			}
			for _, completion := range completionsForDir(val[:n], val[n+1:]) {
				completions = append(completions, prefix[:m+1]+completion)
			}
		}
	}
	return completions
}

func (s *fileSource) expand(str string) (string, error) {
	path, length := "", -1
	for key := range s.shortcuts {
		if strings.HasPrefix(str, key) && len(key) > length {
			path, length = s.shortcuts[key]+strings.TrimPrefix(str, key), len(key)
		}
	}
	if length == -1 {
		return "", errors.New(fmt.Sprintf("can't", str))
	}
	return path, nil
}

const whitespace = " \t"
<|endoftext|>


<commit_before>package collection

import (
	"errors"
	"os"
	"path/filepath"
)

// EnumerateDirectoryOptions is a means of configuring a `Directory` instance to including various children in its enumeration without
// supplying a `Where` clause later.
type DirectoryOptions uint

// These constants define all of the supported options for configuring a `Directory`
const (
	DirectoryOptionsExcludeFiles = 1 << iota
	DirectoryOptionsExcludeDirectories
	DirectoryOptionsRecursive
)

// Directory treats a filesystem path as a collection of filesystem entries, specifically a collection of directories and files.
type Directory struct {
	Location string
	Options  DirectoryOptions
}

func defaultEnumeratePredicate(loc string, info os.FileInfo) bool {
	return true
}

func (d Directory) applyOptions(loc string, info os.FileInfo) bool {
	if info.IsDir() && 0 != (d.Options&DirectoryOptionsExcludeDirectories) {
		return false
	}

	if !info.IsDir() && 0 != d.Options&DirectoryOptionsExcludeFiles {
		return false
	}

	return true
}

// Enumerate lists the items in a `Directory`
func (d Directory) Enumerate(cancel <-chan struct{}) Enumerator {
	results := make(chan interface{})

	go func() {
		defer close(results)

		filepath.Walk(d.Location, func(currentLocation string, info os.FileInfo, openErr error) (err error) {
			if openErr != nil {
				err = openErr
				return
			}

			if d.Location == currentLocation {
				return
			}

			if info.IsDir() && 0 == d.Options&DirectoryOptionsRecursive {
				err = filepath.SkipDir
			}

			if d.applyOptions(currentLocation, info) {
				select {
				case results <- currentLocation:
					// Intentionally Left Blank
				case <-cancel:
					err = errors.New("directory enumeration cancelled")
				}
			}

			return
		})
	}()

	return results
}
<commit_msg>Fixing `golint` errors<commit_after>package collection

import (
	"errors"
	"os"
	"path/filepath"
)

// DirectoryOptions is a means of configuring a `Directory` instance to including various children in its enumeration without
// supplying a `Where` clause later.
type DirectoryOptions uint

// These constants define all of the supported options for configuring a `Directory`
const (
	DirectoryOptionsExcludeFiles = 1 << iota
	DirectoryOptionsExcludeDirectories
	DirectoryOptionsRecursive
)

// Directory treats a filesystem path as a collection of filesystem entries, specifically a collection of directories and files.
type Directory struct {
	Location string
	Options  DirectoryOptions
}

func defaultEnumeratePredicate(loc string, info os.FileInfo) bool {
	return true
}

func (d Directory) applyOptions(loc string, info os.FileInfo) bool {
	if info.IsDir() && 0 != (d.Options&DirectoryOptionsExcludeDirectories) {
		return false
	}

	if !info.IsDir() && 0 != d.Options&DirectoryOptionsExcludeFiles {
		return false
	}

	return true
}

// Enumerate lists the items in a `Directory`
func (d Directory) Enumerate(cancel <-chan struct{}) Enumerator {
	results := make(chan interface{})

	go func() {
		defer close(results)

		filepath.Walk(d.Location, func(currentLocation string, info os.FileInfo, openErr error) (err error) {
			if openErr != nil {
				err = openErr
				return
			}

			if d.Location == currentLocation {
				return
			}

			if info.IsDir() && 0 == d.Options&DirectoryOptionsRecursive {
				err = filepath.SkipDir
			}

			if d.applyOptions(currentLocation, info) {
				select {
				case results <- currentLocation:
					// Intentionally Left Blank
				case <-cancel:
					err = errors.New("directory enumeration cancelled")
				}
			}

			return
		})
	}()

	return results
}
<|endoftext|>


<commit_before>package docker

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	yaml "gopkg.in/yaml.v2"

	"github.com/ViBiOh/dashboard/auth"
	"github.com/ViBiOh/httputils"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
)

const minMemory = 16777216
const maxMemory = 805306368
const defaultTag = `:latest`
const deploySuffix = `_deploy`
const networkMode = `traefik`
const linkSeparator = `:`

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeHealthcheck struct {
	Test     []string
	Interval string
	Timeout  string
	Retries  int
}

type dockerComposeService struct {
	Image       string
	Command     []string
	Environment map[string]string
	Labels      map[string]string
	Links       []string
	Ports       []string
	Healthcheck *dockerComposeHealthcheck
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

type deployedService struct {
	ID   string
	Name string
}

func getConfig(service *dockerComposeService, user *auth.User, appName string) (*container.Config, error) {
	environments := make([]string, 0, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = user.Username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if len(service.Command) != 0 {
		config.Cmd = service.Command
	}

	if service.Healthcheck != nil {
		healthconfig := container.HealthConfig{
			Test:    service.Healthcheck.Test,
			Retries: service.Healthcheck.Retries,
		}

		if service.Healthcheck.Interval != `` {
			interval, err := time.ParseDuration(service.Healthcheck.Interval)
			if err != nil {
				return nil, fmt.Errorf(`Error while parsing healthcheck interval: %v`, err)
			}

			healthconfig.Interval = interval
		}

		if service.Healthcheck.Timeout != `` {
			timeout, err := time.ParseDuration(service.Healthcheck.Timeout)
			if err != nil {
				return nil, fmt.Errorf(`Error while parsing healthcheck timeout: %v`, err)
			}

			healthconfig.Timeout = timeout
		}

		config.Healthcheck = &healthconfig
	}

	return &config, nil
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		NetworkMode:   networkMode,
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = true
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit <= maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func getNetworkConfig(service *dockerComposeService, deployedServices map[string]*deployedService) *network.NetworkingConfig {
	traefikConfig := network.EndpointSettings{}

	for _, link := range service.Links {
		linkParts := strings.Split(link, linkSeparator)

		target := linkParts[0]
		if linkedService, ok := deployedServices[target]; ok {
			target = getFinalName(linkedService.Name)
		}

		alias := linkParts[0]
		if len(linkParts) > 1 {
			alias = linkParts[1]
		}

		traefikConfig.Links = append(traefikConfig.Links, target+linkSeparator+alias)
	}

	return &network.NetworkingConfig{
		EndpointsConfig: map[string]*network.EndpointSettings{
			networkMode: &traefikConfig,
		},
	}
}

func pullImage(image string, user *auth.User) error {
	if !imageTag.MatchString(image) {
		image = image + defaultTag
	}

	ctx, cancel := getGracefulCtx()
	defer cancel()

	pull, err := docker.ImagePull(ctx, image, types.ImagePullOptions{})
	if err != nil {
		return fmt.Errorf(`Error while pulling image: %v`, err)
	}

	httputils.ReadBody(pull)
	return nil
}

func cleanContainers(containers []types.Container, user *auth.User) {
	for _, container := range containers {
		stopContainer(container.ID)
	}

	for _, container := range containers {
		rmContainer(container.ID)
	}
}

func renameDeployedContainers(containers map[string]*deployedService, user *auth.User) error {
	ctx, cancel := getCtx()
	defer cancel()

	for service, container := range containers {
		if err := docker.ContainerRename(ctx, container.ID, getFinalName(container.Name)); err != nil {
			return fmt.Errorf(`Error while renaming container %s: %v`, service, err)
		}
	}

	return nil
}

func getServiceFullName(app string, service string) string {
	return app + `_` + service + deploySuffix
}

func getFinalName(serviceFullName string) string {
	return strings.TrimSuffix(serviceFullName, deploySuffix)
}

func deleteServices(appName []byte, services map[string]*deployedService, user *auth.User) {
	for service, container := range services {
		if infos, err := inspectContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while inspecting service %s: %v`, user.Username, appName, service, err)
		} else if infos.State.Health != nil {
			logs := make([]string, 0)

			logs = append(logs, "\n")
			for _, log := range infos.State.Health.Log {
				logs = append(logs, log.Output)
			}

			log.Printf(`[%s] [%s] Healthcheck output for %s: %s`, user.Username, appName, service, logs)
		}

		if err := stopContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while stopping service %s: %v`, user.Username, appName, service, err)
		}

		if err := rmContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while deleting service %s: %v`, user.Username, appName, service, err)
		}
	}
}

func startServices(appName []byte, services map[string]*deployedService, user *auth.User) error {
	for service, container := range services {
		if err := startContainer(container.ID); err != nil {
			return fmt.Errorf(`[%s] [%s] Error while starting service %s: %v`, user.Username, appName, service, err)
		}
	}

	return nil
}

func inspectServices(services map[string]*deployedService, user *auth.User) []*types.ContainerJSON {
	containers := make([]*types.ContainerJSON, 0, len(services))

	for service, container := range services {
		infos, err := inspectContainer(container.ID)
		if err != nil {
			log.Printf(`[%s] Error while inspecting container %s: %v`, user.Username, service, err)
		}

		containers = append(containers, &infos)
	}

	return containers
}

func areContainersHealthy(ctx context.Context, user *auth.User, appName []byte, containers []*types.ContainerJSON) bool {
	containersIdsWithHealthcheck := make([]string, 0, len(containers))
	for _, container := range containers {
		if container.Config.Healthcheck != nil && len(container.Config.Healthcheck.Test) != 0 {
			containersIdsWithHealthcheck = append(containersIdsWithHealthcheck, container.ID)
		}
	}

	if len(containersIdsWithHealthcheck) == 0 {
		return true
	}

	filtersArgs := filters.NewArgs()
	healthyStatusFilters(&filtersArgs, containersIdsWithHealthcheck)

	timeoutCtx, cancel := context.WithTimeout(ctx, DeployTimeout)
	defer cancel()

	messages, errors := docker.Events(timeoutCtx, types.EventsOptions{Filters: filtersArgs})
	healthyContainers := make(map[string]bool, len(containersIdsWithHealthcheck))

	for {
		select {
		case <-ctx.Done():
			return false
		case message := <-messages:
			healthyContainers[message.ID] = true
			if len(healthyContainers) == len(containersIdsWithHealthcheck) {
				return true
			}
		case err := <-errors:
			log.Printf(`[%s] [%s] Error while reading healthy events: %v`, user.Username, appName, err)
			return false
		}
	}
}

func finishDeploy(ctx context.Context, cancel context.CancelFunc, user *auth.User, appName []byte, services map[string]*deployedService, oldContainers []types.Container) {
	defer cancel()
	defer func() {
		backgroundMutex.Lock()
		defer backgroundMutex.Unlock()

		delete(backgroundTasks, string(appName))
	}()

	if areContainersHealthy(ctx, user, appName, inspectServices(services, user)) {
		cleanContainers(oldContainers, user)

		if err := renameDeployedContainers(services, user); err != nil {
			log.Printf(`[%s] [%s] Error while renaming deployed containers: %v`, user.Username, appName, err)
		}
	} else {
		deleteServices(appName, services, user)
		log.Printf(`[%s] [%s] Failed to deploy: %v`, user.Username, appName, fmt.Errorf(`[Health check failed`))
	}
}

func createContainer(user *auth.User, appName []byte, serviceName string, services map[string]*deployedService, service *dockerComposeService) (*deployedService, error) {
	if err := pullImage(service.Image, user); err != nil {
		return nil, err
	}

	serviceFullName := getServiceFullName(string(appName), serviceName)

	config, err := getConfig(service, user, string(appName))
	if err != nil {
		return nil, fmt.Errorf(`[%s] [%s] Error while getting config: %v`, user.Username, appName, err)
	}

	ctx, cancel := getCtx()
	defer cancel()

	createdContainer, err := docker.ContainerCreate(ctx, config, getHostConfig(service), getNetworkConfig(service, services), serviceFullName)
	if err != nil {
		return nil, fmt.Errorf(`[%s] [%s] Error while creating service %s: %v`, user.Username, appName, serviceName, err)
	}

	return &deployedService{ID: createdContainer.ID, Name: serviceFullName}, nil
}

func composeFailed(w http.ResponseWriter, user *auth.User, appName []byte, err error) {
	httputils.InternalServer(w, fmt.Errorf(`[%s] [%s] Failed to deploy: %v`, user.Username, appName, err))
}

func composeHandler(w http.ResponseWriter, user *auth.User, appName []byte, composeFile []byte) {
	if user == nil {
		httputils.BadRequest(w, fmt.Errorf(`A user is required`))
		return
	}

	if len(appName) == 0 || len(composeFile) == 0 {
		httputils.BadRequest(w, fmt.Errorf(`[%s] An application name and a compose file are required`, user.Username))
		return
	}

	bytes.Replace(composeFile, []byte(`$$`), []byte(`$`), -1)

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		httputils.BadRequest(w, fmt.Errorf(`[%s] [%s] Error while unmarshalling compose file: %v`, user.Username, appName, err))
		return
	}

	appNameStr := string(appName)

	backgroundMutex.Lock()
	if _, ok := backgroundTasks[appNameStr]; ok {
		backgroundMutex.Unlock()
		composeFailed(w, user, appName, fmt.Errorf(`[%s] [%s] Application already in deployment`, user.Username, appName))
		return
	}

	backgroundTasks[appNameStr] = true
	backgroundMutex.Unlock()

	oldContainers, err := listContainers(user, appNameStr)
	if err != nil {
		composeFailed(w, user, appName, err)
		return
	}

	if len(oldContainers) > 0 && oldContainers[0].Labels[ownerLabel] != user.Username {
		composeFailed(w, user, appName, fmt.Errorf(`[%s] [%s] Application not owned`, user.Username, appName))
		httputils.Forbidden(w)
	}

	newServices := make(map[string]*deployedService)
	for serviceName, service := range compose.Services {
		if deployedService, err := createContainer(user, appName, serviceName, newServices, &service); err != nil {
			break
		} else {
			newServices[serviceName] = deployedService
		}
	}

	ctx, cancel := context.WithCancel(context.Background())
	go finishDeploy(ctx, cancel, user, appName, newServices, oldContainers)

	if err == nil {
		err = startServices(appName, newServices, user)
	}

	if err != nil {
		cancel()
		composeFailed(w, user, appName, err)
	} else {
		httputils.ResponseArrayJSON(w, newServices)
	}
}
<commit_msg>Replacing variables with new value, dumb programmer am I<commit_after>package docker

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	yaml "gopkg.in/yaml.v2"

	"github.com/ViBiOh/dashboard/auth"
	"github.com/ViBiOh/httputils"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
)

const minMemory = 16777216
const maxMemory = 805306368
const defaultTag = `:latest`
const deploySuffix = `_deploy`
const networkMode = `traefik`
const linkSeparator = `:`

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeHealthcheck struct {
	Test     []string
	Interval string
	Timeout  string
	Retries  int
}

type dockerComposeService struct {
	Image       string
	Command     []string
	Environment map[string]string
	Labels      map[string]string
	Links       []string
	Ports       []string
	Healthcheck *dockerComposeHealthcheck
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

type deployedService struct {
	ID   string
	Name string
}

func getConfig(service *dockerComposeService, user *auth.User, appName string) (*container.Config, error) {
	environments := make([]string, 0, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = user.Username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if len(service.Command) != 0 {
		config.Cmd = service.Command
	}

	if service.Healthcheck != nil {
		healthconfig := container.HealthConfig{
			Test:    service.Healthcheck.Test,
			Retries: service.Healthcheck.Retries,
		}

		if service.Healthcheck.Interval != `` {
			interval, err := time.ParseDuration(service.Healthcheck.Interval)
			if err != nil {
				return nil, fmt.Errorf(`Error while parsing healthcheck interval: %v`, err)
			}

			healthconfig.Interval = interval
		}

		if service.Healthcheck.Timeout != `` {
			timeout, err := time.ParseDuration(service.Healthcheck.Timeout)
			if err != nil {
				return nil, fmt.Errorf(`Error while parsing healthcheck timeout: %v`, err)
			}

			healthconfig.Timeout = timeout
		}

		config.Healthcheck = &healthconfig
	}

	return &config, nil
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		NetworkMode:   networkMode,
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = true
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit <= maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func getNetworkConfig(service *dockerComposeService, deployedServices map[string]*deployedService) *network.NetworkingConfig {
	traefikConfig := network.EndpointSettings{}

	for _, link := range service.Links {
		linkParts := strings.Split(link, linkSeparator)

		target := linkParts[0]
		if linkedService, ok := deployedServices[target]; ok {
			target = getFinalName(linkedService.Name)
		}

		alias := linkParts[0]
		if len(linkParts) > 1 {
			alias = linkParts[1]
		}

		traefikConfig.Links = append(traefikConfig.Links, target+linkSeparator+alias)
	}

	return &network.NetworkingConfig{
		EndpointsConfig: map[string]*network.EndpointSettings{
			networkMode: &traefikConfig,
		},
	}
}

func pullImage(image string, user *auth.User) error {
	if !imageTag.MatchString(image) {
		image = image + defaultTag
	}

	ctx, cancel := getGracefulCtx()
	defer cancel()

	pull, err := docker.ImagePull(ctx, image, types.ImagePullOptions{})
	if err != nil {
		return fmt.Errorf(`Error while pulling image: %v`, err)
	}

	httputils.ReadBody(pull)
	return nil
}

func cleanContainers(containers []types.Container, user *auth.User) {
	for _, container := range containers {
		stopContainer(container.ID)
	}

	for _, container := range containers {
		rmContainer(container.ID)
	}
}

func renameDeployedContainers(containers map[string]*deployedService, user *auth.User) error {
	ctx, cancel := getCtx()
	defer cancel()

	for service, container := range containers {
		if err := docker.ContainerRename(ctx, container.ID, getFinalName(container.Name)); err != nil {
			return fmt.Errorf(`Error while renaming container %s: %v`, service, err)
		}
	}

	return nil
}

func getServiceFullName(app string, service string) string {
	return app + `_` + service + deploySuffix
}

func getFinalName(serviceFullName string) string {
	return strings.TrimSuffix(serviceFullName, deploySuffix)
}

func deleteServices(appName []byte, services map[string]*deployedService, user *auth.User) {
	for service, container := range services {
		if infos, err := inspectContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while inspecting service %s: %v`, user.Username, appName, service, err)
		} else if infos.State.Health != nil {
			logs := make([]string, 0)

			logs = append(logs, "\n")
			for _, log := range infos.State.Health.Log {
				logs = append(logs, log.Output)
			}

			log.Printf(`[%s] [%s] Healthcheck output for %s: %s`, user.Username, appName, service, logs)
		}

		if err := stopContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while stopping service %s: %v`, user.Username, appName, service, err)
		}

		if err := rmContainer(container.ID); err != nil {
			log.Printf(`[%s] [%s] Error while deleting service %s: %v`, user.Username, appName, service, err)
		}
	}
}

func startServices(appName []byte, services map[string]*deployedService, user *auth.User) error {
	for service, container := range services {
		if err := startContainer(container.ID); err != nil {
			return fmt.Errorf(`[%s] [%s] Error while starting service %s: %v`, user.Username, appName, service, err)
		}
	}

	return nil
}

func inspectServices(services map[string]*deployedService, user *auth.User) []*types.ContainerJSON {
	containers := make([]*types.ContainerJSON, 0, len(services))

	for service, container := range services {
		infos, err := inspectContainer(container.ID)
		if err != nil {
			log.Printf(`[%s] Error while inspecting container %s: %v`, user.Username, service, err)
		}

		containers = append(containers, &infos)
	}

	return containers
}

func areContainersHealthy(ctx context.Context, user *auth.User, appName []byte, containers []*types.ContainerJSON) bool {
	containersIdsWithHealthcheck := make([]string, 0, len(containers))
	for _, container := range containers {
		if container.Config.Healthcheck != nil && len(container.Config.Healthcheck.Test) != 0 {
			containersIdsWithHealthcheck = append(containersIdsWithHealthcheck, container.ID)
		}
	}

	if len(containersIdsWithHealthcheck) == 0 {
		return true
	}

	filtersArgs := filters.NewArgs()
	healthyStatusFilters(&filtersArgs, containersIdsWithHealthcheck)

	timeoutCtx, cancel := context.WithTimeout(ctx, DeployTimeout)
	defer cancel()

	messages, errors := docker.Events(timeoutCtx, types.EventsOptions{Filters: filtersArgs})
	healthyContainers := make(map[string]bool, len(containersIdsWithHealthcheck))

	for {
		select {
		case <-ctx.Done():
			return false
		case message := <-messages:
			healthyContainers[message.ID] = true
			if len(healthyContainers) == len(containersIdsWithHealthcheck) {
				return true
			}
		case err := <-errors:
			log.Printf(`[%s] [%s] Error while reading healthy events: %v`, user.Username, appName, err)
			return false
		}
	}
}

func finishDeploy(ctx context.Context, cancel context.CancelFunc, user *auth.User, appName []byte, services map[string]*deployedService, oldContainers []types.Container) {
	defer cancel()
	defer func() {
		backgroundMutex.Lock()
		defer backgroundMutex.Unlock()

		delete(backgroundTasks, string(appName))
	}()

	if areContainersHealthy(ctx, user, appName, inspectServices(services, user)) {
		cleanContainers(oldContainers, user)

		if err := renameDeployedContainers(services, user); err != nil {
			log.Printf(`[%s] [%s] Error while renaming deployed containers: %v`, user.Username, appName, err)
		}
	} else {
		deleteServices(appName, services, user)
		log.Printf(`[%s] [%s] Failed to deploy: %v`, user.Username, appName, fmt.Errorf(`[Health check failed`))
	}
}

func createContainer(user *auth.User, appName []byte, serviceName string, services map[string]*deployedService, service *dockerComposeService) (*deployedService, error) {
	if err := pullImage(service.Image, user); err != nil {
		return nil, err
	}

	serviceFullName := getServiceFullName(string(appName), serviceName)

	config, err := getConfig(service, user, string(appName))
	if err != nil {
		return nil, fmt.Errorf(`[%s] [%s] Error while getting config: %v`, user.Username, appName, err)
	}

	ctx, cancel := getCtx()
	defer cancel()

	createdContainer, err := docker.ContainerCreate(ctx, config, getHostConfig(service), getNetworkConfig(service, services), serviceFullName)
	if err != nil {
		return nil, fmt.Errorf(`[%s] [%s] Error while creating service %s: %v`, user.Username, appName, serviceName, err)
	}

	return &deployedService{ID: createdContainer.ID, Name: serviceFullName}, nil
}

func composeFailed(w http.ResponseWriter, user *auth.User, appName []byte, err error) {
	httputils.InternalServer(w, fmt.Errorf(`[%s] [%s] Failed to deploy: %v`, user.Username, appName, err))
}

func composeHandler(w http.ResponseWriter, user *auth.User, appName []byte, composeFile []byte) {
	if user == nil {
		httputils.BadRequest(w, fmt.Errorf(`A user is required`))
		return
	}

	if len(appName) == 0 || len(composeFile) == 0 {
		httputils.BadRequest(w, fmt.Errorf(`[%s] An application name and a compose file are required`, user.Username))
		return
	}

	composeFile = bytes.Replace(composeFile, []byte(`$$`), []byte(`$`), -1)

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		httputils.BadRequest(w, fmt.Errorf(`[%s] [%s] Error while unmarshalling compose file: %v`, user.Username, appName, err))
		return
	}

	appNameStr := string(appName)

	backgroundMutex.Lock()
	if _, ok := backgroundTasks[appNameStr]; ok {
		backgroundMutex.Unlock()
		composeFailed(w, user, appName, fmt.Errorf(`[%s] [%s] Application already in deployment`, user.Username, appName))
		return
	}

	backgroundTasks[appNameStr] = true
	backgroundMutex.Unlock()

	oldContainers, err := listContainers(user, appNameStr)
	if err != nil {
		composeFailed(w, user, appName, err)
		return
	}

	if len(oldContainers) > 0 && oldContainers[0].Labels[ownerLabel] != user.Username {
		composeFailed(w, user, appName, fmt.Errorf(`[%s] [%s] Application not owned`, user.Username, appName))
		httputils.Forbidden(w)
	}

	newServices := make(map[string]*deployedService)
	for serviceName, service := range compose.Services {
		if deployedService, err := createContainer(user, appName, serviceName, newServices, &service); err != nil {
			break
		} else {
			newServices[serviceName] = deployedService
		}
	}

	ctx, cancel := context.WithCancel(context.Background())
	go finishDeploy(ctx, cancel, user, appName, newServices, oldContainers)

	if err == nil {
		err = startServices(appName, newServices, user)
	}

	if err != nil {
		cancel()
		composeFailed(w, user, appName, err)
	} else {
		httputils.ResponseArrayJSON(w, newServices)
	}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package leveldb

import (
	"testing"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils/logging"
)

func TestInterface(t *testing.T) {
	for _, test := range database.Tests {
		folder := t.TempDir()
		db, err := New(folder, logging.NoLog{}, 0, 0, 0)
		if err != nil {
			t.Fatalf("leveldb.New(%q, logging.NoLog{}, 0, 0, 0) errored with %s", folder, err)
		}

		test(t, db)

		// The database may have been closed by the test, so we don't care if it
		// errors here.
		_ = db.Close()
	}
}
<commit_msg>re-introduce deferred close in leveldb test<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package leveldb

import (
	"testing"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils/logging"
)

func TestInterface(t *testing.T) {
	for _, test := range database.Tests {
		folder := t.TempDir()
		db, err := New(folder, logging.NoLog{}, 0, 0, 0)
		if err != nil {
			t.Fatalf("leveldb.New(%q, logging.NoLog{}, 0, 0, 0) errored with %s", folder, err)
		}

		// The database may have been closed by the test, so we don't care if it
		// errors here.
		defer db.Close()

		test(t, db)
	}
}
<|endoftext|>


<commit_before>// +build linux,amd64

// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package rocksdb

import (
	"testing"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils/logging"
)

func TestInterface(t *testing.T) {
	for _, test := range database.Tests {
		folder := t.TempDir()
		db, err := New(folder, logging.NoLog{})
		if err != nil {
			t.Fatalf("rocksdb.New(%q, logging.NoLog{}) errored with %s", folder, err)
		}

		test(t, db)

		// The database may have been closed by the test, so we don't care if it
		// errors here.
		_ = db.Close()
	}
}

func BenchmarkInterface(b *testing.B) {
	for _, size := range database.BenchmarkSizes {
		keys, values := database.SetupBenchmark(b, size, size)
		for _, bench := range database.Benchmarks {
			folder := b.TempDir()

			db, err := New(folder, logging.NoLog{})
			if err != nil {
				b.Fatal(err)
			}

			bench(b, db, "rocksdb", keys, values)

			// The database may have been closed by the test, so we don't care if it
			// errors here.
			_ = db.Close()
		}
	}
}
<commit_msg>fixed test<commit_after>// +build linux
// +build amd64

// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package rocksdb

import (
	"testing"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils/logging"
)

func TestInterface(t *testing.T) {
	for _, test := range database.Tests {
		folder := t.TempDir()
		db, err := New(folder, logging.NoLog{})
		if err != nil {
			t.Fatalf("rocksdb.New(%q, logging.NoLog{}) errored with %s", folder, err)
		}

		test(t, db)

		// The database may have been closed by the test, so we don't care if it
		// errors here.
		_ = db.Close()
	}
}

func BenchmarkInterface(b *testing.B) {
	for _, size := range database.BenchmarkSizes {
		keys, values := database.SetupBenchmark(b, size, size)
		for _, bench := range database.Benchmarks {
			folder := b.TempDir()

			db, err := New(folder, logging.NoLog{})
			if err != nil {
				b.Fatal(err)
			}

			bench(b, db, "rocksdb", keys, values)

			// The database may have been closed by the test, so we don't care if it
			// errors here.
			_ = db.Close()
		}
	}
}
<|endoftext|>


<commit_before>package global

import (
	"math"

	"github.com/ready-steady/adapt/algorithm"
	"github.com/ready-steady/adapt/algorithm/internal"
	"github.com/ready-steady/adapt/grid"
)

const (
	none = ^uint(0)
)

var (
	infinity = math.Inf(1.0)
)

// Strategy is a basic strategy.
type Strategy struct {
	ni uint
	no uint

	guide Guide

	lmin uint
	lmax uint

	coarse []float64
	fine   []float64

	active    *internal.Active
	threshold *internal.Threshold
}

// Guide is a grid-refinement tool of a basic strategy.
type Guide interface {
	grid.Indexer
}

// NewStrategy creates a basic strategy.
func NewStrategy(inputs, outputs uint, guide Guide, minLevel, maxLevel uint,
	absoluteError, relativeError float64) *Strategy {

	return &Strategy{
		ni: inputs,
		no: outputs,

		guide: guide,

		lmin: minLevel,
		lmax: maxLevel,

		active:    internal.NewActive(inputs),
		threshold: internal.NewThreshold(outputs, absoluteError, relativeError),
	}
}

func (self *Strategy) First(surrogate *algorithm.Surrogate) *algorithm.State {
	return self.initiate(self.active.First(), surrogate)
}

func (self *Strategy) Next(state *algorithm.State,
	surrogate *algorithm.Surrogate) *algorithm.State {

	for {
		self.consume(state)
		if self.check() {
			return nil
		}
		k := self.choose()
		if k == none {
			return nil
		}
		state = self.initiate(self.active.Next(k), surrogate)
		if len(state.Indices) > 0 {
			return state
		}
	}
}

func (self *Strategy) Score(element *algorithm.Element) float64 {
	return internal.SumAbsolute(element.Surplus)
}

func (self *Strategy) check() bool {
	no, δ := self.no, self.threshold.Values
	for i := range self.active.Positions {
		for j := uint(0); j < no; j++ {
			if self.fine[i*no+j] > δ[j] {
				return false
			}
		}
	}
	return true
}

func (self *Strategy) choose() uint {
	if len(self.active.Positions) == 0 {
		return none
	}
	k, max := none, 0.0
	for i := range self.active.Positions {
		if score := self.coarse[i]; score > max {
			k, max = i, score
		}
	}
	if max <= 0.0 {
		return none
	}
	return k
}

func (self *Strategy) consume(state *algorithm.State) {
	no, nc, nf := self.no, uint(len(self.coarse)), uint(len(self.fine))
	nnc := uint(len(state.Counts))
	nnf := nnc * no

	levels := internal.Levelize(state.Lndices, self.ni)

	self.coarse = append(self.coarse, make([]float64, nnc)...)
	coarse := self.coarse[nc:]

	self.fine = append(self.fine, make([]float64, nnf)...)
	fine := self.fine[nf:]

	for i, offset := uint(0), uint(0); i < nnc; i++ {
		count := state.Counts[i]
		if levels[i] < uint64(self.lmin) {
			coarse[i] = infinity
			for j := uint(0); j < no; j++ {
				fine[i*no+j] = infinity
			}
		} else if levels[i] < uint64(self.lmax) {
			coarse[i] = internal.Average(state.Scores[offset:(offset + count)])
			for j, m := uint(0), count*no; j < m; j++ {
				k := i*no + j%no
				fine[k] = math.Max(fine[k], math.Abs(state.Surpluses[offset+j]))
			}
		}
		offset += count
	}

	self.threshold.Update(state.Values)
}

func (self *Strategy) initiate(lndices []uint64, _ *algorithm.Surrogate) (state *algorithm.State) {
	state = &algorithm.State{Lndices: lndices}
	state.Indices, state.Counts = internal.Index(self.guide, lndices, self.ni)
	return
}
<commit_msg>a/global: rename a couple of variables<commit_after>package global

import (
	"math"

	"github.com/ready-steady/adapt/algorithm"
	"github.com/ready-steady/adapt/algorithm/internal"
	"github.com/ready-steady/adapt/grid"
)

const (
	none = ^uint(0)
)

var (
	infinity = math.Inf(1.0)
)

// Strategy is a basic strategy.
type Strategy struct {
	ni uint
	no uint

	guide Guide

	lmin uint
	lmax uint

	accuracy []float64
	priority []float64

	active    *internal.Active
	threshold *internal.Threshold
}

// Guide is a grid-refinement tool of a basic strategy.
type Guide interface {
	grid.Indexer
}

// NewStrategy creates a basic strategy.
func NewStrategy(inputs, outputs uint, guide Guide, minLevel, maxLevel uint,
	absoluteError, relativeError float64) *Strategy {

	return &Strategy{
		ni: inputs,
		no: outputs,

		guide: guide,

		lmin: minLevel,
		lmax: maxLevel,

		active:    internal.NewActive(inputs),
		threshold: internal.NewThreshold(outputs, absoluteError, relativeError),
	}
}

func (self *Strategy) First(surrogate *algorithm.Surrogate) *algorithm.State {
	return self.initiate(self.active.First(), surrogate)
}

func (self *Strategy) Next(state *algorithm.State,
	surrogate *algorithm.Surrogate) *algorithm.State {

	for {
		self.consume(state)
		if self.check() {
			return nil
		}
		k := self.choose()
		if k == none {
			return nil
		}
		state = self.initiate(self.active.Next(k), surrogate)
		if len(state.Indices) > 0 {
			return state
		}
	}
}

func (self *Strategy) Score(element *algorithm.Element) float64 {
	return internal.SumAbsolute(element.Surplus)
}

func (self *Strategy) check() bool {
	no, δ := self.no, self.threshold.Values
	for i := range self.active.Positions {
		for j := uint(0); j < no; j++ {
			if self.accuracy[i*no+j] > δ[j] {
				return false
			}
		}
	}
	return true
}

func (self *Strategy) choose() uint {
	if len(self.active.Positions) == 0 {
		return none
	}
	k, max := none, 0.0
	for i := range self.active.Positions {
		if priority := self.priority[i]; priority > max {
			k, max = i, priority
		}
	}
	if max <= 0.0 {
		return none
	}
	return k
}

func (self *Strategy) consume(state *algorithm.State) {
	no, nc, nf := self.no, uint(len(self.priority)), uint(len(self.accuracy))
	nnc := uint(len(state.Counts))
	nnf := nnc * no

	levels := internal.Levelize(state.Lndices, self.ni)

	self.priority = append(self.priority, make([]float64, nnc)...)
	priority := self.priority[nc:]

	self.accuracy = append(self.accuracy, make([]float64, nnf)...)
	accuracy := self.accuracy[nf:]

	for i, offset := uint(0), uint(0); i < nnc; i++ {
		count := state.Counts[i]
		if levels[i] < uint64(self.lmin) {
			priority[i] = infinity
			for j := uint(0); j < no; j++ {
				accuracy[i*no+j] = infinity
			}
		} else if levels[i] < uint64(self.lmax) {
			priority[i] = internal.Average(state.Scores[offset:(offset + count)])
			for j, m := uint(0), count*no; j < m; j++ {
				k := i*no + j%no
				accuracy[k] = math.Max(accuracy[k], math.Abs(state.Surpluses[offset+j]))
			}
		}
		offset += count
	}

	self.threshold.Update(state.Values)
}

func (self *Strategy) initiate(lndices []uint64, _ *algorithm.Surrogate) (state *algorithm.State) {
	state = &algorithm.State{Lndices: lndices}
	state.Indices, state.Counts = internal.Index(self.guide, lndices, self.ni)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/mattn/go-colorable"
	"github.com/zetamatta/go-box"
)

var optionIndex = flag.Bool("index", false, "print index as result")

func main1(args []string) error {
	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	data = box.AnsiCutter.ReplaceAll(data, []byte{})
	list := strings.Split(string(data), "\n")
	switch len(list) {
	case 0:
		return nil
	case 1:
		fmt.Println(strings.TrimSpace(list[0]))
		return nil
	}
	for i := 0; i < len(list); i++ {
		list[i] = strings.TrimSpace(list[i])
	}
	console := colorable.NewColorableStderr()
	index := box.Choose(list, console)
	fmt.Fprintln(console)

	if *optionIndex {
		fmt.Println(index)
	} else {
		fmt.Println(list[index])
	}
	return nil
}

func main() {
	flag.Parse()
	if err := main1(flag.Args()); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	os.Exit(0)
}
<commit_msg>Sample crashed by Ctrl-G<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/mattn/go-colorable"
	"github.com/zetamatta/go-box"
)

var optionIndex = flag.Bool("index", false, "print index as result")

func main1(args []string) error {
	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	data = box.AnsiCutter.ReplaceAll(data, []byte{})
	list := strings.Split(string(data), "\n")
	switch len(list) {
	case 0:
		return nil
	case 1:
		fmt.Println(strings.TrimSpace(list[0]))
		return nil
	}
	for i := 0; i < len(list); i++ {
		list[i] = strings.TrimSpace(list[i])
	}
	console := colorable.NewColorableStderr()
	index := box.Choose(list, console)
	fmt.Fprintln(console)

	if *optionIndex {
		fmt.Println(index)
	} else {
		if index >= 0 {
			fmt.Println(list[index])
		} else {
			fmt.Println("canceled")
		}
	}
	return nil
}

func main() {
	flag.Parse()
	if err := main1(flag.Args()); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	os.Exit(0)
}
<|endoftext|>


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

package specs

// Descriptor describes the disposition of targeted content.
type Descriptor struct {
	// MediaType contains the MIME type of the referenced object.
	MediaType string `json:"mediaType"`

	// Digests is the digest of the targeted content.
	Digest string `json:"digest"`

	// Size specifies the size in bytes of the blob
	Size int64 `json:"size"`
}
<commit_msg>Typo: fix typo in descriptor.go<commit_after>// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package specs

// Descriptor describes the disposition of targeted content.
type Descriptor struct {
	// MediaType contains the MIME type of the referenced object.
	MediaType string `json:"mediaType"`

	// Digest is the digest of the targeted content.
	Digest string `json:"digest"`

	// Size specifies the size in bytes of the blob.
	Size int64 `json:"size"`
}
<|endoftext|>


<commit_before>package transport

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

	. "github.com/smartystreets/goconvey/convey"
)

func TestDiskTransport(t *testing.T) {
	var _ Transport = (*DiskTransport)(nil)
}

func TestNewDiskTransport(t *testing.T) {
	Convey("NewDiskTransport", t, func() {
		Convey("It should create temp dir if no path is specified", func() {
			dt, err := NewDiskTransport("")
			So(err, ShouldBeNil)
			So(dt.Path, ShouldNotEqual, "")
			statDirCheck(dt.Path)
		})

		Convey("It should use path if specified", func() {
			mountDir, err := ioutil.TempDir("", "mounttest")
			So(err, ShouldBeNil)

			dt, err := NewDiskTransport(mountDir)
			So(err, ShouldBeNil)
			So(dt.Path, ShouldEqual, mountDir)
		})
	})
}

func TestDTCreateDir(t *testing.T) {
	Convey("CreateDir", t, func() {
		dt := newDiskTransport()

		Convey("It should create dir with mode", func() {
			err := dt.CreateDir("1", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1"))
		})

		Convey("It should create nested dir with mode", func() {
			err := dt.CreateDir("2/a", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("2"))
			statDirCheck(dt.fullPath("2/a"))
		})

		Convey("It should create dir inside existing dir", func() {
			err := dt.CreateDir("1", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1"))

			err = dt.CreateDir("1/a", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1/a"))
		})
	})
}

func TestDTReadDir(t *testing.T) {
	Convey("DiskTransport#ReadDir", t, func() {
		dt := newDiskTransport()

		// create dir with a dir inside
		err := dt.CreateDir("1/a", 0700)
		So(err, ShouldBeNil)

		// create file inside dir
		err = dt.WriteFile("1/b", []byte{})
		So(err, ShouldBeNil)

		resp, err := dt.ReadDir("1", []string{})
		So(err, ShouldBeNil)

		entries := resp.Files

		Convey("It should create return entries of dir", func() {
			So(len(entries), ShouldEqual, 2)
		})

		Convey("It should create return dir with info", func() {
			So(entries[0].IsDir, ShouldEqual, true)
			So(entries[0].Name, ShouldEqual, "a")
		})

		Convey("It should create return file with info", func() {
			So(entries[1].IsDir, ShouldEqual, false)
			So(entries[1].Name, ShouldEqual, "b")
		})
	})
}

func TestDTRename(t *testing.T) {
	Convey("Rename", t, func() {
		dt := newDiskTransport()

		err := dt.WriteFile("file", []byte("hello world!"))
		So(err, ShouldBeNil)
		statFileCheck(dt.fullPath("file"), 0644)

		err = dt.Rename("file", "file1")
		So(err, ShouldBeNil)

		Convey("It should change name of entry from old to new", func() {
			resp, err := dt.ReadFile("file1")
			So(err, ShouldBeNil)
			So(string(resp.Content), ShouldEqual, "hello world!")
		})

		Convey("It should remove old entry", func() {
			_, err = os.Stat(dt.fullPath("file"))
			So(err.Error(), ShouldContainSubstring, "no such file or directory")
		})
	})
}

func TestDTRemove(t *testing.T) {
	Convey("Remove", t, func() {
		dt := newDiskTransport()

		err := dt.WriteFile("file", []byte("hello world!"))
		So(err, ShouldBeNil)

		err = dt.Remove("file")
		So(err, ShouldBeNil)

		Convey("It should remove old entry", func() {
			_, err = os.Stat(dt.fullPath("file"))
			So(err.Error(), ShouldContainSubstring, "no such file or directory")
		})
	})
}

func TestDTReadFile(t *testing.T) {
	Convey("DiskTransport#ReadFile", t, func() {
		dt := newDiskTransport()

		Convey("It should read contents of file", func() {
			err := dt.WriteFile("file", []byte("hello world!"))
			So(err, ShouldBeNil)

			resp, err := dt.ReadFile("file")
			So(err, ShouldBeNil)
			So(string(resp.Content), ShouldEqual, "hello world!")
		})
	})
}

func TestDTWriteFile(t *testing.T) {
	Convey("DiskTransport#WriteFile", t, func() {
		dt := newDiskTransport()

		Convey("It should write file with contents", func() {
			err := dt.WriteFile("1", []byte{1})
			So(err, ShouldBeNil)
			statFileCheck(dt.fullPath("1"), 0644)
		})
	})
}

///// Helpers

func newDiskTransport() *DiskTransport {
	mountDir, err := ioutil.TempDir("", "mounttest")
	if err != nil {
		panic(err)
	}

	//fmt.Printf("Created temp dir at %s\n", mountDir)

	return &DiskTransport{
		Path: mountDir,
	}
}

func statFileCheck(filePath string, mode os.FileMode) {
	fi, err := os.Stat(filePath)
	So(err, ShouldBeNil)

	So(fi.IsDir(), ShouldBeFalse)
	So(fi.Mode(), ShouldEqual, mode)
}

func statDirCheck(dir string) {
	fi, err := os.Stat(dir)
	So(err, ShouldBeNil)

	So(fi.IsDir(), ShouldBeTrue)
	So(fi.Mode(), ShouldEqual, 0700|os.ModeDir)
}
<commit_msg>remove newDiskTransport test helper; other test fixes<commit_after>package transport

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

	. "github.com/smartystreets/goconvey/convey"
)

func TestDiskTransport(t *testing.T) {
	var _ Transport = (*DiskTransport)(nil)
}

func TestNewDiskTransport(t *testing.T) {
	Convey("NewDiskTransport", t, func() {
		Convey("It should create temp dir if no path is specified", func() {
			dt, err := NewDiskTransport("")
			So(err, ShouldBeNil)
			So(dt.Path, ShouldNotEqual, "")
			statDirCheck(dt.Path)
		})

		Convey("It should use path if specified", func() {
			mountDir, err := ioutil.TempDir("", "mounttest")
			So(err, ShouldBeNil)

			dt, err := NewDiskTransport(mountDir)
			So(err, ShouldBeNil)
			So(dt.Path, ShouldEqual, mountDir)
		})
	})
}

func TestDTCreateDir(t *testing.T) {
	Convey("CreateDir", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		Convey("It should create dir with mode", func() {
			err := dt.CreateDir("1", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1"))
		})

		Convey("It should create nested dir with mode", func() {
			err := dt.CreateDir("2/a", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("2"))
			statDirCheck(dt.fullPath("2/a"))
		})

		Convey("It should create dir inside existing dir", func() {
			err := dt.CreateDir("1", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1"))

			err = dt.CreateDir("1/a", 0700)
			So(err, ShouldBeNil)
			statDirCheck(dt.fullPath("1/a"))
		})
	})
}

func TestDTReadDir(t *testing.T) {
	Convey("ReadDir", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		// create dir with a dir inside
		err = dt.CreateDir("1/a", 0700)
		So(err, ShouldBeNil)

		// create file inside dir
		err = dt.WriteFile("1/b", []byte{})
		So(err, ShouldBeNil)

		resp, err := dt.ReadDir("1", []string{})
		So(err, ShouldBeNil)

		entries := resp.Files

		Convey("It should create return entries of dir", func() {
			So(len(entries), ShouldEqual, 2)
		})

		Convey("It should create return dir with info", func() {
			So(entries[0].IsDir, ShouldEqual, true)
			So(entries[0].Name, ShouldEqual, "a")
		})

		Convey("It should create return file with info", func() {
			So(entries[1].IsDir, ShouldEqual, false)
			So(entries[1].Name, ShouldEqual, "b")
		})
	})
}

func TestDTRename(t *testing.T) {
	Convey("Rename", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		err = dt.WriteFile("file", []byte("hello world!"))
		So(err, ShouldBeNil)
		statFileCheck(dt.fullPath("file"), 0644)

		err = dt.Rename("file", "file1")
		So(err, ShouldBeNil)

		Convey("It should change name of entry from old to new", func() {
			resp, err := dt.ReadFile("file1")
			So(err, ShouldBeNil)
			So(string(resp.Content), ShouldEqual, "hello world!")
		})

		Convey("It should remove old entry", func() {
			_, err = os.Stat(dt.fullPath("file"))
			So(err.Error(), ShouldContainSubstring, "no such file or directory")
		})
	})
}

func TestDTRemove(t *testing.T) {
	Convey("Remove", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		err = dt.WriteFile("file", []byte("hello world!"))
		So(err, ShouldBeNil)

		err = dt.Remove("file")
		So(err, ShouldBeNil)

		Convey("It should remove old entry", func() {
			_, err = os.Stat(dt.fullPath("file"))
			So(err.Error(), ShouldContainSubstring, "no such file or directory")
		})
	})
}

func TestDTReadFile(t *testing.T) {
	Convey("ReadFile", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		Convey("It should read contents of file", func() {
			err := dt.WriteFile("file", []byte("hello world!"))
			So(err, ShouldBeNil)

			resp, err := dt.ReadFile("file")
			So(err, ShouldBeNil)
			So(string(resp.Content), ShouldEqual, "hello world!")
		})
	})
}

func TestDTWriteFile(t *testing.T) {
	Convey("WriteFile", t, func() {
		dt, err := NewDiskTransport("")
		So(err, ShouldBeNil)

		Convey("It should write file with contents", func() {
			err := dt.WriteFile("1", []byte{1})
			So(err, ShouldBeNil)
			statFileCheck(dt.fullPath("1"), 0644)
		})
	})
}

func TestDTGetInfo(t *testing.T) {
	Convey("GetInfo", t, func() {
		//dt, err := NewDiskTransport("")
		//So(err, ShouldBeNil)
	})
}

///// Helpers

func statFileCheck(filePath string, mode os.FileMode) {
	fi, err := os.Stat(filePath)
	So(err, ShouldBeNil)

	So(fi.IsDir(), ShouldBeFalse)
	So(fi.Mode(), ShouldEqual, mode)
}

func statDirCheck(dir string) {
	fi, err := os.Stat(dir)
	So(err, ShouldBeNil)

	So(fi.IsDir(), ShouldBeTrue)
	So(fi.Mode(), ShouldEqual, 0700|os.ModeDir)
}
<|endoftext|>


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

package installer

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/tsuru/tsuru/cmd"

	"gopkg.in/check.v1"
)

func (s *S) TestParseConfigDefaultConfig(c *check.C) {
	dmConfig, err := parseConfigFile("")
	c.Assert(err, check.IsNil)
	c.Assert(dmConfig, check.DeepEquals, defaultDockerMachineConfig)
}

func (s *S) TestParseConfigFileNotExists(c *check.C) {
	_, err := parseConfigFile("not-exist-conf.yml")
	c.Assert(err, check.NotNil)
}

func (s *S) TestParseConfigFile(c *check.C) {
	conf := `
name: tsuru-test
ca-path: /tmp/certs
driver:
    name: amazonec2
    options:
        opt1: option1-value
`
	err := ioutil.WriteFile("/tmp/config.yml", []byte(conf), 0644)
	if err != nil {
		c.Fatal("Failed to write config file for test")
	}
	defer os.Remove("/tmp/config.yml")
	expected := &DockerMachineConfig{
		DriverName: "amazonec2",
		DriverOpts: map[string]interface{}{
			"opt1": "option1-value",
		},
		CAPath: "/tmp/certs",
		Name:   "tsuru-test",
	}
	dmConfig, err := parseConfigFile("/tmp/config.yml")
	c.Assert(err, check.IsNil)
	c.Assert(dmConfig, check.DeepEquals, expected)
}

func (s *S) TestInstallInfo(c *check.C) {
	c.Assert((&Install{}).Info(), check.NotNil)
}

func (s *S) TestInstallCommandFlags(c *check.C) {
	command := Install{}
	flags := command.Flags()
	c.Assert(flags, check.NotNil)
	flags.Parse(true, []string{"-c", "my-conf.yml"})
	config := flags.Lookup("c")
	usage := "Configuration file"
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "c")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
	config = flags.Lookup("config")
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "config")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
}

func (s *S) TestInstallTargetAlreadyExists(c *check.C) {
	var stdout, stderr bytes.Buffer
	manager := cmd.BuildBaseManager("uninstall-client", "0.0.0", "", nil)
	client := cmd.NewClient(&http.Client{}, nil, manager)
	context := cmd.Context{
		Args:   []string{"test", fmt.Sprintf("%s:8080", "1.2.3.4")},
		Stdout: &stdout,
		Stderr: &stderr,
	}
	targetadd := manager.Commands["target-add"]
	t, ok := targetadd.(cmd.FlaggedCommand)
	c.Assert(ok, check.Equals, true)
	err := t.Flags().Parse(true, []string{"-s"})
	c.Assert(err, check.IsNil)
	err = t.Run(&context, client)
	c.Assert(err, check.IsNil)
	defer func(manager *cmd.Manager) {
		client := cmd.NewClient(&http.Client{}, nil, manager)
		context := cmd.Context{
			Args:   []string{"test"},
			Stdout: os.Stdout,
			Stderr: os.Stderr,
		}
		targetrm := manager.Commands["target-remove"]
		targetrm.Run(&context, client)
	}(manager)
	command := Install{}
	command.Flags().Parse(true, []string{"-c", "./testdata/wrong-conf.yml"})
	context = cmd.Context{
		Stdout: &stdout,
		Stderr: &stderr,
	}
	expectedErr := "tsuru target \"test\" already exists"
	err = command.Run(&context, client)
	c.Assert(err, check.NotNil)
	c.Assert(expectedErr, check.Equals, err.Error())
}

func (s *S) TestUninstallInfo(c *check.C) {
	c.Assert((&Uninstall{}).Info(), check.NotNil)
}

func (s *S) TestUninstallCommandFlags(c *check.C) {
	command := Uninstall{}
	flags := command.Flags()
	c.Assert(flags, check.NotNil)
	flags.Parse(true, []string{"-c", "my-conf.yml"})
	config := flags.Lookup("c")
	usage := "Configuration file"
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "c")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
	config = flags.Lookup("config")
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "config")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
}
<commit_msg>tsuru/installer/install_test: fix shadowing var.<commit_after>// Copyright 2016 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package installer

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/tsuru/tsuru/cmd"

	"gopkg.in/check.v1"
)

func (s *S) TestParseConfigDefaultConfig(c *check.C) {
	dmConfig, err := parseConfigFile("")
	c.Assert(err, check.IsNil)
	c.Assert(dmConfig, check.DeepEquals, defaultDockerMachineConfig)
}

func (s *S) TestParseConfigFileNotExists(c *check.C) {
	_, err := parseConfigFile("not-exist-conf.yml")
	c.Assert(err, check.NotNil)
}

func (s *S) TestParseConfigFile(c *check.C) {
	conf := `
name: tsuru-test
ca-path: /tmp/certs
driver:
    name: amazonec2
    options:
        opt1: option1-value
`
	err := ioutil.WriteFile("/tmp/config.yml", []byte(conf), 0644)
	if err != nil {
		c.Fatal("Failed to write config file for test")
	}
	defer os.Remove("/tmp/config.yml")
	expected := &DockerMachineConfig{
		DriverName: "amazonec2",
		DriverOpts: map[string]interface{}{
			"opt1": "option1-value",
		},
		CAPath: "/tmp/certs",
		Name:   "tsuru-test",
	}
	dmConfig, err := parseConfigFile("/tmp/config.yml")
	c.Assert(err, check.IsNil)
	c.Assert(dmConfig, check.DeepEquals, expected)
}

func (s *S) TestInstallInfo(c *check.C) {
	c.Assert((&Install{}).Info(), check.NotNil)
}

func (s *S) TestInstallCommandFlags(c *check.C) {
	command := Install{}
	flags := command.Flags()
	c.Assert(flags, check.NotNil)
	flags.Parse(true, []string{"-c", "my-conf.yml"})
	config := flags.Lookup("c")
	usage := "Configuration file"
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "c")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
	config = flags.Lookup("config")
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "config")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
}

func (s *S) TestInstallTargetAlreadyExists(c *check.C) {
	var stdout, stderr bytes.Buffer
	manager := cmd.BuildBaseManager("uninstall-client", "0.0.0", "", nil)
	client := cmd.NewClient(&http.Client{}, nil, manager)
	context := cmd.Context{
		Args:   []string{"test", fmt.Sprintf("%s:8080", "1.2.3.4")},
		Stdout: &stdout,
		Stderr: &stderr,
	}
	targetadd := manager.Commands["target-add"]
	t, ok := targetadd.(cmd.FlaggedCommand)
	c.Assert(ok, check.Equals, true)
	err := t.Flags().Parse(true, []string{"-s"})
	c.Assert(err, check.IsNil)
	err = t.Run(&context, client)
	c.Assert(err, check.IsNil)
	defer func(manager *cmd.Manager) {
		c := cmd.NewClient(&http.Client{}, nil, manager)
		cont := cmd.Context{
			Args:   []string{"test"},
			Stdout: os.Stdout,
			Stderr: os.Stderr,
		}
		targetrm := manager.Commands["target-remove"]
		targetrm.Run(&cont, c)
	}(manager)
	command := Install{}
	command.Flags().Parse(true, []string{"-c", "./testdata/wrong-conf.yml"})
	context = cmd.Context{
		Stdout: &stdout,
		Stderr: &stderr,
	}
	expectedErr := "tsuru target \"test\" already exists"
	err = command.Run(&context, client)
	c.Assert(err, check.NotNil)
	c.Assert(expectedErr, check.Equals, err.Error())
}

func (s *S) TestUninstallInfo(c *check.C) {
	c.Assert((&Uninstall{}).Info(), check.NotNil)
}

func (s *S) TestUninstallCommandFlags(c *check.C) {
	command := Uninstall{}
	flags := command.Flags()
	c.Assert(flags, check.NotNil)
	flags.Parse(true, []string{"-c", "my-conf.yml"})
	config := flags.Lookup("c")
	usage := "Configuration file"
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "c")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
	config = flags.Lookup("config")
	c.Check(config, check.NotNil)
	c.Check(config.Name, check.Equals, "config")
	c.Check(config.Usage, check.Equals, usage)
	c.Check(config.Value.String(), check.Equals, "my-conf.yml")
	c.Check(config.DefValue, check.Equals, "")
}
<|endoftext|>


<commit_before>package graph

import (
	"os"
	"time"
)

// A link shared on a user's wall
type Link struct {
	// The link ID. Publicly accessible.
	ID string
	// The user that created the link. Publicly accessible. Contains the id and name field.
	From Object
	// The URL that was shared. Publicly accessible. Contains a valid URL
	Link string
	// The name of the link. Publicly accessible.
	Name string
	// The caption of the link (appears beneath the link name). Publicly accessible.
	Caption string
	// A description of the link (appears beneath the link caption). Publicly accessible.
	Description string
	// A URL to the link icon that Facebook displays in the news feed. Publicly accessible. Contains a valid URL
	Icon string
	// A URL to the thumbnail image used in the link post. Publicly accessible. Contains a valid URL.
	Picture string
	// The optional message from the user about this link. Publicly accessible.
	Message string
	// The time the message was published. Publicly accessible. Contains a IETF RFC 3339 datetime.
	CreatedTime *time.Time

	// TODO: Connections
}

// Parses Link data. Returns nil for err if no error appeared.
func parseLink(value map[string]interface{}) (l Link, err os.Error) {
	for key, val := range value {
		switch key {
		case "id":
			l.ID = val.(string)
		case "from":
			l.From = parseObject(val.(map[string]interface{}))
		case "link":
			l.Link = val.(string)
		case "name":
			l.Name = val.(string)
		case "caption":
			l.Caption = val.(string)
		case "description":
			l.Description = val.(string)
		case "icon":
			l.Icon = val.(string)
		case "picture":
			l.Picture = val.(string)
		case "message":
			l.Message = val.(string)
		case "created_time":
			l.CreatedTime, err = parseTime(val.(string))
		}
	}
	return
}
<commit_msg>Add getLinks().<commit_after>package graph

import (
	"os"
	"time"
)

// A link shared on a user's wall
type Link struct {
	// The link ID. Publicly accessible.
	ID string
	// The user that created the link. Publicly accessible. Contains the id and name field.
	From Object
	// The URL that was shared. Publicly accessible. Contains a valid URL
	Link string
	// The name of the link. Publicly accessible.
	Name string
	// The caption of the link (appears beneath the link name). Publicly accessible.
	Caption string
	// A description of the link (appears beneath the link caption). Publicly accessible.
	Description string
	// A URL to the link icon that Facebook displays in the news feed. Publicly accessible. Contains a valid URL
	Icon string
	// A URL to the thumbnail image used in the link post. Publicly accessible. Contains a valid URL.
	Picture string
	// The optional message from the user about this link. Publicly accessible.
	Message string
	// The time the message was published. Publicly accessible. Contains a IETF RFC 3339 datetime.
	CreatedTime *time.Time

	// TODO: Connections
}

func getLinks(url string) (ls []Link, err os.Error) {
	data, err := getData(url)
	if err != nil {
		return
	}
	ls = make([]Link, len(data))
	for i, v := range data {
		ls[i], err = parseLink(v.(map[string]interface{}))
		if err != nil {
			return
		}
	}
	return
}

// Parses Link data. Returns nil for err if no error appeared.
func parseLink(value map[string]interface{}) (l Link, err os.Error) {
	for key, val := range value {
		switch key {
		case "id":
			l.ID = val.(string)
		case "from":
			l.From = parseObject(val.(map[string]interface{}))
		case "link":
			l.Link = val.(string)
		case "name":
			l.Name = val.(string)
		case "caption":
			l.Caption = val.(string)
		case "description":
			l.Description = val.(string)
		case "icon":
			l.Icon = val.(string)
		case "picture":
			l.Picture = val.(string)
		case "message":
			l.Message = val.(string)
		case "created_time":
			l.CreatedTime, err = parseTime(val.(string))
		}
	}
	return
}
<|endoftext|>


<commit_before>package facebook

import (
	"strconv"
)

type Page struct {
	ID              string
	Name            string
	Picture         string
	Link            string
	Category        string
	Website         string
	Username        string
	Founded         string
	CompanyOverview string
	Mission         string
	Products        string
	FanCount        float64
}

func (p *Page) String() string {
	return "ID: " + p.ID + "\tName: " + p.Name + "\tPicture: " + p.Picture +
		"\tLink: " + p.Link + "\tCategory: " + p.Category + "\tWebsite: " +
		p.Website + "\tUsername: " + p.Username + "\tFounded: " + p.Founded +
		"\tCompany overview: " + p.CompanyOverview + "\tMission: " + p.Mission +
		"\tProducts: " + p.Products + "\tFan count:" +
		strconv.Ftoa64(p.FanCount, 'e', -1) + "\n"
}
<commit_msg>Add documentation to Page.<commit_after>package facebook

import (
	"strconv"
)

// A Facebook Page.
// http://developers.facebook.com/docs/reference/api/page
type Page struct {
	// ID
	ID string
	// Name
	Name string
	// Profile picture
	Picture string
	// Category
	Category string
	// Number of fans the page has
	FanCount float64

	// Undocumented properties but streamed
	Link            string
	Website         string
	Username        string
	Founded         string
	CompanyOverview string
	Mission         string
	Products        string
}

func (p *Page) String() string {
	return "ID: " + p.ID + "\tName: " + p.Name + "\tPicture: " + p.Picture +
		"\tLink: " + p.Link + "\tCategory: " + p.Category + "\tWebsite: " +
		p.Website + "\tUsername: " + p.Username + "\tFounded: " + p.Founded +
		"\tCompany overview: " + p.CompanyOverview + "\tMission: " + p.Mission +
		"\tProducts: " + p.Products + "\tFan count:" +
		strconv.Ftoa64(p.FanCount, 'e', -1) + "\n"
}
<|endoftext|>