<commit_before>package utils

//#include <stdio.h>
//#include <stdlib.h>
//#include <unistd.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/wait.h>
//#include <sys/time.h>
//#include <sys/resource.h>
//#include <fcntl.h>
/*
int daemonize(char *cmd, char *argv[], int pipe, int fds[], int num) {
	int status = 0, fd, pid, i;
	struct sigaction sa;

	pid = fork();
	if (pid < 0) {
		return -1;
	} else if (pid > 0) {
		if (waitpid(pid, &status, 0) < 0)
			return -1;
		return WEXITSTATUS(status);
	}
	//Become a session leader to lose controlling TTY
	setsid();

	//Ensure future opens won't allocate controlling TTYs
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0) {
		_exit(-1);
	}

	pid = fork();
	if (pid < 0) {
		_exit(-1);
	} else if (pid > 0) {
		_exit(0);
	}

	if (pipe > 0) {
		char buf[4];
		int ret;

		pid = getpid();

		buf[0] = pid >> 24;
		buf[1] = pid >> 16;
		buf[2] = pid >> 8;
		buf[3] = pid;

		ret = write(pipe, buf, 4);
		if (ret != 4)
			_exit(-1);
	}

	//Clear file creation mask
	umask(0);
	//Change the current working directory to the root so we won't prevent file system from being unmounted
	if (chdir("/") < 0)
		_exit(-1);

	//Close all open file descriptors
	for (i = 0; i < num; i++) {
		if (fds[i] == 0 || fds[i] == 1 || fds[i] == 2)
			continue;

		close(fds[i]);
	}
	//Attach file descriptors 0, 1, and 2 to /dev/null
	fd = open("/dev/null", O_RDWR);
	dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);
	close(fd);

	if (execvp(cmd, argv) < 0)
		_exit(-1);
	return -1;
}
*/
import "C"

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"strconv"
	"syscall"
	"unsafe"
)

func ExecInDaemon(cmd string, argv []string) (pid uint32, err error) {
	// convert the args to the C style args
	cargs := make([]*C.char, len(argv))

	for idx, a := range argv {
		cargs[idx] = C.CString(a)
	}

	// collect all the opened fds and close them when exec the daemon
	fds := (*C.int)(nil)
	num := C.int(0)
	fdlist := listFd()
	if len(fdlist) != 0 {
		fds = (*C.int)(unsafe.Pointer(&fdlist[0]))
		num = C.int(len(fdlist))
	}

	// create pipe for geting the daemon pid
	pipe := make([]int, 2)
	err = syscall.Pipe(pipe)
	if err != nil {
		return 0, fmt.Errorf("fail to create pipe: %v", err)
	}

	// do the job!
	ret, err := C.daemonize(C.CString(cmd), (**C.char)(unsafe.Pointer(&cargs[0])), C.int(pipe[1]), fds, num)
	if err != nil || ret < 0 {
		return 0, fmt.Errorf("fail to start %s in daemon mode: %v", argv[0], err)
	}

	// get the daemon pid
	buf := make([]byte, 4)
	nr, err := syscall.Read(pipe[0], buf)
	if err != nil || nr != 4 {
		return 0, fmt.Errorf("fail to start %s in daemon mode or fail to get pid: %v", argv[0], err)
	}
	syscall.Close(pipe[1])
	syscall.Close(pipe[0])
	pid = binary.BigEndian.Uint32(buf[:nr])

	return pid, nil
}

func listFd() []int {
	files, err := ioutil.ReadDir("/proc/self/fd/")
	if err != nil {
		return []int{}
	}

	result := []int{}
	for _, file := range files {
		f, err := strconv.Atoi(file.Name())
		if err != nil {
			continue
		}

		result = append(result, f)
	}

	return result
}
<commit_msg>include <signal.h> for mac<commit_after>package utils

//#include <stdio.h>
//#include <stdlib.h>
//#include <unistd.h>
//#include <signal.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/wait.h>
//#include <sys/time.h>
//#include <sys/resource.h>
//#include <fcntl.h>
/*
int daemonize(char *cmd, char *argv[], int pipe, int fds[], int num) {
	int status = 0, fd, pid, i;
	struct sigaction sa;

	pid = fork();
	if (pid < 0) {
		return -1;
	} else if (pid > 0) {
		if (waitpid(pid, &status, 0) < 0)
			return -1;
		return WEXITSTATUS(status);
	}
	//Become a session leader to lose controlling TTY
	setsid();

	//Ensure future opens won't allocate controlling TTYs
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0) {
		_exit(-1);
	}

	pid = fork();
	if (pid < 0) {
		_exit(-1);
	} else if (pid > 0) {
		_exit(0);
	}

	if (pipe > 0) {
		char buf[4];
		int ret;

		pid = getpid();

		buf[0] = pid >> 24;
		buf[1] = pid >> 16;
		buf[2] = pid >> 8;
		buf[3] = pid;

		ret = write(pipe, buf, 4);
		if (ret != 4)
			_exit(-1);
	}

	//Clear file creation mask
	umask(0);
	//Change the current working directory to the root so we won't prevent file system from being unmounted
	if (chdir("/") < 0)
		_exit(-1);

	//Close all open file descriptors
	for (i = 0; i < num; i++) {
		if (fds[i] == 0 || fds[i] == 1 || fds[i] == 2)
			continue;

		close(fds[i]);
	}
	//Attach file descriptors 0, 1, and 2 to /dev/null
	fd = open("/dev/null", O_RDWR);
	dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);
	close(fd);

	if (execvp(cmd, argv) < 0)
		_exit(-1);
	return -1;
}
*/
import "C"

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"strconv"
	"syscall"
	"unsafe"
)

func ExecInDaemon(cmd string, argv []string) (pid uint32, err error) {
	// convert the args to the C style args
	cargs := make([]*C.char, len(argv))

	for idx, a := range argv {
		cargs[idx] = C.CString(a)
	}

	// collect all the opened fds and close them when exec the daemon
	fds := (*C.int)(nil)
	num := C.int(0)
	fdlist := listFd()
	if len(fdlist) != 0 {
		fds = (*C.int)(unsafe.Pointer(&fdlist[0]))
		num = C.int(len(fdlist))
	}

	// create pipe for geting the daemon pid
	pipe := make([]int, 2)
	err = syscall.Pipe(pipe)
	if err != nil {
		return 0, fmt.Errorf("fail to create pipe: %v", err)
	}

	// do the job!
	ret, err := C.daemonize(C.CString(cmd), (**C.char)(unsafe.Pointer(&cargs[0])), C.int(pipe[1]), fds, num)
	if err != nil || ret < 0 {
		return 0, fmt.Errorf("fail to start %s in daemon mode: %v", argv[0], err)
	}

	// get the daemon pid
	buf := make([]byte, 4)
	nr, err := syscall.Read(pipe[0], buf)
	if err != nil || nr != 4 {
		return 0, fmt.Errorf("fail to start %s in daemon mode or fail to get pid: %v", argv[0], err)
	}
	syscall.Close(pipe[1])
	syscall.Close(pipe[0])
	pid = binary.BigEndian.Uint32(buf[:nr])

	return pid, nil
}

func listFd() []int {
	files, err := ioutil.ReadDir("/proc/self/fd/")
	if err != nil {
		return []int{}
	}

	result := []int{}
	for _, file := range files {
		f, err := strconv.Atoi(file.Name())
		if err != nil {
			continue
		}

		result = append(result, f)
	}

	return result
}
<|endoftext|>


<commit_before>package message

import (
	"errors"
	"fmt"
	"io"
	"math/rand"
	"regexp"
	"sync"
	"time"

	"github.com/shazow/ssh-chat/set"
)

const messageBuffer = 5
const messageTimeout = 5 * time.Second
const reHighlight = `\b(%s)\b`
const timestampTimeout = 30 * time.Minute

var ErrUserClosed = errors.New("user closed")

// User definition, implemented set Item interface and io.Writer
type User struct {
	Identifier
	Ignored  *set.Set
	colorIdx int
	joined   time.Time
	msg      chan Message
	done     chan struct{}

	screen    io.WriteCloser
	closeOnce sync.Once

	mu      sync.Mutex
	config  UserConfig
	replyTo *User     // Set when user gets a /msg, for replying.
	lastMsg time.Time // When the last message was rendered
}

func NewUser(identity Identifier) *User {
	u := User{
		Identifier: identity,
		config:     DefaultUserConfig,
		joined:     time.Now(),
		msg:        make(chan Message, messageBuffer),
		done:       make(chan struct{}),
		Ignored:    set.New(),
	}
	u.setColorIdx(rand.Int())

	return &u
}

func NewUserScreen(identity Identifier, screen io.WriteCloser) *User {
	u := NewUser(identity)
	u.screen = screen

	return u
}

func (u *User) Joined() time.Time {
	return u.joined
}

func (u *User) Config() UserConfig {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.config
}

func (u *User) SetConfig(cfg UserConfig) {
	u.mu.Lock()
	u.config = cfg
	u.mu.Unlock()
}

// Rename the user with a new Identifier.
func (u *User) SetID(id string) {
	u.Identifier.SetID(id)
	u.setColorIdx(rand.Int())
}

// ReplyTo returns the last user that messaged this user.
func (u *User) ReplyTo() *User {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.replyTo
}

// SetReplyTo sets the last user to message this user.
func (u *User) SetReplyTo(user *User) {
	u.mu.Lock()
	defer u.mu.Unlock()
	u.replyTo = user
}

// setColorIdx will set the colorIdx to a specific value, primarily used for
// testing.
func (u *User) setColorIdx(idx int) {
	u.colorIdx = idx
}

// Disconnect user, stop accepting messages
func (u *User) Close() {
	u.closeOnce.Do(func() {
		if u.screen != nil {
			u.screen.Close()
		}
		// close(u.msg) TODO: Close?
		close(u.done)
	})
}

// Consume message buffer into the handler. Will block, should be called in a
// goroutine.
func (u *User) Consume() {
	for {
		select {
		case <-u.done:
			return
		case m, ok := <-u.msg:
			if !ok {
				return
			}
			u.HandleMsg(m)
		}
	}
}

// Consume one message and stop, mostly for testing
func (u *User) ConsumeOne() Message {
	return <-u.msg
}

// Check if there are pending messages, used for testing
func (u *User) HasMessages() bool {
	select {
	case msg := <-u.msg:
		u.msg <- msg
		return true
	default:
		return false
	}
}

// SetHighlight sets the highlighting regular expression to match string.
func (u *User) SetHighlight(s string) error {
	re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
	if err != nil {
		return err
	}
	u.mu.Lock()
	u.config.Highlight = re
	u.mu.Unlock()
	return nil
}

func (u *User) render(m Message) string {
	cfg := u.Config()
	var out string
	switch m := m.(type) {
	case PublicMsg:
		if u == m.From() {
			if !cfg.Echo {
				return ""
			}
			out += m.RenderSelf(cfg)
		} else {
			out += m.RenderFor(cfg)
		}
	case *PrivateMsg:
		out += m.Render(cfg.Theme)
		if cfg.Bell {
			out += Bel
		}
	case *CommandMsg:
		out += m.RenderSelf(cfg)
	default:
		out += m.Render(cfg.Theme)
	}
	if cfg.Timeformat != nil {
		ts := m.Timestamp()
		if cfg.Timezone != nil {
			ts = ts.In(cfg.Timezone)
		} else {
			ts = ts.UTC()
		}
		return cfg.Theme.Timestamp(ts.Format(*cfg.Timeformat)) + "  " + out + Newline
	}
	return out + Newline
}

// writeMsg renders the message and attempts to write it, will Close the user
// if it fails.
func (u *User) writeMsg(m Message) error {
	r := u.render(m)
	_, err := u.screen.Write([]byte(r))
	if err != nil {
		logger.Printf("Write failed to %s, closing: %s", u.Name(), err)
		u.Close()
	}
	return err
}

// HandleMsg will render the message to the screen, blocking.
func (u *User) HandleMsg(m Message) error {
	u.mu.Lock()
	u.lastMsg = m.Timestamp()
	u.mu.Unlock()
	return u.writeMsg(m)
}

// Add message to consume by user
func (u *User) Send(m Message) error {
	select {
	case <-u.done:
		return ErrUserClosed
	case u.msg <- m:
	case <-time.After(messageTimeout):
		logger.Printf("Message buffer full, closing: %s", u.Name())
		u.Close()
		return ErrUserClosed
	}
	return nil
}

// Container for per-user configurations.
type UserConfig struct {
	Highlight  *regexp.Regexp
	Bell       bool
	Quiet      bool
	Echo       bool // Echo shows your own messages after sending, disabled for bots
	Timeformat *string
	Timezone   *time.Location
	Theme      *Theme
}

// Default user configuration to use
var DefaultUserConfig UserConfig

func init() {
	DefaultUserConfig = UserConfig{
		Bell:  true,
		Echo:  true,
		Quiet: false,
	}

	// TODO: Seed random?
}

// RecentActiveUsers is a slice of *Users that knows how to be sorted by the time of the last message.
type RecentActiveUsers []*User

func (a RecentActiveUsers) Len() int      { return len(a) }
func (a RecentActiveUsers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a RecentActiveUsers) Less(i, j int) bool {
	a[i].mu.Lock()
	defer a[i].mu.Unlock()
	a[j].mu.Lock()
	defer a[j].mu.Unlock()

	if a[i].lastMsg.IsZero() {
		return a[i].joined.Before(a[j].joined)
	} else {
		return a[i].lastMsg.After(a[j].lastMsg)
	}

}
<commit_msg>chat/message: Fix RecentActiveUsers sort order<commit_after>package message

import (
	"errors"
	"fmt"
	"io"
	"math/rand"
	"regexp"
	"sync"
	"time"

	"github.com/shazow/ssh-chat/set"
)

const messageBuffer = 5
const messageTimeout = 5 * time.Second
const reHighlight = `\b(%s)\b`
const timestampTimeout = 30 * time.Minute

var ErrUserClosed = errors.New("user closed")

// User definition, implemented set Item interface and io.Writer
type User struct {
	Identifier
	Ignored  *set.Set
	colorIdx int
	joined   time.Time
	msg      chan Message
	done     chan struct{}

	screen    io.WriteCloser
	closeOnce sync.Once

	mu      sync.Mutex
	config  UserConfig
	replyTo *User     // Set when user gets a /msg, for replying.
	lastMsg time.Time // When the last message was rendered
}

func NewUser(identity Identifier) *User {
	u := User{
		Identifier: identity,
		config:     DefaultUserConfig,
		joined:     time.Now(),
		msg:        make(chan Message, messageBuffer),
		done:       make(chan struct{}),
		Ignored:    set.New(),
	}
	u.setColorIdx(rand.Int())

	return &u
}

func NewUserScreen(identity Identifier, screen io.WriteCloser) *User {
	u := NewUser(identity)
	u.screen = screen

	return u
}

func (u *User) Joined() time.Time {
	return u.joined
}

func (u *User) Config() UserConfig {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.config
}

func (u *User) SetConfig(cfg UserConfig) {
	u.mu.Lock()
	u.config = cfg
	u.mu.Unlock()
}

// Rename the user with a new Identifier.
func (u *User) SetID(id string) {
	u.Identifier.SetID(id)
	u.setColorIdx(rand.Int())
}

// ReplyTo returns the last user that messaged this user.
func (u *User) ReplyTo() *User {
	u.mu.Lock()
	defer u.mu.Unlock()
	return u.replyTo
}

// SetReplyTo sets the last user to message this user.
func (u *User) SetReplyTo(user *User) {
	u.mu.Lock()
	defer u.mu.Unlock()
	u.replyTo = user
}

// setColorIdx will set the colorIdx to a specific value, primarily used for
// testing.
func (u *User) setColorIdx(idx int) {
	u.colorIdx = idx
}

// Disconnect user, stop accepting messages
func (u *User) Close() {
	u.closeOnce.Do(func() {
		if u.screen != nil {
			u.screen.Close()
		}
		// close(u.msg) TODO: Close?
		close(u.done)
	})
}

// Consume message buffer into the handler. Will block, should be called in a
// goroutine.
func (u *User) Consume() {
	for {
		select {
		case <-u.done:
			return
		case m, ok := <-u.msg:
			if !ok {
				return
			}
			u.HandleMsg(m)
		}
	}
}

// Consume one message and stop, mostly for testing
func (u *User) ConsumeOne() Message {
	return <-u.msg
}

// Check if there are pending messages, used for testing
func (u *User) HasMessages() bool {
	select {
	case msg := <-u.msg:
		u.msg <- msg
		return true
	default:
		return false
	}
}

// SetHighlight sets the highlighting regular expression to match string.
func (u *User) SetHighlight(s string) error {
	re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
	if err != nil {
		return err
	}
	u.mu.Lock()
	u.config.Highlight = re
	u.mu.Unlock()
	return nil
}

func (u *User) render(m Message) string {
	cfg := u.Config()
	var out string
	switch m := m.(type) {
	case PublicMsg:
		if u == m.From() {
			if !cfg.Echo {
				return ""
			}
			out += m.RenderSelf(cfg)
		} else {
			out += m.RenderFor(cfg)
		}
	case *PrivateMsg:
		out += m.Render(cfg.Theme)
		if cfg.Bell {
			out += Bel
		}
	case *CommandMsg:
		out += m.RenderSelf(cfg)
	default:
		out += m.Render(cfg.Theme)
	}
	if cfg.Timeformat != nil {
		ts := m.Timestamp()
		if cfg.Timezone != nil {
			ts = ts.In(cfg.Timezone)
		} else {
			ts = ts.UTC()
		}
		return cfg.Theme.Timestamp(ts.Format(*cfg.Timeformat)) + "  " + out + Newline
	}
	return out + Newline
}

// writeMsg renders the message and attempts to write it, will Close the user
// if it fails.
func (u *User) writeMsg(m Message) error {
	r := u.render(m)
	_, err := u.screen.Write([]byte(r))
	if err != nil {
		logger.Printf("Write failed to %s, closing: %s", u.Name(), err)
		u.Close()
	}
	return err
}

// HandleMsg will render the message to the screen, blocking.
func (u *User) HandleMsg(m Message) error {
	u.mu.Lock()
	u.lastMsg = m.Timestamp()
	u.mu.Unlock()
	return u.writeMsg(m)
}

// Add message to consume by user
func (u *User) Send(m Message) error {
	select {
	case <-u.done:
		return ErrUserClosed
	case u.msg <- m:
	case <-time.After(messageTimeout):
		logger.Printf("Message buffer full, closing: %s", u.Name())
		u.Close()
		return ErrUserClosed
	}
	return nil
}

// Container for per-user configurations.
type UserConfig struct {
	Highlight  *regexp.Regexp
	Bell       bool
	Quiet      bool
	Echo       bool // Echo shows your own messages after sending, disabled for bots
	Timeformat *string
	Timezone   *time.Location
	Theme      *Theme
}

// Default user configuration to use
var DefaultUserConfig UserConfig

func init() {
	DefaultUserConfig = UserConfig{
		Bell:  true,
		Echo:  true,
		Quiet: false,
	}

	// TODO: Seed random?
}

// RecentActiveUsers is a slice of *Users that knows how to be sorted by the time of the last message.
type RecentActiveUsers []*User

func (a RecentActiveUsers) Len() int      { return len(a) }
func (a RecentActiveUsers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a RecentActiveUsers) Less(i, j int) bool {
	a[i].mu.Lock()
	defer a[i].mu.Unlock()
	a[j].mu.Lock()
	defer a[j].mu.Unlock()

	if a[i].lastMsg.IsZero() {
		return a[i].joined.Before(a[j].joined)
	} else {
		return a[i].lastMsg.Before(a[j].lastMsg)
	}

}
<|endoftext|>


<commit_before>// Package chlog provides clog-based logging for testing
package chlog

import (
	"testing"

	"github.com/thatguystone/cog/check"
	"github.com/thatguystone/cog/clog"
)

// New creates a new TestLog that outputs all log messages to the given TB. This
// logs at level Debug by default.
func New(tb testing.TB) (*check.C, *clog.Log) {
	c := check.New(tb)

	lcfg := clog.Config{
		Outputs: map[string]*clog.ConfigOutput{
			"testlog": {
				Which: "testlog",
				Level: clog.Debug,
				Args: clog.ConfigOutputArgs{
					"log": c,
				},
			},
		},
		Modules: map[string]*clog.ConfigModule{
			"": {
				Outputs: []string{"testlog"},
				Level:   clog.Debug,
			},
		},
	}

	log, err := clog.New(lcfg)
	c.MustNotError(err)

	return c, log
}
<commit_msg>check: Update chlog with new clog stuff<commit_after>// Package chlog provides clog-based logging for testing
package chlog

import (
	"testing"

	"github.com/thatguystone/cog/check"
	"github.com/thatguystone/cog/clog"
)

// New creates a new TestLog that outputs all log messages to the given TB. This
// logs at level Debug by default.
func New(tb testing.TB) (*check.C, *clog.Log) {
	c := check.New(tb)

	lcfg := clog.Config{
		Outputs: map[string]*clog.ConfigOutput{
			"testlog": {
				Which: "testlog",
				Level: clog.Debug,
				Args: clog.ConfigArgs{
					"log": c,
				},
			},
		},
		Modules: map[string]*clog.ConfigModule{
			"": {
				Outputs: []string{"testlog"},
				Level:   clog.Debug,
			},
		},
	}

	log, err := clog.New(lcfg)
	c.MustNotError(err)

	return c, log
}
<|endoftext|>


<commit_before>package microsoft

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestLanguageCodes(t *testing.T) {
	expectedCodes := []string{"ab", "cd", "ef", "gh", "ij"}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/xml")

		response, err := xml.Marshal(newArrayOfStrings(expectedCodes))
		if err != nil {
			t.Fatalf("Unexpected error marshalling xml repsonse: %s", err)
		}

		fmt.Fprint(w, string(response))
		return
	}))
	defer server.Close()

	authenticator := NewMockAuthenticator()
	authenticator.accessToken = NewMockAccessToken(100)

	router := NewMockRouter()
	router.languageCodesUrl = server.URL

	api := NewMockApi()
	api.router = router
	api.authenticator = authenticator

	actualCodes, err := api.languageCodes()
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	if len(actualCodes) != len(expectedCodes) {
		t.Fatalf("Unexpected number of languages codes: %q", actualCodes)
	}

	for i := range expectedCodes {
		if actualCodes[i] != expectedCodes[i] {
			t.Fatalf("Unexpected language code '%s'. Expected '%s'", actualCodes[i], expectedCodes[i])
		}
	}
}
<commit_msg>Verify headers for languageCodes request<commit_after>package microsoft

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestLanguageCodes(t *testing.T) {
	expectedCodes := []string{"ab", "cd", "ef", "gh", "ij"}

	authenticator := NewMockAuthenticator()
	authenticator.accessToken = NewMockAccessToken(100)

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/xml")

		if r.Header.Get("Content-Type") != "text/plain" {
			t.Fatalf("Unexpected content type in request header: %s", r.Header.Get("Content-Type"))
		}

		expectedAuthToken, err := authenticator.authToken()
		if err != nil {
			t.Fatalf("Unexpected error getting expected authToken: %s", err)
		}

		if r.Header.Get("Authorization") != expectedAuthToken {
			t.Fatalf("Unexpected authorization header for request: %s", r.Header.Get("Authorization"))
		}

		response, err := xml.Marshal(newArrayOfStrings(expectedCodes))
		if err != nil {
			t.Fatalf("Unexpected error marshalling xml repsonse: %s", err)
		}

		fmt.Fprint(w, string(response))
		return
	}))
	defer server.Close()

	router := NewMockRouter()
	router.languageCodesUrl = server.URL

	api := NewMockApi()
	api.router = router
	api.authenticator = authenticator

	actualCodes, err := api.languageCodes()
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	if len(actualCodes) != len(expectedCodes) {
		t.Fatalf("Unexpected number of languages codes: %q", actualCodes)
	}

	for i := range expectedCodes {
		if actualCodes[i] != expectedCodes[i] {
			t.Fatalf("Unexpected language code '%s'. Expected '%s'", actualCodes[i], expectedCodes[i])
		}
	}
}
<|endoftext|>


<commit_before>package yo

import (
	"net/http"
	"net/url"
)

// YoAll sends a Yo to all of your subscribers. The API token is issued by Yo
// for a specific account and is required.
func (c *Client) YoAll(apiToken string) (*http.Response, error) {
	u := "yoall"
	body := url.Values{"api_token": {apiToken}}
	req, err := c.NewRequestForm(u, body)
	if err != nil {
		return nil, err
	}

	resp, err := c.Do(req, nil)
	if err != nil {
		return nil, err
	}

	return resp, nil
}
<commit_msg>Trailing slash in yoall call.<commit_after>package yo

import (
	"net/http"
	"net/url"
)

// YoAll sends a Yo to all of your subscribers. The API token is issued by Yo
// for a specific account and is required.
func (c *Client) YoAll(apiToken string) (*http.Response, error) {
	u := "yoall/"
	body := url.Values{"api_token": {apiToken}}
	req, err := c.NewRequestForm(u, body)
	if err != nil {
		return nil, err
	}

	resp, err := c.Do(req, nil)
	if err != nil {
		return nil, err
	}

	return resp, nil
}
<|endoftext|>


<commit_before>package logger

import (
	"fmt"
	stdlog "log"
	"log/syslog"
	"os"
	"runtime"

	"github.com/sent-hil/go-logging"
)

var modules []string

func init() {
	modules = []string{}
}

// Default Log implementation.
type GoLogger struct {
	log *logging.Logger
}

func NewGoLog(name string) *GoLogger {
	logging.SetFormatter(logging.MustStringFormatter("%{module} [%{level:.8s}] - %{message}"))

	// Send log to stdout
	var logBackend = logging.NewLogBackend(os.Stderr, "", stdlog.LstdFlags|stdlog.Lshortfile)
	logBackend.Color = true

	// Send log to syslog
	var syslogBackend, err = logging.NewSyslogBackend("", syslog.LOG_DEBUG|syslog.LOG_LOCAL0)
	if err != nil {
		panic(err)
	}

	logging.SetBackend(logBackend, syslogBackend)

	loggingLevel = getLoggingLevelFromConfig(name)

	// go-logging calls Reset() each time it is imported. So if this
	// pkg is imported in a library and then in a worker, the library
	// defaults back to DEBUG logging level. This fixes that by
	// re-setting the log level for already set modules.
	modules = append(modules, name)
	for _, mod := range modules {
		logging.SetLevel(loggingLevel, mod)
	}

	var goLog = &GoLogger{logging.MustGetLogger(name)}

	return goLog
}

func (g *GoLogger) Fatal(args ...interface{}) {
	g.log.Fatal(args...)
}

func (g *GoLogger) Panic(format string, args ...interface{}) {
	g.log.Panicf(format, args...)
}

func (g *GoLogger) Critical(format string, args ...interface{}) {
	g.log.Critical(format, args...)
}

func (g *GoLogger) Error(format string, args ...interface{}) {
	g.log.Error(format, args...)
}

func (g *GoLogger) Warning(format string, args ...interface{}) {
	g.log.Warning(format, args...)
}

func (g *GoLogger) Notice(format string, args ...interface{}) {
	g.log.Notice(format, args...)
}

func (g *GoLogger) Info(format string, args ...interface{}) {
	g.log.Info(format, args...)
}

func (g *GoLogger) Debug(format string, args ...interface{}) {
	g.log.Debug(format, args...)
}

func (g *GoLogger) Name() string {
	return g.log.Module
}

//----------------------------------------------------------
// Originally from koding/tools/log
//----------------------------------------------------------

func (g *GoLogger) RecoverAndLog() {
	if err := recover(); err != nil {
		g.Critical("Panicked %v", err)
	}
}

func (g *GoLogger) LogError(err interface{}, stackOffset int, additionalData ...interface{}) {
	data := make([]interface{}, 0)
	data = append(data, fmt.Sprintln(err))
	for i := 1 + stackOffset; ; i++ {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		name := "<unknown>"
		if fn := runtime.FuncForPC(pc); fn != nil {
			name = fn.Name()
		}
		data = append(data, fmt.Sprintf("at %s (%s:%d)\n", name, file, line))
	}
	data = append(data, additionalData...)
	g.Error("LogError %v", data)
}
<commit_msg>logger: remove 'LogError' prefix<commit_after>package logger

import (
	"fmt"
	stdlog "log"
	"log/syslog"
	"os"
	"runtime"

	"github.com/sent-hil/go-logging"
)

var modules []string

func init() {
	modules = []string{}
}

// Default Log implementation.
type GoLogger struct {
	log *logging.Logger
}

func NewGoLog(name string) *GoLogger {
	logging.SetFormatter(logging.MustStringFormatter("%{module} [%{level:.8s}] - %{message}"))

	// Send log to stdout
	var logBackend = logging.NewLogBackend(os.Stderr, "", stdlog.LstdFlags|stdlog.Lshortfile)
	logBackend.Color = true

	// Send log to syslog
	var syslogBackend, err = logging.NewSyslogBackend("", syslog.LOG_DEBUG|syslog.LOG_LOCAL0)
	if err != nil {
		panic(err)
	}

	logging.SetBackend(logBackend, syslogBackend)

	loggingLevel = getLoggingLevelFromConfig(name)

	// go-logging calls Reset() each time it is imported. So if this
	// pkg is imported in a library and then in a worker, the library
	// defaults back to DEBUG logging level. This fixes that by
	// re-setting the log level for already set modules.
	modules = append(modules, name)
	for _, mod := range modules {
		logging.SetLevel(loggingLevel, mod)
	}

	var goLog = &GoLogger{logging.MustGetLogger(name)}

	return goLog
}

func (g *GoLogger) Fatal(args ...interface{}) {
	g.log.Fatal(args...)
}

func (g *GoLogger) Panic(format string, args ...interface{}) {
	g.log.Panicf(format, args...)
}

func (g *GoLogger) Critical(format string, args ...interface{}) {
	g.log.Critical(format, args...)
}

func (g *GoLogger) Error(format string, args ...interface{}) {
	g.log.Error(format, args...)
}

func (g *GoLogger) Warning(format string, args ...interface{}) {
	g.log.Warning(format, args...)
}

func (g *GoLogger) Notice(format string, args ...interface{}) {
	g.log.Notice(format, args...)
}

func (g *GoLogger) Info(format string, args ...interface{}) {
	g.log.Info(format, args...)
}

func (g *GoLogger) Debug(format string, args ...interface{}) {
	g.log.Debug(format, args...)
}

func (g *GoLogger) Name() string {
	return g.log.Module
}

//----------------------------------------------------------
// Originally from koding/tools/log
//----------------------------------------------------------

func (g *GoLogger) RecoverAndLog() {
	if err := recover(); err != nil {
		g.Critical("Panicked %v", err)
	}
}

func (g *GoLogger) LogError(err interface{}, stackOffset int, additionalData ...interface{}) {
	data := make([]interface{}, 0)
	data = append(data, fmt.Sprintln(err))
	for i := 1 + stackOffset; ; i++ {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		name := "<unknown>"
		if fn := runtime.FuncForPC(pc); fn != nil {
			name = fn.Name()
		}
		data = append(data, fmt.Sprintf("at %s (%s:%d)\n", name, file, line))
	}
	data = append(data, additionalData...)
	g.Error("%v", data)
}
<|endoftext|>


<commit_before>package mock

import (
	"fmt"
	"os"

	"github.com/bunsenapp/migrator"
)

// ValidConfiguration yields a configuration object that will pass validation.
func ValidConfiguration() migrator.Configuration {
	return migrator.Configuration{
		DatabaseConnectionString: "my-database-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}
}

// ValidConfigurationAndDirectories yields a configuration object and a clean
// up function to ensure no directories are left over.
func ValidConfigurationAndDirectories() (migrator.Configuration, func()) {
	config := migrator.Configuration{
		DatabaseConnectionString: "my-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}

	os.Mkdir(config.MigrationsDir, 0700)
	os.Mkdir(config.RollbacksDir, 0700)

	cleanup := func() {
		os.RemoveAll(config.MigrationsDir)
		os.RemoveAll(config.RollbacksDir)
	}

	return config, cleanup
}

// ValidConfigurationAndDirectoriesAndFiles yields a configuration object, a cleanup
// function, creates the required directories and also creates an up/down file
// for a fake SQL migration.
func ValidConfigurationDirectoriesAndFiles() (migrator.Configuration, func()) {
	config := migrator.Configuration{
		DatabaseConnectionString: "my-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}

	os.Mkdir(config.MigrationsDir, 0700)
	os.Mkdir(config.RollbacksDir, 0700)

	cleanup := func() {
		os.RemoveAll(config.MigrationsDir)
		os.RemoveAll(config.RollbacksDir)
	}

	os.Create(fmt.Sprintf("%s/1_first-migration_up.sql", config.MigrationsDir))
	os.Create(fmt.Sprintf("%s/1_first-migration_down.sql", config.RollbacksDir))

	return config, cleanup
}
<commit_msg>Report card fix - last one<commit_after>package mock

import (
	"fmt"
	"os"

	"github.com/bunsenapp/migrator"
)

// ValidConfiguration yields a configuration object that will pass validation.
func ValidConfiguration() migrator.Configuration {
	return migrator.Configuration{
		DatabaseConnectionString: "my-database-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}
}

// ValidConfigurationAndDirectories yields a configuration object and a clean
// up function to ensure no directories are left over.
func ValidConfigurationAndDirectories() (migrator.Configuration, func()) {
	config := migrator.Configuration{
		DatabaseConnectionString: "my-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}

	os.Mkdir(config.MigrationsDir, 0700)
	os.Mkdir(config.RollbacksDir, 0700)

	cleanup := func() {
		os.RemoveAll(config.MigrationsDir)
		os.RemoveAll(config.RollbacksDir)
	}

	return config, cleanup
}

// ValidConfigurationDirectoriesAndFiles yields a configuration object, a cleanup
// function, creates the required directories and also creates an up/down file
// for a fake SQL migration.
func ValidConfigurationDirectoriesAndFiles() (migrator.Configuration, func()) {
	config := migrator.Configuration{
		DatabaseConnectionString: "my-connection-string",
		MigrationsDir:            "my-migrations-directory",
		RollbacksDir:             "my-rollbacks-directory",
	}

	os.Mkdir(config.MigrationsDir, 0700)
	os.Mkdir(config.RollbacksDir, 0700)

	cleanup := func() {
		os.RemoveAll(config.MigrationsDir)
		os.RemoveAll(config.RollbacksDir)
	}

	os.Create(fmt.Sprintf("%s/1_first-migration_up.sql", config.MigrationsDir))
	os.Create(fmt.Sprintf("%s/1_first-migration_down.sql", config.RollbacksDir))

	return config, cleanup
}
<|endoftext|>


<commit_before>// +build linux

/*
Copyright 2014 The Kubernetes 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 mount

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/golang/glog"
	utilio "k8s.io/kubernetes/pkg/util/io"
	"k8s.io/kubernetes/pkg/util/nsenter"
)

const (
	// hostProcMountsPath is the default mount path for rootfs
	hostProcMountsPath = "/rootfs/proc/1/mounts"
	// hostProcMountinfoPath is the default mount info path for rootfs
	hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
	// hostProcSelfStatusPath is the default path to /proc/self/status on the host
	hostProcSelfStatusPath = "/rootfs/proc/self/status"
)

var (
	// pidRegExp matches "Pid:	<pid>" in /proc/self/status
	pidRegExp = regexp.MustCompile(`\nPid:\t([0-9]*)\n`)
)

// Currently, all docker containers receive their own mount namespaces.
// NsenterMounter works by executing nsenter to run commands in
// the host's mount namespace.
type NsenterMounter struct {
	ne *nsenter.Nsenter
}

func NewNsenterMounter() (*NsenterMounter, error) {
	ne, err := nsenter.NewNsenter()
	if err != nil {
		return nil, err
	}
	return &NsenterMounter{ne: ne}, nil
}

// NsenterMounter implements mount.Interface
var _ = Interface(&NsenterMounter{})

// Mount runs mount(8) in the host's root mount namespace.  Aside from this
// aspect, Mount has the same semantics as the mounter returned by mount.New()
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
	bind, bindRemountOpts := isBind(options)

	if bind {
		err := n.doNsenterMount(source, target, fstype, []string{"bind"})
		if err != nil {
			return err
		}
		return n.doNsenterMount(source, target, fstype, bindRemountOpts)
	}

	return n.doNsenterMount(source, target, fstype, options)
}

// doNsenterMount nsenters the host's mount namespace and performs the
// requested mount.
func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error {
	glog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
	cmd, args := n.makeNsenterArgs(source, target, fstype, options)
	outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput()
	if len(outputBytes) != 0 {
		glog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
	}
	return err
}

// makeNsenterArgs makes a list of argument to nsenter in order to do the
// requested mount.
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) {
	mountCmd := n.ne.AbsHostPath("mount")
	mountArgs := makeMountArgs(source, target, fstype, options)

	if systemdRunPath, hasSystemd := n.ne.SupportsSystemd(); hasSystemd {
		// Complete command line:
		// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/systemd-run --description=... --scope -- /bin/mount -t <type> <what> <where>
		// Expected flow is:
		// * nsenter breaks out of container's mount namespace and executes
		//   host's systemd-run.
		// * systemd-run creates a transient scope (=~ cgroup) and executes its
		//   argument (/bin/mount) there.
		// * mount does its job, forks a fuse daemon if necessary and finishes.
		//   (systemd-run --scope finishes at this point, returning mount's exit
		//   code and stdout/stderr - thats one of --scope benefits).
		// * systemd keeps the fuse daemon running in the scope (i.e. in its own
		//   cgroup) until the fuse daemon dies (another --scope benefit).
		//   Kubelet container can be restarted and the fuse daemon survives.
		// * When the daemon dies (e.g. during unmount) systemd removes the
		//   scope automatically.
		mountCmd, mountArgs = addSystemdScope(systemdRunPath, target, mountCmd, mountArgs)
	} else {
		// Fall back to simple mount when the host has no systemd.
		// Complete command line:
		// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/mount -t <type> <what> <where>
		// Expected flow is:
		// * nsenter breaks out of container's mount namespace and executes host's /bin/mount.
		// * mount does its job, forks a fuse daemon if necessary and finishes.
		// * Any fuse daemon runs in cgroup of kubelet docker container,
		//   restart of kubelet container will kill it!

		// No code here, mountCmd and mountArgs use /bin/mount
	}

	return mountCmd, mountArgs
}

// Unmount runs umount(8) in the host's mount namespace.
func (n *NsenterMounter) Unmount(target string) error {
	args := []string{target}
	// No need to execute systemd-run here, it's enough that unmount is executed
	// in the host's mount namespace. It will finish appropriate fuse daemon(s)
	// running in any scope.
	glog.V(5).Infof("nsenter unmount args: %v", args)
	outputBytes, err := n.ne.Exec("umount", args).CombinedOutput()
	if len(outputBytes) != 0 {
		glog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
	}
	return err
}

// List returns a list of all mounted filesystems in the host's mount namespace.
func (*NsenterMounter) List() ([]MountPoint, error) {
	return listProcMounts(hostProcMountsPath)
}

func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) {
	return IsNotMountPoint(m, dir)
}

func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
	deletedDir := fmt.Sprintf("%s\\040(deleted)", dir)
	return (mp.Path == dir) || (mp.Path == deletedDir)
}

// IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt
// in the host's root mount namespace.
func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
	file, err := filepath.Abs(file)
	if err != nil {
		return true, err
	}

	// Check the directory exists
	if _, err = os.Stat(file); os.IsNotExist(err) {
		glog.V(5).Infof("findmnt: directory %s does not exist", file)
		return true, err
	}
	// Add --first-only option: since we are testing for the absence of a mountpoint, it is sufficient to get only
	// the first of multiple possible mountpoints using --first-only.
	// Also add fstype output to make sure that the output of target file will give the full path
	// TODO: Need more refactoring for this function. Track the solution with issue #26996
	args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
	glog.V(5).Infof("nsenter findmnt args: %v", args)
	out, err := n.ne.Exec("findmnt", args).CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Failed findmnt command for path %s: %s %v", file, out, err)
		// Different operating systems behave differently for paths which are not mount points.
		// On older versions (e.g. 2.20.1) we'd get error, on newer ones (e.g. 2.26.2) we'd get "/".
		// It's safer to assume that it's not a mount point.
		return true, nil
	}
	mountTarget, err := parseFindMnt(string(out))
	if err != nil {
		return false, err
	}

	glog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", file, mountTarget)

	if mountTarget == file {
		glog.V(5).Infof("IsLikelyNotMountPoint: %s is a mount point", file)
		return false, nil
	}
	glog.V(5).Infof("IsLikelyNotMountPoint: %s is not a mount point", file)
	return true, nil
}

// parse output of "findmnt -o target,fstype" and return just the target
func parseFindMnt(out string) (string, error) {
	// cut trailing newline
	out = strings.TrimSuffix(out, "\n")
	// cut everything after the last space - it's the filesystem type
	i := strings.LastIndex(out, " ")
	if i == -1 {
		return "", fmt.Errorf("error parsing findmnt output, expected at least one space: %q", out)
	}
	return out[:i], nil
}

// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
// Returns true if open returns errno EBUSY, and false if errno is nil.
// Returns an error if errno is any error other than EBUSY.
// Returns with error if pathname is not a device.
func (n *NsenterMounter) DeviceOpened(pathname string) (bool, error) {
	return exclusiveOpenFailsOnDevice(pathname)
}

// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
// to a device.
func (n *NsenterMounter) PathIsDevice(pathname string) (bool, error) {
	pathType, err := n.GetFileType(pathname)
	isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
	return isDevice, err
}

//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
	return getDeviceNameFromMount(n, mountPath, pluginDir)
}

func (n *NsenterMounter) MakeRShared(path string) error {
	return doMakeRShared(path, hostProcMountinfoPath)
}

func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) {
	var pathType FileType
	outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput()
	if err != nil {
		if strings.Contains(string(outputBytes), "No such file") {
			err = fmt.Errorf("%s does not exist", pathname)
		} else {
			err = fmt.Errorf("stat %s error: %v", pathname, string(outputBytes))
		}
		return pathType, err
	}

	switch string(outputBytes) {
	case "socket":
		return FileTypeSocket, nil
	case "character special file":
		return FileTypeCharDev, nil
	case "block special file":
		return FileTypeBlockDev, nil
	case "directory":
		return FileTypeDirectory, nil
	case "regular file":
		return FileTypeFile, nil
	}

	return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
}

func (mounter *NsenterMounter) MakeDir(pathname string) error {
	args := []string{"-p", pathname}
	if _, err := mounter.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
		return err
	}
	return nil
}

func (mounter *NsenterMounter) MakeFile(pathname string) error {
	args := []string{pathname}
	if _, err := mounter.ne.Exec("touch", args).CombinedOutput(); err != nil {
		return err
	}
	return nil
}

func (mounter *NsenterMounter) ExistsPath(pathname string) bool {
	args := []string{pathname}
	_, err := mounter.ne.Exec("ls", args).CombinedOutput()
	if err == nil {
		return true
	}
	return false
}

func (mounter *NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
	return doCleanSubPaths(mounter, podDir, volumeName)
}

// getPidOnHost returns kubelet's pid in the host pid namespace
func (mounter *NsenterMounter) getPidOnHost(procStatusPath string) (int, error) {
	// Get the PID from /rootfs/proc/self/status
	statusBytes, err := utilio.ConsistentRead(procStatusPath, maxListTries)
	if err != nil {
		return 0, fmt.Errorf("error reading %s: %s", procStatusPath, err)
	}
	matches := pidRegExp.FindSubmatch(statusBytes)
	if len(matches) < 2 {
		return 0, fmt.Errorf("cannot parse %s: no Pid:", procStatusPath)
	}
	return strconv.Atoi(string(matches[1]))
}

func (mounter *NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
	hostPid, err := mounter.getPidOnHost(hostProcSelfStatusPath)
	if err != nil {
		return "", nil, err
	}
	glog.V(4).Infof("Kubelet's PID on the host is %d", hostPid)

	// Bind-mount the subpath to avoid using symlinks in subpaths.
	newHostPath, err = doBindSubPath(mounter, subPath, hostPid)

	// There is no action when the container starts. Bind-mount will be cleaned
	// when container stops by CleanSubPaths.
	cleanupAction = nil
	return newHostPath, cleanupAction, err
}

func (mounter *NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
	return doSafeMakeDir(pathname, base, perm)
}

func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
	hostpath, err := mounter.ne.EvalSymlinks(pathname)
	if err != nil {
		return nil, err
	}
	return searchMountPoints(hostpath, procMountInfoPath)
}

func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) {
	kubeletpath, err := mounter.ne.KubeletPath(pathname)
	if err != nil {
		return 0, err
	}
	return getFSGroup(kubeletpath)
}

func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
	return getSELinuxSupport(pathname, procMountInfoPath)
}
<commit_msg>Should use `hostProcMountinfoPath` constant in nsenter_mount.go.<commit_after>// +build linux

/*
Copyright 2014 The Kubernetes 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 mount

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/golang/glog"
	utilio "k8s.io/kubernetes/pkg/util/io"
	"k8s.io/kubernetes/pkg/util/nsenter"
)

const (
	// hostProcMountsPath is the default mount path for rootfs
	hostProcMountsPath = "/rootfs/proc/1/mounts"
	// hostProcMountinfoPath is the default mount info path for rootfs
	hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
	// hostProcSelfStatusPath is the default path to /proc/self/status on the host
	hostProcSelfStatusPath = "/rootfs/proc/self/status"
)

var (
	// pidRegExp matches "Pid:	<pid>" in /proc/self/status
	pidRegExp = regexp.MustCompile(`\nPid:\t([0-9]*)\n`)
)

// Currently, all docker containers receive their own mount namespaces.
// NsenterMounter works by executing nsenter to run commands in
// the host's mount namespace.
type NsenterMounter struct {
	ne *nsenter.Nsenter
}

func NewNsenterMounter() (*NsenterMounter, error) {
	ne, err := nsenter.NewNsenter()
	if err != nil {
		return nil, err
	}
	return &NsenterMounter{ne: ne}, nil
}

// NsenterMounter implements mount.Interface
var _ = Interface(&NsenterMounter{})

// Mount runs mount(8) in the host's root mount namespace.  Aside from this
// aspect, Mount has the same semantics as the mounter returned by mount.New()
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
	bind, bindRemountOpts := isBind(options)

	if bind {
		err := n.doNsenterMount(source, target, fstype, []string{"bind"})
		if err != nil {
			return err
		}
		return n.doNsenterMount(source, target, fstype, bindRemountOpts)
	}

	return n.doNsenterMount(source, target, fstype, options)
}

// doNsenterMount nsenters the host's mount namespace and performs the
// requested mount.
func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error {
	glog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
	cmd, args := n.makeNsenterArgs(source, target, fstype, options)
	outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput()
	if len(outputBytes) != 0 {
		glog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
	}
	return err
}

// makeNsenterArgs makes a list of argument to nsenter in order to do the
// requested mount.
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) {
	mountCmd := n.ne.AbsHostPath("mount")
	mountArgs := makeMountArgs(source, target, fstype, options)

	if systemdRunPath, hasSystemd := n.ne.SupportsSystemd(); hasSystemd {
		// Complete command line:
		// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/systemd-run --description=... --scope -- /bin/mount -t <type> <what> <where>
		// Expected flow is:
		// * nsenter breaks out of container's mount namespace and executes
		//   host's systemd-run.
		// * systemd-run creates a transient scope (=~ cgroup) and executes its
		//   argument (/bin/mount) there.
		// * mount does its job, forks a fuse daemon if necessary and finishes.
		//   (systemd-run --scope finishes at this point, returning mount's exit
		//   code and stdout/stderr - thats one of --scope benefits).
		// * systemd keeps the fuse daemon running in the scope (i.e. in its own
		//   cgroup) until the fuse daemon dies (another --scope benefit).
		//   Kubelet container can be restarted and the fuse daemon survives.
		// * When the daemon dies (e.g. during unmount) systemd removes the
		//   scope automatically.
		mountCmd, mountArgs = addSystemdScope(systemdRunPath, target, mountCmd, mountArgs)
	} else {
		// Fall back to simple mount when the host has no systemd.
		// Complete command line:
		// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/mount -t <type> <what> <where>
		// Expected flow is:
		// * nsenter breaks out of container's mount namespace and executes host's /bin/mount.
		// * mount does its job, forks a fuse daemon if necessary and finishes.
		// * Any fuse daemon runs in cgroup of kubelet docker container,
		//   restart of kubelet container will kill it!

		// No code here, mountCmd and mountArgs use /bin/mount
	}

	return mountCmd, mountArgs
}

// Unmount runs umount(8) in the host's mount namespace.
func (n *NsenterMounter) Unmount(target string) error {
	args := []string{target}
	// No need to execute systemd-run here, it's enough that unmount is executed
	// in the host's mount namespace. It will finish appropriate fuse daemon(s)
	// running in any scope.
	glog.V(5).Infof("nsenter unmount args: %v", args)
	outputBytes, err := n.ne.Exec("umount", args).CombinedOutput()
	if len(outputBytes) != 0 {
		glog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
	}
	return err
}

// List returns a list of all mounted filesystems in the host's mount namespace.
func (*NsenterMounter) List() ([]MountPoint, error) {
	return listProcMounts(hostProcMountsPath)
}

func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) {
	return IsNotMountPoint(m, dir)
}

func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
	deletedDir := fmt.Sprintf("%s\\040(deleted)", dir)
	return (mp.Path == dir) || (mp.Path == deletedDir)
}

// IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt
// in the host's root mount namespace.
func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
	file, err := filepath.Abs(file)
	if err != nil {
		return true, err
	}

	// Check the directory exists
	if _, err = os.Stat(file); os.IsNotExist(err) {
		glog.V(5).Infof("findmnt: directory %s does not exist", file)
		return true, err
	}
	// Add --first-only option: since we are testing for the absence of a mountpoint, it is sufficient to get only
	// the first of multiple possible mountpoints using --first-only.
	// Also add fstype output to make sure that the output of target file will give the full path
	// TODO: Need more refactoring for this function. Track the solution with issue #26996
	args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
	glog.V(5).Infof("nsenter findmnt args: %v", args)
	out, err := n.ne.Exec("findmnt", args).CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Failed findmnt command for path %s: %s %v", file, out, err)
		// Different operating systems behave differently for paths which are not mount points.
		// On older versions (e.g. 2.20.1) we'd get error, on newer ones (e.g. 2.26.2) we'd get "/".
		// It's safer to assume that it's not a mount point.
		return true, nil
	}
	mountTarget, err := parseFindMnt(string(out))
	if err != nil {
		return false, err
	}

	glog.V(5).Infof("IsLikelyNotMountPoint findmnt output for path %s: %v:", file, mountTarget)

	if mountTarget == file {
		glog.V(5).Infof("IsLikelyNotMountPoint: %s is a mount point", file)
		return false, nil
	}
	glog.V(5).Infof("IsLikelyNotMountPoint: %s is not a mount point", file)
	return true, nil
}

// parse output of "findmnt -o target,fstype" and return just the target
func parseFindMnt(out string) (string, error) {
	// cut trailing newline
	out = strings.TrimSuffix(out, "\n")
	// cut everything after the last space - it's the filesystem type
	i := strings.LastIndex(out, " ")
	if i == -1 {
		return "", fmt.Errorf("error parsing findmnt output, expected at least one space: %q", out)
	}
	return out[:i], nil
}

// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
// Returns true if open returns errno EBUSY, and false if errno is nil.
// Returns an error if errno is any error other than EBUSY.
// Returns with error if pathname is not a device.
func (n *NsenterMounter) DeviceOpened(pathname string) (bool, error) {
	return exclusiveOpenFailsOnDevice(pathname)
}

// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
// to a device.
func (n *NsenterMounter) PathIsDevice(pathname string) (bool, error) {
	pathType, err := n.GetFileType(pathname)
	isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
	return isDevice, err
}

//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
	return getDeviceNameFromMount(n, mountPath, pluginDir)
}

func (n *NsenterMounter) MakeRShared(path string) error {
	return doMakeRShared(path, hostProcMountinfoPath)
}

func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) {
	var pathType FileType
	outputBytes, err := mounter.ne.Exec("stat", []string{"-L", "--printf=%F", pathname}).CombinedOutput()
	if err != nil {
		if strings.Contains(string(outputBytes), "No such file") {
			err = fmt.Errorf("%s does not exist", pathname)
		} else {
			err = fmt.Errorf("stat %s error: %v", pathname, string(outputBytes))
		}
		return pathType, err
	}

	switch string(outputBytes) {
	case "socket":
		return FileTypeSocket, nil
	case "character special file":
		return FileTypeCharDev, nil
	case "block special file":
		return FileTypeBlockDev, nil
	case "directory":
		return FileTypeDirectory, nil
	case "regular file":
		return FileTypeFile, nil
	}

	return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
}

func (mounter *NsenterMounter) MakeDir(pathname string) error {
	args := []string{"-p", pathname}
	if _, err := mounter.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
		return err
	}
	return nil
}

func (mounter *NsenterMounter) MakeFile(pathname string) error {
	args := []string{pathname}
	if _, err := mounter.ne.Exec("touch", args).CombinedOutput(); err != nil {
		return err
	}
	return nil
}

func (mounter *NsenterMounter) ExistsPath(pathname string) bool {
	args := []string{pathname}
	_, err := mounter.ne.Exec("ls", args).CombinedOutput()
	if err == nil {
		return true
	}
	return false
}

func (mounter *NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
	return doCleanSubPaths(mounter, podDir, volumeName)
}

// getPidOnHost returns kubelet's pid in the host pid namespace
func (mounter *NsenterMounter) getPidOnHost(procStatusPath string) (int, error) {
	// Get the PID from /rootfs/proc/self/status
	statusBytes, err := utilio.ConsistentRead(procStatusPath, maxListTries)
	if err != nil {
		return 0, fmt.Errorf("error reading %s: %s", procStatusPath, err)
	}
	matches := pidRegExp.FindSubmatch(statusBytes)
	if len(matches) < 2 {
		return 0, fmt.Errorf("cannot parse %s: no Pid:", procStatusPath)
	}
	return strconv.Atoi(string(matches[1]))
}

func (mounter *NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
	hostPid, err := mounter.getPidOnHost(hostProcSelfStatusPath)
	if err != nil {
		return "", nil, err
	}
	glog.V(4).Infof("Kubelet's PID on the host is %d", hostPid)

	// Bind-mount the subpath to avoid using symlinks in subpaths.
	newHostPath, err = doBindSubPath(mounter, subPath, hostPid)

	// There is no action when the container starts. Bind-mount will be cleaned
	// when container stops by CleanSubPaths.
	cleanupAction = nil
	return newHostPath, cleanupAction, err
}

func (mounter *NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
	return doSafeMakeDir(pathname, base, perm)
}

func (mounter *NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
	hostpath, err := mounter.ne.EvalSymlinks(pathname)
	if err != nil {
		return nil, err
	}
	return searchMountPoints(hostpath, hostProcMountinfoPath)
}

func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) {
	kubeletpath, err := mounter.ne.KubeletPath(pathname)
	if err != nil {
		return 0, err
	}
	return getFSGroup(kubeletpath)
}

func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
	return getSELinuxSupport(pathname, hostProcMountsPath)
}
<|endoftext|>


<commit_before>package chipmunk

import (
	//"container/list"
	//"fmt"
	. "github.com/vova616/chipmunk/vect"
	"time"
)

var VoidQueryFunc = func(a, b Indexable, data Data) {}

type HashSet map[HashValue]*Node

func (set HashSet) Each(fnc HashSetIterator, data Data) {
	for _, node := range set {
		fnc(node, data)
	}
}

type BBTree struct {
	SpatialIndexClass
	SpatialIndex *SpatialIndex

	leaves HashSet
	root   *Node

	pooledNodes      *Node
	pooledPairs      *Pair
	allocatedBuffers []Contact

	stamp time.Duration
}

type Children struct {
	A, B *Node
}

type Leaf struct {
	stamp time.Duration
	pairs *Pair
}

type node struct {
	Children
	Leaf
}

type Node struct {
	obj    Indexable
	bb     AABB
	parent *Node

	node
}

func (node *Node) IsLeaf() bool {
	return node.obj != nil
}

func (node *Node) NodeSetA(value *Node) {
	node.A = value
	value.parent = node
}

func (node *Node) NodeSetB(value *Node) {
	node.B = value
	value.parent = node
}

func (node *Node) NodeOther(child *Node) *Node {
	if node.A == child {
		return node.B
	}
	return node.A
}

type Thread struct {
	prev *Pair
	leaf *Node
	next *Pair
}

type Pair struct {
	a, b Thread
}

func NewBBTree(staticIndex *SpatialIndex) *SpatialIndex {
	tree := &BBTree{}
	tree.leaves = make(map[HashValue]*Node)
	tree.allocatedBuffers = make([]Contact, 0)
	tree.SpatialIndex = NewSpartialIndex(tree, staticIndex)

	return tree.SpatialIndex
}

func (tree *BBTree) Count() int {
	return len(tree.leaves)
}

func (tree *BBTree) NewLeaf(obj Indexable) *Node {
	node := tree.NodeFromPool()
	node.obj = obj
	node.bb = tree.GetBB(obj)

	return node
}

func (tree *BBTree) NodeNew(a, b *Node) *Node {
	node := tree.NodeFromPool()
	node.bb = Combine(a.bb, b.bb)

	node.NodeSetA(a)
	node.NodeSetB(b)

	return node
}

func (tree *BBTree) GetBB(obj Indexable) AABB {
	bb := obj.AABB()

	v, ok := obj.Velocity()
	if ok {

		coef := Float(0.1)

		l := bb.Lower.X
		b := bb.Lower.Y
		r := bb.Upper.X
		t := bb.Upper.Y

		x := (r - l) * coef
		y := (t - b) * coef

		v = Mult(v, 0.1)

		return NewAABB(l+FMin(-x, v.X), b+FMin(-y, v.Y), r+FMax(x, v.X), t+FMax(y, v.Y))
	}

	return bb
}

func (tree *BBTree) SubtreeInsert(subtree, leaf *Node) *Node {
	if subtree == nil {
		return leaf
	} else if subtree.IsLeaf() {
		return tree.NodeNew(leaf, subtree)
	}

	cost_a := subtree.B.bb.Area() + MergedArea(subtree.A.bb, leaf.bb)
	cost_b := subtree.A.bb.Area() + MergedArea(subtree.B.bb, leaf.bb)

	if cost_a == cost_b {

		cost_a = Proximity(subtree.A.bb, leaf.bb)
		cost_b = Proximity(subtree.B.bb, leaf.bb)
	}

	if cost_b < cost_a {
		subtree.NodeSetB(tree.SubtreeInsert(subtree.B, leaf))
	} else {
		subtree.NodeSetA(tree.SubtreeInsert(subtree.A, leaf))
	}

	subtree.bb = Combine(subtree.bb, leaf.bb)

	return subtree
}

func GetTree(index SpatialIndexClass) *BBTree {
	if index != nil {
		tree, _ := index.(*BBTree)
		return tree
	}
	return nil
}

func (tree *BBTree) GetMasterTree() SpatialIndexClass {
	dynamicTree := tree.SpatialIndex.dynamicIndex
	if dynamicTree != nil {
		return dynamicTree
	}
	return tree
}

func (tree *BBTree) Stamp() time.Duration {
	return tree.stamp
}

func GetRootIfTree(index SpatialIndexClass) *Node {
	if index != nil {
		tree, ok := index.(*BBTree)
		if ok {
			return tree.root
		}
	}
	return nil
}

func (tree *BBTree) LeafAddPairs(leaf *Node) {
	dynamicIndex := tree.SpatialIndex.dynamicIndex
	if dynamicIndex != nil {
		dynamicRoot := GetRootIfTree(dynamicIndex)
		if dynamicRoot != nil {
			dynamicTree := GetTree(dynamicIndex)
			context := MarkContext{dynamicTree, nil, nil, nil}
			context.MarkLeafQuery(dynamicRoot, leaf, true)
		}
	} else {
		staticRoot := GetRootIfTree(tree.SpatialIndex.staticIndex)
		context := MarkContext{tree, staticRoot, VoidQueryFunc, nil}
		context.MarkLeaf(leaf)
	}
}

func (tree *BBTree) IncrementStamp() {
	dynamicTree := GetTree(tree.SpatialIndex.dynamicIndex)
	if dynamicTree != nil {
		dynamicTree.stamp++
	} else {
		tree.stamp++
	}
}

func (tree *BBTree) Insert(obj Indexable) {

	leaf := tree.NewLeaf(obj)

	tree.leaves[obj.Hash()] = leaf

	root := tree.root
	tree.root = tree.SubtreeInsert(root, leaf)

	leaf.stamp = tree.GetMasterTree().Stamp()

	tree.LeafAddPairs(leaf)
	tree.IncrementStamp()
}

func (tree *BBTree) PairInsert(a, b *Node) {
	nextA := a.pairs
	nextB := b.pairs
	pair := tree.PairFromPool()
	temp := Pair{Thread{nil, a, nextA}, Thread{nil, b, nextB}}

	b.pairs = pair
	a.pairs = pair

	*pair = temp

	if nextA != nil {
		if nextA.a.leaf == a {
			nextA.a.prev = pair
		} else {
			nextA.b.prev = pair
		}
	}

	if nextB != nil {
		if nextB.a.leaf == b {
			nextB.a.prev = pair
		} else {
			nextB.b.prev = pair
		}
	}
}

func (tree *BBTree) NodeRecycle(node *Node) {

}

func (tree *BBTree) NodeFromPool() *Node {
	return &Node{}
}

func (tree *BBTree) PairRecycle(pair *Pair) {

}

func (tree *BBTree) PairFromPool() *Pair {
	return &Pair{}
}

func (tree *BBTree) NodeReplaceChild(parent, child, value *Node) {
	if parent.IsLeaf() {
		panic("Internal Error: Cannot replace child of a leaf.")
	}

	if (child == parent.A || child == parent.B) == false {
		panic("Internal Error: Node is not a child of parent.")
	}

	if parent.A == child {
		tree.NodeRecycle(parent.A)
		parent.NodeSetA(value)
	} else {
		tree.NodeRecycle(parent.B)
		parent.NodeSetB(value)
	}

	for node := parent; node != nil; node = node.parent {
		node.bb = Combine(node.A.bb, node.B.bb)
	}
}

func (tree *BBTree) Remove(obj Indexable) {
	leaf := tree.leaves[obj.Hash()]
	delete(tree.leaves, obj.Hash())

	if leaf == nil {
		return
	}

	tree.root = tree.SubtreeRemove(tree.root, leaf)
	tree.PairsClear(leaf)
	tree.NodeRecycle(leaf)
}

func (tree *BBTree) SubtreeRemove(subtree, leaf *Node) *Node {
	if leaf == subtree {
		return nil
	}

	parent := leaf.parent
	if parent == subtree {
		other := subtree.NodeOther(leaf)
		other.parent = subtree.parent
		tree.NodeRecycle(subtree)
		return other
	}

	tree.NodeReplaceChild(parent.parent, parent, parent.NodeOther(leaf))
	return subtree
}

func ThreadUnlink(thread Thread) {
	next := thread.next
	prev := thread.prev

	if next != nil {
		if next.a.leaf == thread.leaf {
			next.a.prev = prev
		} else {
			next.b.prev = prev
		}
	}

	if prev != nil {
		if prev.a.leaf == thread.leaf {
			prev.a.next = next
		} else {
			prev.b.next = next
		}
	} else {
		thread.leaf.pairs = next
	}
}

func (tree *BBTree) PairsClear(leaf *Node) {
	pair := leaf.pairs
	leaf.pairs = nil

	for pair != nil {
		if pair.a.leaf == leaf {
			next := pair.a.next
			ThreadUnlink(pair.b)
			tree.PairRecycle(pair)
			pair = next
		} else {
			next := pair.b.next
			ThreadUnlink(pair.a)
			tree.PairRecycle(pair)
			pair = next
		}
	}
}

func LeafUpdate(leaf *Node, tree *BBTree) bool {
	root := tree.root
	bb := leaf.obj.AABB()

	if !leaf.bb.Contains(bb) {
		leaf.bb = tree.GetBB(leaf.obj)

		root = tree.SubtreeRemove(root, leaf)
		tree.root = tree.SubtreeInsert(root, leaf)

		tree.PairsClear(leaf)
		leaf.stamp = tree.GetMasterTree().Stamp()

		return true
	}

	return false
}

func (tree *BBTree) Each(fnc HashSetIterator, data Data) {
	tree.leaves.Each(fnc, data)
}

func (tree *BBTree) Each2(fnc HashSetIterator, data Data) {
	tree.leaves.Each(fnc, data)
}

func (tree *BBTree) ReindexQuery(fnc SpatialIndexQueryFunc, data Data) {
	if tree.root == nil {
		return
	}

	// LeafUpdate() may modify tree->root. Don't cache it.
	for _, node := range tree.leaves {
		LeafUpdate(node, tree)
	}

	staticIndex := GetTree(tree.SpatialIndex.staticIndex)
	var staticRoot *Node = nil
	if staticIndex != nil {
		staticRoot = staticIndex.root
	}

	context := MarkContext{tree, staticRoot, fnc, data}
	context.MarkSubtree(tree.root)
	if staticIndex != nil && staticRoot == nil {
		SpatialIndexCollideStatic(tree.SpatialIndex, staticIndex.SpatialIndex, fnc, data)
	}

	tree.IncrementStamp()
}

func (tree *BBTree) Query(obj Indexable, aabb AABB, fnc SpatialIndexQueryFunc, data Data) {
	if tree.root != nil {
		SubtreeQuery(tree.root, obj, aabb, fnc, data)
	}
}

func SubtreeQuery(subtree *Node, obj Indexable, bb AABB, fnc SpatialIndexQueryFunc, data Data) {
	if TestOverlap(subtree.bb, bb) {
		if subtree.IsLeaf() {
			fnc(obj, subtree.obj, data)
		} else {
			SubtreeQuery(subtree.A, obj, bb, fnc, data)
			SubtreeQuery(subtree.B, obj, bb, fnc, data)
		}
	}
}

type MarkContext struct {
	tree       *BBTree
	staticRoot *Node
	fnc        SpatialIndexQueryFunc
	data       Data
}

func (context *MarkContext) MarkSubtree(subtree *Node) {
	if subtree.IsLeaf() {
		context.MarkLeaf(subtree)
	} else {
		context.MarkSubtree(subtree.A)
		context.MarkSubtree(subtree.B)
	}
}

func (context *MarkContext) MarkLeafQuery(subtree, leaf *Node, left bool) {

	if TestOverlap(leaf.bb, subtree.bb) {
		if subtree.IsLeaf() {
			if left {
				context.tree.PairInsert(leaf, subtree)
			} else {
				if subtree.stamp < leaf.stamp {
					context.tree.PairInsert(subtree, leaf)
				}
				context.fnc(leaf.obj, subtree.obj, context.data)
			}
		} else {
			context.MarkLeafQuery(subtree.A, leaf, left)
			context.MarkLeafQuery(subtree.B, leaf, left)
		}
	}
}

func (context *MarkContext) MarkLeaf(leaf *Node) {
	tree := context.tree
	if leaf.stamp == tree.GetMasterTree().Stamp() {
		staticRoot := context.staticRoot
		if staticRoot != nil {
			context.MarkLeafQuery(staticRoot, leaf, false)
		}

		for node := leaf; node.parent != nil; node = node.parent {
			if node == node.parent.A {
				context.MarkLeafQuery(node.parent.B, leaf, true)
			} else {
				context.MarkLeafQuery(node.parent.A, leaf, false)
			}
		}
	} else {
		pair := leaf.pairs
		i := 0
		for pair != nil {
			if leaf == pair.b.leaf {
				context.fnc(pair.a.leaf.obj, leaf.obj, context.data)
				pair = pair.b.next
			} else {
				pair = pair.a.next
			}
			i++
		}
		//fmt.Println(i)
	}
}
<commit_msg>Cleanup and added pools :)<commit_after>package chipmunk

import (
	//"container/list"
	. "github.com/vova616/chipmunk/vect"
	//"log"
	"time"
)

var VoidQueryFunc = func(a, b Indexable, data Data) {}

type HashSet map[HashValue]*Node

func (set HashSet) Each(fnc HashSetIterator, data Data) {
	for _, node := range set {
		fnc(node, data)
	}
}

type BBTree struct {
	SpatialIndexClass
	SpatialIndex *SpatialIndex

	leaves HashSet
	root   *Node

	pairBuffer []*Pair
	nodeBuffer []*Node

	stamp time.Duration
}

type Children struct {
	A, B *Node
}

type Leaf struct {
	stamp time.Duration
	pairs *Pair
}

type node struct {
	Children
	Leaf
}

type Node struct {
	obj    Indexable
	bb     AABB
	parent *Node

	node
}

func (node *Node) IsLeaf() bool {
	return node.obj != nil
}

func (node *Node) NodeSetA(value *Node) {
	node.A = value
	value.parent = node
}

func (node *Node) NodeSetB(value *Node) {
	node.B = value
	value.parent = node
}

func (node *Node) NodeOther(child *Node) *Node {
	if node.A == child {
		return node.B
	}
	return node.A
}

type Thread struct {
	prev *Pair
	leaf *Node
	next *Pair
}

type Pair struct {
	a, b Thread
}

func NewBBTree(staticIndex *SpatialIndex) *SpatialIndex {
	tree := &BBTree{}
	tree.leaves = make(map[HashValue]*Node)

	tree.SpatialIndex = NewSpartialIndex(tree, staticIndex)
	tree.pairBuffer = make([]*Pair, 0)
	tree.nodeBuffer = make([]*Node, 0)
	return tree.SpatialIndex
}

func (tree *BBTree) Count() int {
	return len(tree.leaves)
}

func (tree *BBTree) NewLeaf(obj Indexable) *Node {
	node := tree.NodeFromPool()
	node.obj = obj
	node.bb = tree.GetBB(obj)

	return node
}

func (tree *BBTree) NodeNew(a, b *Node) *Node {
	node := tree.NodeFromPool()
	node.bb = Combine(a.bb, b.bb)

	node.NodeSetA(a)
	node.NodeSetB(b)

	return node
}

func (tree *BBTree) GetBB(obj Indexable) AABB {
	bb := obj.AABB()

	v, ok := obj.Velocity()
	if ok {

		coef := Float(0.1)

		l := bb.Lower.X
		b := bb.Lower.Y
		r := bb.Upper.X
		t := bb.Upper.Y

		x := (r - l) * coef
		y := (t - b) * coef

		v = Mult(v, 0.1)

		return NewAABB(l+FMin(-x, v.X), b+FMin(-y, v.Y), r+FMax(x, v.X), t+FMax(y, v.Y))
	}

	return bb
}

func (tree *BBTree) SubtreeInsert(subtree, leaf *Node) *Node {
	if subtree == nil {
		return leaf
	} else if subtree.IsLeaf() {
		return tree.NodeNew(leaf, subtree)
	}

	cost_a := subtree.B.bb.Area() + MergedArea(subtree.A.bb, leaf.bb)
	cost_b := subtree.A.bb.Area() + MergedArea(subtree.B.bb, leaf.bb)

	if cost_a == cost_b {

		cost_a = Proximity(subtree.A.bb, leaf.bb)
		cost_b = Proximity(subtree.B.bb, leaf.bb)
	}

	if cost_b < cost_a {
		subtree.NodeSetB(tree.SubtreeInsert(subtree.B, leaf))
	} else {
		subtree.NodeSetA(tree.SubtreeInsert(subtree.A, leaf))
	}

	subtree.bb = Combine(subtree.bb, leaf.bb)

	return subtree
}

func GetTree(index SpatialIndexClass) *BBTree {
	if index != nil {
		tree, _ := index.(*BBTree)
		return tree
	}
	return nil
}

func (tree *BBTree) GetMasterTree() SpatialIndexClass {
	dynamicTree := tree.SpatialIndex.dynamicIndex
	if dynamicTree != nil {
		return dynamicTree
	}
	return tree
}

func (tree *BBTree) Stamp() time.Duration {
	return tree.stamp
}

func GetRootIfTree(index SpatialIndexClass) *Node {
	if index != nil {
		tree, ok := index.(*BBTree)
		if ok {
			return tree.root
		}
	}
	return nil
}

func (tree *BBTree) LeafAddPairs(leaf *Node) {
	dynamicIndex := tree.SpatialIndex.dynamicIndex
	if dynamicIndex != nil {
		dynamicRoot := GetRootIfTree(dynamicIndex)
		if dynamicRoot != nil {
			dynamicTree := GetTree(dynamicIndex)
			context := MarkContext{dynamicTree, nil, nil, nil}
			context.MarkLeafQuery(dynamicRoot, leaf, true)
		}
	} else {
		staticRoot := GetRootIfTree(tree.SpatialIndex.staticIndex)
		context := MarkContext{tree, staticRoot, VoidQueryFunc, nil}
		context.MarkLeaf(leaf)
	}
}

func (tree *BBTree) IncrementStamp() {
	dynamicTree := GetTree(tree.SpatialIndex.dynamicIndex)
	if dynamicTree != nil {
		dynamicTree.stamp++
	} else {
		tree.stamp++
	}
}

func (tree *BBTree) Insert(obj Indexable) {

	leaf := tree.NewLeaf(obj)

	tree.leaves[obj.Hash()] = leaf

	root := tree.root
	tree.root = tree.SubtreeInsert(root, leaf)

	leaf.stamp = tree.GetMasterTree().Stamp()

	tree.LeafAddPairs(leaf)
	tree.IncrementStamp()
}

func (tree *BBTree) PairInsert(a, b *Node) {
	nextA := a.pairs
	nextB := b.pairs
	pair := tree.PairFromPool()
	temp := Pair{Thread{nil, a, nextA}, Thread{nil, b, nextB}}

	b.pairs = pair
	a.pairs = pair

	*pair = temp

	if nextA != nil {
		if nextA.a.leaf == a {
			nextA.a.prev = pair
		} else {
			nextA.b.prev = pair
		}
	}

	if nextB != nil {
		if nextB.a.leaf == b {
			nextB.a.prev = pair
		} else {
			nextB.b.prev = pair
		}
	}
}

func (tree *BBTree) NodeRecycle(node *Node) {
	*node = Node{}
	tree.nodeBuffer = append(tree.nodeBuffer, node)
}

func (tree *BBTree) NodeFromPool() *Node {
	var node *Node
	if len(tree.nodeBuffer) > 0 {
		node, tree.nodeBuffer = tree.nodeBuffer[len(tree.nodeBuffer)-1], tree.nodeBuffer[:len(tree.nodeBuffer)-1]
	} else {
		buff := make([]*Node, 100)
		//log.Println("New node buff")
		for i, _ := range buff {
			buff[i] = &Node{}
		}
		tree.nodeBuffer = append(tree.nodeBuffer, buff...)
		node, tree.nodeBuffer = tree.nodeBuffer[len(tree.nodeBuffer)-1], tree.nodeBuffer[:len(tree.nodeBuffer)-1]
	}
	return node
}

func (tree *BBTree) PairRecycle(pair *Pair) {
	*pair = Pair{}
	tree.pairBuffer = append(tree.pairBuffer, pair)
}

func (tree *BBTree) PairFromPool() *Pair {
	var pair *Pair
	if len(tree.pairBuffer) > 0 {
		pair, tree.pairBuffer = tree.pairBuffer[len(tree.pairBuffer)-1], tree.pairBuffer[:len(tree.pairBuffer)-1]
	} else {
		buff := make([]*Pair, 100)
		//log.Println("New pair buff")
		for i, _ := range buff {
			buff[i] = &Pair{}
		}
		tree.pairBuffer = append(tree.pairBuffer, buff...)
		pair, tree.pairBuffer = tree.pairBuffer[len(tree.pairBuffer)-1], tree.pairBuffer[:len(tree.pairBuffer)-1]
	}
	return pair
}

func (tree *BBTree) NodeReplaceChild(parent, child, value *Node) {
	if parent.IsLeaf() {
		panic("Internal Error: Cannot replace child of a leaf.")
	}

	if (child == parent.A || child == parent.B) == false {
		panic("Internal Error: Node is not a child of parent.")
	}

	if parent.A == child {
		tree.NodeRecycle(parent.A)
		parent.NodeSetA(value)
	} else {
		tree.NodeRecycle(parent.B)
		parent.NodeSetB(value)
	}

	for node := parent; node != nil; node = node.parent {
		node.bb = Combine(node.A.bb, node.B.bb)
	}
}

func (tree *BBTree) Remove(obj Indexable) {
	leaf := tree.leaves[obj.Hash()]
	delete(tree.leaves, obj.Hash())

	if leaf == nil {
		return
	}

	tree.root = tree.SubtreeRemove(tree.root, leaf)
	tree.PairsClear(leaf)
	tree.NodeRecycle(leaf)
}

func (tree *BBTree) SubtreeRemove(subtree, leaf *Node) *Node {
	if leaf == subtree {
		return nil
	}

	parent := leaf.parent
	if parent == subtree {
		other := subtree.NodeOther(leaf)
		other.parent = subtree.parent
		tree.NodeRecycle(subtree)
		return other
	}

	tree.NodeReplaceChild(parent.parent, parent, parent.NodeOther(leaf))
	return subtree
}

func ThreadUnlink(thread Thread) {
	next := thread.next
	prev := thread.prev

	if next != nil {
		if next.a.leaf == thread.leaf {
			next.a.prev = prev
		} else {
			next.b.prev = prev
		}
	}

	if prev != nil {
		if prev.a.leaf == thread.leaf {
			prev.a.next = next
		} else {
			prev.b.next = next
		}
	} else {
		thread.leaf.pairs = next
	}
}

func (tree *BBTree) PairsClear(leaf *Node) {
	pair := leaf.pairs
	leaf.pairs = nil

	for pair != nil {
		if pair.a.leaf == leaf {
			next := pair.a.next
			ThreadUnlink(pair.b)
			tree.PairRecycle(pair)
			pair = next
		} else {
			next := pair.b.next
			ThreadUnlink(pair.a)
			tree.PairRecycle(pair)
			pair = next
		}
	}
}

func LeafUpdate(leaf *Node, tree *BBTree) bool {
	root := tree.root
	bb := leaf.obj.AABB()

	if !leaf.bb.Contains(bb) {
		leaf.bb = tree.GetBB(leaf.obj)

		root = tree.SubtreeRemove(root, leaf)
		tree.root = tree.SubtreeInsert(root, leaf)

		tree.PairsClear(leaf)
		leaf.stamp = tree.GetMasterTree().Stamp()

		return true
	}

	return false
}

func (tree *BBTree) Each(fnc HashSetIterator, data Data) {
	tree.leaves.Each(fnc, data)
}

func (tree *BBTree) Each2(fnc HashSetIterator, data Data) {
	tree.leaves.Each(fnc, data)
}

func (tree *BBTree) ReindexQuery(fnc SpatialIndexQueryFunc, data Data) {
	if tree.root == nil {
		return
	}

	// LeafUpdate() may modify tree->root. Don't cache it.
	for _, node := range tree.leaves {
		LeafUpdate(node, tree)
	}

	staticIndex := GetTree(tree.SpatialIndex.staticIndex)
	var staticRoot *Node = nil
	if staticIndex != nil {
		staticRoot = staticIndex.root
	}

	context := MarkContext{tree, staticRoot, fnc, data}
	context.MarkSubtree(tree.root)
	if staticIndex != nil && staticRoot == nil {
		SpatialIndexCollideStatic(tree.SpatialIndex, staticIndex.SpatialIndex, fnc, data)
	}

	tree.IncrementStamp()
}

func (tree *BBTree) Query(obj Indexable, aabb AABB, fnc SpatialIndexQueryFunc, data Data) {
	if tree.root != nil {
		SubtreeQuery(tree.root, obj, aabb, fnc, data)
	}
}

func SubtreeQuery(subtree *Node, obj Indexable, bb AABB, fnc SpatialIndexQueryFunc, data Data) {
	if TestOverlap(subtree.bb, bb) {
		if subtree.IsLeaf() {
			fnc(obj, subtree.obj, data)
		} else {
			SubtreeQuery(subtree.A, obj, bb, fnc, data)
			SubtreeQuery(subtree.B, obj, bb, fnc, data)
		}
	}
}

type MarkContext struct {
	tree       *BBTree
	staticRoot *Node
	fnc        SpatialIndexQueryFunc
	data       Data
}

func (context *MarkContext) MarkSubtree(subtree *Node) {
	if subtree.IsLeaf() {
		context.MarkLeaf(subtree)
	} else {
		context.MarkSubtree(subtree.A)
		context.MarkSubtree(subtree.B)
	}
}

func (context *MarkContext) MarkLeafQuery(subtree, leaf *Node, left bool) {

	if TestOverlap(leaf.bb, subtree.bb) {
		if subtree.IsLeaf() {
			if left {
				context.tree.PairInsert(leaf, subtree)
			} else {
				if subtree.stamp < leaf.stamp {
					context.tree.PairInsert(subtree, leaf)
				}
				context.fnc(leaf.obj, subtree.obj, context.data)
			}
		} else {
			context.MarkLeafQuery(subtree.A, leaf, left)
			context.MarkLeafQuery(subtree.B, leaf, left)
		}
	}
}

func (context *MarkContext) MarkLeaf(leaf *Node) {
	tree := context.tree
	if leaf.stamp == tree.GetMasterTree().Stamp() {
		staticRoot := context.staticRoot
		if staticRoot != nil {
			context.MarkLeafQuery(staticRoot, leaf, false)
		}

		for node := leaf; node.parent != nil; node = node.parent {
			if node == node.parent.A {
				context.MarkLeafQuery(node.parent.B, leaf, true)
			} else {
				context.MarkLeafQuery(node.parent.A, leaf, false)
			}
		}
	} else {
		pair := leaf.pairs
		i := 0
		for pair != nil {
			if leaf == pair.b.leaf {
				context.fnc(pair.a.leaf.obj, leaf.obj, context.data)
				pair = pair.b.next
			} else {
				pair = pair.a.next
			}
			i++
		}
		//fmt.Println(i)
	}
}
<|endoftext|>


<commit_before>/* Copyright (C) 2019 Monomax Software Pty Ltd
 *
 * This file is part of Dnote CLI.
 *
 * Dnote CLI is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dnote CLI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dnote CLI.  If not, see <https://www.gnu.org/licenses/>.
 */

package edit

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/dnote/dnote/cli/core"
	"github.com/dnote/dnote/cli/infra"
	"github.com/dnote/dnote/cli/log"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var newContent string

var example = `
  * Edit the note by its id
  dnote edit 3

	* Skip the prompt by providing new content directly
	dnote edit 3 -c "new content"`

// NewCmd returns a new edit command
func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
	cmd := &cobra.Command{
		Use:     "edit",
		Short:   "Edit a note or a book",
		Aliases: []string{"e"},
		Example: example,
		PreRunE: preRun,
		RunE:    newRun(ctx),
	}

	f := cmd.Flags()
	f.StringVarP(&newContent, "content", "c", "", "The new content for the note")

	return cmd
}

func preRun(cmd *cobra.Command, args []string) error {
	if len(args) != 1 && len(args) != 2 {
		return errors.New("Incorrect number of argument")
	}

	return nil
}

func newRun(ctx infra.DnoteCtx) core.RunEFunc {
	return func(cmd *cobra.Command, args []string) error {
		db := ctx.DB

		var noteRowID string

		if len(args) == 2 {
			log.Plain(log.ColorYellow.Sprintf("DEPRECATED: you no longer need to pass book name to the view command. e.g. `dnote view 123`.\n\n"))

			noteRowID = args[1]
		} else {
			noteRowID = args[0]
		}

		var noteUUID, oldContent string
		err := db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND deleted = false", noteRowID).Scan(&noteUUID, &oldContent)
		if err == sql.ErrNoRows {
			return errors.Errorf("note %s not found", noteRowID)
		} else if err != nil {
			return errors.Wrap(err, "querying the book")
		}

		if newContent == "" {
			fpath := core.GetDnoteTmpContentPath(ctx)

			e := ioutil.WriteFile(fpath, []byte(oldContent), 0644)
			if e != nil {
				return errors.Wrap(e, "preparing tmp content file")
			}

			e = core.GetEditorInput(ctx, fpath, &newContent)
			if e != nil {
				return errors.Wrap(err, "getting editor input")
			}
		}

		if oldContent == newContent {
			return errors.New("Nothing changed")
		}

		ts := time.Now().UnixNano()
		newContent = core.SanitizeContent(newContent)

		tx, err := db.Begin()
		if err != nil {
			return errors.Wrap(err, "beginning a transaction")
		}

		_, err = tx.Exec(`UPDATE notes
			SET body = ?, edited_on = ?, dirty = ?
			WHERE rowid = ?`, newContent, ts, true, noteRowID)
		if err != nil {
			tx.Rollback()
			return errors.Wrap(err, "updating the note")
		}

		tx.Commit()

		log.Success("edited the note\n")
		fmt.Printf("\n------------------------content------------------------\n")
		fmt.Printf("%s", newContent)
		fmt.Printf("\n-------------------------------------------------------\n")

		return nil
	}
}
<commit_msg>Remove mention of unsupported feature (#205)<commit_after>/* Copyright (C) 2019 Monomax Software Pty Ltd
 *
 * This file is part of Dnote CLI.
 *
 * Dnote CLI is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dnote CLI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dnote CLI.  If not, see <https://www.gnu.org/licenses/>.
 */

package edit

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/dnote/dnote/cli/core"
	"github.com/dnote/dnote/cli/infra"
	"github.com/dnote/dnote/cli/log"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var newContent string

var example = `
  * Edit the note by its id
  dnote edit 3

	* Skip the prompt by providing new content directly
	dnote edit 3 -c "new content"`

// NewCmd returns a new edit command
func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
	cmd := &cobra.Command{
		Use:     "edit",
		Short:   "Edit a note",
		Aliases: []string{"e"},
		Example: example,
		PreRunE: preRun,
		RunE:    newRun(ctx),
	}

	f := cmd.Flags()
	f.StringVarP(&newContent, "content", "c", "", "The new content for the note")

	return cmd
}

func preRun(cmd *cobra.Command, args []string) error {
	if len(args) != 1 && len(args) != 2 {
		return errors.New("Incorrect number of argument")
	}

	return nil
}

func newRun(ctx infra.DnoteCtx) core.RunEFunc {
	return func(cmd *cobra.Command, args []string) error {
		db := ctx.DB

		var noteRowID string

		if len(args) == 2 {
			log.Plain(log.ColorYellow.Sprintf("DEPRECATED: you no longer need to pass book name to the view command. e.g. `dnote view 123`.\n\n"))

			noteRowID = args[1]
		} else {
			noteRowID = args[0]
		}

		var noteUUID, oldContent string
		err := db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND deleted = false", noteRowID).Scan(&noteUUID, &oldContent)
		if err == sql.ErrNoRows {
			return errors.Errorf("note %s not found", noteRowID)
		} else if err != nil {
			return errors.Wrap(err, "querying the book")
		}

		if newContent == "" {
			fpath := core.GetDnoteTmpContentPath(ctx)

			e := ioutil.WriteFile(fpath, []byte(oldContent), 0644)
			if e != nil {
				return errors.Wrap(e, "preparing tmp content file")
			}

			e = core.GetEditorInput(ctx, fpath, &newContent)
			if e != nil {
				return errors.Wrap(err, "getting editor input")
			}
		}

		if oldContent == newContent {
			return errors.New("Nothing changed")
		}

		ts := time.Now().UnixNano()
		newContent = core.SanitizeContent(newContent)

		tx, err := db.Begin()
		if err != nil {
			return errors.Wrap(err, "beginning a transaction")
		}

		_, err = tx.Exec(`UPDATE notes
			SET body = ?, edited_on = ?, dirty = ?
			WHERE rowid = ?`, newContent, ts, true, noteRowID)
		if err != nil {
			tx.Rollback()
			return errors.Wrap(err, "updating the note")
		}

		tx.Commit()

		log.Success("edited the note\n")
		fmt.Printf("\n------------------------content------------------------\n")
		fmt.Printf("%s", newContent)
		fmt.Printf("\n-------------------------------------------------------\n")

		return nil
	}
}
<|endoftext|>