<commit_before>package gosseract

import (
	"image"
	"image/png"
	"os"
)

// Servant of gosseract providing interactive setting
type Servant struct {
	source  source
	lang	lang
	options options
}
type source struct {
	FilePath string
	isTmp	bool
	// TODO: accept multiple image formats
}
type lang struct {
	Value	  string
	Availables []string
}
type options struct {
	UseFile  bool
	FilePath string
	Digest   map[string]string
}
type VersionInfo struct {
	TesseractVersion string
	GosseractVersion string
}

// Provide new servant instance
func SummonServant() Servant {

	if !tesseractInstalled() {
		panic("Missin `tesseract` command!! install tessearct at first.")
	}

	lang := lang{}
	lang.init()
	opts := options{}
	opts.init()
	return Servant{
		lang:	lang,
		options: opts,
	}
}

// Check information of tesseract and gosseract
func (s *Servant) Info() VersionInfo {
	tessVersion := getTesseractVersion()
	info := VersionInfo{
		TesseractVersion: tessVersion,
		GosseractVersion: VERSION,
	}
	return info
}

// Give source file to servant by file path
func (s *Servant) Target(filepath string) *Servant {
	// TODO: check existence of this file
	s.source.FilePath = filepath
	return s
}

// Give source file to servant by image.Image
func (s *Servant) Eat(img image.Image) *Servant {
	filepath := genTmpFilePath()
	f, e := os.Create(filepath)
	if e != nil {
		panic(e)
	}
	defer f.Close()
	png.Encode(f, img)

	s.source.FilePath = filepath
	s.source.isTmp = true

	return s
}

// Get result (or error?)
func (s *Servant) Out() (string, error) {
	result := execute(s.source.FilePath, s.buildArguments())
	// TODO? : should make `gosseract.servant` package?

	if !s.options.UseFile {
		_ = os.Remove(s.options.FilePath)
	}
	if s.source.isTmp {
		_ = os.Remove(s.source.FilePath)
	}

	// TODO: handle errors
	return result, nil
}

// Make up arguments appropriate to tesseract command
func (s *Servant) buildArguments() []string {
	var args []string
	args = append(args, "-l", s.lang.Value)
	if !s.options.UseFile {
		s.options.FilePath = makeUpOptionFile(s.options.Digest)
	}
	args = append(args, s.options.FilePath)
	return args
}
// Make up option file for tesseract command.
// (is needless if tesseract accepts such options by cli options)
func makeUpOptionFile(digestMap map[string]string) (fpath string) {
	fpath = ""
	var digestFileContents string
	for k, v := range digestMap {
		digestFileContents = digestFileContents + k + " " + v + "\n"
	}
	if digestFileContents == "" {
		return fpath
	}
	fpath = genTmpFilePath()
	f, _ := os.Create(fpath)
	defer f.Close()
	_, _ = f.WriteString(digestFileContents)
	return fpath
}
<commit_msg>Execute `go fmt`<commit_after>package gosseract

import (
	"image"
	"image/png"
	"os"
)

// Servant of gosseract providing interactive setting
type Servant struct {
	source  source
	lang    lang
	options options
}
type source struct {
	FilePath string
	isTmp    bool
	// TODO: accept multiple image formats
}
type lang struct {
	Value      string
	Availables []string
}
type options struct {
	UseFile  bool
	FilePath string
	Digest   map[string]string
}
type VersionInfo struct {
	TesseractVersion string
	GosseractVersion string
}

// Provide new servant instance
func SummonServant() Servant {

	if !tesseractInstalled() {
		panic("Missin `tesseract` command!! install tessearct at first.")
	}

	lang := lang{}
	lang.init()
	opts := options{}
	opts.init()
	return Servant{
		lang:    lang,
		options: opts,
	}
}

// Check information of tesseract and gosseract
func (s *Servant) Info() VersionInfo {
	tessVersion := getTesseractVersion()
	info := VersionInfo{
		TesseractVersion: tessVersion,
		GosseractVersion: VERSION,
	}
	return info
}

// Give source file to servant by file path
func (s *Servant) Target(filepath string) *Servant {
	// TODO: check existence of this file
	s.source.FilePath = filepath
	return s
}

// Give source file to servant by image.Image
func (s *Servant) Eat(img image.Image) *Servant {
	filepath := genTmpFilePath()
	f, e := os.Create(filepath)
	if e != nil {
		panic(e)
	}
	defer f.Close()
	png.Encode(f, img)

	s.source.FilePath = filepath
	s.source.isTmp = true

	return s
}

// Get result (or error?)
func (s *Servant) Out() (string, error) {
	result := execute(s.source.FilePath, s.buildArguments())
	// TODO? : should make `gosseract.servant` package?

	if !s.options.UseFile {
		_ = os.Remove(s.options.FilePath)
	}
	if s.source.isTmp {
		_ = os.Remove(s.source.FilePath)
	}

	// TODO: handle errors
	return result, nil
}

// Make up arguments appropriate to tesseract command
func (s *Servant) buildArguments() []string {
	var args []string
	args = append(args, "-l", s.lang.Value)
	if !s.options.UseFile {
		s.options.FilePath = makeUpOptionFile(s.options.Digest)
	}
	args = append(args, s.options.FilePath)
	return args
}

// Make up option file for tesseract command.
// (is needless if tesseract accepts such options by cli options)
func makeUpOptionFile(digestMap map[string]string) (fpath string) {
	fpath = ""
	var digestFileContents string
	for k, v := range digestMap {
		digestFileContents = digestFileContents + k + " " + v + "\n"
	}
	if digestFileContents == "" {
		return fpath
	}
	fpath = genTmpFilePath()
	f, _ := os.Create(fpath)
	defer f.Close()
	_, _ = f.WriteString(digestFileContents)
	return fpath
}
<|endoftext|>


<commit_before>package rkv

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/relab/raft"
)

// Service exposes the Store api as a http service.
type Service struct {
	store *Store
}

// NewService creates a new Service backed by store.
func NewService(store *Store) *Service {
	return &Service{
		store: store,
	}
}

// ServeHTTP implements the http.Handler interface.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(r.URL.Path, "/")

	if len(path) < 2 {
		http.Error(w, "400 Bad Request", http.StatusBadRequest)
		return
	}

	switch path[1] {
	case "register":
		id, err := s.store.Register()

		if err != nil {
			raftError(w, r, err)
			return
		}

		fmt.Fprintln(w, id)
		return
	case "store":
		if len(path) != 3 {
			http.Error(w, "400 Bad Request", http.StatusBadRequest)
			return
		}

		key := path[2]

		if len(key) < 1 {
			http.Error(w, "400 Bad Request", http.StatusBadRequest)
			return
		}

		switch r.Method {
		case http.MethodGet:
			value, err := s.store.Lookup(key, false)

			if err != nil {
				raftError(w, r, err)
				return
			}

			fmt.Fprintln(w, value)

		case http.MethodPut:
			value, err := ioutil.ReadAll(r.Body)

			if err != nil {
				http.Error(w, "400 Bad Request", http.StatusBadRequest)
				return
			}

			query := r.URL.Query()
			// TODO Bound check.
			id := query["id"][0]
			seq := query["seq"][0]
			sequ, err := strconv.ParseUint(seq, 10, 64)

			if err != nil {
				http.Error(w, "400 Bad Request", http.StatusBadRequest)
				return
			}

			err = s.store.Insert(id, sequ, key, string(value))

			if err != nil {
				raftError(w, r, err)
				return
			}

			// TODO Change to StatusOK when we actually verify commitment.
			w.WriteHeader(http.StatusAccepted)
		}
	default:
		http.NotFound(w, r)
		return
	}
}

func raftError(w http.ResponseWriter, r *http.Request, err error) {
	switch err := err.(type) {
	case raft.ErrNotLeader:
		// TODO Assumes a valid addr is returned.
		// Try random server if err.LeaderAddr == "".
		host, port, _ := net.SplitHostPort(err.LeaderAddr)

		if host == "" {
			host = "localhost"
		}

		// TODO Hack. Since LeaderAddr is the Raft port, we just assume
		// the application is using Raft port - 100. Fix means changing
		// Raft to put the application port into LeaderAddr, however we
		// don't have a way of knowing the application ports, as they
		// are set locally.
		p, _ := strconv.Atoi(port)
		port = strconv.Itoa(p - 100)

		addr := net.JoinHostPort(host, port)

		http.Redirect(w, r, "http://"+addr+r.URL.RequestURI(), http.StatusTemporaryRedirect)
	default:
		http.Error(w, "503 Service Unavailable", http.StatusServiceUnavailable)
	}
}
<commit_msg>service.go: Handle missing leader<commit_after>package rkv

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/relab/raft"
)

// Service exposes the Store api as a http service.
type Service struct {
	store *Store
}

// NewService creates a new Service backed by store.
func NewService(store *Store) *Service {
	return &Service{
		store: store,
	}
}

// ServeHTTP implements the http.Handler interface.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(r.URL.Path, "/")

	if len(path) < 2 {
		http.Error(w, "400 Bad Request", http.StatusBadRequest)
		return
	}

	switch path[1] {
	case "register":
		id, err := s.store.Register()

		if err != nil {
			raftError(w, r, err)
			return
		}

		fmt.Fprintln(w, id)
		return
	case "store":
		if len(path) != 3 {
			http.Error(w, "400 Bad Request", http.StatusBadRequest)
			return
		}

		key := path[2]

		if len(key) < 1 {
			http.Error(w, "400 Bad Request", http.StatusBadRequest)
			return
		}

		switch r.Method {
		case http.MethodGet:
			value, err := s.store.Lookup(key, false)

			if err != nil {
				raftError(w, r, err)
				return
			}

			fmt.Fprintln(w, value)

		case http.MethodPut:
			value, err := ioutil.ReadAll(r.Body)

			if err != nil {
				http.Error(w, "400 Bad Request", http.StatusBadRequest)
				return
			}

			query := r.URL.Query()
			// TODO Bound check.
			id := query["id"][0]
			seq := query["seq"][0]
			sequ, err := strconv.ParseUint(seq, 10, 64)

			if err != nil {
				http.Error(w, "400 Bad Request", http.StatusBadRequest)
				return
			}

			err = s.store.Insert(id, sequ, key, string(value))

			if err != nil {
				raftError(w, r, err)
				return
			}

			// TODO Change to StatusOK when we actually verify commitment.
			w.WriteHeader(http.StatusAccepted)
		}
	default:
		http.NotFound(w, r)
		return
	}
}

func raftError(w http.ResponseWriter, r *http.Request, err error) {
	switch err := err.(type) {
	case raft.ErrNotLeader:
		if err.LeaderAddr == "" {
			// TODO Document that this means the client should
			// change to a random server.
			w.Header().Set("Retry-After", "-1")
			http.Error(w, "503 Service Unavailable", http.StatusServiceUnavailable)
		}

		host, port, erri := net.SplitHostPort(err.LeaderAddr)

		if erri != nil {
			http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
		}

		if host == "" {
			host = "localhost"
		}

		// TODO Hack. Since LeaderAddr is the Raft port, we just assume
		// the application is using Raft port - 100. Fix means changing
		// Raft to put the application port into LeaderAddr, however we
		// don't have a way of knowing the application ports, as they
		// are set locally.
		p, _ := strconv.Atoi(port)
		port = strconv.Itoa(p - 100)

		addr := net.JoinHostPort(host, port)

		http.Redirect(w, r, "http://"+addr+r.URL.RequestURI(), http.StatusTemporaryRedirect)
	default:
		http.Error(w, "503 Service Unavailable", http.StatusServiceUnavailable)
	}
}
<|endoftext|>


<commit_before>package siesta

import (
	"net/http"
	"path"
	"regexp"
	"strings"
)

// Registered services keyed by base URI.
var services = map[string]*Service{}

// A Service is a container for routes with a common base URI.
// It also has two middleware chains, named "pre" and "post".
//
// The "pre" chain is run before the main handler. The first
// handler in the "pre" chain is guaranteed to run, but execution
// may quit anywhere else in the chain.
//
// If the "pre" chain executes completely, the main handler is executed.
// It is skipped otherwise.
//
// The "post" chain runs after the main handler, whether it is skipped
// or not. The first handler in the "post" chain is guaranteed to run, but
// execution may quit anywhere else in the chain if the quit function
// is called.
type Service struct {
	baseURI string

	pre  []contextHandler
	post []contextHandler

	handlers map[*regexp.Regexp]contextHandler

	routes map[string]*node

	notFound contextHandler
}

// NewService returns a new Service with the given base URI
// or panics if the base URI has already been registered.
func NewService(baseURI string) *Service {
	if services[baseURI] != nil {
		panic("service already registered")
	}

	return &Service{
		baseURI:  path.Join("/", baseURI, "/"),
		handlers: make(map[*regexp.Regexp]contextHandler),
		routes:   map[string]*node{},
	}
}

func addToChain(f interface{}, chain []contextHandler) []contextHandler {
	m := toContextHandler(f)
	return append(chain, m)
}

// AddPre adds f to the end of the "pre" chain.
// It panics if f cannot be converted to a contextHandler (see Service.Route).
func (s *Service) AddPre(f interface{}) {
	s.pre = addToChain(f, s.pre)
}

// AddPost adds f to the end of the "post" chain.
// It panics if f cannot be converted to a contextHandler (see Service.Route).
func (s *Service) AddPost(f interface{}) {
	s.post = addToChain(f, s.post)
}

// Service satisfies the http.Handler interface.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.ServeHTTPInContext(NewSiestaContext(), w, r)
}

// ServiceHTTPInContext serves an HTTP request within the Context c.
// A Service will run through both of its internal chains, quitting
// when requested.
func (s *Service) ServeHTTPInContext(c Context, w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	quit := false
	for _, m := range s.pre {
		m(c, w, r, func() {
			quit = true
		})

		if quit {
			// Break out of the "pre" loop, but
			// continue on.
			break
		}
	}

	if !quit {
		// The main handler is only run if we have not
		// been signaled to quit.

		if r.URL.Path != "/" {
			r.URL.Path = strings.TrimRight(r.URL.Path, "/")
		}

		var (
			handler contextHandler
			params  routeParams
		)

		// Lookup the tree for this method
		routeNode, ok := s.routes[r.Method]

		if ok {
			handler, params, _ = routeNode.getValue(r.URL.Path)
		}

		if handler == nil {
			if s.notFound != nil {
				// Use user-defined handler.
				s.notFound(c, w, r, func() {})
			} else {
				// Default to the net/http NotFoundHandler.
				http.NotFoundHandler().ServeHTTP(w, r)
			}
		} else {
			for _, p := range params {
				r.Form.Set(p.Key, p.Value)
			}

			handler(c, w, r, func() {
				quit = true
			})
		}
	}

	quit = false
	for _, m := range s.post {
		m(c, w, r, func() {
			quit = true
		})

		if quit {
			return
		}
	}
}

// Route adds a new route to the Service.
// f must be a function with one of the following signatures:
//
//     func(http.ResponseWriter, *http.Request)
//     func(http.ResponseWriter, *http.Request, func())
//     func(Context, http.ResponseWriter, *http.Request)
//     func(Context, http.ResponseWriter, *http.Request, func())
//
// Note that Context is an interface type defined in this package.
// The last argument is a function which is called to signal the
// quitting of the current execution sequence.
func (s *Service) Route(verb, uriPath, usage string, f interface{}) {
	handler := toContextHandler(f)

	if n := s.routes[verb]; n == nil {
		s.routes[verb] = &node{}
	}

	s.routes[verb].addRoute(path.Join(s.baseURI, strings.TrimRight(uriPath, "/")), handler)
}

// SetNotFound sets the handler for all paths that do not
// match any existing routes. It accepts the same function
// signatures that Route does with the addition of `nil`.
func (s *Service) SetNotFound(f interface{}) {
	if f == nil {
		s.notFound = nil
		return
	}

	handler := toContextHandler(f)
	s.notFound = handler
}

// Register registers s by adding it as a handler to the
// DefaultServeMux in the net/http package.
func (s *Service) Register() {
	http.Handle(s.baseURI, s)
}
<commit_msg>remove dead regexp code<commit_after>package siesta

import (
	"net/http"
	"path"
	"strings"
)

// Registered services keyed by base URI.
var services = map[string]*Service{}

// A Service is a container for routes with a common base URI.
// It also has two middleware chains, named "pre" and "post".
//
// The "pre" chain is run before the main handler. The first
// handler in the "pre" chain is guaranteed to run, but execution
// may quit anywhere else in the chain.
//
// If the "pre" chain executes completely, the main handler is executed.
// It is skipped otherwise.
//
// The "post" chain runs after the main handler, whether it is skipped
// or not. The first handler in the "post" chain is guaranteed to run, but
// execution may quit anywhere else in the chain if the quit function
// is called.
type Service struct {
	baseURI string

	pre  []contextHandler
	post []contextHandler

	routes map[string]*node

	notFound contextHandler
}

// NewService returns a new Service with the given base URI
// or panics if the base URI has already been registered.
func NewService(baseURI string) *Service {
	if services[baseURI] != nil {
		panic("service already registered")
	}

	return &Service{
		baseURI: path.Join("/", baseURI, "/"),
		routes:  map[string]*node{},
	}
}

func addToChain(f interface{}, chain []contextHandler) []contextHandler {
	m := toContextHandler(f)
	return append(chain, m)
}

// AddPre adds f to the end of the "pre" chain.
// It panics if f cannot be converted to a contextHandler (see Service.Route).
func (s *Service) AddPre(f interface{}) {
	s.pre = addToChain(f, s.pre)
}

// AddPost adds f to the end of the "post" chain.
// It panics if f cannot be converted to a contextHandler (see Service.Route).
func (s *Service) AddPost(f interface{}) {
	s.post = addToChain(f, s.post)
}

// Service satisfies the http.Handler interface.
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.ServeHTTPInContext(NewSiestaContext(), w, r)
}

// ServiceHTTPInContext serves an HTTP request within the Context c.
// A Service will run through both of its internal chains, quitting
// when requested.
func (s *Service) ServeHTTPInContext(c Context, w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	quit := false
	for _, m := range s.pre {
		m(c, w, r, func() {
			quit = true
		})

		if quit {
			// Break out of the "pre" loop, but
			// continue on.
			break
		}
	}

	if !quit {
		// The main handler is only run if we have not
		// been signaled to quit.

		if r.URL.Path != "/" {
			r.URL.Path = strings.TrimRight(r.URL.Path, "/")
		}

		var (
			handler contextHandler
			params  routeParams
		)

		// Lookup the tree for this method
		routeNode, ok := s.routes[r.Method]

		if ok {
			handler, params, _ = routeNode.getValue(r.URL.Path)
		}

		if handler == nil {
			if s.notFound != nil {
				// Use user-defined handler.
				s.notFound(c, w, r, func() {})
			} else {
				// Default to the net/http NotFoundHandler.
				http.NotFoundHandler().ServeHTTP(w, r)
			}
		} else {
			for _, p := range params {
				r.Form.Set(p.Key, p.Value)
			}

			handler(c, w, r, func() {
				quit = true
			})
		}
	}

	quit = false
	for _, m := range s.post {
		m(c, w, r, func() {
			quit = true
		})

		if quit {
			return
		}
	}
}

// Route adds a new route to the Service.
// f must be a function with one of the following signatures:
//
//     func(http.ResponseWriter, *http.Request)
//     func(http.ResponseWriter, *http.Request, func())
//     func(Context, http.ResponseWriter, *http.Request)
//     func(Context, http.ResponseWriter, *http.Request, func())
//
// Note that Context is an interface type defined in this package.
// The last argument is a function which is called to signal the
// quitting of the current execution sequence.
func (s *Service) Route(verb, uriPath, usage string, f interface{}) {
	handler := toContextHandler(f)

	if n := s.routes[verb]; n == nil {
		s.routes[verb] = &node{}
	}

	s.routes[verb].addRoute(path.Join(s.baseURI, strings.TrimRight(uriPath, "/")), handler)
}

// SetNotFound sets the handler for all paths that do not
// match any existing routes. It accepts the same function
// signatures that Route does with the addition of `nil`.
func (s *Service) SetNotFound(f interface{}) {
	if f == nil {
		s.notFound = nil
		return
	}

	handler := toContextHandler(f)
	s.notFound = handler
}

// Register registers s by adding it as a handler to the
// DefaultServeMux in the net/http package.
func (s *Service) Register() {
	http.Handle(s.baseURI, s)
}
<|endoftext|>


<commit_before>package session

import (
	_ "net/http"
	"sync"
	"time"
)

type Session struct {
	id        string
	store     Store
	mutex     sync.Mutex
	data      map[string]interface{}
	expiresAt time.Time
}

func (s *Session) Id() string {
	return s.id
}

func (s *Session) Has(key string) bool {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	_, ok := s.data[key]
	return ok
}

func (s *Session) Get(key string) interface{} {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	return s.data[key]
}

func (s *Session) Set(key string, value interface{}) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.data[key] = value
}

func (s *Session) Unset(key string) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	delete(s.data, key)
}

func (s *Session) ExpiresAt() time.Time {
	return s.expiresAt
}

func NewSession(id string) *Session {
	return &Session{
		id:   id,
		data: make(map[string]interface{}),
	}
}

type Store interface {
	// Check session existence
	Has(id string) (bool, error)

	// Load a session by id, if not found, return nil
	Load(id string) (*Session, error)

	// Delete a session
	Revoke(id string) error

	// Extend session expiry
	Renew(session *Session) error

	// Save a session. Session expiry gets updated too
	Save(session *Session) error

	// Clean up
	Close() error
}
<commit_msg>Remve unused package.<commit_after>package session

import (
	"sync"
	"time"
)

type Session struct {
	id        string
	store     Store
	mutex     sync.Mutex
	data      map[string]interface{}
	expiresAt time.Time
}

func (s *Session) Id() string {
	return s.id
}

func (s *Session) Has(key string) bool {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	_, ok := s.data[key]
	return ok
}

func (s *Session) Get(key string) interface{} {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	return s.data[key]
}

func (s *Session) Set(key string, value interface{}) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.data[key] = value
}

func (s *Session) Unset(key string) {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	delete(s.data, key)
}

func (s *Session) ExpiresAt() time.Time {
	return s.expiresAt
}

func NewSession(id string) *Session {
	return &Session{
		id:   id,
		data: make(map[string]interface{}),
	}
}

type Store interface {
	// Check session existence
	Has(id string) (bool, error)

	// Load a session by id, if not found, return nil
	Load(id string) (*Session, error)

	// Delete a session
	Revoke(id string) error

	// Extend session expiry
	Renew(session *Session) error

	// Save a session. Session expiry gets updated too
	Save(session *Session) error

	// Clean up
	Close() error
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

type session struct {
	sp       *subProcess
	conn     *connection
	messages chan string
}

func NewSession(conn *connection) (s *session, err error) {
	s = &session{
		conn: conn,
	}

	s.sendMessage("hilo")

	sp, err := NewSubProcess("bash")
	if err != nil {
		return
	}
	s.sp = sp

	go func() {
		line := ""
		for {
			message := conn.Read()
			if len(message) == 0 {
				continue
			}

			if message[0] == 13 {
				fmt.Println("message received: ", line)
				sp.input <- line + "\n"
				line = ""
			} else {
				msg := string(message)
				line += msg
			}
		}
	}()

	go func() {
		for line := range sp.output {
			fmt.Print(line)
			conn.Write(line)
		}
	}()

	return
}

func (s *session) sendMessage(message string) {
	s.conn.Write(message)
}

func (s *session) End() {
	s.sp.kill()
}
<commit_msg>terminate session when client disappears<commit_after>package main

import (
	"fmt"
)

type session struct {
	sp       *subProcess
	conn     *connection
	messages chan string
}

func NewSession(conn *connection) (s *session, err error) {
	s = &session{
		conn: conn,
	}

	s.sendMessage("hilo")

	sp, err := NewSubProcess("bash")
	if err != nil {
		return
	}
	s.sp = sp

	go func() {
		line := ""
		for {
			message := conn.Read()
			if len(message) == 0 {
				fmt.Println("connection closed, terminating subprocess")
				sp.kill()
				break
			}

			if message[0] == 13 {
				fmt.Println("message received: ", line)
				sp.input <- line + "\n"
				line = ""
			} else {
				msg := string(message)
				line += msg
			}
		}
	}()

	go func() {
		for line := range sp.output {
			fmt.Print(line)
			conn.Write(line)
		}
	}()

	return
}

func (s *session) sendMessage(message string) {
	s.conn.Write(message)
}

func (s *session) End() {
	s.sp.kill()
}
<|endoftext|>


<commit_before>package qb

import (
	"database/sql"
	"fmt"
)

// NewSession generates a new Session given engine and returns session pointer
func NewSession(metadata *MetaData) *Session {
	return &Session{
		queries: []*Query{},
		mapper:  NewMapper(metadata.Engine().Driver()),
		metadata: metadata,
	}
}

// Session is the composition of engine connection & orm mappings
type Session struct {
	queries []*Query
	mapper  *Mapper
	metadata *MetaData
	tx      *sql.Tx
}

func (s *Session) add(query *Query) {
	var err error
	if s.tx == nil {
		s.tx, err = s.metadata.Engine().DB().Begin()
		if err != nil {
			panic(err)
		}
	}
	s.queries = append(s.queries, query)
}

// Delete adds a single delete query to the session
func (s *Session) Delete(model interface{}) {

	kv := s.mapper.ConvertStructToMap(model)

	d := s.metadata.Table(s.mapper.ModelName(model)).Delete()

	ands := []string{}
	bindings := []interface{}{}
	for k, v := range kv {
		ands = append(ands, fmt.Sprintf("%s = %s", s.mapper.ColName(k), d.Placeholder()))
		bindings = append(bindings, v)
	}

	del := d.Where(d.And(ands...), bindings...).Query()
	s.add(del)
}

// Add adds a single query to the session. The query must be insert or update
func (s *Session) Add(model interface{}) {

	rawMap := s.mapper.ConvertStructToMap(model)

	kv := map[string]interface{}{}

	for k, v := range rawMap {
		kv[s.mapper.ColName(k)] = v
	}

	q := s.metadata.Table(s.mapper.ModelName(model)).Insert(kv).Query()
	s.add(q)
}

// AddAll adds multiple models an adds an insert statement to current queries
func (s *Session) AddAll(models ...interface{}) {
	for _, m := range models {
		s.Add(m)
	}
}

// Commit commits the current transaction with queries
func (s *Session) Commit() error {

	for _, q := range s.queries {
		_, err := s.tx.Exec(q.SQL(), q.Bindings()...)
		if err != nil {
			return err
		}
	}

	return s.tx.Commit()
}

// Select makers
<commit_msg>fix a bug that causes error when multiple transactions are executed in order<commit_after>package qb

import (
	"database/sql"
	"fmt"
)

// NewSession generates a new Session given engine and returns session pointer
func NewSession(metadata *MetaData) *Session {
	return &Session{
		queries: []*Query{},
		mapper:  NewMapper(metadata.Engine().Driver()),
		metadata: metadata,
	}
}

// Session is the composition of engine connection & orm mappings
type Session struct {
	queries []*Query
	mapper  *Mapper
	metadata *MetaData
	tx      *sql.Tx
}

func (s *Session) add(query *Query) {
	var err error
	if s.tx == nil {
		s.queries = []*Query{}
		s.tx, err = s.metadata.Engine().DB().Begin()
		if err != nil {
			panic(err)
		}
	}
	s.queries = append(s.queries, query)
}

// Delete adds a single delete query to the session
func (s *Session) Delete(model interface{}) {

	kv := s.mapper.ConvertStructToMap(model)

	tName := s.mapper.ModelName(model)

	d := s.metadata.Table(tName).Delete()
	ands := []string{}
	bindings := []interface{}{}

	pcols := s.metadata.Table(tName).PrimaryKey()

	// if table has primary key
	if len(pcols) > 0 {

		for _, pk := range pcols {
			// find
			b := kv[pk]
			ands = append(ands, fmt.Sprintf("%s = %s", pk, d.Placeholder()))
			bindings = append(bindings, b)
		}

	} else {
		for k, v := range kv {
			ands = append(ands, fmt.Sprintf("%s = %s", s.mapper.ColName(k), d.Placeholder()))
			bindings = append(bindings, v)
		}
	}

	del := d.Where(d.And(ands...), bindings...).Query()
	s.add(del)
}

// Add adds a single query to the session. The query must be insert or update
func (s *Session) Add(model interface{}) {

	rawMap := s.mapper.ConvertStructToMap(model)

	kv := map[string]interface{}{}

	for k, v := range rawMap {
		kv[s.mapper.ColName(k)] = v
	}

	q := s.metadata.Table(s.mapper.ModelName(model)).Insert(kv).Query()
	s.add(q)
}

// AddAll adds multiple models an adds an insert statement to current queries
func (s *Session) AddAll(models ...interface{}) {
	for _, m := range models {
		s.Add(m)
	}
}

// Commit commits the current transaction with queries
func (s *Session) Commit() error {

	for _, q := range s.queries {
		_, err := s.tx.Exec(q.SQL(), q.Bindings()...)
		if err != nil {
			return err
		}
	}

	err := s.tx.Commit()
	s.tx = nil
	return err
}

// Select makers
<|endoftext|>


<commit_before>// sudo hexdump -v -e '5/1 "%02x " "\n"' /dev/hidraw4
// lsusb
// http://stackoverflow.com/questions/15949163/read-from-dev-input
// http://reactivated.net/writing_udev_rules.html
// /lib/udev/rules.d/
// sudo service udev restart
// sudo udevadm control --reload-rules
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"time"
)

type ReadValue struct {
	Jog        int8
	Wheel      uint8
	WheelDelta int8
	Buttons    [5]bool
}

type Mode int

const (
	ModeScroll Mode = iota
	ModeTab
	ModeSelect
)

var (
	mode      = ModeScroll
	jog  int8 = 0
)

func ToReadValue(buf []byte) *ReadValue {
	b := [5]bool{}
	b[0] = buf[3]&0x10 != 0
	b[1] = buf[3]&0x20 != 0
	b[2] = buf[3]&0x40 != 0
	b[3] = buf[3]&0x80 != 0
	b[4] = buf[4]&0x01 != 0
	return &ReadValue{
		Jog:     int8(buf[0]),
		Wheel:   uint8(buf[1]),
		Buttons: b,
	}
}

func findDevice() string {
	return "/dev/hidraw5"
}

func action(v *ReadValue) {
	fmt.Printf("val: %#v\n", v)
	fmt.Printf("mode: %#v\n", mode)

	switch {
	case v.Buttons[0]:
		exec.Command("xdotool", "key", "Return").Run()
	case v.Buttons[1]:
		mode = ModeScroll
	case v.Buttons[2]:
		mode = ModeTab
	case v.Buttons[3]:
		mode = ModeSelect
	case v.Buttons[4]:
		exec.Command("xdotool", "key", "Return").Run()
	}

	if v.WheelDelta > 0 {
		switch mode {
		case ModeScroll:
			exec.Command("xdotool", "click", "5").Run()
		case ModeTab:
			exec.Command("xdotool", "key", "Ctrl+Tab").Run()
		case ModeSelect:
			exec.Command("xdotool", "key", "Tab").Run()
		}
	}
	if v.WheelDelta < 0 {
		switch mode {
		case ModeScroll:
			exec.Command("xdotool", "click", "4").Run()
		case ModeTab:
			exec.Command("xdotool", "key", "Ctrl+Shift+Tab").Run()
		case ModeSelect:
			exec.Command("xdotool", "key", "Shift+Tab").Run()
		}
	}
	jog = v.Jog
}

func loop(c <-chan *ReadValue) {
	p := <-c
	for {
		select {
		case v := <-c:
			v.WheelDelta = int8(v.Wheel) - int8(p.Wheel)
			action(v)
			p = v
		}
	}
}

func jogLoop() {
	t := time.NewTicker(10 * time.Millisecond)
	i := 0
	for _ = range t.C {
		i++
		thr := (1 << 4) - (1 << uint(abs(int(jog))))
		if i > thr {
			if jog > 0 {
				log.Printf("tick %d %d/%d", jog, i, thr)
				exec.Command("xdotool", "click", "5").Run()
			}
			if jog < 0 {
				log.Printf("tick %d %d/%d", jog, i, thr)
				exec.Command("xdotool", "click", "4").Run()
			}
			i = 0
		}
	}
}

func abs(x int) int {
	if x >= 0 {
		return x
	} else {
		return -x
	}
}

func generate(c chan<- *ReadValue) {
	f, err := os.Open(findDevice())
	if err != nil {
		log.Fatalf("invalid file name: %s", findDevice())
		return
	}

	buf := make([]byte, 5)
	for {
		f.Read(buf)
		v := ToReadValue(buf)
		c <- v
	}
}

func main() {
	flag.Parse()

	go jogLoop()

	c := make(chan *ReadValue)
	go generate(c)
	loop(c)

}
<commit_msg>use evdev -- not working yet<commit_after>// sudo hexdump -v -e '5/1 "%02x " "\n"' /dev/hidraw4
// lsusb
// http://stackoverflow.com/questions/15949163/read-from-dev-input
// http://reactivated.net/writing_udev_rules.html
// /lib/udev/rules.d/
// sudo service udev restart
// sudo udevadm control --reload-rules
package main

import (
	"flag"
	"fmt"
	"github.com/jteeuwen/evdev"
	"log"
	"os/exec"
	"time"
)

type ReadValue struct {
	Jog        int8
	Wheel      uint8
	WheelDelta int8
	Buttons    [5]bool
}

type Mode int

const (
	ModeScroll Mode = iota
	ModeTab
	ModeSelect
)

var (
	mode      = ModeScroll
	jog  int8 = 0
)

func findDevice() string {
	return "/dev/input/by-id/usb-Contour_Design_ShuttleXpress-event-if00"
}

func action(v *ReadValue) {
	fmt.Printf("val: %#v\n", v)
	fmt.Printf("mode: %#v\n", mode)

	switch {
	case v.Buttons[0]:
		exec.Command("xdotool", "key", "Return").Run()
	case v.Buttons[1]:
		mode = ModeScroll
	case v.Buttons[2]:
		mode = ModeTab
	case v.Buttons[3]:
		mode = ModeSelect
	case v.Buttons[4]:
		exec.Command("xdotool", "key", "Return").Run()
	}

	if v.WheelDelta > 0 {
		switch mode {
		case ModeScroll:
			exec.Command("xdotool", "click", "5").Run()
		case ModeTab:
			exec.Command("xdotool", "key", "Ctrl+Tab").Run()
		case ModeSelect:
			exec.Command("xdotool", "key", "Tab").Run()
		}
	}
	if v.WheelDelta < 0 {
		switch mode {
		case ModeScroll:
			exec.Command("xdotool", "click", "4").Run()
		case ModeTab:
			exec.Command("xdotool", "key", "Ctrl+Shift+Tab").Run()
		case ModeSelect:
			exec.Command("xdotool", "key", "Shift+Tab").Run()
		}
	}
	jog = v.Jog
}

func loop(c <-chan *ReadValue) {
	p := <-c
	for {
		select {
		case v := <-c:
			v.WheelDelta = int8(v.Wheel) - int8(p.Wheel)
			action(v)
			p = v
		}
	}
}

func jogLoop() {
	t := time.NewTicker(10 * time.Millisecond)
	i := 0
	for _ = range t.C {
		i++
		thr := (1 << 4) - (1 << uint(abs(int(jog))))
		if i > thr {
			if jog > 0 {
				log.Printf("tick %d %d/%d", jog, i, thr)
				exec.Command("xdotool", "click", "5").Run()
			}
			if jog < 0 {
				log.Printf("tick %d %d/%d", jog, i, thr)
				exec.Command("xdotool", "click", "4").Run()
			}
			i = 0
		}
	}
}

func abs(x int) int {
	if x >= 0 {
		return x
	} else {
		return -x
	}
}

func generate(c chan<- *ReadValue) {
	dev, err := evdev.Open(findDevice())
	if err != nil {
		log.Fatalf("error opening device: %v", err)
		return
	}

	for evt := range dev.Inbox {
		log.Printf("Input event: %#v", evt)
	}
}

func main() {
	flag.Parse()

	go jogLoop()

	c := make(chan *ReadValue)
	go generate(c)
	loop(c)

}
<|endoftext|>


<commit_before>package sitemap

import (
	"encoding/xml"
	"errors"
	"io/ioutil"
	"net/http"
	"time"
)

// Index is a structure of <sitemapindex>
type Index struct {
	XMLName xml.Name `xml:"sitemapindex"`
	Sitemap []parts  `xml:"sitemap"`
}

// parts is a structure of <sitemap> in <sitemapindex>
type parts struct {
	Loc     string `xml:"loc"`
	LastMod string `xml:"lastmod"`
}

// Sitemap is a structure of <sitemap>
type Sitemap struct {
	XMLName xml.Name `xml:"urlset"`
	URL     []URL    `xml:"url"`
}

// URL is a structure of <url> in <sitemap>
type URL struct {
	Loc        string  `xml:"loc"`
	LastMod    string  `xml:"lastmod"`
	ChangeFreq string  `xml:"changefreq"`
	Priority   float32 `xml:"priority"`
}

// fetch is page acquisition function
var fetch = func(URL string, options interface{}) ([]byte, error) {
	var body []byte

	res, err := http.Get(URL)
	if err != nil {
		return body, err
	}
	defer res.Body.Close()

	return ioutil.ReadAll(res.Body)
}

// Time interval to be used in Index.get
var interval = time.Second

// Get sitemap data from URL
func Get(URL string, options interface{}) (Sitemap, error) {
	data, err := fetch(URL, options)
	if err != nil {
		return Sitemap{}, err
	}

	idx, idxErr := ParseIndex(data)
	smap, smapErr := Parse(data)

	if idxErr != nil && smapErr != nil {
		err = errors.New("URL is not a sitemap or sitemapindex")
		return Sitemap{}, err
	}

	if idxErr == nil {
		smap, err = idx.get(data, options)
		if err != nil {
			return Sitemap{}, err
		}
	}

	return smap, err
}

// Get Sitemap data from sitemapindex file
func (s *Index) get(data []byte, options interface{}) (Sitemap, error) {
	idx, err := ParseIndex(data)
	if err != nil {
		return Sitemap{}, err
	}

	var smap Sitemap
	for _, s := range idx.Sitemap {
		time.Sleep(interval)
		data, err := fetch(s.Loc, options)
		if err != nil {
			return smap, err
		}

		err = xml.Unmarshal(data, &smap)
		if err != nil {
			return smap, err
		}
	}

	return smap, err
}

// Parse create Sitemap data from text
func Parse(data []byte) (smap Sitemap, err error) {
	err = xml.Unmarshal(data, &smap)
	return
}

// ParseIndex create Index data from text
func ParseIndex(data []byte) (idx Index, err error) {
	err = xml.Unmarshal(data, &idx)
	return
}

// SetInterval change Time interval to be used in Index.get
func SetInterval(time time.Duration) {
	interval = time
}

// SetFetch change fetch closure
func SetFetch(f func(URL string, options interface{}) ([]byte, error)) {
	fetch = f
}
<commit_msg>Refactor Get function<commit_after>package sitemap

import (
	"encoding/xml"
	"errors"
	"io/ioutil"
	"net/http"
	"time"
)

// Index is a structure of <sitemapindex>
type Index struct {
	XMLName xml.Name `xml:"sitemapindex"`
	Sitemap []parts  `xml:"sitemap"`
}

// parts is a structure of <sitemap> in <sitemapindex>
type parts struct {
	Loc     string `xml:"loc"`
	LastMod string `xml:"lastmod"`
}

// Sitemap is a structure of <sitemap>
type Sitemap struct {
	XMLName xml.Name `xml:"urlset"`
	URL     []URL    `xml:"url"`
}

// URL is a structure of <url> in <sitemap>
type URL struct {
	Loc        string  `xml:"loc"`
	LastMod    string  `xml:"lastmod"`
	ChangeFreq string  `xml:"changefreq"`
	Priority   float32 `xml:"priority"`
}

// fetch is page acquisition function
var fetch = func(URL string, options interface{}) ([]byte, error) {
	var body []byte

	res, err := http.Get(URL)
	if err != nil {
		return body, err
	}
	defer res.Body.Close()

	return ioutil.ReadAll(res.Body)
}

// Time interval to be used in Index.get
var interval = time.Second

// Get sitemap data from URL
func Get(URL string, options interface{}) (Sitemap, error) {
	data, err := fetch(URL, options)
	if err != nil {
		return Sitemap{}, err
	}

	idx, idxErr := ParseIndex(data)
	smap, smapErr := Parse(data)

	if idxErr != nil && smapErr != nil {
		return Sitemap{}, errors.New("URL is not a sitemap or sitemapindex")
	} else if idxErr != nil {
		return smap, nil
	}

	smap, err = idx.get(data, options)
	if err != nil {
		return Sitemap{}, err
	}

	return smap, nil
}

// Get Sitemap data from sitemapindex file
func (s *Index) get(data []byte, options interface{}) (Sitemap, error) {
	idx, err := ParseIndex(data)
	if err != nil {
		return Sitemap{}, err
	}

	var smap Sitemap
	for _, s := range idx.Sitemap {
		time.Sleep(interval)
		data, err := fetch(s.Loc, options)
		if err != nil {
			return smap, err
		}

		err = xml.Unmarshal(data, &smap)
		if err != nil {
			return smap, err
		}
	}

	return smap, err
}

// Parse create Sitemap data from text
func Parse(data []byte) (smap Sitemap, err error) {
	err = xml.Unmarshal(data, &smap)
	return
}

// ParseIndex create Index data from text
func ParseIndex(data []byte) (idx Index, err error) {
	err = xml.Unmarshal(data, &idx)
	return
}

// SetInterval change Time interval to be used in Index.get
func SetInterval(time time.Duration) {
	interval = time
}

// SetFetch change fetch closure
func SetFetch(f func(URL string, options interface{}) ([]byte, error)) {
	fetch = f
}
<|endoftext|>


<commit_before>package local // import "github.com/docker/docker/volume/local"

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"github.com/docker/docker/pkg/idtools"
	"github.com/docker/docker/pkg/mount"
)

func TestGetAddress(t *testing.T) {
	cases := map[string]string{
		"addr=11.11.11.1":   "11.11.11.1",
		" ":                 "",
		"addr=":             "",
		"addr=2001:db8::68": "2001:db8::68",
	}
	for name, success := range cases {
		v := getAddress(name)
		if v != success {
			t.Errorf("Test case failed for %s actual: %s expected : %s", name, v, success)
		}
	}

}

func TestRemove(t *testing.T) {
	// TODO Windows: Investigate why this test fails on Windows under CI
	//               but passes locally.
	if runtime.GOOS == "windows" {
		t.Skip("Test failing on Windows CI")
	}
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	vol, err := r.Create("testing", nil)
	if err != nil {
		t.Fatal(err)
	}

	if err := r.Remove(vol); err != nil {
		t.Fatal(err)
	}

	vol, err = r.Create("testing2", nil)
	if err != nil {
		t.Fatal(err)
	}
	if err := os.RemoveAll(vol.Path()); err != nil {
		t.Fatal(err)
	}

	if err := r.Remove(vol); err != nil {
		t.Fatal(err)
	}

	if _, err := os.Stat(vol.Path()); err != nil && !os.IsNotExist(err) {
		t.Fatal("volume dir not removed")
	}

	if l, _ := r.List(); len(l) != 0 {
		t.Fatal("expected there to be no volumes")
	}
}

func TestInitializeWithVolumes(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	vol, err := r.Create("testing", nil)
	if err != nil {
		t.Fatal(err)
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	v, err := r.Get(vol.Name())
	if err != nil {
		t.Fatal(err)
	}

	if v.Path() != vol.Path() {
		t.Fatal("expected to re-initialize root with existing volumes")
	}
}

func TestCreate(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	cases := map[string]bool{
		"name":                  true,
		"name-with-dash":        true,
		"name_with_underscore":  true,
		"name/with/slash":       false,
		"name/with/../../slash": false,
		"./name":                false,
		"../name":               false,
		"./":                    false,
		"../":                   false,
		"~":                     false,
		".":                     false,
		"..":                    false,
		"...":                   false,
	}

	for name, success := range cases {
		v, err := r.Create(name, nil)
		if success {
			if err != nil {
				t.Fatal(err)
			}
			if v.Name() != name {
				t.Fatalf("Expected volume with name %s, got %s", name, v.Name())
			}
		} else {
			if err == nil {
				t.Fatalf("Expected error creating volume with name %s, got nil", name)
			}
		}
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}
}

func TestValidateName(t *testing.T) {
	r := &Root{}
	names := map[string]bool{
		"x":           false,
		"/testvol":    false,
		"thing.d":     true,
		"hello-world": true,
		"./hello":     false,
		".hello":      false,
	}

	for vol, expected := range names {
		err := r.validateName(vol)
		if expected && err != nil {
			t.Fatalf("expected %s to be valid got %v", vol, err)
		}
		if !expected && err == nil {
			t.Fatalf("expected %s to be invalid", vol)
		}
	}
}

func TestCreateWithOpts(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip()
	}
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test", map[string]string{"invalidopt": "notsupported"}); err == nil {
		t.Fatal("expected invalid opt to cause error")
	}

	vol, err := r.Create("test", map[string]string{"device": "tmpfs", "type": "tmpfs", "o": "size=1m,uid=1000"})
	if err != nil {
		t.Fatal(err)
	}
	v := vol.(*localVolume)

	dir, err := v.Mount("1234")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := v.Unmount("1234"); err != nil {
			t.Fatal(err)
		}
	}()

	mountInfos, err := mount.GetMounts(nil)
	if err != nil {
		t.Fatal(err)
	}

	var found bool
	for _, info := range mountInfos {
		if info.Mountpoint == dir {
			found = true
			if info.Fstype != "tmpfs" {
				t.Fatalf("expected tmpfs mount, got %q", info.Fstype)
			}
			if info.Source != "tmpfs" {
				t.Fatalf("expected tmpfs mount, got %q", info.Source)
			}
			if !strings.Contains(info.VfsOpts, "uid=1000") {
				t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts)
			}
			if !strings.Contains(info.VfsOpts, "size=1024k") {
				t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts)
			}
			break
		}
	}

	if !found {
		t.Fatal("mount not found")
	}

	if v.active.count != 1 {
		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
	}

	// test double mount
	if _, err := v.Mount("1234"); err != nil {
		t.Fatal(err)
	}
	if v.active.count != 2 {
		t.Fatalf("Expected active mount count to be 2, got %d", v.active.count)
	}

	if err := v.Unmount("1234"); err != nil {
		t.Fatal(err)
	}
	if v.active.count != 1 {
		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
	}

	mounted, err := mount.Mounted(v.path)
	if err != nil {
		t.Fatal(err)
	}
	if !mounted {
		t.Fatal("expected mount to still be active")
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	v2, exists := r.volumes["test"]
	if !exists {
		t.Fatal("missing volume on restart")
	}

	if !reflect.DeepEqual(v.opts, v2.opts) {
		t.Fatal("missing volume options on restart")
	}
}

func TestRealodNoOpts(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "volume-test-reload-no-opts")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test1", nil); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Create("test2", nil); err != nil {
		t.Fatal(err)
	}
	// make sure a file with `null` (.e.g. empty opts map from older daemon) is ok
	if err := ioutil.WriteFile(filepath.Join(rootDir, "test2"), []byte("null"), 600); err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test3", nil); err != nil {
		t.Fatal(err)
	}
	// make sure an empty opts file doesn't break us too
	if err := ioutil.WriteFile(filepath.Join(rootDir, "test3"), nil, 600); err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test4", map[string]string{}); err != nil {
		t.Fatal(err)
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	for _, name := range []string{"test1", "test2", "test3", "test4"} {
		v, err := r.Get(name)
		if err != nil {
			t.Fatal(err)
		}
		lv, ok := v.(*localVolume)
		if !ok {
			t.Fatalf("expected *localVolume got: %v", reflect.TypeOf(v))
		}
		if lv.opts != nil {
			t.Fatalf("expected opts to be nil, got: %v", lv.opts)
		}
		if _, err := lv.Mount("1234"); err != nil {
			t.Fatal(err)
		}
	}
}
<commit_msg>volume/local/TestCreateWithOpts(): use mount filter<commit_after>package local // import "github.com/docker/docker/volume/local"

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"github.com/docker/docker/pkg/idtools"
	"github.com/docker/docker/pkg/mount"
)

func TestGetAddress(t *testing.T) {
	cases := map[string]string{
		"addr=11.11.11.1":   "11.11.11.1",
		" ":                 "",
		"addr=":             "",
		"addr=2001:db8::68": "2001:db8::68",
	}
	for name, success := range cases {
		v := getAddress(name)
		if v != success {
			t.Errorf("Test case failed for %s actual: %s expected : %s", name, v, success)
		}
	}

}

func TestRemove(t *testing.T) {
	// TODO Windows: Investigate why this test fails on Windows under CI
	//               but passes locally.
	if runtime.GOOS == "windows" {
		t.Skip("Test failing on Windows CI")
	}
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	vol, err := r.Create("testing", nil)
	if err != nil {
		t.Fatal(err)
	}

	if err := r.Remove(vol); err != nil {
		t.Fatal(err)
	}

	vol, err = r.Create("testing2", nil)
	if err != nil {
		t.Fatal(err)
	}
	if err := os.RemoveAll(vol.Path()); err != nil {
		t.Fatal(err)
	}

	if err := r.Remove(vol); err != nil {
		t.Fatal(err)
	}

	if _, err := os.Stat(vol.Path()); err != nil && !os.IsNotExist(err) {
		t.Fatal("volume dir not removed")
	}

	if l, _ := r.List(); len(l) != 0 {
		t.Fatal("expected there to be no volumes")
	}
}

func TestInitializeWithVolumes(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	vol, err := r.Create("testing", nil)
	if err != nil {
		t.Fatal(err)
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	v, err := r.Get(vol.Name())
	if err != nil {
		t.Fatal(err)
	}

	if v.Path() != vol.Path() {
		t.Fatal("expected to re-initialize root with existing volumes")
	}
}

func TestCreate(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	cases := map[string]bool{
		"name":                  true,
		"name-with-dash":        true,
		"name_with_underscore":  true,
		"name/with/slash":       false,
		"name/with/../../slash": false,
		"./name":                false,
		"../name":               false,
		"./":                    false,
		"../":                   false,
		"~":                     false,
		".":                     false,
		"..":                    false,
		"...":                   false,
	}

	for name, success := range cases {
		v, err := r.Create(name, nil)
		if success {
			if err != nil {
				t.Fatal(err)
			}
			if v.Name() != name {
				t.Fatalf("Expected volume with name %s, got %s", name, v.Name())
			}
		} else {
			if err == nil {
				t.Fatalf("Expected error creating volume with name %s, got nil", name)
			}
		}
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}
}

func TestValidateName(t *testing.T) {
	r := &Root{}
	names := map[string]bool{
		"x":           false,
		"/testvol":    false,
		"thing.d":     true,
		"hello-world": true,
		"./hello":     false,
		".hello":      false,
	}

	for vol, expected := range names {
		err := r.validateName(vol)
		if expected && err != nil {
			t.Fatalf("expected %s to be valid got %v", vol, err)
		}
		if !expected && err == nil {
			t.Fatalf("expected %s to be invalid", vol)
		}
	}
}

func TestCreateWithOpts(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip()
	}
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	rootDir, err := ioutil.TempDir("", "local-volume-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test", map[string]string{"invalidopt": "notsupported"}); err == nil {
		t.Fatal("expected invalid opt to cause error")
	}

	vol, err := r.Create("test", map[string]string{"device": "tmpfs", "type": "tmpfs", "o": "size=1m,uid=1000"})
	if err != nil {
		t.Fatal(err)
	}
	v := vol.(*localVolume)

	dir, err := v.Mount("1234")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := v.Unmount("1234"); err != nil {
			t.Fatal(err)
		}
	}()

	mountInfos, err := mount.GetMounts(mount.SingleEntryFilter(dir))
	if err != nil {
		t.Fatal(err)
	}
	if len(mountInfos) != 1 {
		t.Fatalf("expected 1 mount, found %d: %+v", len(mountInfos), mountInfos)
	}

	info := mountInfos[0]
	t.Logf("%+v", info)
	if info.Fstype != "tmpfs" {
		t.Fatalf("expected tmpfs mount, got %q", info.Fstype)
	}
	if info.Source != "tmpfs" {
		t.Fatalf("expected tmpfs mount, got %q", info.Source)
	}
	if !strings.Contains(info.VfsOpts, "uid=1000") {
		t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts)
	}
	if !strings.Contains(info.VfsOpts, "size=1024k") {
		t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts)
	}

	if v.active.count != 1 {
		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
	}

	// test double mount
	if _, err := v.Mount("1234"); err != nil {
		t.Fatal(err)
	}
	if v.active.count != 2 {
		t.Fatalf("Expected active mount count to be 2, got %d", v.active.count)
	}

	if err := v.Unmount("1234"); err != nil {
		t.Fatal(err)
	}
	if v.active.count != 1 {
		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
	}

	mounted, err := mount.Mounted(v.path)
	if err != nil {
		t.Fatal(err)
	}
	if !mounted {
		t.Fatal("expected mount to still be active")
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	v2, exists := r.volumes["test"]
	if !exists {
		t.Fatal("missing volume on restart")
	}

	if !reflect.DeepEqual(v.opts, v2.opts) {
		t.Fatal("missing volume options on restart")
	}
}

func TestRealodNoOpts(t *testing.T) {
	rootDir, err := ioutil.TempDir("", "volume-test-reload-no-opts")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(rootDir)

	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test1", nil); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Create("test2", nil); err != nil {
		t.Fatal(err)
	}
	// make sure a file with `null` (.e.g. empty opts map from older daemon) is ok
	if err := ioutil.WriteFile(filepath.Join(rootDir, "test2"), []byte("null"), 600); err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test3", nil); err != nil {
		t.Fatal(err)
	}
	// make sure an empty opts file doesn't break us too
	if err := ioutil.WriteFile(filepath.Join(rootDir, "test3"), nil, 600); err != nil {
		t.Fatal(err)
	}

	if _, err := r.Create("test4", map[string]string{}); err != nil {
		t.Fatal(err)
	}

	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
	if err != nil {
		t.Fatal(err)
	}

	for _, name := range []string{"test1", "test2", "test3", "test4"} {
		v, err := r.Get(name)
		if err != nil {
			t.Fatal(err)
		}
		lv, ok := v.(*localVolume)
		if !ok {
			t.Fatalf("expected *localVolume got: %v", reflect.TypeOf(v))
		}
		if lv.opts != nil {
			t.Fatalf("expected opts to be nil, got: %v", lv.opts)
		}
		if _, err := lv.Mount("1234"); err != nil {
			t.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package vspherecli

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/plugins/products/bosh-init"
	"github.com/enaml-ops/omg-cli/utils"
)

// GetFlags returns the available CLI flags
func GetFlags() []cli.Flag {
	boshdefaults := boshinit.GetVSphereDefaults()

	boshFlags := boshinit.BoshFlags(boshdefaults)
	vsphereFlags := []cli.Flag{
		// vsphere specific flags
		cli.StringFlag{Name: "vsphere-address", Value: "", Usage: "IP of the vCenter"},
		cli.StringFlag{Name: "vsphere-user", Value: "", Usage: "vSphere user"},
		cli.StringFlag{Name: "vsphere-password", Value: "", Usage: "vSphere user's password"},
		cli.StringFlag{Name: "vsphere-datacenter-name", Value: "", Usage: "name of the datacenter the Director will use for VM creation"},
		cli.StringFlag{Name: "vsphere-vm-folder", Value: "", Usage: "name of the folder created to hold VMs"},
		cli.StringFlag{Name: "vsphere-template-folder", Value: "", Usage: "the name of the folder created to hold stemcells"},
		cli.StringFlag{Name: "vsphere-datastore", Value: "", Usage: "name of the datastore the Director will use for storing VMs"},
		cli.StringFlag{Name: "vsphere-disk-path", Value: "", Usage: "name of the VMs folder, disk folder will be automatically created in the chosen datastore."},
		cli.StringSliceFlag{Name: "vsphere-clusters", Value: &cli.StringSlice{""}, Usage: "one or more vSphere datacenter cluster names"},
		cli.StringFlag{Name: "vsphere-resource-pool", Value: "", Usage: "Name of resource pool for vsphere cluster"},
		// vsphere subnet1 flags
		cli.StringFlag{Name: "vsphere-subnet1-name", Usage: "name of the vSphere network for subnet1"},
		cli.StringFlag{Name: "vsphere-subnet1-range", Usage: "CIDR range for subnet1"},
		cli.StringFlag{Name: "vsphere-subnet1-gateway", Usage: "IP of the default gateway for subnet1"},
		cli.StringSliceFlag{Name: "vsphere-subnet1-dns", Usage: "IP of the DNS server(s) for subnet1"},
	}
	for _, flag := range vsphereFlags {
		boshFlags = append(boshFlags, flag)
	}
	return boshFlags
}

// GetAction returns a function action that can be registered with the CLI
func GetAction(boshInitDeploy func(string)) func(c *cli.Context) error {
	return func(c *cli.Context) (e error) {
		var boshBase *boshinit.BoshBase
		if boshBase, e = boshinit.NewBoshBase(c); e != nil {
			return
		}
		utils.CheckRequired(c, "vsphere-address", "vsphere-user", "vsphere-password", "vsphere-datacenter-name",
			"vsphere-vm-folder", "vsphere-template-folder", "vsphere-datastore", "vsphere-disk-path",
			"vsphere-clusters", "vsphere-resource-pool", "vsphere-subnet1-name", "vsphere-subnet1-range", "vsphere-subnet1-range", "vsphere-subnet1-dns")

		manifest := boshinit.NewVSphereBosh(boshinit.VSphereInitConfig{
			// vsphere specific
			VSphereAddress:        c.String("vsphere-address"),
			VSphereUser:           c.String("vsphere-user"),
			VSpherePassword:       c.String("vsphere-password"),
			VSphereDatacenterName: c.String("vsphere-datacenter-name"),
			VSphereVMFolder:       c.String("vsphere-vm-folder"),
			VSphereTemplateFolder: c.String("vsphere-template-folder"),
			VSphereDataStore:      c.String("vsphere-datastore"),
			VSphereDiskPath:       c.String("vsphere-disk-path"),
			VSphereClusters:       utils.ClearDefaultStringSliceValue(c.StringSlice("vsphere-clusters")...),
			VSphereResourcePool:   c.String("vsphere-resource-pool"),
			VSphereNetworks: []boshinit.Network{boshinit.Network{
				Name:    c.String("vsphere-subnet1-name"),
				Range:   c.String("vsphere-subnet1-range"),
				Gateway: c.String("vsphere-subnet1-range"),
				DNS:     utils.ClearDefaultStringSliceValue(c.StringSlice("vsphere-subnet1-dns")...),
			}},
		}, boshBase)

		if yamlString, err := enaml.Paint(manifest); err == nil {

			if c.Bool("print-manifest") {
				fmt.Println(yamlString)

			} else {
				utils.DeployYaml(yamlString, boshInitDeploy)
			}
		} else {
			e = err
		}
		return
	}
}
<commit_msg>fixed bug with typo in vSphere bosh-init<commit_after>package vspherecli

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/plugins/products/bosh-init"
	"github.com/enaml-ops/omg-cli/utils"
)

// GetFlags returns the available CLI flags
func GetFlags() []cli.Flag {
	boshdefaults := boshinit.GetVSphereDefaults()

	boshFlags := boshinit.BoshFlags(boshdefaults)
	vsphereFlags := []cli.Flag{
		// vsphere specific flags
		cli.StringFlag{Name: "vsphere-address", Value: "", Usage: "IP of the vCenter"},
		cli.StringFlag{Name: "vsphere-user", Value: "", Usage: "vSphere user"},
		cli.StringFlag{Name: "vsphere-password", Value: "", Usage: "vSphere user's password"},
		cli.StringFlag{Name: "vsphere-datacenter-name", Value: "", Usage: "name of the datacenter the Director will use for VM creation"},
		cli.StringFlag{Name: "vsphere-vm-folder", Value: "", Usage: "name of the folder created to hold VMs"},
		cli.StringFlag{Name: "vsphere-template-folder", Value: "", Usage: "the name of the folder created to hold stemcells"},
		cli.StringFlag{Name: "vsphere-datastore", Value: "", Usage: "name of the datastore the Director will use for storing VMs"},
		cli.StringFlag{Name: "vsphere-disk-path", Value: "", Usage: "name of the VMs folder, disk folder will be automatically created in the chosen datastore."},
		cli.StringSliceFlag{Name: "vsphere-clusters", Value: &cli.StringSlice{""}, Usage: "one or more vSphere datacenter cluster names"},
		cli.StringFlag{Name: "vsphere-resource-pool", Value: "", Usage: "Name of resource pool for vsphere cluster"},
		// vsphere subnet1 flags
		cli.StringFlag{Name: "vsphere-subnet1-name", Usage: "name of the vSphere network for subnet1"},
		cli.StringFlag{Name: "vsphere-subnet1-range", Usage: "CIDR range for subnet1"},
		cli.StringFlag{Name: "vsphere-subnet1-gateway", Usage: "IP of the default gateway for subnet1"},
		cli.StringSliceFlag{Name: "vsphere-subnet1-dns", Usage: "IP of the DNS server(s) for subnet1"},
	}
	for _, flag := range vsphereFlags {
		boshFlags = append(boshFlags, flag)
	}
	return boshFlags
}

// GetAction returns a function action that can be registered with the CLI
func GetAction(boshInitDeploy func(string)) func(c *cli.Context) error {
	return func(c *cli.Context) (e error) {
		var boshBase *boshinit.BoshBase
		if boshBase, e = boshinit.NewBoshBase(c); e != nil {
			return
		}
		utils.CheckRequired(c, "vsphere-address", "vsphere-user", "vsphere-password", "vsphere-datacenter-name",
			"vsphere-vm-folder", "vsphere-template-folder", "vsphere-datastore", "vsphere-disk-path",
			"vsphere-clusters", "vsphere-resource-pool", "vsphere-subnet1-name", "vsphere-subnet1-range", "vsphere-subnet1-range", "vsphere-subnet1-dns")

		manifest := boshinit.NewVSphereBosh(boshinit.VSphereInitConfig{
			// vsphere specific
			VSphereAddress:        c.String("vsphere-address"),
			VSphereUser:           c.String("vsphere-user"),
			VSpherePassword:       c.String("vsphere-password"),
			VSphereDatacenterName: c.String("vsphere-datacenter-name"),
			VSphereVMFolder:       c.String("vsphere-vm-folder"),
			VSphereTemplateFolder: c.String("vsphere-template-folder"),
			VSphereDataStore:      c.String("vsphere-datastore"),
			VSphereDiskPath:       c.String("vsphere-disk-path"),
			VSphereClusters:       utils.ClearDefaultStringSliceValue(c.StringSlice("vsphere-clusters")...),
			VSphereResourcePool:   c.String("vsphere-resource-pool"),
			VSphereNetworks: []boshinit.Network{boshinit.Network{
				Name:    c.String("vsphere-subnet1-name"),
				Range:   c.String("vsphere-subnet1-range"),
				Gateway: c.String("vsphere-subnet1-gateway"),
				DNS:     utils.ClearDefaultStringSliceValue(c.StringSlice("vsphere-subnet1-dns")...),
			}},
		}, boshBase)

		if yamlString, err := enaml.Paint(manifest); err == nil {

			if c.Bool("print-manifest") {
				fmt.Println(yamlString)

			} else {
				utils.DeployYaml(yamlString, boshInitDeploy)
			}
		} else {
			e = err
		}
		return
	}
}
<|endoftext|>


<commit_before>package instances

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/echo"
)

type apiInstance struct {
	*instance.Instance
}

func (i *apiInstance) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.Instance)
}

// Links is used to generate a JSON-API link for the instance
func (i *apiInstance) Links() *jsonapi.LinksList {
	return &jsonapi.LinksList{Self: "/instances/" + i.Instance.DocID}
}

// Relationships is used to generate the content relationship in JSON-API format
func (i *apiInstance) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (i *apiInstance) Included() []jsonapi.Object {
	return nil
}

func createHandler(c echo.Context) error {
	var diskQuota int64
	if c.QueryParam("DiskQuota") != "" {
		var err error
		diskQuota, err = strconv.ParseInt(c.QueryParam("DiskQuota"), 10, 64)
		if err != nil {
			return wrapError(err)
		}
	}
	var settings couchdb.JSONDoc
	settings.M = make(map[string]interface{})
	for _, setting := range strings.Split(c.QueryParam("Settings"), ",") {
		if parts := strings.SplitN(setting, ":", 2); len(parts) == 2 {
			settings.M[parts[0]] = parts[1]
		}
	}
	if tz := c.QueryParam("Timezone"); tz != "" {
		settings.M["tz"] = tz
	}
	if email := c.QueryParam("Email"); email != "" {
		settings.M["email"] = email
	}
	if name := c.QueryParam("PublicName"); name != "" {
		settings.M["public_name"] = name
	}
	in, err := instance.Create(&instance.Options{
		Domain:    c.QueryParam("Domain"),
		Locale:    c.QueryParam("Locale"),
		DiskQuota: diskQuota,
		Settings:  settings,
		Apps:      utils.SplitTrimString(c.QueryParam("Apps"), ","),
		Dev:       (c.QueryParam("Dev") == "true"),
	})
	if err != nil {
		return wrapError(err)
	}
	in.OAuthSecret = nil
	in.SessionSecret = nil
	in.PassphraseHash = nil
	pass := c.QueryParam("Passphrase")
	if pass != "" {
		if err = in.RegisterPassphrase([]byte(pass), in.RegisterToken); err != nil {
			return err
		}
	}
	return jsonapi.Data(c, http.StatusCreated, &apiInstance{in}, nil)
}

func showHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func modifyHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	var shouldUpdate bool
	if quota := c.QueryParam("DiskQuota"); quota != "" {
		var diskQuota int64
		diskQuota, err = strconv.ParseInt(quota, 10, 64)
		if err != nil {
			return wrapError(err)
		}
		i.BytesDiskQuota = diskQuota
		shouldUpdate = true
	}
	if locale := c.QueryParam("Locale"); locale != "" {
		i.Locale = locale
		shouldUpdate = true
	}
	if shouldUpdate {
		if err = instance.Update(i); err != nil {
			return wrapError(err)
		}
	}
	if debug, err := strconv.ParseBool(c.QueryParam("Debug")); err == nil {
		if debug {
			err = logger.AddDebugDomain(domain)
		} else {
			err = logger.RemoveDebugDomain(domain)
		}
		if err != nil {
			return wrapError(err)
		}
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func listHandler(c echo.Context) error {
	is, err := instance.List()
	if err != nil {
		if couchdb.IsNoDatabaseError(err) {
			return jsonapi.DataList(c, http.StatusOK, nil, nil)
		}
		return wrapError(err)
	}

	objs := make([]jsonapi.Object, len(is))
	for i, in := range is {
		objs[i] = &apiInstance{in}
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

func deleteHandler(c echo.Context) error {
	domain := c.Param("domain")
	err := instance.Destroy(domain)
	if err != nil {
		return wrapError(err)
	}
	return c.NoContent(http.StatusNoContent)
}

func createToken(c echo.Context) error {
	domain := c.QueryParam("Domain")
	audience := c.QueryParam("Audience")
	scope := c.QueryParam("Scope")
	subject := c.QueryParam("Subject")
	expire := c.QueryParam("Expire")
	in, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	switch audience {
	case "app":
		audience = permissions.AppAudience
	case "konn", "konnector":
		audience = permissions.KonnectorAudience
	case "access-token":
		audience = permissions.AccessTokenAudience
	case "cli":
		audience = permissions.CLIAudience
	default:
		return echo.NewHTTPError(http.StatusBadRequest, "Unknown audience %s", audience)
	}
	issuedAt := time.Now()
	if expire != "" && expire != "0s" {
		var duration time.Duration
		if duration, err = time.ParseDuration(expire); err == nil {
			issuedAt = issuedAt.Add(duration - permissions.TokenValidityDuration)
		}
	}
	token, err := in.MakeJWT(audience, subject, scope, issuedAt)
	if err != nil {
		return err
	}
	return c.String(http.StatusOK, token)
}

func registerClient(c echo.Context) error {
	in, err := instance.Get(c.QueryParam("Domain"))
	if err != nil {
		return wrapError(err)
	}
	client := oauth.Client{
		RedirectURIs: []string{c.QueryParam("RedirectURI")},
		ClientName:   c.QueryParam("ClientName"),
		SoftwareID:   c.QueryParam("SoftwareID"),
	}
	if regErr := client.Create(in); regErr != nil {
		return c.String(http.StatusBadRequest, regErr.Description)
	}
	return c.String(http.StatusOK, client.ClientID)
}

func wrapError(err error) error {
	switch err {
	case instance.ErrNotFound:
		return jsonapi.NotFound(err)
	case instance.ErrExists:
		return jsonapi.Conflict(err)
	case instance.ErrIllegalDomain:
		return jsonapi.InvalidParameter("domain", err)
	case instance.ErrMissingToken:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidToken:
		return jsonapi.BadRequest(err)
	case instance.ErrMissingPassphrase:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidPassphrase:
		return jsonapi.BadRequest(err)
	}
	return err
}

// Routes sets the routing for the instances service
func Routes(router *echo.Group) {
	router.GET("", listHandler)
	router.POST("", createHandler)
	router.GET("/:domain", showHandler)
	router.PATCH("/:domain", modifyHandler)
	router.DELETE("/:domain", deleteHandler)
	router.POST("/token", createToken)
	router.POST("/oauth_client", registerClient)
}
<commit_msg>Continue to filter out secrets from admin api<commit_after>package instances

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/echo"
)

type apiInstance struct {
	*instance.Instance
}

func (i *apiInstance) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.Instance)
}

// Links is used to generate a JSON-API link for the instance
func (i *apiInstance) Links() *jsonapi.LinksList {
	return &jsonapi.LinksList{Self: "/instances/" + i.Instance.DocID}
}

// Relationships is used to generate the content relationship in JSON-API format
func (i *apiInstance) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (i *apiInstance) Included() []jsonapi.Object {
	return nil
}

func createHandler(c echo.Context) error {
	var diskQuota int64
	if c.QueryParam("DiskQuota") != "" {
		var err error
		diskQuota, err = strconv.ParseInt(c.QueryParam("DiskQuota"), 10, 64)
		if err != nil {
			return wrapError(err)
		}
	}
	var settings couchdb.JSONDoc
	settings.M = make(map[string]interface{})
	for _, setting := range strings.Split(c.QueryParam("Settings"), ",") {
		if parts := strings.SplitN(setting, ":", 2); len(parts) == 2 {
			settings.M[parts[0]] = parts[1]
		}
	}
	if tz := c.QueryParam("Timezone"); tz != "" {
		settings.M["tz"] = tz
	}
	if email := c.QueryParam("Email"); email != "" {
		settings.M["email"] = email
	}
	if name := c.QueryParam("PublicName"); name != "" {
		settings.M["public_name"] = name
	}
	in, err := instance.Create(&instance.Options{
		Domain:    c.QueryParam("Domain"),
		Locale:    c.QueryParam("Locale"),
		DiskQuota: diskQuota,
		Settings:  settings,
		Apps:      utils.SplitTrimString(c.QueryParam("Apps"), ","),
		Dev:       (c.QueryParam("Dev") == "true"),
	})
	if err != nil {
		return wrapError(err)
	}
	in.OAuthSecret = nil
	in.SessionSecret = nil
	pass := c.QueryParam("Passphrase")
	if pass != "" {
		if err = in.RegisterPassphrase([]byte(pass), in.RegisterToken); err != nil {
			return err
		}
	}
	return jsonapi.Data(c, http.StatusCreated, &apiInstance{in}, nil)
}

func showHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func modifyHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	var shouldUpdate bool
	if quota := c.QueryParam("DiskQuota"); quota != "" {
		var diskQuota int64
		diskQuota, err = strconv.ParseInt(quota, 10, 64)
		if err != nil {
			return wrapError(err)
		}
		i.BytesDiskQuota = diskQuota
		shouldUpdate = true
	}
	if locale := c.QueryParam("Locale"); locale != "" {
		i.Locale = locale
		shouldUpdate = true
	}
	if shouldUpdate {
		if err = instance.Update(i); err != nil {
			return wrapError(err)
		}
	}
	if debug, err := strconv.ParseBool(c.QueryParam("Debug")); err == nil {
		if debug {
			err = logger.AddDebugDomain(domain)
		} else {
			err = logger.RemoveDebugDomain(domain)
		}
		if err != nil {
			return wrapError(err)
		}
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func listHandler(c echo.Context) error {
	is, err := instance.List()
	if err != nil {
		if couchdb.IsNoDatabaseError(err) {
			return jsonapi.DataList(c, http.StatusOK, nil, nil)
		}
		return wrapError(err)
	}

	objs := make([]jsonapi.Object, len(is))
	for i, in := range is {
		in.OAuthSecret = nil
		in.SessionSecret = nil
		objs[i] = &apiInstance{in}
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

func deleteHandler(c echo.Context) error {
	domain := c.Param("domain")
	err := instance.Destroy(domain)
	if err != nil {
		return wrapError(err)
	}
	return c.NoContent(http.StatusNoContent)
}

func createToken(c echo.Context) error {
	domain := c.QueryParam("Domain")
	audience := c.QueryParam("Audience")
	scope := c.QueryParam("Scope")
	subject := c.QueryParam("Subject")
	expire := c.QueryParam("Expire")
	in, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	switch audience {
	case "app":
		audience = permissions.AppAudience
	case "konn", "konnector":
		audience = permissions.KonnectorAudience
	case "access-token":
		audience = permissions.AccessTokenAudience
	case "cli":
		audience = permissions.CLIAudience
	default:
		return echo.NewHTTPError(http.StatusBadRequest, "Unknown audience %s", audience)
	}
	issuedAt := time.Now()
	if expire != "" && expire != "0s" {
		var duration time.Duration
		if duration, err = time.ParseDuration(expire); err == nil {
			issuedAt = issuedAt.Add(duration - permissions.TokenValidityDuration)
		}
	}
	token, err := in.MakeJWT(audience, subject, scope, issuedAt)
	if err != nil {
		return err
	}
	return c.String(http.StatusOK, token)
}

func registerClient(c echo.Context) error {
	in, err := instance.Get(c.QueryParam("Domain"))
	if err != nil {
		return wrapError(err)
	}
	client := oauth.Client{
		RedirectURIs: []string{c.QueryParam("RedirectURI")},
		ClientName:   c.QueryParam("ClientName"),
		SoftwareID:   c.QueryParam("SoftwareID"),
	}
	if regErr := client.Create(in); regErr != nil {
		return c.String(http.StatusBadRequest, regErr.Description)
	}
	return c.String(http.StatusOK, client.ClientID)
}

func wrapError(err error) error {
	switch err {
	case instance.ErrNotFound:
		return jsonapi.NotFound(err)
	case instance.ErrExists:
		return jsonapi.Conflict(err)
	case instance.ErrIllegalDomain:
		return jsonapi.InvalidParameter("domain", err)
	case instance.ErrMissingToken:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidToken:
		return jsonapi.BadRequest(err)
	case instance.ErrMissingPassphrase:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidPassphrase:
		return jsonapi.BadRequest(err)
	}
	return err
}

// Routes sets the routing for the instances service
func Routes(router *echo.Group) {
	router.GET("", listHandler)
	router.POST("", createHandler)
	router.GET("/:domain", showHandler)
	router.PATCH("/:domain", modifyHandler)
	router.DELETE("/:domain", deleteHandler)
	router.POST("/token", createToken)
	router.POST("/oauth_client", registerClient)
}
<|endoftext|>


<commit_before>// +build !windows

/*
 Copyright 2020 Padduck, LLC
  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 tty

import (
	"fmt"
	"github.com/creack/pty"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/logging"
	"github.com/pufferpanel/pufferpanel/v2/messages"
	"github.com/shirou/gopsutil/process"
	"github.com/spf13/cast"
	"io"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"
)

type tty struct {
	*pufferpanel.BaseEnvironment
	mainProcess *exec.Cmd
	stdInWriter io.Writer
}

func (t *tty) ttyExecuteAsync(steps pufferpanel.ExecutionData) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if running {
		err = pufferpanel.ErrProcessRunning
		return
	}
	t.Wait.Wait()

	pr := exec.Command(steps.Command, steps.Arguments...)
	pr.Dir = steps.WorkingDirectory
	pr.Env = append(os.Environ(), "HOME="+s.RootDirectory, "TERM=xterm-256color")
	for k, v := range steps.Environment {
		pr.Env = append(pr.Env, fmt.Sprintf("%s=%s", k, v))
	}

	wrapper := t.CreateWrapper()
	t.Wait.Add(1)
	pr.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	t.mainProcess = pr
	logging.Info().Printf("Starting process: %s %s", t.mainProcess.Path, strings.Join(t.mainProcess.Args[1:], " "))

	msg := messages.Status{Running:true}
	_ = t.WSManager.WriteMessage(msg)

	tty, err := pty.Start(pr)
	if err != nil {
		return
	}

	t.stdInWriter = tty

	go func(proxy io.Writer) {
		_, _ = io.Copy(proxy, tty)
	}(wrapper)

	go t.handleClose(steps.Callback)
	return
}

func (t *tty) ExecuteInMainProcess(cmd string) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return err
	}
	if !running {
		err = pufferpanel.ErrServerOffline
		return
	}
	stdIn := t.stdInWriter
	_, err = io.WriteString(stdIn, cmd+"\n")
	return
}

func (t *tty) Kill() (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if !running {
		return
	}
	return t.mainProcess.Process.Kill()
}

func (t *tty) IsRunning() (isRunning bool, err error) {
	isRunning = t.mainProcess != nil && t.mainProcess.Process != nil
	if isRunning {
		pr, pErr := os.FindProcess(t.mainProcess.Process.Pid)
		if pr == nil || pErr != nil {
			isRunning = false
		} else if pr.Signal(syscall.Signal(0)) != nil {
			isRunning = false
		}
	}
	return
}

func (t *tty) GetStats() (*pufferpanel.ServerStats, error) {
	running, err := t.IsRunning()
	if err != nil {
		return nil, err
	}
	if !running {
		return nil, pufferpanel.ErrServerOffline
	}
	pr, err := process.NewProcess(int32(t.mainProcess.Process.Pid))
	if err != nil {
		return nil, err
	}

	memMap, _ := pr.MemoryInfo()
	cpu, _ := pr.Percent(time.Second * 1)

	return &pufferpanel.ServerStats{
		Cpu:    cpu,
		Memory: cast.ToFloat64(memMap.RSS),
	}, nil
}

func (t *tty) Create() error {
	return os.Mkdir(t.RootDirectory, 0755)
}

func (t *tty) WaitForMainProcess() error {
	return t.WaitForMainProcessFor(0)
}

func (t *tty) WaitForMainProcessFor(timeout int) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if running {
		if timeout > 0 {
			var timer = time.AfterFunc(time.Duration(timeout)*time.Millisecond, func() {
				err = t.Kill()
			})
			t.Wait.Wait()
			timer.Stop()
		} else {
			t.Wait.Wait()
		}
	}
	return
}

func (t *tty) SendCode(code int) error {
	running, err := t.IsRunning()

	if err != nil || !running {
		return err
	}

	return t.mainProcess.Process.Signal(syscall.Signal(code))
}

func (t *tty) handleClose(callback func(graceful bool)) {
	err := t.mainProcess.Wait()

	var success bool
	if t.mainProcess == nil || t.mainProcess.ProcessState == nil || err != nil {
		success = false
	} else {
		success = t.mainProcess.ProcessState.Success()
	}

	if t.mainProcess != nil && t.mainProcess.Process != nil {
		_ = t.mainProcess.Process.Release()
	}
	t.mainProcess = nil
	t.Wait.Done()

	msg := messages.Status{Running:false}
	_ = t.WSManager.WriteMessage(msg)

	if callback != nil {
		callback(success)
	}
}
<commit_msg>Fix build<commit_after>// +build !windows

/*
 Copyright 2020 Padduck, LLC
  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 tty

import (
	"fmt"
	"github.com/creack/pty"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/logging"
	"github.com/pufferpanel/pufferpanel/v2/messages"
	"github.com/shirou/gopsutil/process"
	"github.com/spf13/cast"
	"io"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"
)

type tty struct {
	*pufferpanel.BaseEnvironment
	mainProcess *exec.Cmd
	stdInWriter io.Writer
}

func (t *tty) ttyExecuteAsync(steps pufferpanel.ExecutionData) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if running {
		err = pufferpanel.ErrProcessRunning
		return
	}
	t.Wait.Wait()

	pr := exec.Command(steps.Command, steps.Arguments...)
	pr.Dir = steps.WorkingDirectory
	pr.Env = append(os.Environ(), "HOME="+t.RootDirectory, "TERM=xterm-256color")
	for k, v := range steps.Environment {
		pr.Env = append(pr.Env, fmt.Sprintf("%s=%s", k, v))
	}

	wrapper := t.CreateWrapper()
	t.Wait.Add(1)
	pr.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	t.mainProcess = pr
	logging.Info().Printf("Starting process: %s %s", t.mainProcess.Path, strings.Join(t.mainProcess.Args[1:], " "))

	msg := messages.Status{Running:true}
	_ = t.WSManager.WriteMessage(msg)

	tty, err := pty.Start(pr)
	if err != nil {
		return
	}

	t.stdInWriter = tty

	go func(proxy io.Writer) {
		_, _ = io.Copy(proxy, tty)
	}(wrapper)

	go t.handleClose(steps.Callback)
	return
}

func (t *tty) ExecuteInMainProcess(cmd string) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return err
	}
	if !running {
		err = pufferpanel.ErrServerOffline
		return
	}
	stdIn := t.stdInWriter
	_, err = io.WriteString(stdIn, cmd+"\n")
	return
}

func (t *tty) Kill() (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if !running {
		return
	}
	return t.mainProcess.Process.Kill()
}

func (t *tty) IsRunning() (isRunning bool, err error) {
	isRunning = t.mainProcess != nil && t.mainProcess.Process != nil
	if isRunning {
		pr, pErr := os.FindProcess(t.mainProcess.Process.Pid)
		if pr == nil || pErr != nil {
			isRunning = false
		} else if pr.Signal(syscall.Signal(0)) != nil {
			isRunning = false
		}
	}
	return
}

func (t *tty) GetStats() (*pufferpanel.ServerStats, error) {
	running, err := t.IsRunning()
	if err != nil {
		return nil, err
	}
	if !running {
		return nil, pufferpanel.ErrServerOffline
	}
	pr, err := process.NewProcess(int32(t.mainProcess.Process.Pid))
	if err != nil {
		return nil, err
	}

	memMap, _ := pr.MemoryInfo()
	cpu, _ := pr.Percent(time.Second * 1)

	return &pufferpanel.ServerStats{
		Cpu:    cpu,
		Memory: cast.ToFloat64(memMap.RSS),
	}, nil
}

func (t *tty) Create() error {
	return os.Mkdir(t.RootDirectory, 0755)
}

func (t *tty) WaitForMainProcess() error {
	return t.WaitForMainProcessFor(0)
}

func (t *tty) WaitForMainProcessFor(timeout int) (err error) {
	running, err := t.IsRunning()
	if err != nil {
		return
	}
	if running {
		if timeout > 0 {
			var timer = time.AfterFunc(time.Duration(timeout)*time.Millisecond, func() {
				err = t.Kill()
			})
			t.Wait.Wait()
			timer.Stop()
		} else {
			t.Wait.Wait()
		}
	}
	return
}

func (t *tty) SendCode(code int) error {
	running, err := t.IsRunning()

	if err != nil || !running {
		return err
	}

	return t.mainProcess.Process.Signal(syscall.Signal(code))
}

func (t *tty) handleClose(callback func(graceful bool)) {
	err := t.mainProcess.Wait()

	var success bool
	if t.mainProcess == nil || t.mainProcess.ProcessState == nil || err != nil {
		success = false
	} else {
		success = t.mainProcess.ProcessState.Success()
	}

	if t.mainProcess != nil && t.mainProcess.Process != nil {
		_ = t.mainProcess.Process.Release()
	}
	t.mainProcess = nil
	t.Wait.Done()

	msg := messages.Status{Running:false}
	_ = t.WSManager.WriteMessage(msg)

	if callback != nil {
		callback(success)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers

import (
)

// IdenticalTo(x) returns a matcher that matches values v such that all of the
// following hold:
//
//  *  v and x have identical types.
//
//  *  If v and x are of a reference type (slice, map, function, channel), then
//     they are either both nil or are references to the same object.
//
//  *  If v and x are not of a reference type, then v == x.
//
// This function will panic if x is of a value type that is not comparable. For
// example, x cannot be an array of functions.
func IdenticalTo(x interface{}) Matcher {
	// TODO
	return &hasSubstrMatcher{"asd"}
}
<commit_msg>Added the skeleton of a type check.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglematchers

import (
	"errors"
	"reflect"
)

// Should the supplied type be allowed as an argument to IdenticalTo?
func isLegalForIdenticalTo(t reflect.Type) (bool, error) {
	return false, errors.New("TODO")
}

// IdenticalTo(x) returns a matcher that matches values v such that all of the
// following hold:
//
//  *  v and x have identical types.
//
//  *  If v and x are of a reference type (slice, map, function, channel), then
//     they are either both nil or are references to the same object.
//
//  *  If v and x are not of a reference type, then v == x.
//
// This function will panic if x is of a value type that is not comparable. For
// example, x cannot be an array of functions.
func IdenticalTo(x interface{}) Matcher {
	t := reflect.TypeOf(x)

	// Reject illegal arguments.
	if ok, err := isLegalForIdenticalTo(t); !ok {
		panic("IdenticalTo: " + err.Error())
	}

	// TODO
	return &hasSubstrMatcher{"asd"}
}
<|endoftext|>