<commit_before>package library

import (
	"path/filepath"
	"sync"

	"github.com/richardwilkes/toolbox/errs"
	"github.com/richardwilkes/toolbox/log/jot"
	"github.com/richardwilkes/toolbox/taskqueue"
	"github.com/richardwilkes/unison"
	"github.com/rjeczalik/notify"
	"golang.org/x/exp/slices"
)

// EventRootSync the event code used when the root path being monitored has been changed to a new path. Also occurs as
// the first event received.
const EventRootSync = 0xFFFFFFFF

type monitor struct {
	library *Library
	lock    sync.RWMutex
	events  chan notify.EventInfo
	done    chan bool
	queue   *taskqueue.Queue
	tokens  []*MonitorToken
}

func newMonitor(library *Library) *monitor {
	return &monitor{library: library}
}

func (m *monitor) newWatch(callback func(lib *Library, fullPath string, what notify.Event), callbackOnUIThread bool) *MonitorToken {
	token := &MonitorToken{
		monitor:    m,
		callback:   callback,
		onUIThread: callbackOnUIThread,
	}
	m.startWatch(token, false)
	return token
}

func (m *monitor) startWatch(token *MonitorToken, sendSync bool) {
	m.lock.Lock()
	defer m.lock.Unlock()
	token.root = m.library.Path()
	token.subPaths = make(map[string]bool)
	m.tokens = append(m.tokens, token)
	if m.events == nil {
		m.queue = taskqueue.New(taskqueue.Workers(1))
		m.done = make(chan bool)
		m.events = make(chan notify.EventInfo, 16)
		if err := notify.Watch(token.root+"/...", m.events, notify.Create|notify.Remove|notify.Rename); err != nil {
			jot.Error(errs.NewWithCausef(err, "unable to watch filesystem path: %s", token.root))
			m.events = nil
			m.done = nil
			m.queue.Shutdown()
			m.queue = nil
		} else {
			go m.listenForEvents()
		}
	}
	if sendSync {
		m.send(token.root, EventRootSync)
	}
}

func (m *monitor) stop() []*MonitorToken {
	m.lock.Lock()
	tokens := m.internalStop()
	m.lock.Unlock()
	return tokens
}

func (m *monitor) internalStop() []*MonitorToken {
	var tokens []*MonitorToken
	if m.events != nil {
		tokens = make([]*MonitorToken, len(m.tokens))
		copy(tokens, m.tokens)
		notify.Stop(m.events)
		close(m.events)
		<-m.done
		m.queue.Shutdown()
		m.queue = nil
		m.events = nil
		m.done = nil
		m.tokens = nil
	}
	return tokens
}

func (m *monitor) listenForEvents() {
	for evt := range m.events {
		m.send(evt.Path(), evt.Event())
	}
	m.done <- true
}

func (m *monitor) send(fullPath string, what notify.Event) {
	m.queue.Submit(func() {
		m.lock.RLock()
		tokens := make([]*MonitorToken, len(m.tokens))
		copy(tokens, m.tokens)
		m.lock.RUnlock()
		for _, token := range tokens {
			if token.onUIThread {
				unison.InvokeTask(func() { token.callback(m.library, fullPath, what) })
			} else {
				token.callback(m.library, fullPath, what)
			}
		}
	})
}

// MonitorToken holds a token that can be used to stop a library watch.
type MonitorToken struct {
	monitor    *monitor
	callback   func(*Library, string, notify.Event)
	root       string
	subPaths   map[string]bool
	onUIThread bool
}

// Library returns the library this token is attached to.
func (m *MonitorToken) Library() *Library {
	return m.monitor.library
}

// AddSubPath adds a sub-path within the library to watch. Should only be called for symlinks, since the native OS
// monitoring typically does not traverse those on its own.
func (m *MonitorToken) AddSubPath(relativePath string) {
	m.monitor.lock.Lock()
	defer m.monitor.lock.Unlock()
	if m.monitor.events != nil {
		if fullPath, err := filepath.Abs(filepath.Join(m.root, relativePath)); err != nil {
			jot.Error(errs.Wrap(err))
		} else if !m.subPaths[fullPath] {
			if err = notify.Watch(fullPath+"/...", m.monitor.events, notify.Create|notify.Remove|notify.Rename); err != nil {
				jot.Error(errs.NewWithCausef(err, "unable to watch filesystem path: %s", fullPath))
			} else {
				m.subPaths[fullPath] = true
			}
		}
	}
}

// Stop this watch.
func (m *MonitorToken) Stop() {
	m.monitor.lock.Lock()
	defer m.monitor.lock.Unlock()
	if i := slices.Index(m.monitor.tokens, m); i != -1 {
		m.monitor.tokens = slices.Delete(m.monitor.tokens, i, i+1)
		if len(m.monitor.tokens) == 0 {
			m.monitor.internalStop()
		}
	}
}
<commit_msg>Fix #502: Using UI to change location of library deadlocks<commit_after>package library

import (
	"path/filepath"
	"sync"

	"github.com/richardwilkes/toolbox/errs"
	"github.com/richardwilkes/toolbox/log/jot"
	"github.com/richardwilkes/toolbox/taskqueue"
	"github.com/richardwilkes/unison"
	"github.com/rjeczalik/notify"
	"golang.org/x/exp/slices"
)

// EventRootSync the event code used when the root path being monitored has been changed to a new path. Also occurs as
// the first event received.
const EventRootSync = 0xFFFFFFFF

type monitor struct {
	library    *Library
	lock       sync.RWMutex
	events     chan notify.EventInfo
	done       chan bool
	queue      *taskqueue.Queue
	tokensLock sync.RWMutex
	tokens     []*MonitorToken
}

func newMonitor(library *Library) *monitor {
	return &monitor{library: library}
}

func (m *monitor) newWatch(callback func(lib *Library, fullPath string, what notify.Event), callbackOnUIThread bool) *MonitorToken {
	token := &MonitorToken{
		monitor:    m,
		callback:   callback,
		onUIThread: callbackOnUIThread,
	}
	m.startWatch(token, false)
	return token
}

func (m *monitor) startWatch(token *MonitorToken, sendSync bool) {
	m.lock.Lock()
	defer m.lock.Unlock()
	token.root = m.library.Path()
	token.subPaths = make(map[string]bool)
	m.tokensLock.Lock()
	m.tokens = append(m.tokens, token)
	m.tokensLock.Unlock()
	if m.events == nil {
		m.queue = taskqueue.New(taskqueue.Workers(1))
		m.done = make(chan bool)
		m.events = make(chan notify.EventInfo, 16)
		if err := notify.Watch(token.root+"/...", m.events, notify.Create|notify.Remove|notify.Rename); err != nil {
			jot.Error(errs.NewWithCausef(err, "unable to watch filesystem path: %s", token.root))
			m.events = nil
			m.done = nil
			m.queue.Shutdown()
			m.queue = nil
		} else {
			go m.listenForEvents()
		}
	}
	if sendSync {
		m.send(token.root, EventRootSync)
	}
}

func (m *monitor) stop() []*MonitorToken {
	m.lock.Lock()
	defer m.lock.Unlock()
	var tokens []*MonitorToken
	if m.events != nil {
		m.tokensLock.RLock()
		tokens = make([]*MonitorToken, len(m.tokens))
		copy(tokens, m.tokens)
		m.tokensLock.RUnlock()
		notify.Stop(m.events)
		close(m.events)
		<-m.done
		m.queue.Shutdown()
		m.queue = nil
		m.events = nil
		m.done = nil
		m.tokensLock.Lock()
		m.tokens = nil
		m.tokensLock.Unlock()
	}
	return tokens
}

func (m *monitor) listenForEvents() {
	for evt := range m.events {
		m.send(evt.Path(), evt.Event())
	}
	m.done <- true
}

func (m *monitor) send(fullPath string, what notify.Event) {
	m.queue.Submit(func() {
		m.tokensLock.RLock()
		tokens := make([]*MonitorToken, len(m.tokens))
		copy(tokens, m.tokens)
		m.tokensLock.RUnlock()
		for _, token := range tokens {
			if token.onUIThread {
				unison.InvokeTask(func() { token.callback(m.library, fullPath, what) })
			} else {
				token.callback(m.library, fullPath, what)
			}
		}
	})
}

// MonitorToken holds a token that can be used to stop a library watch.
type MonitorToken struct {
	monitor    *monitor
	callback   func(*Library, string, notify.Event)
	root       string
	subPaths   map[string]bool
	onUIThread bool
}

// Library returns the library this token is attached to.
func (m *MonitorToken) Library() *Library {
	return m.monitor.library
}

// AddSubPath adds a sub-path within the library to watch. Should only be called for symlinks, since the native OS
// monitoring typically does not traverse those on its own.
func (m *MonitorToken) AddSubPath(relativePath string) {
	m.monitor.lock.Lock()
	defer m.monitor.lock.Unlock()
	if m.monitor.events != nil {
		if fullPath, err := filepath.Abs(filepath.Join(m.root, relativePath)); err != nil {
			jot.Error(errs.Wrap(err))
		} else if !m.subPaths[fullPath] {
			if err = notify.Watch(fullPath+"/...", m.monitor.events, notify.Create|notify.Remove|notify.Rename); err != nil {
				jot.Error(errs.NewWithCausef(err, "unable to watch filesystem path: %s", fullPath))
			} else {
				m.subPaths[fullPath] = true
			}
		}
	}
}

// Stop this watch.
func (m *MonitorToken) Stop() {
	m.monitor.tokensLock.Lock()
	if i := slices.Index(m.monitor.tokens, m); i != -1 {
		m.monitor.tokens = slices.Delete(m.monitor.tokens, i, i+1)
		if len(m.monitor.tokens) == 0 {
			m.monitor.tokensLock.Unlock()
			m.monitor.stop()
			return
		}
	}
	m.monitor.tokensLock.Unlock()
}
<|endoftext|>


<commit_before>package utils

import (
	"database/sql"

	e "github.com/techjanitor/pram-get/errors"
)

// user struct
type User struct {
	Id        uint   `json:"id"`
	Name      string `json:"name"`
	Group     uint   `json:"group"`
	Confirmed bool   `json:"-"`
	Locked    bool   `json:"-"`
	Banned    bool   `json:"-"`
}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 {
		return e.ErrInvalidParam
	}

	err = db.QueryRow("SELECT usergroup_id,user_name,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?", u.Id).Scan(&u.Group, &u.Name, &u.Confirmed, &u.Locked, &u.Banned)
	if err == sql.ErrNoRows {
		return e.ErrNotFound
	} else if err != nil {
		return
	}

	return

}
<commit_msg>add email to user struct<commit_after>package utils

import (
	"database/sql"

	e "github.com/techjanitor/pram-get/errors"
)

// user struct
type User struct {
	Id        uint   `json:"id"`
	Name      string `json:"name"`
	Email     string `json:"email"`
	Group     uint   `json:"group"`
	Confirmed bool   `json:"-"`
	Locked    bool   `json:"-"`
	Banned    bool   `json:"-"`
}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 {
		return e.ErrInvalidParam
	}

	err = db.QueryRow("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?", u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.Confirmed, &u.Locked, &u.Banned)
	if err == sql.ErrNoRows {
		return e.ErrNotFound
	} else if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package scipipe

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestExecCmd_EchoFooBar(t *testing.T) {
	output := ExecCmd("echo foo bar")
	if output != "foo bar\n" {
		t.Errorf("output = %swant: foo bar\n", output)
	}
}

func TestCheck_Panics(t *testing.T) {
	// Recover the panic, and check that the recover "was needed" (r was not
	// nil)
	defer func() {
		if r := recover(); r == nil {
			t.Error("The code did not panic as it should!")
		}
	}()
	err := errors.New("A test-error")
	Check(err, "Checking the test-error")
}

func TestRegexPatternMatchesCases(t *testing.T) {
	r := getShellCommandPlaceHolderRegex()
	placeHolders := []string{
		"{i:hej}",
		"{is:hej}",
		"{o:hej}",
		"{os:hej}",
		"{i:hej:r}",
		"{i:hej:r: }",
		"{i:hej:r:,}",
	}
	for _, ph := range placeHolders {
		assert.True(t, r.Match([]byte(ph)), "Regex does not match placeholder: "+ph)
	}
}
<commit_msg>Trim space and newline before testing output in ExecCmd<commit_after>package scipipe

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"strings"
)

func TestExecCmd_EchoFooBar(t *testing.T) {
	output := ExecCmd("echo foo bar")
	output = strings.TrimSpace(strings.TrimSuffix(output, "\n"))
	if output != "foo bar" {
		t.Errorf("output = %swant: foo bar\n", output)
	}
}

func TestCheck_Panics(t *testing.T) {
	// Recover the panic, and check that the recover "was needed" (r was not
	// nil)
	defer func() {
		if r := recover(); r == nil {
			t.Error("The code did not panic as it should!")
		}
	}()
	err := errors.New("A test-error")
	Check(err, "Checking the test-error")
}

func TestRegexPatternMatchesCases(t *testing.T) {
	r := getShellCommandPlaceHolderRegex()
	placeHolders := []string{
		"{i:hej}",
		"{is:hej}",
		"{o:hej}",
		"{os:hej}",
		"{i:hej:r}",
		"{i:hej:r: }",
		"{i:hej:r:,}",
	}
	for _, ph := range placeHolders {
		assert.True(t, r.Match([]byte(ph)), "Regex does not match placeholder: "+ph)
	}
}
<|endoftext|>


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

package public

import (
	"log"
	"net/http"
	"path"
	"path/filepath"
	"strings"

	"code.gitea.io/gitea/modules/httpcache"
	"code.gitea.io/gitea/modules/setting"
)

// Options represents the available options to configure the macaron handler.
type Options struct {
	Directory   string
	IndexFile   string
	SkipLogging bool
	FileSystem  http.FileSystem
	Prefix      string
}

// KnownPublicEntries list all direct children in the `public` directory
var KnownPublicEntries = []string{
	"css",
	"img",
	"js",
	"serviceworker.js",
	"vendor",
}

// Custom implements the macaron static handler for serving custom assets.
func Custom(opts *Options) func(next http.Handler) http.Handler {
	return opts.staticHandler(path.Join(setting.CustomPath, "public"))
}

// staticFileSystem implements http.FileSystem interface.
type staticFileSystem struct {
	dir *http.Dir
}

func newStaticFileSystem(directory string) staticFileSystem {
	if !filepath.IsAbs(directory) {
		directory = filepath.Join(setting.AppWorkPath, directory)
	}
	dir := http.Dir(directory)
	return staticFileSystem{&dir}
}

func (fs staticFileSystem) Open(name string) (http.File, error) {
	return fs.dir.Open(name)
}

// StaticHandler sets up a new middleware for serving static files in the
func StaticHandler(dir string, opts *Options) func(next http.Handler) http.Handler {
	return opts.staticHandler(dir)
}

func (opts *Options) staticHandler(dir string) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		// Defaults
		if len(opts.IndexFile) == 0 {
			opts.IndexFile = "index.html"
		}
		// Normalize the prefix if provided
		if opts.Prefix != "" {
			// Ensure we have a leading '/'
			if opts.Prefix[0] != '/' {
				opts.Prefix = "/" + opts.Prefix
			}
			// Remove any trailing '/'
			opts.Prefix = strings.TrimRight(opts.Prefix, "/")
		}
		if opts.FileSystem == nil {
			opts.FileSystem = newStaticFileSystem(dir)
		}

		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			if !opts.handle(w, req, opts) {
				next.ServeHTTP(w, req)
			}
		})
	}
}

// parseAcceptEncoding parse Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 as compress methods
func parseAcceptEncoding(val string) map[string]bool {
	parts := strings.Split(val, ";")
	var types = make(map[string]bool)
	for _, v := range strings.Split(parts[0], ",") {
		types[strings.TrimSpace(v)] = true
	}
	return types
}

func (opts *Options) handle(w http.ResponseWriter, req *http.Request, opt *Options) bool {
	if req.Method != "GET" && req.Method != "HEAD" {
		return false
	}

	file := req.URL.Path
	// if we have a prefix, filter requests by stripping the prefix
	if opt.Prefix != "" {
		if !strings.HasPrefix(file, opt.Prefix) {
			return false
		}
		file = file[len(opt.Prefix):]
		if file != "" && file[0] != '/' {
			return false
		}
	}

	f, err := opt.FileSystem.Open(file)
	if err != nil {
		// 404 requests to any known entries in `public`
		if path.Base(opts.Directory) == "public" {
			parts := strings.Split(file, "/")
			if len(parts) < 2 {
				return false
			}
			for _, entry := range KnownPublicEntries {
				if entry == parts[1] {
					w.WriteHeader(404)
					return true
				}
			}
		}
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		log.Printf("[Static] %q exists, but fails to open: %v", file, err)
		return true
	}

	// Try to serve index file
	if fi.IsDir() {
		// Redirect if missing trailing slash.
		if !strings.HasSuffix(req.URL.Path, "/") {
			http.Redirect(w, req, path.Clean(req.URL.Path+"/"), http.StatusFound)
			return true
		}

		f, err = opt.FileSystem.Open(file)
		if err != nil {
			return false // Discard error.
		}
		defer f.Close()

		fi, err = f.Stat()
		if err != nil || fi.IsDir() {
			return false
		}
	}

	if !opt.SkipLogging {
		log.Println("[Static] Serving " + file)
	}

	if httpcache.HandleEtagCache(req, w, fi) {
		return true
	}

	ServeContent(w, req, fi, fi.ModTime(), f)
	return true
}
<commit_msg>When visit /favicon.ico but the static file is not exist return 404 but not continue to handle the route (#14211)<commit_after>// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package public

import (
	"log"
	"net/http"
	"path"
	"path/filepath"
	"strings"

	"code.gitea.io/gitea/modules/httpcache"
	"code.gitea.io/gitea/modules/setting"
)

// Options represents the available options to configure the macaron handler.
type Options struct {
	Directory   string
	IndexFile   string
	SkipLogging bool
	FileSystem  http.FileSystem
	Prefix      string
}

// KnownPublicEntries list all direct children in the `public` directory
var KnownPublicEntries = []string{
	"css",
	"img",
	"js",
	"serviceworker.js",
	"vendor",
	"favicon.ico",
}

// Custom implements the macaron static handler for serving custom assets.
func Custom(opts *Options) func(next http.Handler) http.Handler {
	return opts.staticHandler(path.Join(setting.CustomPath, "public"))
}

// staticFileSystem implements http.FileSystem interface.
type staticFileSystem struct {
	dir *http.Dir
}

func newStaticFileSystem(directory string) staticFileSystem {
	if !filepath.IsAbs(directory) {
		directory = filepath.Join(setting.AppWorkPath, directory)
	}
	dir := http.Dir(directory)
	return staticFileSystem{&dir}
}

func (fs staticFileSystem) Open(name string) (http.File, error) {
	return fs.dir.Open(name)
}

// StaticHandler sets up a new middleware for serving static files in the
func StaticHandler(dir string, opts *Options) func(next http.Handler) http.Handler {
	return opts.staticHandler(dir)
}

func (opts *Options) staticHandler(dir string) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		// Defaults
		if len(opts.IndexFile) == 0 {
			opts.IndexFile = "index.html"
		}
		// Normalize the prefix if provided
		if opts.Prefix != "" {
			// Ensure we have a leading '/'
			if opts.Prefix[0] != '/' {
				opts.Prefix = "/" + opts.Prefix
			}
			// Remove any trailing '/'
			opts.Prefix = strings.TrimRight(opts.Prefix, "/")
		}
		if opts.FileSystem == nil {
			opts.FileSystem = newStaticFileSystem(dir)
		}

		return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			if !opts.handle(w, req, opts) {
				next.ServeHTTP(w, req)
			}
		})
	}
}

// parseAcceptEncoding parse Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 as compress methods
func parseAcceptEncoding(val string) map[string]bool {
	parts := strings.Split(val, ";")
	var types = make(map[string]bool)
	for _, v := range strings.Split(parts[0], ",") {
		types[strings.TrimSpace(v)] = true
	}
	return types
}

func (opts *Options) handle(w http.ResponseWriter, req *http.Request, opt *Options) bool {
	if req.Method != "GET" && req.Method != "HEAD" {
		return false
	}

	file := req.URL.Path
	// if we have a prefix, filter requests by stripping the prefix
	if opt.Prefix != "" {
		if !strings.HasPrefix(file, opt.Prefix) {
			return false
		}
		file = file[len(opt.Prefix):]
		if file != "" && file[0] != '/' {
			return false
		}
	}

	f, err := opt.FileSystem.Open(file)
	if err != nil {
		// 404 requests to any known entries in `public`
		if path.Base(opts.Directory) == "public" {
			parts := strings.Split(file, "/")
			if len(parts) < 2 {
				return false
			}
			for _, entry := range KnownPublicEntries {
				if entry == parts[1] {
					w.WriteHeader(404)
					return true
				}
			}
		}
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		log.Printf("[Static] %q exists, but fails to open: %v", file, err)
		return true
	}

	// Try to serve index file
	if fi.IsDir() {
		// Redirect if missing trailing slash.
		if !strings.HasSuffix(req.URL.Path, "/") {
			http.Redirect(w, req, path.Clean(req.URL.Path+"/"), http.StatusFound)
			return true
		}

		f, err = opt.FileSystem.Open(file)
		if err != nil {
			return false // Discard error.
		}
		defer f.Close()

		fi, err = f.Stat()
		if err != nil || fi.IsDir() {
			return false
		}
	}

	if !opt.SkipLogging {
		log.Println("[Static] Serving " + file)
	}

	if httpcache.HandleEtagCache(req, w, fi) {
		return true
	}

	ServeContent(w, req, fi, fi.ModTime(), f)
	return true
}
<|endoftext|>


<commit_before>package erro

import (
	"fmt"
	"runtime"
)

// デバッグ用エラー。
type Tracer struct {
	cause error
	trace string
}

func (err *Tracer) Error() string {
	return err.cause.Error() + "\n" +
		//"--------------------------------------------------\n" +
		err.trace
}

func (err *Tracer) Cause() error {
	return err.cause
}

const traceLen = 8192

// スタックトレースを付加する。
// nil をそのまま返すので、 return Wrap(func() error) みたいな使い方ができる。
// 囲うのは最初だけでも良いし、既に Wrap されている場合はそのまま返すので、
// 最初かどうか分からなければ、毎回囲っても良い。
// スタックトレースの先頭はこの関数になるが、気にしない。
func Wrap(err error) error {
	if err == nil {
		return nil
	} else if _, ok := err.(*Tracer); ok {
		return err
	}

	buff := make([]byte, traceLen)
	len := runtime.Stack(buff, false)

	for len > 0 && buff[len-1] == '\n' {
		len--
	}

	return &Tracer{err, string(buff[:len])}
}

func Unwrap(err error) error {
	for {
		tr, ok := err.(*Tracer)
		if ok {
			err = tr.cause
		} else {
			return err
		}
	}
}

type Error string

func (err Error) Error() string {
	return string(err)
}

// 引数から 1 つの文字列をつくって最初のエラーにして、それを Wrap して返す。
// 文字列の成形は fmt.Print() 形式。
func New(a ...interface{}) error {
	return Wrap(Error(fmt.Sprint(a...)))
}
<commit_msg>スタックトレースだけを取得する関数を追加<commit_after>package erro

import (
	"fmt"
	"runtime"
)

// デバッグ用エラー。
type Tracer struct {
	cause error
	trace string
}

func (err *Tracer) Error() string {
	return err.cause.Error() + "\n" +
		//"--------------------------------------------------\n" +
		err.trace
}

func (err *Tracer) Cause() error {
	return err.cause
}

func (err *Tracer) Stack() string {
	return err.trace
}

const traceLen = 8192

// スタックトレースを付加する。
// nil をそのまま返すので、 return Wrap(func() error) みたいな使い方ができる。
// 囲うのは最初だけでも良いし、既に Wrap されている場合はそのまま返すので、
// 最初かどうか分からなければ、毎回囲っても良い。
// スタックトレースの先頭はこの関数になるが、気にしない。
func Wrap(err error) error {
	if err == nil {
		return nil
	} else if _, ok := err.(*Tracer); ok {
		return err
	}

	buff := make([]byte, traceLen)
	len := runtime.Stack(buff, false)

	for len > 0 && buff[len-1] == '\n' {
		len--
	}

	return &Tracer{err, string(buff[:len])}
}

func Unwrap(err error) error {
	for {
		tr, ok := err.(*Tracer)
		if ok {
			err = tr.cause
		} else {
			return err
		}
	}
}

type Error string

func (err Error) Error() string {
	return string(err)
}

// 引数から 1 つの文字列をつくって最初のエラーにして、それを Wrap して返す。
// 文字列の成形は fmt.Print() 形式。
func New(a ...interface{}) error {
	return Wrap(Error(fmt.Sprint(a...)))
}
<|endoftext|>


<commit_before>// Copyright 2014 The Azul3D 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 wav

import (
	"encoding/binary"
	"errors"
	"io"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	var sample audio.PCM8
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM8ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	var sample audio.PCM16
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM16ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample [3]uint8
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample audio.PCM32
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM32ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	var sample audio.F32
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			b.Set(read, audio.F64(sample))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	var sample audio.F64
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 8) // 8 == binary.Size(sample))
		if err != nil {
			return
		}

		b.Set(read, sample)
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	var sample audio.MuLaw
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.MuLawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	var sample audio.ALaw
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.ALawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)
	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	default:
		panic("invalid format")
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<commit_msg>Make use of encoding/binary fast-paths; See azul3d/audio#5<commit_after>// Copyright 2014 The Azul3D 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 wav

import (
	"encoding/binary"
	"errors"
	"io"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM8(sample)
		} else {
			f64 := audio.PCM8ToF64(audio.PCM8(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	var sample int16
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM16(sample)
		} else {
			f64 := audio.PCM16ToF64(audio.PCM16(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample [3]uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample int32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.PCM32(sample)
		} else {
			f64 := audio.PCM32ToF64(audio.PCM32(sample))
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	var sample float32
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.F32(sample)
		} else {
			b.Set(read, audio.F64(sample))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	var sample float64
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(8) // 8 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		b.Set(read, audio.F64(sample))
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.MuLaw(sample)
		} else {
			p16 := audio.MuLawToPCM16(audio.MuLaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	var sample uint8
	for read = 0; read < b.Len(); read++ {
		// Advance the reader.
		err = d.advance(1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		// Pull one sample from the reader.
		err = binary.Read(d.rd, binary.LittleEndian, &sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = audio.ALaw(sample)
		} else {
			p16 := audio.ALawToPCM16(audio.ALaw(sample))
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		default:
			panic("invalid bits per sample")
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)
	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	default:
		panic("invalid format")
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<|endoftext|>


<commit_before>// Copyright 2015 go-dockerclient 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the
// network already exists.
var ErrNetworkAlreadyExists = errors.New("network already exists")

// Network represents a network.
//
// See https://goo.gl/6GugX3 for more details.
type Network struct {
	Name       string
	ID         string `json:"Id"`
	Scope      string
	Driver     string
	IPAM       IPAMOptions
	Containers map[string]Endpoint
	Options    map[string]string
	Internal   bool
	EnableIPv6 bool `json:"EnableIPv6"`
}

// Endpoint contains network resources allocated and used for a container in a network
//
// See https://goo.gl/6GugX3 for more details.
type Endpoint struct {
	Name        string
	ID          string `json:"EndpointID"`
	MacAddress  string
	IPv4Address string
	IPv6Address string
}

// ListNetworks returns all networks.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) ListNetworks() ([]Network, error) {
	resp, err := c.do("GET", "/networks", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkFilterOpts is an aggregation of key=value that Docker
// uses to filter networks
type NetworkFilterOpts map[string]map[string]bool

// FilteredListNetworks returns all networks with the filters applied
//
// See goo.gl/zd2mx4 for more details.
func (c *Client) FilteredListNetworks(opts NetworkFilterOpts) ([]Network, error) {
	params := bytes.NewBuffer(nil)
	if err := json.NewEncoder(params).Encode(&opts); err != nil {
		return nil, err
	}
	path := "/networks?filters=" + params.String()
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkInfo returns information about a network by its ID.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) NetworkInfo(id string) (*Network, error) {
	path := "/networks/" + id
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return nil, &NoSuchNetwork{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var network Network
	if err := json.NewDecoder(resp.Body).Decode(&network); err != nil {
		return nil, err
	}
	return &network, nil
}

// CreateNetworkOptions specify parameters to the CreateNetwork function and
// (for now) is the expected body of the "create network" http request message
//
// See https://goo.gl/6GugX3 for more details.
type CreateNetworkOptions struct {
	Name           string                 `json:"Name" yaml:"Name"`
	CheckDuplicate bool                   `json:"CheckDuplicate" yaml:"CheckDuplicate"`
	Driver         string                 `json:"Driver" yaml:"Driver"`
	IPAM           IPAMOptions            `json:"IPAM" yaml:"IPAM"`
	Options        map[string]interface{} `json:"Options" yaml:"Options"`
	Internal       bool                   `json:"Internal yaml:"Internal""`
	EnableIPv6     bool                   `json:"EnableIPv6" yaml:"EnableIPv6"`
}

// IPAMOptions controls IP Address Management when creating a network
//
// See https://goo.gl/T8kRVH for more details.
type IPAMOptions struct {
	Driver string       `json:"Driver" yaml:"Driver"`
	Config []IPAMConfig `json:"Config" yaml:"Config"`
}

// IPAMConfig represents IPAM configurations
//
// See https://goo.gl/T8kRVH for more details.
type IPAMConfig struct {
	Subnet     string            `json:",omitempty"`
	IPRange    string            `json:",omitempty"`
	Gateway    string            `json:",omitempty"`
	AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}

// CreateNetwork creates a new network, returning the network instance,
// or an error in case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) {
	resp, err := c.do(
		"POST",
		"/networks/create",
		doOptions{
			data: opts,
		},
	)
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusConflict {
			return nil, ErrNetworkAlreadyExists
		}
		return nil, err
	}
	defer resp.Body.Close()

	type createNetworkResponse struct {
		ID string
	}
	var (
		network Network
		cnr     createNetworkResponse
	)
	if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
		return nil, err
	}

	network.Name = opts.Name
	network.ID = cnr.ID
	network.Driver = opts.Driver

	return &network, nil
}

// RemoveNetwork removes a network or returns an error in case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) RemoveNetwork(id string) error {
	resp, err := c.do("DELETE", "/networks/"+id, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetwork{ID: id}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NetworkConnectionOptions specify parameters to the ConnectNetwork and
// DisconnectNetwork function.
//
// See https://goo.gl/RV7BJU for more details.
type NetworkConnectionOptions struct {
	Container string

	// EndpointConfig is only applicable to the ConnectNetwork call
	EndpointConfig *EndpointConfig `json:"EndpointConfig,omitempty"`

	// Force is only applicable to the DisconnectNetwork call
	Force bool
}

// EndpointConfig stores network endpoint details
//
// See https://goo.gl/RV7BJU for more details.
type EndpointConfig struct {
	IPAMConfig          *EndpointIPAMConfig `json:"IPAMConfig,omitempty" yaml:"IPAMConfig,omitempty"`
	Links               []string            `json:"Links,omitempty" yaml:"Links,omitempty"`
	Aliases             []string            `json:"Aliases,omitempty" yaml:"Aliases,omitempty"`
	NetworkID           string              `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty"`
	EndpointID          string              `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty"`
	Gateway             string              `json:"Gateway,omitempty" yaml:"Gateway,omitempty"`
	IPAddress           string              `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
	IPPrefixLen         int                 `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
	IPv6Gateway         string              `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty"`
	GlobalIPv6Address   string              `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty"`
	GlobalIPv6PrefixLen int                 `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty"`
	MacAddress          string              `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
}

// EndpointIPAMConfig represents IPAM configurations for an
// endpoint
//
// See https://goo.gl/RV7BJU for more details.
type EndpointIPAMConfig struct {
	IPv4Address string `json:",omitempty"`
	IPv6Address string `json:",omitempty"`
}

// ConnectNetwork adds a container to a network or returns an error in case of
// failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) ConnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/connect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// DisconnectNetwork removes a container from a network or returns an error in
// case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) DisconnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/disconnect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NoSuchNetwork is the error returned when a given network does not exist.
type NoSuchNetwork struct {
	ID string
}

func (err *NoSuchNetwork) Error() string {
	return fmt.Sprintf("No such network: %s", err.ID)
}

// NoSuchNetworkOrContainer is the error returned when a given network or
// container does not exist.
type NoSuchNetworkOrContainer struct {
	NetworkID   string
	ContainerID string
}

func (err *NoSuchNetworkOrContainer) Error() string {
	return fmt.Sprintf("No such network (%s) or container (%s)", err.NetworkID, err.ContainerID)
}
<commit_msg>network: fix yaml struct tag<commit_after>// Copyright 2015 go-dockerclient 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the
// network already exists.
var ErrNetworkAlreadyExists = errors.New("network already exists")

// Network represents a network.
//
// See https://goo.gl/6GugX3 for more details.
type Network struct {
	Name       string
	ID         string `json:"Id"`
	Scope      string
	Driver     string
	IPAM       IPAMOptions
	Containers map[string]Endpoint
	Options    map[string]string
	Internal   bool
	EnableIPv6 bool `json:"EnableIPv6"`
}

// Endpoint contains network resources allocated and used for a container in a network
//
// See https://goo.gl/6GugX3 for more details.
type Endpoint struct {
	Name        string
	ID          string `json:"EndpointID"`
	MacAddress  string
	IPv4Address string
	IPv6Address string
}

// ListNetworks returns all networks.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) ListNetworks() ([]Network, error) {
	resp, err := c.do("GET", "/networks", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkFilterOpts is an aggregation of key=value that Docker
// uses to filter networks
type NetworkFilterOpts map[string]map[string]bool

// FilteredListNetworks returns all networks with the filters applied
//
// See goo.gl/zd2mx4 for more details.
func (c *Client) FilteredListNetworks(opts NetworkFilterOpts) ([]Network, error) {
	params := bytes.NewBuffer(nil)
	if err := json.NewEncoder(params).Encode(&opts); err != nil {
		return nil, err
	}
	path := "/networks?filters=" + params.String()
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkInfo returns information about a network by its ID.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) NetworkInfo(id string) (*Network, error) {
	path := "/networks/" + id
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return nil, &NoSuchNetwork{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var network Network
	if err := json.NewDecoder(resp.Body).Decode(&network); err != nil {
		return nil, err
	}
	return &network, nil
}

// CreateNetworkOptions specify parameters to the CreateNetwork function and
// (for now) is the expected body of the "create network" http request message
//
// See https://goo.gl/6GugX3 for more details.
type CreateNetworkOptions struct {
	Name           string                 `json:"Name" yaml:"Name"`
	CheckDuplicate bool                   `json:"CheckDuplicate" yaml:"CheckDuplicate"`
	Driver         string                 `json:"Driver" yaml:"Driver"`
	IPAM           IPAMOptions            `json:"IPAM" yaml:"IPAM"`
	Options        map[string]interface{} `json:"Options" yaml:"Options"`
	Internal       bool                   `json:"Internal" yaml:"Internal"`
	EnableIPv6     bool                   `json:"EnableIPv6" yaml:"EnableIPv6"`
}

// IPAMOptions controls IP Address Management when creating a network
//
// See https://goo.gl/T8kRVH for more details.
type IPAMOptions struct {
	Driver string       `json:"Driver" yaml:"Driver"`
	Config []IPAMConfig `json:"Config" yaml:"Config"`
}

// IPAMConfig represents IPAM configurations
//
// See https://goo.gl/T8kRVH for more details.
type IPAMConfig struct {
	Subnet     string            `json:",omitempty"`
	IPRange    string            `json:",omitempty"`
	Gateway    string            `json:",omitempty"`
	AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}

// CreateNetwork creates a new network, returning the network instance,
// or an error in case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) {
	resp, err := c.do(
		"POST",
		"/networks/create",
		doOptions{
			data: opts,
		},
	)
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusConflict {
			return nil, ErrNetworkAlreadyExists
		}
		return nil, err
	}
	defer resp.Body.Close()

	type createNetworkResponse struct {
		ID string
	}
	var (
		network Network
		cnr     createNetworkResponse
	)
	if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
		return nil, err
	}

	network.Name = opts.Name
	network.ID = cnr.ID
	network.Driver = opts.Driver

	return &network, nil
}

// RemoveNetwork removes a network or returns an error in case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) RemoveNetwork(id string) error {
	resp, err := c.do("DELETE", "/networks/"+id, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetwork{ID: id}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NetworkConnectionOptions specify parameters to the ConnectNetwork and
// DisconnectNetwork function.
//
// See https://goo.gl/RV7BJU for more details.
type NetworkConnectionOptions struct {
	Container string

	// EndpointConfig is only applicable to the ConnectNetwork call
	EndpointConfig *EndpointConfig `json:"EndpointConfig,omitempty"`

	// Force is only applicable to the DisconnectNetwork call
	Force bool
}

// EndpointConfig stores network endpoint details
//
// See https://goo.gl/RV7BJU for more details.
type EndpointConfig struct {
	IPAMConfig          *EndpointIPAMConfig `json:"IPAMConfig,omitempty" yaml:"IPAMConfig,omitempty"`
	Links               []string            `json:"Links,omitempty" yaml:"Links,omitempty"`
	Aliases             []string            `json:"Aliases,omitempty" yaml:"Aliases,omitempty"`
	NetworkID           string              `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty"`
	EndpointID          string              `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty"`
	Gateway             string              `json:"Gateway,omitempty" yaml:"Gateway,omitempty"`
	IPAddress           string              `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
	IPPrefixLen         int                 `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
	IPv6Gateway         string              `json:"IPv6Gateway,omitempty" yaml:"IPv6Gateway,omitempty"`
	GlobalIPv6Address   string              `json:"GlobalIPv6Address,omitempty" yaml:"GlobalIPv6Address,omitempty"`
	GlobalIPv6PrefixLen int                 `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty"`
	MacAddress          string              `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
}

// EndpointIPAMConfig represents IPAM configurations for an
// endpoint
//
// See https://goo.gl/RV7BJU for more details.
type EndpointIPAMConfig struct {
	IPv4Address string `json:",omitempty"`
	IPv6Address string `json:",omitempty"`
}

// ConnectNetwork adds a container to a network or returns an error in case of
// failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) ConnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/connect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// DisconnectNetwork removes a container from a network or returns an error in
// case of failure.
//
// See https://goo.gl/6GugX3 for more details.
func (c *Client) DisconnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/disconnect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NoSuchNetwork is the error returned when a given network does not exist.
type NoSuchNetwork struct {
	ID string
}

func (err *NoSuchNetwork) Error() string {
	return fmt.Sprintf("No such network: %s", err.ID)
}

// NoSuchNetworkOrContainer is the error returned when a given network or
// container does not exist.
type NoSuchNetworkOrContainer struct {
	NetworkID   string
	ContainerID string
}

func (err *NoSuchNetworkOrContainer) Error() string {
	return fmt.Sprintf("No such network (%s) or container (%s)", err.NetworkID, err.ContainerID)
}
<|endoftext|>


<commit_before>/**
 * (C) Copyright 2014, Deft Labs
 *
 * 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 dlshared

import "net/http"

type RecordingResponseWriter struct {
	header http.Header
	HeaderCode int
	Data []byte
}

func (self *RecordingResponseWriter) reset() {
	self.header = make(map[string][]string)
	self.HeaderCode = 0
	self.Data = nil
}

func (self *RecordingResponseWriter) Header() http.Header {
	return self.header
}

func (self *RecordingResponseWriter) Write(data []byte) (int, error) {
	self.Data = append(self.Data, data...)
	return len(data), nil
}

func NewRecordingResponseWriter() *RecordingResponseWriter {
	return &RecordingResponseWriter{ header : make(map[string][]string) }
}

func (self *RecordingResponseWriter) WriteHeader(code int) {
	self.HeaderCode = code
}

<commit_msg>added conv method for creating a very basicy http request.<commit_after>/**
 * (C) Copyright 2014, Deft Labs
 *
 * 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 dlshared

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

func NewTestHttpPostRequest() *http.Request {
	request := &http.Request{ Method : "POST" }
	request.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
	return request
}

type RecordingResponseWriter struct {
	header http.Header
	HeaderCode int
	Data []byte
}

func (self *RecordingResponseWriter) reset() {
	self.header = make(map[string][]string)
	self.HeaderCode = 0
	self.Data = nil
}

func (self *RecordingResponseWriter) Header() http.Header {
	return self.header
}

func (self *RecordingResponseWriter) Write(data []byte) (int, error) {
	self.Data = append(self.Data, data...)
	return len(data), nil
}

func NewRecordingResponseWriter() *RecordingResponseWriter {
	return &RecordingResponseWriter{ header : make(map[string][]string) }
}

func (self *RecordingResponseWriter) WriteHeader(code int) {
	self.HeaderCode = code
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/deis/deisctl/client"
	"github.com/deis/deisctl/cmd"
	"github.com/deis/deisctl/constant"
	"github.com/deis/deisctl/updatectl"
	"github.com/deis/deisctl/utils"
	docopt "github.com/docopt/docopt-go"
)

func exit(err error, code int) {
	fmt.Printf("Error: %v\n", err)
	os.Exit(code)
}

func Update(args []string) {

	if len(args) != 4 {
		fmt.Println("unsufficient args")
		fmt.Println("usage:  deisctl update instance deis")
		return
	}
	if args[2] != "instance" && args[3] != "deis" {
		fmt.Println("wrong args ")
		fmt.Println("usage:  deisctl update instance deis")
		return
	}
	Args := []string{
		"instance",
		"deis",
		"--clients-per-app=1",
		"--min-sleep=5",
		"--max-sleep=10",
	}
	if err := utils.Execute(constant.HooksDir + "pre-update"); err != nil {
		fmt.Println("pre-updatehook failed")
	}
	updatectl.Update(Args)
	if err := utils.Execute(constant.HooksDir + "post-update"); err != nil {
		fmt.Println("post-updatehook failed")
	}
}

func setGlobalFlags(args map[string]interface{}) {
	client.Flags.Debug = args["--debug"].(bool)
	client.Flags.Version = args["--version"].(bool)
	client.Flags.Endpoint = args["--endpoint"].(string)
	client.Flags.EtcdKeyPrefix = args["--etcd-key-prefix"].(string)
	client.Flags.EtcdKeyFile = args["--etcd-keyfile"].(string)
	client.Flags.EtcdCertFile = args["--etcd-certfile"].(string)
	client.Flags.EtcdCAFile = args["--etcd-cafile"].(string)
	//client.Flags.UseAPI = args["--experimental-api"].(bool)
	client.Flags.KnownHostsFile = args["--known-hosts-file"].(string)
	client.Flags.StrictHostKeyChecking = args["--strict-host-key-checking"].(bool)
	timeout, _ := strconv.ParseFloat(args["--request-timeout"].(string), 64)
	client.Flags.RequestTimeout = timeout
	tunnel := args["--tunnel"].(string)
	if tunnel != "" {
		client.Flags.Tunnel = tunnel
	} else {
		client.Flags.Tunnel = os.Getenv("FLEETCTL_TUNNEL")
	}
}

func main() {
	usage := `Deis Control Utility

Usage:
  deisctl <command> [<target>...] [options]

Example Commands:

  deisctl install
  deisctl uninstall
  deisctl list-units
  deisctl list-unit-files
  deisctl scale router=2
  deisctl start router@2
  deisctl stop router builder
  deisctl status controller
  deisctl journal controller

Options:
  --debug                     print debug information to stderr
  --version                   print version and exit
  --endpoint=<url>            etcd endpoint for fleet [default: http://127.0.0.1:4001]
  --etcd-key-prefix=<path>    keyspace for fleet data in etcd [default: /_coreos.com/fleet/]
  --etcd-keyfile=<path>       etcd key file authentication [default: ]
  --etcd-certfile=<path>      etcd cert file authentication [default: ]
  --etcd-cafile=<path>        etcd CA file authentication [default: ]
  --known-hosts-file=<path>   file used to store remote machine fingerprints [default: ~/.fleetctl/known_hosts]
  --strict-host-key-checking  verify SSH host keys [default: true]
  --tunnel=<host>             establish an SSH tunnel for communication with fleet and etcd [default: ]
  --request-timeout=<secs>    amount of time to allow a single request before considering it failed. [default: 3.0]
`
	// parse command-line arguments
	args, err := docopt.Parse(usage, nil, true, "", true)
	if err != nil {
		exit(err, 2)
	}
	command := args["<command>"]
	targets := args["<target>"].([]string)
	setGlobalFlags(args)
	// construct a client
	c, err := client.NewClient()
	if err != nil {
		exit(err, 1)
	}
	// dispatch the command
	switch command {
	case "list":
		err = cmd.ListUnits(c)
	case "list-units":
		err = cmd.ListUnits(c)
	case "list-unit-files":
		err = cmd.ListUnitFiles(c)
	case "scale":
		err = cmd.Scale(c, targets)
	case "start":
		err = cmd.Start(c, targets)
	case "stop":
		err = cmd.Stop(c, targets)
	case "status":
		err = cmd.Status(c, targets)
	case "journal":
		err = cmd.Journal(c, targets)
	case "install":
		err = cmd.Install(c, targets)
	case "uninstall":
		err = cmd.Uninstall(c, targets)
	case "update":
		Update(os.Args)
	default:
		fmt.Printf(usage)
		os.Exit(2)
	}
	if err != nil {
		exit(err, 1)
	}
}
<commit_msg>chore(flags): switch to DEISCTL_TUNNEL<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/deis/deisctl/client"
	"github.com/deis/deisctl/cmd"
	"github.com/deis/deisctl/constant"
	"github.com/deis/deisctl/updatectl"
	"github.com/deis/deisctl/utils"
	docopt "github.com/docopt/docopt-go"
)

func exit(err error, code int) {
	fmt.Printf("Error: %v\n", err)
	os.Exit(code)
}

func Update(args []string) {

	if len(args) != 4 {
		fmt.Println("unsufficient args")
		fmt.Println("usage:  deisctl update instance deis")
		return
	}
	if args[2] != "instance" && args[3] != "deis" {
		fmt.Println("wrong args ")
		fmt.Println("usage:  deisctl update instance deis")
		return
	}
	Args := []string{
		"instance",
		"deis",
		"--clients-per-app=1",
		"--min-sleep=5",
		"--max-sleep=10",
	}
	if err := utils.Execute(constant.HooksDir + "pre-update"); err != nil {
		fmt.Println("pre-updatehook failed")
	}
	updatectl.Update(Args)
	if err := utils.Execute(constant.HooksDir + "post-update"); err != nil {
		fmt.Println("post-updatehook failed")
	}
}

func setGlobalFlags(args map[string]interface{}) {
	client.Flags.Debug = args["--debug"].(bool)
	client.Flags.Version = args["--version"].(bool)
	client.Flags.Endpoint = args["--endpoint"].(string)
	client.Flags.EtcdKeyPrefix = args["--etcd-key-prefix"].(string)
	client.Flags.EtcdKeyFile = args["--etcd-keyfile"].(string)
	client.Flags.EtcdCertFile = args["--etcd-certfile"].(string)
	client.Flags.EtcdCAFile = args["--etcd-cafile"].(string)
	//client.Flags.UseAPI = args["--experimental-api"].(bool)
	client.Flags.KnownHostsFile = args["--known-hosts-file"].(string)
	client.Flags.StrictHostKeyChecking = args["--strict-host-key-checking"].(bool)
	timeout, _ := strconv.ParseFloat(args["--request-timeout"].(string), 64)
	client.Flags.RequestTimeout = timeout
	tunnel := args["--tunnel"].(string)
	if tunnel != "" {
		client.Flags.Tunnel = tunnel
	} else {
		client.Flags.Tunnel = os.Getenv("DEISCTL_TUNNEL")
	}
}

func main() {
	usage := `Deis Control Utility

Usage:
  deisctl <command> [<target>...] [options]

Example Commands:

  deisctl install
  deisctl uninstall
  deisctl list-units
  deisctl list-unit-files
  deisctl scale router=2
  deisctl start router@2
  deisctl stop router builder
  deisctl status controller
  deisctl journal controller

Options:
  --debug                     print debug information to stderr
  --version                   print version and exit
  --endpoint=<url>            etcd endpoint for fleet [default: http://127.0.0.1:4001]
  --etcd-key-prefix=<path>    keyspace for fleet data in etcd [default: /_coreos.com/fleet/]
  --etcd-keyfile=<path>       etcd key file authentication [default: ]
  --etcd-certfile=<path>      etcd cert file authentication [default: ]
  --etcd-cafile=<path>        etcd CA file authentication [default: ]
  --known-hosts-file=<path>   file used to store remote machine fingerprints [default: ~/.fleetctl/known_hosts]
  --strict-host-key-checking  verify SSH host keys [default: true]
  --tunnel=<host>             establish an SSH tunnel for communication with fleet and etcd [default: ]
  --request-timeout=<secs>    amount of time to allow a single request before considering it failed. [default: 3.0]
`
	// parse command-line arguments
	args, err := docopt.Parse(usage, nil, true, "", true)
	if err != nil {
		exit(err, 2)
	}
	command := args["<command>"]
	targets := args["<target>"].([]string)
	setGlobalFlags(args)
	// construct a client
	c, err := client.NewClient()
	if err != nil {
		exit(err, 1)
	}
	// dispatch the command
	switch command {
	case "list":
		err = cmd.ListUnits(c)
	case "list-units":
		err = cmd.ListUnits(c)
	case "list-unit-files":
		err = cmd.ListUnitFiles(c)
	case "scale":
		err = cmd.Scale(c, targets)
	case "start":
		err = cmd.Start(c, targets)
	case "stop":
		err = cmd.Stop(c, targets)
	case "status":
		err = cmd.Status(c, targets)
	case "journal":
		err = cmd.Journal(c, targets)
	case "install":
		err = cmd.Install(c, targets)
	case "uninstall":
		err = cmd.Uninstall(c, targets)
	case "update":
		Update(os.Args)
	default:
		fmt.Printf(usage)
		os.Exit(2)
	}
	if err != nil {
		exit(err, 1)
	}
}
<|endoftext|>


<commit_before>package raw_socket

import (
	"log"
	"sort"
	"time"
)

const MSG_EXPIRE = 300000 * time.Millisecond

// TCPMessage ensure that all TCP packets for given request is received, and processed in right sequence
// Its needed because all TCP message can be fragmented or re-transmitted
//
// Each TCP Packet have 2 ids: acknowledgment - message_id, and sequence - packet_id
// Message can be compiled from unique packets with same message_id which sorted by sequence
// Message is received if we didn't receive any packets for 200ms
type TCPMessage struct {
	ID      string // Message ID
	packets []*TCPPacket

	timer *time.Timer // Used for expire check

	c_packets chan *TCPPacket

	c_del_message chan *TCPMessage
}

// NewTCPMessage pointer created from a Acknowledgment number and a channel of messages readuy to be deleted
func NewTCPMessage(ID string, c_del chan *TCPMessage) (msg *TCPMessage) {
	msg = &TCPMessage{ID: ID}

	msg.c_packets = make(chan *TCPPacket)
	msg.c_del_message = c_del // used for notifying that message completed or expired

	// Every time we receive packet we reset this timer
	msg.timer = time.AfterFunc(MSG_EXPIRE, msg.Timeout)

	go msg.listen()

	return
}

func (t *TCPMessage) listen() {
	for {
		select {
		case packet, more := <-t.c_packets:
			if more {
				t.AddPacket(packet)
			} else {
				// Stop loop if channel closed
				return
			}
		}
	}
}

// Timeout notifies message to stop listening, close channel and message ready to be sent
func (t *TCPMessage) Timeout() {
	close(t.c_packets)   // Notify to stop listen loop and close channel
	t.c_del_message <- t // Notify RAWListener that message is ready to be send to replay server
}

// Bytes sorts packets in right orders and return message content
func (t *TCPMessage) Bytes() (output []byte) {
	mk := make([]int, len(t.packets))

	i := 0
	for k, _ := range t.packets {
		mk[i] = k
		i++
	}

	sort.Ints(mk)

	for _, k := range mk {
		output = append(output, t.packets[k].Data...)
	}

	return
}

// AddPacket to the message and ensure packet uniqueness
// TCP allows that packet can be re-send multiple times
func (t *TCPMessage) AddPacket(packet *TCPPacket) {
	packetFound := false

	for _, pkt := range t.packets {
		if packet.Seq == pkt.Seq {
			packetFound = true
			break
		}
	}

	if packetFound {
		log.Println("Received packet with same sequence")
	} else {
		t.packets = append(t.packets, packet)
	}

	// Reset message timeout timer
	t.timer.Reset(MSG_EXPIRE)
}
<commit_msg>20 second timeout on a message<commit_after>package raw_socket

import (
	"log"
	"sort"
	"time"
)

const MSG_EXPIRE = 20000 * time.Millisecond

// TCPMessage ensure that all TCP packets for given request is received, and processed in right sequence
// Its needed because all TCP message can be fragmented or re-transmitted
//
// Each TCP Packet have 2 ids: acknowledgment - message_id, and sequence - packet_id
// Message can be compiled from unique packets with same message_id which sorted by sequence
// Message is received if we didn't receive any packets for 20000ms
type TCPMessage struct {
	ID      string // Message ID
	packets []*TCPPacket

	timer *time.Timer // Used for expire check

	c_packets chan *TCPPacket

	c_del_message chan *TCPMessage
}

// NewTCPMessage pointer created from a Acknowledgment number and a channel of messages readuy to be deleted
func NewTCPMessage(ID string, c_del chan *TCPMessage) (msg *TCPMessage) {
	msg = &TCPMessage{ID: ID}

	msg.c_packets = make(chan *TCPPacket)
	msg.c_del_message = c_del // used for notifying that message completed or expired

	// Every time we receive packet we reset this timer
	msg.timer = time.AfterFunc(MSG_EXPIRE, msg.Timeout)

	go msg.listen()

	return
}

func (t *TCPMessage) listen() {
	for {
		select {
		case packet, more := <-t.c_packets:
			if more {
				t.AddPacket(packet)
			} else {
				// Stop loop if channel closed
				return
			}
		}
	}
}

// Timeout notifies message to stop listening, close channel and message ready to be sent
func (t *TCPMessage) Timeout() {
	close(t.c_packets)   // Notify to stop listen loop and close channel
	t.c_del_message <- t // Notify RAWListener that message is ready to be send to replay server
}

// Bytes sorts packets in right orders and return message content
func (t *TCPMessage) Bytes() (output []byte) {
	mk := make([]int, len(t.packets))

	i := 0
	for k, _ := range t.packets {
		mk[i] = k
		i++
	}

	sort.Ints(mk)

	for _, k := range mk {
		output = append(output, t.packets[k].Data...)
	}

	return
}

// AddPacket to the message and ensure packet uniqueness
// TCP allows that packet can be re-send multiple times
func (t *TCPMessage) AddPacket(packet *TCPPacket) {
	packetFound := false

	for _, pkt := range t.packets {
		if packet.Seq == pkt.Seq {
			packetFound = true
			break
		}
	}

	if packetFound {
		log.Println("Received packet with same sequence")
	} else {
		t.packets = append(t.packets, packet)
	}

	// Reset message timeout timer
	t.timer.Reset(MSG_EXPIRE)
}
<|endoftext|>


<commit_before>package notable

import (
	"fmt"
	slack "github.com/harvesthq/notable/Godeps/_workspace/src/github.com/nlopes/slack"
	"log"
	"regexp"
	"strings"
)

func Record(authorID string, category string, text string, channel string, slackToken string) {
	var authorName, avatarURL string

	api := slack.New(slackToken)
	user, err := api.GetUserInfo(authorID)
	text, category = effectiveTextAndCategory(text, category)

	if err == nil {
		authorName = user.Profile.RealName
		avatarURL = user.Profile.Image24
	} else {
		fmt.Printf("Error getting author information from Slack: %s\n", err)
		authorName = authorID
		avatarURL = ""
	}

	text = strings.TrimSpace(strings.TrimPrefix(text, category))
	note := Note{authorName, avatarURL, category, text}

	AddNote(note)

	if channel != "testbotroom" {
		notifyRoom(api, note)
	}
}

func effectiveTextAndCategory(text string, category string) (string, string) {
	hashtag := extractHashtag(text)

	if len(hashtag) > 0 {
		category = hashtag
		text = strings.TrimSuffix(text, hashtag)
	}

	if len(category) == 0 {
		category = "notable"
	}

	return text, strings.Trim(category, ":# ")
}

func extractHashtag(text string) string {
	pattern := regexp.MustCompile(` #\w+\z`)

	return pattern.FindString(text)
}

func notifyRoom(api *slack.Client, note Note) {
	var attachments []slack.Attachment
	avatar := slack.Attachment{Text: note.Text}
	params := slack.PostMessageParameters{IconURL: note.AvatarURL, Attachments: append(attachments, avatar)}
	_, _, err := api.PostMessage("#testbotroom", "", params)
	check(err)
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Adding category to notification<commit_after>package notable

import (
	"fmt"
	slack "github.com/harvesthq/notable/Godeps/_workspace/src/github.com/nlopes/slack"
	"log"
	"regexp"
	"strings"
)

func Record(authorID string, category string, text string, channel string, slackToken string) {
	var authorName, avatarURL string

	api := slack.New(slackToken)
	user, err := api.GetUserInfo(authorID)
	text, category = effectiveTextAndCategory(text, category)

	if err == nil {
		authorName = user.Profile.RealName
		avatarURL = user.Profile.Image24
	} else {
		fmt.Printf("Error getting author information from Slack: %s\n", err)
		authorName = authorID
		avatarURL = ""
	}

	text = strings.TrimSpace(strings.TrimPrefix(text, category))
	note := Note{authorName, avatarURL, category, text}

	AddNote(note)

	if channel != "testbotroom" {
		notifyRoom(api, note)
	}
}

func effectiveTextAndCategory(text string, category string) (string, string) {
	hashtag := extractHashtag(text)

	if len(hashtag) > 0 {
		category = hashtag
		text = strings.TrimSuffix(text, hashtag)
	}

	if len(category) == 0 {
		category = "notable"
	}

	return text, strings.Trim(category, ":# ")
}

func extractHashtag(text string) string {
	pattern := regexp.MustCompile(` #\w+\z`)

	return pattern.FindString(text)
}

func notifyRoom(api *slack.Client, note Note) {
	var attachments []slack.Attachment
	avatar := slack.Attachment{Text: note.Text}
	params := slack.PostMessageParameters{Username: note.Category, IconURL: note.AvatarURL, Attachments: append(attachments, avatar)}
	_, _, err := api.PostMessage("#testbotroom", "", params)
	check(err)
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package instance_types

import (
	"fmt"
	"path"
	"runtime"

	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/gce"
)

const (
	GS_URL_GITCONFIG = "gs://skia-buildbots/artifacts/bots/.gitconfig"
	GS_URL_NETRC     = "gs://skia-buildbots/artifacts/bots/.netrc"
	GS_URL_BOTO      = "gs://skia-buildbots/artifacts/bots/.boto-ct"

	CT_WORKER_PREFIX = "ct-gce-"
)

// Base config for CT GCE instances.
func CT20170602(name string) *gce.Instance {
	_, filename, _, _ := runtime.Caller(0)
	dir := path.Dir(path.Dir(filename))
	return &gce.Instance{
		BootDisk: &gce.Disk{
			Name:        name,
			SourceImage: "skia-swarming-v3",
			Type:        gce.DISK_TYPE_PERSISTENT_STANDARD,
		},
		DataDisk: &gce.Disk{
			Name:   fmt.Sprintf("%s-data", name),
			SizeGb: 300,
			Type:   gce.DISK_TYPE_PERSISTENT_STANDARD,
		},
		GSDownloads: map[string]string{
			"/home/chrome-bot/.gitconfig": GS_URL_GITCONFIG,
			"/home/chrome-bot/.netrc":     GS_URL_NETRC,
			"/home/chrome-bot/.boto":      GS_URL_BOTO,
		},
		MachineType:       gce.MACHINE_TYPE_HIGHMEM_2,
		Metadata:          map[string]string{},
		MetadataDownloads: map[string]string{},
		Name:              name,
		Os:                gce.OS_LINUX,
		ServiceAccount:    gce.SERVICE_ACCOUNT_CHROME_SWARMING,
		Scopes: []string{
			auth.SCOPE_FULL_CONTROL,
			auth.SCOPE_USERINFO_EMAIL,
			auth.SCOPE_PUBSUB,
		},
		SetupScript: path.Join(dir, "setup-script.sh"),
		Tags:        []string{"use-swarming-auth"},
		User:        gce.USER_CHROME_BOT,
	}
}

// CT GCE instances.
func CTInstance(num int) *gce.Instance {
	return CT20170602(fmt.Sprintf("%s%03d", CT_WORKER_PREFIX, num))
}

// CT Android Builder GCE instances.
func CTAndroidBuilderInstance(num int) *gce.Instance {
	vm := CT20170602(fmt.Sprintf("ct-android-builder-%03d", num))
	vm.MachineType = "custom-32-70400"
	return vm
}

// CT Linux Builder GCE instances.
func CTLinuxBuilderInstance(num int) *gce.Instance {
	vm := CT20170602(fmt.Sprintf("ct-linux-builder-%03d", num))
	vm.MachineType = "custom-32-70400"
	return vm
}
<commit_msg>Rename CT .netrc file.<commit_after>package instance_types

import (
	"fmt"
	"path"
	"runtime"

	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/gce"
)

const (
	GS_URL_GITCONFIG = "gs://skia-buildbots/artifacts/bots/.gitconfig"
	GS_URL_NETRC     = "gs://skia-buildbots/artifacts/bots/.netrc_ct"
	GS_URL_BOTO      = "gs://skia-buildbots/artifacts/bots/.boto-ct"

	CT_WORKER_PREFIX = "ct-gce-"
)

// Base config for CT GCE instances.
func CT20170602(name string) *gce.Instance {
	_, filename, _, _ := runtime.Caller(0)
	dir := path.Dir(path.Dir(filename))
	return &gce.Instance{
		BootDisk: &gce.Disk{
			Name:        name,
			SourceImage: "skia-swarming-v3",
			Type:        gce.DISK_TYPE_PERSISTENT_STANDARD,
		},
		DataDisk: &gce.Disk{
			Name:   fmt.Sprintf("%s-data", name),
			SizeGb: 300,
			Type:   gce.DISK_TYPE_PERSISTENT_STANDARD,
		},
		GSDownloads: map[string]string{
			"/home/chrome-bot/.gitconfig": GS_URL_GITCONFIG,
			"/home/chrome-bot/.netrc":     GS_URL_NETRC,
			"/home/chrome-bot/.boto":      GS_URL_BOTO,
		},
		MachineType:       gce.MACHINE_TYPE_HIGHMEM_2,
		Metadata:          map[string]string{},
		MetadataDownloads: map[string]string{},
		Name:              name,
		Os:                gce.OS_LINUX,
		ServiceAccount:    gce.SERVICE_ACCOUNT_CHROME_SWARMING,
		Scopes: []string{
			auth.SCOPE_FULL_CONTROL,
			auth.SCOPE_USERINFO_EMAIL,
			auth.SCOPE_PUBSUB,
		},
		SetupScript: path.Join(dir, "setup-script.sh"),
		Tags:        []string{"use-swarming-auth"},
		User:        gce.USER_CHROME_BOT,
	}
}

// CT GCE instances.
func CTInstance(num int) *gce.Instance {
	return CT20170602(fmt.Sprintf("%s%03d", CT_WORKER_PREFIX, num))
}

// CT Android Builder GCE instances.
func CTAndroidBuilderInstance(num int) *gce.Instance {
	vm := CT20170602(fmt.Sprintf("ct-android-builder-%03d", num))
	vm.MachineType = "custom-32-70400"
	return vm
}

// CT Linux Builder GCE instances.
func CTLinuxBuilderInstance(num int) *gce.Instance {
	vm := CT20170602(fmt.Sprintf("ct-linux-builder-%03d", num))
	vm.MachineType = "custom-32-70400"
	return vm
}
<|endoftext|>


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

// Except for this comment, this file is a verbatim copy of the file
// with the same name in $GOROOT/src/go/internal/gccgoimporter without
// the import of "testenv".

package gccgoimporter

import (
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"testing"
)

type importerTest struct {
	pkgpath, name, want, wantval string
	wantinits                    []string
}

func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) {
	pkg, err := imp(make(map[string]*types.Package), test.pkgpath, ".", nil)
	if err != nil {
		t.Error(err)
		return
	}

	if test.name != "" {
		obj := pkg.Scope().Lookup(test.name)
		if obj == nil {
			t.Errorf("%s: object not found", test.name)
			return
		}

		got := types.ObjectString(obj, types.RelativeTo(pkg))
		if got != test.want {
			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
		}

		if test.wantval != "" {
			gotval := obj.(*types.Const).Val().String()
			if gotval != test.wantval {
				t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
			}
		}
	}

	if len(test.wantinits) > 0 {
		initdata := initmap[pkg]
		found := false
		// Check that the package's own init function has the package's priority
		for _, pkginit := range initdata.Inits {
			if pkginit.InitFunc == test.wantinits[0] {
				found = true
				break
			}
		}

		if !found {
			t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
		}

		// FIXME: the original version of this test was written against
		// the v1 export data scheme for capturing init functions, so it
		// verified the priority values. We moved away from the priority
		// scheme some time ago; it is not clear how much work it would be
		// to validate the new init export data.
	}
}

var importerTests = [...]importerTest{
	{pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
	{pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1 + -1i)"},
	{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1 + 1i)"},
	{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
	{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
	{pkgpath: "conversions", name: "Bits", want: "const Bits Units", wantval: `"bits"`},
	{pkgpath: "time", name: "Duration", want: "type Duration int64"},
	{pkgpath: "time", name: "Nanosecond", want: "const Nanosecond Duration", wantval: "1"},
	{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
	{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
	{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import"}},
	{pkgpath: "importsar", name: "Hello", want: "var Hello string"},
	{pkgpath: "aliases", name: "A14", want: "type A14 = func(int, T0) chan T2"},
	{pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
	{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
	{pkgpath: "issue27856", name: "M", want: "type M struct{E F}"},
	{pkgpath: "v1reflect", name: "Type", want: "type Type interface{Align() int; AssignableTo(u Type) bool; Bits() int; ChanDir() ChanDir; Elem() Type; Field(i int) StructField; FieldAlign() int; FieldByIndex(index []int) StructField; FieldByName(name string) (StructField, bool); FieldByNameFunc(match func(string) bool) (StructField, bool); Implements(u Type) bool; In(i int) Type; IsVariadic() bool; Key() Type; Kind() Kind; Len() int; Method(int) Method; MethodByName(string) (Method, bool); Name() string; NumField() int; NumIn() int; NumMethod() int; NumOut() int; Out(i int) Type; PkgPath() string; Size() uintptr; String() string; common() *commonType; rawString() string; runtimeType() *runtimeType; uncommon() *uncommonType}"},
	{pkgpath: "nointerface", name: "I", want: "type I int"},
	{pkgpath: "issue29198", name: "FooServer", want: "type FooServer struct{FooServer *FooServer; user string; ctx context.Context}"},
	{pkgpath: "issue30628", name: "Apple", want: "type Apple struct{hey sync.RWMutex; x int; RQ [517]struct{Count uintptr; NumBytes uintptr; Last uintptr}}"},
	{pkgpath: "issue31540", name: "S", want: "type S struct{b int; map[Y]Z}"}}

func TestGoxImporter(t *testing.T) {
	testenv.MustHaveExec(t) // this is to skip nacl, js
	initmap := make(map[*types.Package]InitData)
	imp := GetImporter([]string{"testdata"}, initmap)

	for _, test := range importerTests {
		runImporterTest(t, imp, initmap, &test)
	}
}

// gccgoPath returns a path to gccgo if it is present (either in
// path or specified via GCCGO environment variable), or an
// empty string if no gccgo is available.
func gccgoPath() string {
	gccgoname := os.Getenv("GCCGO")
	if gccgoname == "" {
		gccgoname = "gccgo"
	}
	if gpath, gerr := exec.LookPath(gccgoname); gerr == nil {
		return gpath
	}
	return ""
}

func TestObjImporter(t *testing.T) {
	// This test relies on gccgo being around.
	gpath := gccgoPath()
	if gpath == "" {
		t.Skip("This test needs gccgo")
	}

	verout, err := exec.Command(gpath, "--version").CombinedOutput()
	if err != nil {
		t.Logf("%s", verout)
		t.Fatal(err)
	}
	vers := regexp.MustCompile(`([0-9]+)\.([0-9]+)`).FindSubmatch(verout)
	if len(vers) == 0 {
		t.Fatalf("could not find version number in %s", verout)
	}
	major, err := strconv.Atoi(string(vers[1]))
	if err != nil {
		t.Fatal(err)
	}
	minor, err := strconv.Atoi(string(vers[2]))
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("gccgo version %d.%d", major, minor)

	tmpdir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatal(err)
	}
	initmap := make(map[*types.Package]InitData)
	imp := GetImporter([]string{tmpdir}, initmap)

	artmpdir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatal(err)
	}
	arinitmap := make(map[*types.Package]InitData)
	arimp := GetImporter([]string{artmpdir}, arinitmap)

	for _, test := range importerTests {
		// Support for type aliases was added in GCC 7.
		if test.pkgpath == "aliases" || test.pkgpath == "issue27856" || test.pkgpath == "issue29198" {
			if major < 7 {
				t.Logf("skipping %q: not supported before gccgo version 7", test.pkgpath)
				continue
			}
		}

		gofile := filepath.Join("testdata", test.pkgpath+".go")
		if _, err := os.Stat(gofile); os.IsNotExist(err) {
			continue
		}
		ofile := filepath.Join(tmpdir, test.pkgpath+".o")
		afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a")

		cmd := exec.Command(gpath, "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile)
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Logf("%s", out)
			t.Fatalf("gccgo %s failed: %s", gofile, err)
		}

		runImporterTest(t, imp, initmap, &test)

		cmd = exec.Command("ar", "cr", afile, ofile)
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Logf("%s", out)
			t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err)
		}

		runImporterTest(t, arimp, arinitmap, &test)

		if err = os.Remove(ofile); err != nil {
			t.Fatal(err)
		}
		if err = os.Remove(afile); err != nil {
			t.Fatal(err)
		}
	}

	if err = os.Remove(tmpdir); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>go/internal/gccgoimporter: update importer tests to match std lib version<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Except for this comment, this file is a verbatim copy of the file
// with the same name in $GOROOT/src/go/internal/gccgoimporter without
// the import of "testenv".

package gccgoimporter

import (
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"testing"
)

type importerTest struct {
	pkgpath, name, want, wantval string
	wantinits                    []string
	gccgoVersion                 int // minimum gccgo version (0 => any)
}

func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) {
	pkg, err := imp(make(map[string]*types.Package), test.pkgpath, ".", nil)
	if err != nil {
		t.Error(err)
		return
	}

	if test.name != "" {
		obj := pkg.Scope().Lookup(test.name)
		if obj == nil {
			t.Errorf("%s: object not found", test.name)
			return
		}

		got := types.ObjectString(obj, types.RelativeTo(pkg))
		if got != test.want {
			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
		}

		if test.wantval != "" {
			gotval := obj.(*types.Const).Val().String()
			if gotval != test.wantval {
				t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
			}
		}
	}

	if len(test.wantinits) > 0 {
		initdata := initmap[pkg]
		found := false
		// Check that the package's own init function has the package's priority
		for _, pkginit := range initdata.Inits {
			if pkginit.InitFunc == test.wantinits[0] {
				found = true
				break
			}
		}

		if !found {
			t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
		}

		// FIXME: the original version of this test was written against
		// the v1 export data scheme for capturing init functions, so it
		// verified the priority values. We moved away from the priority
		// scheme some time ago; it is not clear how much work it would be
		// to validate the new init export data.
	}
}

// When adding tests to this list, be sure to set the 'gccgoVersion'
// field if the testcases uses a "recent" Go addition (ex: aliases).
var importerTests = [...]importerTest{
	{pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
	{pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1 + -1i)"},
	{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1 + 1i)"},
	{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
	{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
	{pkgpath: "conversions", name: "Bits", want: "const Bits Units", wantval: `"bits"`},
	{pkgpath: "time", name: "Duration", want: "type Duration int64"},
	{pkgpath: "time", name: "Nanosecond", want: "const Nanosecond Duration", wantval: "1"},
	{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
	{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
	{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import"}},
	{pkgpath: "importsar", name: "Hello", want: "var Hello string"},
	{pkgpath: "aliases", name: "A14", gccgoVersion: 7, want: "type A14 = func(int, T0) chan T2"},
	{pkgpath: "aliases", name: "C0", gccgoVersion: 7, want: "type C0 struct{f1 C1; f2 C1}"},
	{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
	{pkgpath: "issue27856", name: "M", gccgoVersion: 7, want: "type M struct{E F}"},
	{pkgpath: "v1reflect", name: "Type", want: "type Type interface{Align() int; AssignableTo(u Type) bool; Bits() int; ChanDir() ChanDir; Elem() Type; Field(i int) StructField; FieldAlign() int; FieldByIndex(index []int) StructField; FieldByName(name string) (StructField, bool); FieldByNameFunc(match func(string) bool) (StructField, bool); Implements(u Type) bool; In(i int) Type; IsVariadic() bool; Key() Type; Kind() Kind; Len() int; Method(int) Method; MethodByName(string) (Method, bool); Name() string; NumField() int; NumIn() int; NumMethod() int; NumOut() int; Out(i int) Type; PkgPath() string; Size() uintptr; String() string; common() *commonType; rawString() string; runtimeType() *runtimeType; uncommon() *uncommonType}"},
	{pkgpath: "nointerface", name: "I", want: "type I int"},
	{pkgpath: "issue29198", name: "FooServer", gccgoVersion: 7, want: "type FooServer struct{FooServer *FooServer; user string; ctx context.Context}"},
	{pkgpath: "issue30628", name: "Apple", want: "type Apple struct{hey sync.RWMutex; x int; RQ [517]struct{Count uintptr; NumBytes uintptr; Last uintptr}}"},
	{pkgpath: "issue31540", name: "S", gccgoVersion: 7, want: "type S struct{b int; map[Y]Z}"},
}

func TestGoxImporter(t *testing.T) {
	testenv.MustHaveExec(t) // this is to skip nacl, js
	initmap := make(map[*types.Package]InitData)
	imp := GetImporter([]string{"testdata"}, initmap)

	for _, test := range importerTests {
		runImporterTest(t, imp, initmap, &test)
	}
}

// gccgoPath returns a path to gccgo if it is present (either in
// path or specified via GCCGO environment variable), or an
// empty string if no gccgo is available.
func gccgoPath() string {
	gccgoname := os.Getenv("GCCGO")
	if gccgoname == "" {
		gccgoname = "gccgo"
	}
	if gpath, gerr := exec.LookPath(gccgoname); gerr == nil {
		return gpath
	}
	return ""
}

func TestObjImporter(t *testing.T) {
	// This test relies on gccgo being around.
	gpath := gccgoPath()
	if gpath == "" {
		t.Skip("This test needs gccgo")
	}

	verout, err := exec.Command(gpath, "--version").CombinedOutput()
	if err != nil {
		t.Logf("%s", verout)
		t.Fatal(err)
	}
	vers := regexp.MustCompile(`([0-9]+)\.([0-9]+)`).FindSubmatch(verout)
	if len(vers) == 0 {
		t.Fatalf("could not find version number in %s", verout)
	}
	major, err := strconv.Atoi(string(vers[1]))
	if err != nil {
		t.Fatal(err)
	}
	minor, err := strconv.Atoi(string(vers[2]))
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("gccgo version %d.%d", major, minor)

	tmpdir, err := ioutil.TempDir("", "TestObjImporter")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	initmap := make(map[*types.Package]InitData)
	imp := GetImporter([]string{tmpdir}, initmap)

	artmpdir, err := ioutil.TempDir("", "TestObjImporter")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(artmpdir)

	arinitmap := make(map[*types.Package]InitData)
	arimp := GetImporter([]string{artmpdir}, arinitmap)

	for _, test := range importerTests {
		if major < test.gccgoVersion {
			// Support for type aliases was added in GCC 7.
			t.Logf("skipping %q: not supported before gccgo version %d", test.pkgpath, test.gccgoVersion)
			continue
		}

		gofile := filepath.Join("testdata", test.pkgpath+".go")
		if _, err := os.Stat(gofile); os.IsNotExist(err) {
			continue
		}
		ofile := filepath.Join(tmpdir, test.pkgpath+".o")
		afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a")

		cmd := exec.Command(gpath, "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile)
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Logf("%s", out)
			t.Fatalf("gccgo %s failed: %s", gofile, err)
		}

		runImporterTest(t, imp, initmap, &test)

		cmd = exec.Command("ar", "cr", afile, ofile)
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Logf("%s", out)
			t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err)
		}

		runImporterTest(t, arimp, arinitmap, &test)

		if err = os.Remove(ofile); err != nil {
			t.Fatal(err)
		}
		if err = os.Remove(afile); err != nil {
			t.Fatal(err)
		}
	}
}
<|endoftext|>