<commit_before>package ergo

import (
	"net/http"

	"github.com/wlMalk/ergo/constants"
	"github.com/wlMalk/ergo/validation"
)

type Wrapper interface {
	Match(*http.Request) http.Handler
	Set([]*Route)
}

var (
	DefSchemes  = []string{constants.SCHEME_HTTP}
	DefConsumes = []string{constants.MIME_JSON}
	DefProduces = []string{constants.MIME_JSON}
)

type Ergoer interface {
	schemer
	consumer
	producer
	NotFound(*Context)
	MethodNotAllowed(*Route, *Context)
	Err(error, *Response, *Request)
	Panic(*Context)
}

// Ergo

type Ergo struct {
	root   *Route
	router Wrapper

	schemes  []string
	consumes []string
	produces []string

	operations []*Operation

	NotFoundHandler      Handler
	MethodNotAllowedFunc MethodNotAllowedFunc
	ErrHandler           ErrHandler
	PanicHandler         Handler
}

func New() *Ergo {
	e := &Ergo{
		root:                 NewRoute(""),
		schemes:              DefSchemes,
		consumes:             DefConsumes,
		produces:             DefProduces,
		NotFoundHandler:      DefNotFoundHandler,
		MethodNotAllowedFunc: DefMethodNotAllowedFunc,
		ErrHandler:           DefErrHandler,
		PanicHandler:         DefPanicHandler,
	}
	return e
}

func NewWith(w Wrapper) *Ergo {
	e := New()
	e.Router(w)
	return e
}

func (e *Ergo) New(path string) *Route {
	return e.root.New(path)
}

// Use allows setting middleware for every operation in Ergo
func (e *Ergo) Use(middleware ...Middleware) *Ergo {
	e.root.Use(middleware...)
	return e
}

func (e *Ergo) UseFunc(middleware ...MiddlewareFunc) *Ergo {
	e.root.UseFunc(middleware...)
	return e
}

func (e *Ergo) Schemes(s ...string) *Ergo {
	schemes(e, s)
	return e
}

func (e *Ergo) Consumes(mimes ...string) *Ergo {
	consumes(e, mimes)
	return e
}

func (e *Ergo) Produces(mimes ...string) *Ergo {
	produces(e, mimes)
	return e
}

func (e *Ergo) Params(params ...*validation.Param) *Ergo {
	addParams(e.root, params)
	return e
}

// Router uses a router that implement Router interface
// as the main router.
func (e *Ergo) Router(w Wrapper) {
	e.router = w
}

// GetSchemes returns the default schemes.
func (e *Ergo) GetSchemes() []string {
	return e.schemes
}

// GetConsumes returns the default consumable content types.
func (e *Ergo) GetConsumes() []string {
	return e.consumes
}

// GetProduces returns the default producible content types.
func (e *Ergo) GetProduces() []string {
	return e.produces
}

func (e *Ergo) setSchemes(schemes []string) {
	e.schemes = schemes
}

func (e *Ergo) setConsumes(consumes []string) {
	e.consumes = consumes
}

func (e *Ergo) setProduces(produces []string) {
	e.produces = produces
}

func (e *Ergo) Prepare() error {
	e.PrepareRouter()
	return nil
}

func (e *Ergo) PrepareRouter() {
	for _, r := range e.root.GetAllRoutes() {
		ops := r.GetOperations()
		for _, o := range ops {
			o.Handler = getHandler(o.Handler, append(o.middleware, MiddlewareFunc(o.Validate)))
			o.ergo = e
		}
		e.operations = append(e.operations, ops...)
	}
	e.router.Set(e.root.GetAllRoutes())
}

func (e *Ergo) NotFound(ctx *Context) {
	e.NotFoundHandler.ServeHTTP(ctx)
}

func (e *Ergo) MethodNotAllowed(r *Route, ctx *Context) {
	e.MethodNotAllowedFunc(r).ServeHTTP(ctx)
}

func (e *Ergo) Err(err error, res *Response, req *Request) {
	e.ErrHandler.ServeHTTP(err, res, req)
}

func (e *Ergo) Panic(ctx *Context) {
	e.PanicHandler.ServeHTTP(ctx)
}

func (e *Ergo) Run(address string) error {
	err := e.Prepare()
	if err != nil {
		return err
	}
	return http.ListenAndServe(address, e)
}

func (e *Ergo) RunTLS(addr, certFile, keyFile string) error {
	err := e.Prepare()
	if err != nil {
		return err
	}
	return http.ListenAndServeTLS(addr, certFile, keyFile, e)
}

func (e *Ergo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := preparePath(r.URL.Path)
	if r.URL.Path != path && r.Method == "GET" {
		r.URL.Path = path
		http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
		return
	}

	handler := e.router.Match(r)
	if handler == nil {
		// not found
		return
	}

	handler.ServeHTTP(w, r)
}
<commit_msg>Setting default mime types<commit_after>package ergo

import (
	"net/http"

	"github.com/wlMalk/ergo/constants"
	"github.com/wlMalk/ergo/validation"
)

type Wrapper interface {
	Match(*http.Request) http.Handler
	Set([]*Route)
}

var (
	DefMimeType = constants.MIME_JSON

	DefSchemes  = []string{constants.SCHEME_HTTP}
	DefConsumes = []string{DefMimeType}
	DefProduces = []string{DefMimeType}
)

type Ergoer interface {
	schemer
	consumer
	producer
	NotFound(*Context)
	MethodNotAllowed(*Route, *Context)
	Err(error, *Response, *Request)
	Panic(*Context)
}

// Ergo

type Ergo struct {
	root   *Route
	router Wrapper

	schemes  []string
	consumes []string
	produces []string

	operations []*Operation

	NotFoundHandler      Handler
	MethodNotAllowedFunc MethodNotAllowedFunc
	ErrHandler           ErrHandler
	PanicHandler         Handler
}

func New() *Ergo {
	e := &Ergo{
		root:                 NewRoute(""),
		schemes:              DefSchemes,
		consumes:             DefConsumes,
		produces:             DefProduces,
		NotFoundHandler:      DefNotFoundHandler,
		MethodNotAllowedFunc: DefMethodNotAllowedFunc,
		ErrHandler:           DefErrHandler,
		PanicHandler:         DefPanicHandler,
	}
	return e
}

func NewWith(w Wrapper) *Ergo {
	e := New()
	e.Router(w)
	return e
}

func (e *Ergo) New(path string) *Route {
	return e.root.New(path)
}

// Use allows setting middleware for every operation in Ergo
func (e *Ergo) Use(middleware ...Middleware) *Ergo {
	e.root.Use(middleware...)
	return e
}

func (e *Ergo) UseFunc(middleware ...MiddlewareFunc) *Ergo {
	e.root.UseFunc(middleware...)
	return e
}

func (e *Ergo) Schemes(s ...string) *Ergo {
	schemes(e, s)
	return e
}

func (e *Ergo) Consumes(mimes ...string) *Ergo {
	consumes(e, mimes)
	return e
}

func (e *Ergo) Produces(mimes ...string) *Ergo {
	produces(e, mimes)
	return e
}

func (e *Ergo) Params(params ...*validation.Param) *Ergo {
	addParams(e.root, params)
	return e
}

// Router uses a router that implement Router interface
// as the main router.
func (e *Ergo) Router(w Wrapper) {
	e.router = w
}

// GetSchemes returns the default schemes.
func (e *Ergo) GetSchemes() []string {
	return e.schemes
}

// GetConsumes returns the default consumable content types.
func (e *Ergo) GetConsumes() []string {
	return e.consumes
}

// GetProduces returns the default producible content types.
func (e *Ergo) GetProduces() []string {
	return e.produces
}

func (e *Ergo) setSchemes(schemes []string) {
	e.schemes = schemes
}

func (e *Ergo) setConsumes(consumes []string) {
	e.consumes = consumes
}

func (e *Ergo) setProduces(produces []string) {
	e.produces = produces
}

func (e *Ergo) Prepare() error {
	e.PrepareRouter()
	return nil
}

func (e *Ergo) PrepareRouter() {
	for _, r := range e.root.GetAllRoutes() {
		ops := r.GetOperations()
		for _, o := range ops {
			o.Handler = getHandler(o.Handler, append(o.middleware, MiddlewareFunc(o.Validate)))
			o.ergo = e
		}
		e.operations = append(e.operations, ops...)
	}
	e.router.Set(e.root.GetAllRoutes())
}

func (e *Ergo) NotFound(ctx *Context) {
	e.NotFoundHandler.ServeHTTP(ctx)
}

func (e *Ergo) MethodNotAllowed(r *Route, ctx *Context) {
	e.MethodNotAllowedFunc(r).ServeHTTP(ctx)
}

func (e *Ergo) Err(err error, res *Response, req *Request) {
	e.ErrHandler.ServeHTTP(err, res, req)
}

func (e *Ergo) Panic(ctx *Context) {
	e.PanicHandler.ServeHTTP(ctx)
}

func (e *Ergo) Run(address string) error {
	err := e.Prepare()
	if err != nil {
		return err
	}
	return http.ListenAndServe(address, e)
}

func (e *Ergo) RunTLS(addr, certFile, keyFile string) error {
	err := e.Prepare()
	if err != nil {
		return err
	}
	return http.ListenAndServeTLS(addr, certFile, keyFile, e)
}

func (e *Ergo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := preparePath(r.URL.Path)
	if r.URL.Path != path && r.Method == "GET" {
		r.URL.Path = path
		http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
		return
	}

	handler := e.router.Match(r)
	if handler == nil {
		// not found
		return
	}

	handler.ServeHTTP(w, r)
}
<|endoftext|>


<commit_before>package daemonigo

import (
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

// Name of environment variable used to distinguish parent and child processes.
const EnvVarName = "_DAEMONIGO"
// Value of environment variable used to distinguish parent and child processes.
const EnvVarValue = "1"

const (
	fileMask = 0644
	umask    = 027
)

var (
	Name    = "daemon"
	PidFile = "daemon.pid"
	AppPath = "./" + filepath.Base(os.Args[0])

	pidFile *os.File
)

func Daemonize(workDir string) (isDeamon bool, err error) {
	const errLoc = "daemonic.Daemonize()"
	isDeamon = os.Getenv(EnvVarName) == EnvVarValue
	if len(workDir) != 0 {
		if err = os.Chdir(workDir); err != nil {
			err = fmt.Errorf("%s: changing working directory failed, reason -> %s", err.Error())
			return
		}
	}
	if isDeamon {
		syscall.Umask(int(umask))
		if _, err = syscall.Setsid(); err != nil {
			err = fmt.Errorf("%s: setsid failed, reason -> %s", err.Error())
			return
		}
		if pidFile, err = lockPidFile(); err != nil {
			err = fmt.Errorf("%s: locking PID file failed, reason -> %s: ", err.Error())
		}
	} else {
		if !flag.Parsed() {
			flag.Parse()
		}
		action, exist := actions[flag.Arg(0)]
		if exist {
			action()
		} else {
			arr := make([]string, 0, len(actions))
			for k, _ := range actions {
				arr = append(arr, k)
			}
			fmt.Println("Usage: " + os.Args[0] + " {" + strings.Join(arr, "|") + "}")
		}
	}
	return
}

func lockPidFile() (pidFile *os.File, err error) {
	var file *os.File
	file, err = os.OpenFile(PidFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMask)
	if err != nil {
		return
	}
	defer func() {
		// file must be open whole runtime to keep lock on itself
		if err != nil {
			file.Close()
		}
	}()

	if err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX); err != nil {
		return
	}
	var fileLen int
	fileLen, err = fmt.Fprint(file, os.Getpid())
	if err != nil {
		return
	}
	if err = file.Truncate(int64(fileLen)); err != nil {
		return
	}

	return file, err
}

func UnlockPidFile() {
	if pidFile != nil {
		syscall.Flock(int(pidFile.Fd()), syscall.LOCK_UN)
		pidFile.Close()
	}
}

func Status() (isRunning bool, pr *os.Process, e error) {
	var (
		err  error
		file *os.File
	)

	file, err = os.Open(PidFile)
	if err != nil {
		if !os.IsNotExist(err) {
			e = fmt.Errorf("could not open PID file: " + err.Error())
		}
		return
	}
	defer file.Close()
	fd := int(file.Fd())
	if err = syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB); err != syscall.EWOULDBLOCK {
		if err == nil {
			syscall.Flock(fd, syscall.LOCK_UN)
		} else {
			e = fmt.Errorf("PID file locking attempt failed: " + err.Error())
		}
		return
	}

	isRunning = true
	var n, pid int
	content := make([]byte, 128)
	n, err = file.Read(content)
	if err != nil && err != io.EOF {
		e = fmt.Errorf("could not read from PID file: " + err.Error())
		return
	}
	pid, err = strconv.Atoi(string(content[:n]))
	if n < 1 || err != nil {
		e = fmt.Errorf("bad PID format, PID file is possibly corrupted")
		return
	}
	pr, err = os.FindProcess(pid)
	if err != nil {
		e = fmt.Errorf("cannot find process by PID: " + err.Error())
	}

	return
}
<commit_msg>make umask and pid file mask exportable<commit_after>package daemonigo

import (
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

// Name of environment variable used to distinguish
// parent and daemonized processes.
var EnvVarName = "_DAEMONIGO"
// Value of environment variable used to distinguish
// parent and daemonized processes.
var EnvVarValue = "1"

// Value of file mask for PID-file.
var PidFileMask = 0644
// Value of umask for daemonized process.
var Umask = 027

var (
	Name    = "daemon"
	PidFile = "daemon.pid"
	AppPath = "./" + filepath.Base(os.Args[0])

	pidFile *os.File
)

func Daemonize(workDir string) (isDeamon bool, err error) {
	const errLoc = "daemonic.Daemonize()"
	isDeamon = os.Getenv(EnvVarName) == EnvVarValue
	if len(workDir) != 0 {
		if err = os.Chdir(workDir); err != nil {
			err = fmt.Errorf("%s: changing working directory failed, reason -> %s", err.Error())
			return
		}
	}
	if isDeamon {
		syscall.Umask(int(Umask))
		if _, err = syscall.Setsid(); err != nil {
			err = fmt.Errorf("%s: setsid failed, reason -> %s", err.Error())
			return
		}
		if pidFile, err = lockPidFile(); err != nil {
			err = fmt.Errorf("%s: locking PID file failed, reason -> %s: ", err.Error())
		}
	} else {
		if !flag.Parsed() {
			flag.Parse()
		}
		action, exist := actions[flag.Arg(0)]
		if exist {
			action()
		} else {
			arr := make([]string, 0, len(actions))
			for k, _ := range actions {
				arr = append(arr, k)
			}
			fmt.Println("Usage: " + os.Args[0] + " {" + strings.Join(arr, "|") + "}")
		}
	}
	return
}

func lockPidFile() (pidFile *os.File, err error) {
	var file *os.File
	file, err = os.OpenFile(PidFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, PidFileMask)
	if err != nil {
		return
	}
	defer func() {
		// file must be open whole runtime to keep lock on itself
		if err != nil {
			file.Close()
		}
	}()

	if err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX); err != nil {
		return
	}
	var fileLen int
	fileLen, err = fmt.Fprint(file, os.Getpid())
	if err != nil {
		return
	}
	if err = file.Truncate(int64(fileLen)); err != nil {
		return
	}

	return file, err
}

func UnlockPidFile() {
	if pidFile != nil {
		syscall.Flock(int(pidFile.Fd()), syscall.LOCK_UN)
		pidFile.Close()
	}
}

func Status() (isRunning bool, pr *os.Process, e error) {
	var (
		err  error
		file *os.File
	)

	file, err = os.Open(PidFile)
	if err != nil {
		if !os.IsNotExist(err) {
			e = fmt.Errorf("could not open PID file: " + err.Error())
		}
		return
	}
	defer file.Close()
	fd := int(file.Fd())
	if err = syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB); err != syscall.EWOULDBLOCK {
		if err == nil {
			syscall.Flock(fd, syscall.LOCK_UN)
		} else {
			e = fmt.Errorf("PID file locking attempt failed: " + err.Error())
		}
		return
	}

	isRunning = true
	var n, pid int
	content := make([]byte, 128)
	n, err = file.Read(content)
	if err != nil && err != io.EOF {
		e = fmt.Errorf("could not read from PID file: " + err.Error())
		return
	}
	pid, err = strconv.Atoi(string(content[:n]))
	if n < 1 || err != nil {
		e = fmt.Errorf("bad PID format, PID file is possibly corrupted")
		return
	}
	pr, err = os.FindProcess(pid)
	if err != nil {
		e = fmt.Errorf("cannot find process by PID: " + err.Error())
	}

	return
}
<|endoftext|>


<commit_before>package darksky

import (
	"fmt"
	"github.com/google/go-querystring/query"
)

var (
	BaseUrl = "https://api.darksky.net/forecast"
)

// DarkSky Api client
type DarkSky interface {
	Forecast(request ForecastRequest) (ForecastResponse, error)
}

type darkSky struct {
	ApiKey string
}

// New creates a new DarkSky client
func New(apiKey string) DarkSky {
	return &darkSky{apiKey}
}

// Forecast request a forecast
func (d *darkSky) Forecast(request ForecastRequest) (ForecastResponse, error) {
	response := ForecastResponse{}

	url := d.buildRequestUrl(request)

	err := get(url, nil, &response)

	return response, err
}

func (d *darkSky) buildRequestUrl(request ForecastRequest) string {
	url := fmt.Sprintf("%s/%s/%f,%f", BaseUrl, d.ApiKey, request.Latitude, request.Longitude)

	if request.Time != nil {
		url = url + fmt.Sprintf(",%d", request.Time)
	}

	values, _ := query.Values(request.Options)
	queryString := values.Encode()

	if len(queryString) > 0 {
		url = url + "?" + queryString
	}

	return url
}
<commit_msg>comment<commit_after>package darksky

import (
	"fmt"
	"github.com/google/go-querystring/query"
)

// DarkSky API endpoint
var (
	BaseUrl = "https://api.darksky.net/forecast"
)

// DarkSky Api client
type DarkSky interface {
	Forecast(request ForecastRequest) (ForecastResponse, error)
}

type darkSky struct {
	ApiKey string
}

// New creates a new DarkSky client
func New(apiKey string) DarkSky {
	return &darkSky{apiKey}
}

// Forecast request a forecast
func (d *darkSky) Forecast(request ForecastRequest) (ForecastResponse, error) {
	response := ForecastResponse{}

	url := d.buildRequestUrl(request)

	err := get(url, nil, &response)

	return response, err
}

func (d *darkSky) buildRequestUrl(request ForecastRequest) string {
	url := fmt.Sprintf("%s/%s/%f,%f", BaseUrl, d.ApiKey, request.Latitude, request.Longitude)

	if request.Time != nil {
		url = url + fmt.Sprintf(",%d", request.Time)
	}

	values, _ := query.Values(request.Options)
	queryString := values.Encode()

	if len(queryString) > 0 {
		url = url + "?" + queryString
	}

	return url
}
<|endoftext|>


<commit_before>package cupaloy

import (
	"fmt"
)

// Config can be used to run cupaloy with customised behaviour e.g. changing how it decides to update snapshots
type Config struct {
	// ShouldUpdate allows you to control the decision of whether to update snapshots
	// The default behaviour is to check if the UPDATE_SNASPHOTS environment variable is set
	ShouldUpdate      func() bool
	subDirName        string
	snapshotExtension string
}

func DefaultConfig() *Config {
	return &Config{
		ShouldUpdate:      shouldUpdate,
		subDirName:        ".snapshots",
		snapshotExtension: "",
	}
}

// Snapshot compares the given value to the it's previous value stored on the filesystem.
// An error containing a diff is returned if the snapshots do not match.
// Snapshot determines the snapshot file automatically from the name of the calling function.
func Snapshot(i ...interface{}) error {
	return DefaultConfig().snapshot(getNameOfCaller(), i...)
}

// SnapshotMulti is identical to Snapshot but can be called multiple times from the same function.
// This is done by providing a unique snapshotId for each invocation.
func SnapshotMulti(snapshotId string, i ...interface{}) error {
	snapshotName := fmt.Sprintf("%s-%s", getNameOfCaller(), snapshotId)
	return DefaultConfig().snapshot(snapshotName, i...)
}

func (c *Config) Snapshot(i ...interface{}) error {
	return c.snapshot(getNameOfCaller(), i...)
}

func (c *Config) SnapshotMulti(snapshotId string, i ...interface{}) error {
	snapshotName := fmt.Sprintf("%s-%s", getNameOfCaller(), snapshotId)
	return c.snapshot(snapshotName, i...)
}

func (c *Config) snapshot(snapshotName string, i ...interface{}) error {
	snapshot := takeSnapshot(i...)

	if c.ShouldUpdate() {
		return c.writeSnapshot(snapshotName, snapshot)
	}

	prevSnapshot, err := c.readSnapshot(snapshotName)
	if err != nil {
		return err
	}

	if snapshot != prevSnapshot {
		diff := diffSnapshots(prevSnapshot, snapshot)
		return fmt.Errorf("snapshot not equal:\n%s\n", diff)
	}

	return nil
}
<commit_msg>Add more godoc<commit_after>package cupaloy

import (
	"fmt"
)

// Config can be used to run cupaloy with customised behaviour e.g. changing how it decides to update snapshots
type Config struct {
	// ShouldUpdate allows you to control the decision of whether to update snapshots
	// The default behaviour is to check if the UPDATE_SNASPHOTS environment variable is set
	ShouldUpdate      func() bool
	subDirName        string
	snapshotExtension string
}

// DefaultConfig returns the default configuration for cupaloy.
// This should be used as the basis for custom configurations
func DefaultConfig() *Config {
	return &Config{
		ShouldUpdate:      shouldUpdate,
		subDirName:        ".snapshots",
		snapshotExtension: "",
	}
}

// Snapshot calls http://godoc.org/github.com/bradleyjkemp/cupaloy#Config.Snapshot with the default config
func Snapshot(i ...interface{}) error {
	return DefaultConfig().snapshot(getNameOfCaller(), i...)
}

// SnapshotMulti calls http://godoc.org/github.com/bradleyjkemp/cupaloy#Config.SnapshotMulti with the default config
func SnapshotMulti(snapshotId string, i ...interface{}) error {
	snapshotName := fmt.Sprintf("%s-%s", getNameOfCaller(), snapshotId)
	return DefaultConfig().snapshot(snapshotName, i...)
}

// Snapshot compares the given value to the it's previous value stored on the filesystem.
// An error containing a diff is returned if the snapshots do not match.
// Snapshot determines the snapshot file automatically from the name of the calling function.
func (c *Config) Snapshot(i ...interface{}) error {
	return c.snapshot(getNameOfCaller(), i...)
}

// SnapshotMulti is identical to Snapshot but can be called multiple times from the same function.
// This is done by providing a unique snapshotId for each invocation.
func (c *Config) SnapshotMulti(snapshotId string, i ...interface{}) error {
	snapshotName := fmt.Sprintf("%s-%s", getNameOfCaller(), snapshotId)
	return c.snapshot(snapshotName, i...)
}

func (c *Config) snapshot(snapshotName string, i ...interface{}) error {
	snapshot := takeSnapshot(i...)

	if c.ShouldUpdate() {
		return c.writeSnapshot(snapshotName, snapshot)
	}

	prevSnapshot, err := c.readSnapshot(snapshotName)
	if err != nil {
		return err
	}

	if snapshot != prevSnapshot {
		diff := diffSnapshots(prevSnapshot, snapshot)
		return fmt.Errorf("snapshot not equal:\n%s\n", diff)
	}

	return nil
}
<|endoftext|>


<commit_before>package datefmt

/*
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void parsetime(const char* src, const char* fmt, struct tm* tm) {
	strptime(src, fmt, tm);
}

char* formattime(const char* fmt, const struct tm* tm) {
	const size_t size = 64;
	char *timestamp;
	if (timestamp = malloc(size * sizeof(char))) {
		strftime(timestamp, size, fmt, tm);
		return timestamp;
	} else {
		errno = EINVAL;
		return NULL;
	}
}
*/
import "C"

import (
	"fmt"
	"time"
	"unsafe"
)

func Strptime(format, timestamp string) (t time.Time, err error) {
	c_timestamp := C.CString(timestamp)
	c_format := C.CString(format)
	defer func() {
		C.free(unsafe.Pointer(c_timestamp))
		C.free(unsafe.Pointer(c_format))
	}()
	var c_time C.struct_tm
	if _, trr := C.parsetime(c_timestamp, c_format, &c_time); trr != nil {
		err = fmt.Errorf("%s - %s:%s", trr, timestamp, format)
		return
	}
	t = time.Date(int(c_time.tm_year)+1900,
		time.Month(c_time.tm_mon+1),
		int(c_time.tm_mday),
		int(c_time.tm_hour),
		int(c_time.tm_min),
		int(c_time.tm_sec),
		0,
		time.FixedZone("", int(c_time.tm_gmtoff)),
	)
	return
}

func Strftime(format string, t time.Time) (timestamp string, err error) {
	c_format := C.CString(format)
	defer func() { C.free(unsafe.Pointer(c_format)) }()

	tz, offset := t.Zone()
	c_tz := C.CString(tz)
	defer func() { C.free(unsafe.Pointer(c_tz)) }()

	c_time := C.struct_tm{
		tm_year:   C.int(t.Year() - 1900),
		tm_mon:    C.int(t.Month() - 1),
		tm_mday:   C.int(t.Day()),
		tm_hour:   C.int(t.Hour()),
		tm_min:    C.int(t.Minute()),
		tm_sec:    C.int(t.Second()),
		tm_gmtoff: C.long(offset),
		tm_zone:   c_tz,
	}

	c_timestamp, trr := C.formattime(c_format, &c_time)
	defer func() { C.free(unsafe.Pointer(c_timestamp)) }()

	timestamp = C.GoString(c_timestamp)
	if trr == nil {
		timestamp = C.GoString(c_timestamp)
	} else {
		err = fmt.Errorf("%s - %s", trr, t)
	}
	return
}
<commit_msg>Fix compiler warning<commit_after>package datefmt

/*
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void parsetime(const char* src, const char* fmt, struct tm* tm) {
	strptime(src, fmt, tm);
}

char* formattime(const char* fmt, const struct tm* tm) {
	const size_t size = 64;
	char *timestamp;
	if ((timestamp = malloc(size * sizeof(char)))) {
		strftime(timestamp, size, fmt, tm);
		return timestamp;
	} else {
		errno = EINVAL;
		return NULL;
	}
}
*/
import "C"

import (
	"fmt"
	"time"
	"unsafe"
)

func Strptime(format, timestamp string) (t time.Time, err error) {
	c_timestamp := C.CString(timestamp)
	c_format := C.CString(format)
	defer func() {
		C.free(unsafe.Pointer(c_timestamp))
		C.free(unsafe.Pointer(c_format))
	}()
	var c_time C.struct_tm
	if _, trr := C.parsetime(c_timestamp, c_format, &c_time); trr != nil {
		err = fmt.Errorf("%s - %s:%s", trr, timestamp, format)
		return
	}
	t = time.Date(int(c_time.tm_year)+1900,
		time.Month(c_time.tm_mon+1),
		int(c_time.tm_mday),
		int(c_time.tm_hour),
		int(c_time.tm_min),
		int(c_time.tm_sec),
		0,
		time.FixedZone("", int(c_time.tm_gmtoff)),
	)
	return
}

func Strftime(format string, t time.Time) (timestamp string, err error) {
	c_format := C.CString(format)
	defer func() { C.free(unsafe.Pointer(c_format)) }()

	tz, offset := t.Zone()
	c_tz := C.CString(tz)
	defer func() { C.free(unsafe.Pointer(c_tz)) }()

	c_time := C.struct_tm{
		tm_year:   C.int(t.Year() - 1900),
		tm_mon:    C.int(t.Month() - 1),
		tm_mday:   C.int(t.Day()),
		tm_hour:   C.int(t.Hour()),
		tm_min:    C.int(t.Minute()),
		tm_sec:    C.int(t.Second()),
		tm_gmtoff: C.long(offset),
		tm_zone:   c_tz,
	}

	c_timestamp, trr := C.formattime(c_format, &c_time)
	defer func() { C.free(unsafe.Pointer(c_timestamp)) }()

	timestamp = C.GoString(c_timestamp)
	if trr == nil {
		timestamp = C.GoString(c_timestamp)
	} else {
		err = fmt.Errorf("%s - %s", trr, t)
	}
	return
}
<|endoftext|>


<commit_before>package project

import (
	"bufio"
	"bytes"
	"fmt"
	"path"
	"strings"

	"github.com/Sirupsen/logrus"
	yaml "gopkg.in/yaml.v2"
)

var (
	// ValidRemotes list the of valid prefixes that can be sent to Docker as a build remote location
	// This is public for consumers of libcompose to use
	ValidRemotes = []string{
		"git://",
		"git@github.com:",
		"github.com",
		"http:",
		"https:",
	}
	noMerge = []string{
		"links",
		"volumes_from",
	}
)

type rawSchema struct {
	Version  string        `yaml:"version"`
	Services rawServiceMap `yaml:"services"`
}

type rawService map[string]interface{}
type rawServiceMap map[string]rawService

func mergeProject(p *Project, file string, bytes []byte) (map[string]*ServiceConfig, error) {
	configs := make(map[string]*ServiceConfig)

	var schema rawSchema
	if err := yaml.Unmarshal(bytes, &schema); err != nil {
		return nil, err
	}

	var datas = make(rawServiceMap)
	switch {
	case schema.Version == "2":
		datas = schema.Services
	case len(schema.Version) == 0:
		datas = make(rawServiceMap)
		if err := yaml.Unmarshal(bytes, &datas); err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("docker-compose file with schema version %q is not supported", schema.Version)
	}

	if err := interpolate(p.context.EnvironmentLookup, &datas); err != nil {
		return nil, err
	}

	for name, data := range datas {
		data, err := parse(p.context.ResourceLookup, p.context.EnvironmentLookup, file, data, datas)
		if err != nil {
			logrus.Errorf("Failed to parse service %s: %v", name, err)
			return nil, err
		}

		if _, ok := p.Configs[name]; ok {
			var rawExistingService rawService
			if err := Convert(p.Configs[name], &rawExistingService); err != nil {
				return nil, err
			}

			data = mergeConfig(rawExistingService, data)
		}

		datas[name] = data
	}

	if err := Convert(datas, &configs); err != nil {
		return nil, err
	}

	adjustValues(configs)

	return configs, nil
}

func adjustValues(configs map[string]*ServiceConfig) {
	// yaml parser turns "no" into "false" but that is not valid for a restart policy
	for _, v := range configs {
		if v.Restart == "false" {
			v.Restart = "no"
		}
	}
}

func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData rawService) (rawService, error) {
	var config ServiceConfig

	if err := Convert(serviceData, &config); err != nil {
		return nil, err
	}

	if len(config.EnvFile.Slice()) == 0 {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
	}

	vars := config.Environment.Slice()

	for i := len(config.EnvFile.Slice()) - 1; i >= 0; i-- {
		envFile := config.EnvFile.Slice()[i]
		content, _, err := resourceLookup.Lookup(envFile, inFile)
		if err != nil {
			return nil, err
		}

		if err != nil {
			return nil, err
		}

		scanner := bufio.NewScanner(bytes.NewBuffer(content))
		for scanner.Scan() {
			line := strings.TrimSpace(scanner.Text())
			key := strings.SplitAfter(line, "=")[0]

			found := false
			for _, v := range vars {
				if strings.HasPrefix(v, key) {
					found = true
					break
				}
			}

			if !found {
				vars = append(vars, line)
			}
		}

		if scanner.Err() != nil {
			return nil, scanner.Err()
		}
	}

	serviceData["environment"] = vars

	delete(serviceData, "env_file")

	return serviceData, nil
}

func resolveBuild(inFile string, serviceData rawService) (rawService, error) {

	build := asString(serviceData["build"])
	if build == "" {
		return serviceData, nil
	}

	for _, remote := range ValidRemotes {
		if strings.HasPrefix(build, remote) {
			return serviceData, nil
		}
	}

	current := path.Dir(inFile)

	if build == "." {
		build = current
	} else {
		current = path.Join(current, build)
	}

	serviceData["build"] = current

	return serviceData, nil
}

func parse(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData rawService, datas rawServiceMap) (rawService, error) {
	serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
	if err != nil {
		return nil, err
	}

	serviceData, err = resolveBuild(inFile, serviceData)
	if err != nil {
		return nil, err
	}

	value, ok := serviceData["extends"]
	if !ok {
		return serviceData, nil
	}

	mapValue, ok := value.(map[interface{}]interface{})
	if !ok {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
	}

	file := asString(mapValue["file"])
	service := asString(mapValue["service"])

	if service == "" {
		return serviceData, nil
	}

	var baseService rawService

	if file == "" {
		if serviceData, ok := datas[service]; ok {
			baseService, err = parse(resourceLookup, environmentLookup, inFile, serviceData, datas)
		} else {
			return nil, fmt.Errorf("Failed to find service %s to extend", service)
		}
	} else {
		bytes, resolved, err := resourceLookup.Lookup(file, inFile)
		if err != nil {
			logrus.Errorf("Failed to lookup file %s: %v", file, err)
			return nil, err
		}

		var baseRawServices rawServiceMap
		if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
			return nil, err
		}

		err = interpolate(environmentLookup, &baseRawServices)
		if err != nil {
			return nil, err
		}

		baseService, ok = baseRawServices[service]
		if !ok {
			return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
		}

		baseService, err = parse(resourceLookup, environmentLookup, resolved, baseService, baseRawServices)
	}

	if err != nil {
		return nil, err
	}

	baseService = clone(baseService)

	logrus.Debugf("Merging %#v, %#v", baseService, serviceData)

	for _, k := range noMerge {
		if _, ok := baseService[k]; ok {
			source := file
			if source == "" {
				source = inFile
			}
			return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
		}
	}

	baseService = mergeConfig(baseService, serviceData)

	logrus.Debugf("Merged result %#v", baseService)

	return baseService, nil
}

func mergeConfig(baseService, serviceData rawService) rawService {
	for k, v := range serviceData {
		// Image and build are mutually exclusive in merge
		if k == "image" {
			delete(baseService, "build")
		} else if k == "build" {
			delete(baseService, "image")
		}
		existing, ok := baseService[k]
		if ok {
			baseService[k] = merge(existing, v)
		} else {
			baseService[k] = v
		}
	}

	return baseService
}

func merge(existing, value interface{}) interface{} {
	// append strings
	if left, lok := existing.([]interface{}); lok {
		if right, rok := value.([]interface{}); rok {
			return append(left, right...)
		}
	}

	//merge maps
	if left, lok := existing.(map[interface{}]interface{}); lok {
		if right, rok := value.(map[interface{}]interface{}); rok {
			newLeft := make(map[interface{}]interface{})
			for k, v := range left {
				newLeft[k] = v
			}
			for k, v := range right {
				newLeft[k] = v
			}
			return newLeft
		}
	}

	return value
}

func clone(in rawService) rawService {
	result := rawService{}
	for k, v := range in {
		result[k] = v
	}

	return result
}

func asString(obj interface{}) string {
	if v, ok := obj.(string); ok {
		return v
	}
	return ""
}
<commit_msg>Added checks in build path for docker-compose import<commit_after>package project

import (
	"bufio"
	"bytes"
	"fmt"
	"path"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	yaml "gopkg.in/yaml.v2"
)

var (
	// ValidRemotes list the of valid prefixes that can be sent to Docker as a build remote location
	// This is public for consumers of libcompose to use
	ValidRemotes = []string{
		"git://",
		"git@github.com:",
		"github.com",
		"http:",
		"https:",
	}
	noMerge = []string{
		"links",
		"volumes_from",
	}
)

type rawSchema struct {
	Version  string        `yaml:"version"`
	Services rawServiceMap `yaml:"services"`
}

type rawService map[string]interface{}
type rawServiceMap map[string]rawService

func mergeProject(p *Project, file string, bytes []byte) (map[string]*ServiceConfig, error) {
	configs := make(map[string]*ServiceConfig)

	var schema rawSchema
	if err := yaml.Unmarshal(bytes, &schema); err != nil {
		return nil, err
	}

	var datas = make(rawServiceMap)
	switch {
	case schema.Version == "2":
		datas = schema.Services
	case len(schema.Version) == 0:
		datas = make(rawServiceMap)
		if err := yaml.Unmarshal(bytes, &datas); err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("docker-compose file with schema version %q is not supported", schema.Version)
	}

	if err := interpolate(p.context.EnvironmentLookup, &datas); err != nil {
		return nil, err
	}

	for name, data := range datas {
		data, err := parse(p.context.ResourceLookup, p.context.EnvironmentLookup, file, data, datas)
		if err != nil {
			logrus.Errorf("Failed to parse service %s: %v", name, err)
			return nil, err
		}

		if _, ok := p.Configs[name]; ok {
			var rawExistingService rawService
			if err := Convert(p.Configs[name], &rawExistingService); err != nil {
				return nil, err
			}

			data = mergeConfig(rawExistingService, data)
		}

		datas[name] = data
	}

	if err := Convert(datas, &configs); err != nil {
		return nil, err
	}

	adjustValues(configs)

	return configs, nil
}

func adjustValues(configs map[string]*ServiceConfig) {
	// yaml parser turns "no" into "false" but that is not valid for a restart policy
	for _, v := range configs {
		if v.Restart == "false" {
			v.Restart = "no"
		}
	}
}

func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData rawService) (rawService, error) {
	var config ServiceConfig

	if err := Convert(serviceData, &config); err != nil {
		return nil, err
	}

	if len(config.EnvFile.Slice()) == 0 {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
	}

	vars := config.Environment.Slice()

	for i := len(config.EnvFile.Slice()) - 1; i >= 0; i-- {
		envFile := config.EnvFile.Slice()[i]
		content, _, err := resourceLookup.Lookup(envFile, inFile)
		if err != nil {
			return nil, err
		}

		if err != nil {
			return nil, err
		}

		scanner := bufio.NewScanner(bytes.NewBuffer(content))
		for scanner.Scan() {
			line := strings.TrimSpace(scanner.Text())
			key := strings.SplitAfter(line, "=")[0]

			found := false
			for _, v := range vars {
				if strings.HasPrefix(v, key) {
					found = true
					break
				}
			}

			if !found {
				vars = append(vars, line)
			}
		}

		if scanner.Err() != nil {
			return nil, scanner.Err()
		}
	}

	serviceData["environment"] = vars

	delete(serviceData, "env_file")

	return serviceData, nil
}

func resolveBuild(inFile string, serviceData rawService) (rawService, error) {

	build := asString(serviceData["build"])
	if build == "" {
		return serviceData, nil
	}

	for _, remote := range ValidRemotes {
		if strings.HasPrefix(build, remote) {
			return serviceData, nil
		}
	}
	if filepath.IsAbs(build) {
		return serviceData, nil
	}

	current := path.Dir(inFile)

	if build == "." {
		build = current
	} else {
		current = path.Join(current, build)
	}

	serviceData["build"] = current

	return serviceData, nil
}

func parse(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData rawService, datas rawServiceMap) (rawService, error) {
	serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
	if err != nil {
		return nil, err
	}

	serviceData, err = resolveBuild(inFile, serviceData)
	if err != nil {
		return nil, err
	}

	value, ok := serviceData["extends"]
	if !ok {
		return serviceData, nil
	}

	mapValue, ok := value.(map[interface{}]interface{})
	if !ok {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
	}

	file := asString(mapValue["file"])
	service := asString(mapValue["service"])

	if service == "" {
		return serviceData, nil
	}

	var baseService rawService

	if file == "" {
		if serviceData, ok := datas[service]; ok {
			baseService, err = parse(resourceLookup, environmentLookup, inFile, serviceData, datas)
		} else {
			return nil, fmt.Errorf("Failed to find service %s to extend", service)
		}
	} else {
		bytes, resolved, err := resourceLookup.Lookup(file, inFile)
		if err != nil {
			logrus.Errorf("Failed to lookup file %s: %v", file, err)
			return nil, err
		}

		var baseRawServices rawServiceMap
		if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
			return nil, err
		}

		err = interpolate(environmentLookup, &baseRawServices)
		if err != nil {
			return nil, err
		}

		baseService, ok = baseRawServices[service]
		if !ok {
			return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
		}

		baseService, err = parse(resourceLookup, environmentLookup, resolved, baseService, baseRawServices)
	}

	if err != nil {
		return nil, err
	}

	baseService = clone(baseService)

	logrus.Debugf("Merging %#v, %#v", baseService, serviceData)

	for _, k := range noMerge {
		if _, ok := baseService[k]; ok {
			source := file
			if source == "" {
				source = inFile
			}
			return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
		}
	}

	baseService = mergeConfig(baseService, serviceData)

	logrus.Debugf("Merged result %#v", baseService)

	return baseService, nil
}

func mergeConfig(baseService, serviceData rawService) rawService {
	for k, v := range serviceData {
		// Image and build are mutually exclusive in merge
		if k == "image" {
			delete(baseService, "build")
		} else if k == "build" {
			delete(baseService, "image")
		}
		existing, ok := baseService[k]
		if ok {
			baseService[k] = merge(existing, v)
		} else {
			baseService[k] = v
		}
	}

	return baseService
}

func merge(existing, value interface{}) interface{} {
	// append strings
	if left, lok := existing.([]interface{}); lok {
		if right, rok := value.([]interface{}); rok {
			return append(left, right...)
		}
	}

	//merge maps
	if left, lok := existing.(map[interface{}]interface{}); lok {
		if right, rok := value.(map[interface{}]interface{}); rok {
			newLeft := make(map[interface{}]interface{})
			for k, v := range left {
				newLeft[k] = v
			}
			for k, v := range right {
				newLeft[k] = v
			}
			return newLeft
		}
	}

	return value
}

func clone(in rawService) rawService {
	result := rawService{}
	for k, v := range in {
		result[k] = v
	}

	return result
}

func asString(obj interface{}) string {
	if v, ok := obj.(string); ok {
		return v
	}
	return ""
}
<|endoftext|>


<commit_before>package immortal

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"syscall"
)

func (self *Daemon) FIFO() error {
	// create status pipe
	status_fifo := fmt.Sprintf("%s/status", self.sdir)
	syscall.Mknod(status_fifo, syscall.S_IFIFO|0666, 0)

	file, err := os.OpenFile(self.sdir+"/status", os.O_RDWR, os.ModeNamedPipe)
	if err != nil {
		return err
	}

	reader := bufio.NewReader(file)

	go func() {
		defer file.Close()
		for {
			text, err := reader.ReadString('\n')
			if err != nil {
				self.ctrl.err <- err
			}
			self.ctrl.fifo <- strings.TrimSpace(text)
		}
	}()

	return nil
}
<commit_msg>	modified:   fifo.go<commit_after>package immortal

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
	"syscall"
)

func (self *Daemon) FIFO() error {
	// create status pipe
	status_fifo := fmt.Sprintf("%s/status", self.sdir)
	syscall.Mknod(status_fifo, syscall.S_IFIFO|0666, 0)

	file, err := os.OpenFile(self.sdir+"/status", os.O_RDWR, os.ModeNamedPipe)
	if err != nil {
		return err
	}

	r := bufio.NewReader(file)
	buf := make([]byte, 0, 8)

	go func() {
		defer file.Close()
		for {
			n, err := r.Read(buf[:cap(buf)])
			buf = buf[:n]
			if n == 0 {
				if err == nil {
					continue
				}
				if err == io.EOF {
					continue
				}
				self.ctrl.err <- err
			}
			self.ctrl.fifo <- strings.TrimSpace(string(buf))
		}
	}()

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 kvscheduler

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/unrolled/render"

	"github.com/ligato/cn-infra/rpc/rest"
	. "github.com/ligato/cn-infra/kvscheduler/api"
	"github.com/ligato/cn-infra/kvscheduler/internal/graph"
)

const (
	// prefix used for REST urls of the scheduler.
	urlPrefix = "/scheduler/"

	// txnHistoryURL is URL used to obtain the transaction history.
	txnHistoryURL = urlPrefix + "txn-history"

	// sinceArg is the name of the argument used to define the start of the time
	// window for the transaction history to display.
	sinceArg = "since"

	// untilArg is the name of the argument used to define the end of the time
	// window for the transaction history to display.
	untilArg = "until"

	// seqNumArg is the name of the argument used to define the sequence number
	// of the transaction to display (txnHistoryURL).
	seqNumArg = "seq-num"

	// keyTimelineURL is URL used to obtain timeline of value changes for a given key.
	keyTimelineURL = urlPrefix + "key-timeline"

	// keyArg is the name of the argument used to define key for "key-timeline" API.
	keyArg = "key"

	// graphSnapshotURL is URL used to obtain graph snapshot from a given point in time.
	graphSnapshotURL = urlPrefix + "graph-snapshot"

	// flagStatsURL is URL used to obtain flag statistics.
	flagStatsURL = urlPrefix + "flag-stats"

	// flagArg is the name of the argument used to define flag for "flag-stats" API.
	flagArg = "flag"

	// prefixArg is the name of the argument used to define prefix to filter keys
	// for "flag-stats" API.
	prefixArg = "prefix"

	// time is the name of the argument used to define point in time for a graph snapshot
	// to retrieve.
	timeArg = "time"

	// downstreamResyncURL is URL used to trigger downstream-resync.
	downstreamResyncURL = urlPrefix + "downstream-resync"

	// retryArg is the name of the argument used for "downstream-resync" API to tell whether
	// to retry failed operations or not.
	retryArg = "retry"

	// dumpURL is URL used to dump either SB or scheduler's internal state of kv-pairs
	// under the given descriptor.
	dumpURL = urlPrefix + "dump"

	// descriptorArg is the name of the argument used to define descriptor for "dump" API.
	descriptorArg = "descriptor"

	// internalArg is the name of the argument used for "dump" API to tell whether
	// to dump SB or the scheduler's internal view of SB.
	internalArg = "internal"
)

// errorString wraps string representation of an error that, unlike the original
// error, can be marshalled.
type errorString struct {
	Error string
}

// registerHandlers registers all supported REST APIs.
func (scheduler *Scheduler) registerHandlers(http rest.HTTPHandlers) {
	if http == nil {
		scheduler.Log.Warn("No http handler provided, skipping registration of KVScheduler REST handlers")
		return
	}
	http.RegisterHTTPHandler(txnHistoryURL, scheduler.txnHistoryGetHandler, "GET")
	http.RegisterHTTPHandler(keyTimelineURL, scheduler.keyTimelineGetHandler, "GET")
	http.RegisterHTTPHandler(graphSnapshotURL, scheduler.graphSnapshotGetHandler, "GET")
	http.RegisterHTTPHandler(flagStatsURL, scheduler.flagStatsGetHandler, "GET")
	http.RegisterHTTPHandler(downstreamResyncURL, scheduler.downstreamResyncPostHandler, "POST")
	http.RegisterHTTPHandler(dumpURL, scheduler.dumpGetHandler, "GET")
}

// txnHistoryGetHandler is the GET handler for "txn-history" API.
func (scheduler *Scheduler) txnHistoryGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		var since, until time.Time
		var seqNum int
		args := req.URL.Query()

		// parse optional *seq-num* argument
		if seqNumStr, withSeqNum := args[seqNumArg]; withSeqNum && len(seqNumStr) == 1 {
			var err error
			seqNum, err = strconv.Atoi(seqNumStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}

			// sequence number takes precedence over the since-until time window
			txn := scheduler.getRecordedTransaction(uint(seqNum))
			if txn == nil {
				err := errors.New("transaction with such sequence is not recorded")
				formatter.JSON(w, http.StatusNotFound, errorString{err.Error()})
				return
			}

			formatter.Text(w, http.StatusOK, txn.StringWithOpts(false, 0))
			return
		}

		// parse optional *until* argument
		if untilStr, withUntil := args[untilArg]; withUntil && len(untilStr) == 1 {
			var err error
			until, err = stringToTime(untilStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		// parse optional *since* argument
		if sinceStr, withSince := args[sinceArg]; withSince && len(sinceStr) == 1 {
			var err error
			since, err = stringToTime(sinceStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		txnHistory := scheduler.getTransactionHistory(since, until)
		formatter.Text(w, http.StatusOK, txnHistory.StringWithOpts(false, 0))
	}
}

// keyTimelineGetHandler is the GET handler for "key-timeline" API.
func (scheduler *Scheduler) keyTimelineGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()

		// parse mandatory *key* argument
		if keys, withKey := args[keyArg]; withKey && len(keys) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			timeline := graphR.GetNodeTimeline(keys[0])
			formatter.JSON(w, http.StatusOK, timeline)
			return
		}

		err := errors.New("missing key argument")
		formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
		return
	}
}

// graphSnapshotGetHandler is the GET handler for "graph-snapshot" API.
func (scheduler *Scheduler) graphSnapshotGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		timeVal := time.Now()
		args := req.URL.Query()

		// parse optional *time* argument
		if timeStr, withTime := args[timeArg]; withTime && len(timeStr) == 1 {
			var err error
			timeVal, err = stringToTime(timeStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		snapshot := graphR.GetSnapshot(timeVal)
		formatter.JSON(w, http.StatusOK, snapshot)
	}
}

// flagStatsGetHandler is the GET handler for "flag-stats" API.
func (scheduler *Scheduler) flagStatsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()
		var prefixes []string

		// parse repeated *prefix* argument
		prefixes, _ = args[prefixArg]

		if flags, withFlag := args[flagArg]; withFlag && len(flags) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			stats := graphR.GetFlagStats(flags[0], func(key string) bool {
				if len(prefixes) == 0 {
					return true
				}
				for _, prefix := range prefixes {
					if strings.HasPrefix(key, prefix) {
						return true
					}
				}
				return false
			})
			formatter.JSON(w, http.StatusOK, stats)
			return
		}

		err := errors.New("missing flag argument")
		formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
		return
	}
}

// downstreamResyncPostHandler is the POST handler for "downstream-resync" API.
func (scheduler *Scheduler) downstreamResyncPostHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		// parse optional *retry* argument
		args := req.URL.Query()
		retry := false
		if retryStr, withRetry := args[retryArg]; withRetry && len(retryStr) == 1 {
			retryVal := retryStr[0]
			if retryVal == "true" || retryVal == "1" {
				retry = true
			}
		}

		ctx := context.Background()
		ctx = WithDownstreamResync(ctx)
		if retry {
			ctx = WithRetry(ctx, time.Second, true)
		}
		kvErrors, txnError := scheduler.StartNBTransaction().Commit(ctx)
		if txnError != nil {
			formatter.JSON(w, http.StatusInternalServerError, errorString{txnError.Error()})
			return
		}
		if len(kvErrors) > 0 {
			kvErrorMap := make(map[string]errorString)
			for _, keyWithError := range kvErrors {
				kvErrorMap[keyWithError.Key] = errorString{keyWithError.Error.Error()}
			}
			formatter.JSON(w, http.StatusInternalServerError, kvErrorMap)
			return
		}
		formatter.Text(w, http.StatusOK, "SB was successfully synchronized with KVScheduler\n")
		return
	}
}

// dumpGetHandler is the GET handler for "dump" API.
func (scheduler *Scheduler) dumpGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()

		// parse mandatory *descriptor* argument
		descriptors, withDescriptor := args[descriptorArg]
		if !withDescriptor {
			err := errors.New("missing descriptor argument")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		if len(descriptors) != 1 {
			err := errors.New("descriptor argument listed more than once")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		descriptor := descriptors[0]

		// parse optional *internal* argument
		internalDump := false
		if internalStr, withInternal := args[internalArg]; withInternal && len(internalStr) == 1 {
			internalVal := internalStr[0]
			if internalVal == "true" || internalVal == "1" {
				internalDump = true
			}
		}

		// pause transaction processing
		if !internalDump {
			scheduler.txnLock.Lock()
			defer scheduler.txnLock.Unlock()
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		// dump from the in-memory graph first (for SB Dump it is used for correlation)
		inMemNodes := nodesToKVPairsWithMetadata(
			graphR.GetNodes(nil,
				graph.WithFlags(&DescriptorFlag{descriptor}),
				graph.WithoutFlags(&PendingFlag{}, &DerivedFlag{})))

		if internalDump {
			// return the scheduler's view of SB for the given descriptor
			formatter.JSON(w, http.StatusOK, inMemNodes)
			return
		}

		// obtain Dump handler from the descriptor
		kvDescriptor := scheduler.registry.GetDescriptor(descriptor)
		if kvDescriptor == nil {
			err := errors.New("descriptor is not registered")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		if kvDescriptor.Dump == nil {
			err := errors.New("descriptor does not support Dump operation")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}

		// dump the state directly from SB via descriptor
		dump, err := kvDescriptor.Dump(inMemNodes)
		if err != nil {
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		formatter.JSON(w, http.StatusOK, dump)
		return
	}
}

// stringToTime converts Unix timestamp from string to time.Time.
func stringToTime(s string) (time.Time, error) {
	sec, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return time.Time{}, err
	}
	return time.Unix(sec, 0), nil
}
<commit_msg>Allow to dump SB, internal and also the requested state via REST API.<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// 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 kvscheduler

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/unrolled/render"

	"github.com/ligato/cn-infra/rpc/rest"
	. "github.com/ligato/cn-infra/kvscheduler/api"
	"github.com/ligato/cn-infra/kvscheduler/internal/graph"
)

const (
	// prefix used for REST urls of the scheduler.
	urlPrefix = "/scheduler/"

	// txnHistoryURL is URL used to obtain the transaction history.
	txnHistoryURL = urlPrefix + "txn-history"

	// sinceArg is the name of the argument used to define the start of the time
	// window for the transaction history to display.
	sinceArg = "since"

	// untilArg is the name of the argument used to define the end of the time
	// window for the transaction history to display.
	untilArg = "until"

	// seqNumArg is the name of the argument used to define the sequence number
	// of the transaction to display (txnHistoryURL).
	seqNumArg = "seq-num"

	// keyTimelineURL is URL used to obtain timeline of value changes for a given key.
	keyTimelineURL = urlPrefix + "key-timeline"

	// keyArg is the name of the argument used to define key for "key-timeline" API.
	keyArg = "key"

	// graphSnapshotURL is URL used to obtain graph snapshot from a given point in time.
	graphSnapshotURL = urlPrefix + "graph-snapshot"

	// flagStatsURL is URL used to obtain flag statistics.
	flagStatsURL = urlPrefix + "flag-stats"

	// flagArg is the name of the argument used to define flag for "flag-stats" API.
	flagArg = "flag"

	// prefixArg is the name of the argument used to define prefix to filter keys
	// for "flag-stats" API.
	prefixArg = "prefix"

	// time is the name of the argument used to define point in time for a graph snapshot
	// to retrieve.
	timeArg = "time"

	// downstreamResyncURL is URL used to trigger downstream-resync.
	downstreamResyncURL = urlPrefix + "downstream-resync"

	// retryArg is the name of the argument used for "downstream-resync" API to tell whether
	// to retry failed operations or not.
	retryArg = "retry"

	// dumpURL is URL used to dump either SB or scheduler's internal state of kv-pairs
	// under the given descriptor.
	dumpURL = urlPrefix + "dump"

	// descriptorArg is the name of the argument used to define descriptor for "dump" API.
	descriptorArg = "descriptor"

	// stateArg is the name of the argument used for "dump" API to tell whether
	// to dump "SB" (what there really is), "internal" state (what scheduler thinks
	// there is) or "NB" (the requested state). Default is to dump SB.
	stateArg = "state"

	/* recognized system states: */
	// SB = southbound (what there really is)
	SB = "SB"
	// internalState (scheduler's view of SB)
	internalState = "internal"
	// NB = northbound (the requested state)
	NB = "NB"
)

// errorString wraps string representation of an error that, unlike the original
// error, can be marshalled.
type errorString struct {
	Error string
}

// registerHandlers registers all supported REST APIs.
func (scheduler *Scheduler) registerHandlers(http rest.HTTPHandlers) {
	if http == nil {
		scheduler.Log.Warn("No http handler provided, skipping registration of KVScheduler REST handlers")
		return
	}
	http.RegisterHTTPHandler(txnHistoryURL, scheduler.txnHistoryGetHandler, "GET")
	http.RegisterHTTPHandler(keyTimelineURL, scheduler.keyTimelineGetHandler, "GET")
	http.RegisterHTTPHandler(graphSnapshotURL, scheduler.graphSnapshotGetHandler, "GET")
	http.RegisterHTTPHandler(flagStatsURL, scheduler.flagStatsGetHandler, "GET")
	http.RegisterHTTPHandler(downstreamResyncURL, scheduler.downstreamResyncPostHandler, "POST")
	http.RegisterHTTPHandler(dumpURL, scheduler.dumpGetHandler, "GET")
}

// txnHistoryGetHandler is the GET handler for "txn-history" API.
func (scheduler *Scheduler) txnHistoryGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		var since, until time.Time
		var seqNum int
		args := req.URL.Query()

		// parse optional *seq-num* argument
		if seqNumStr, withSeqNum := args[seqNumArg]; withSeqNum && len(seqNumStr) == 1 {
			var err error
			seqNum, err = strconv.Atoi(seqNumStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}

			// sequence number takes precedence over the since-until time window
			txn := scheduler.getRecordedTransaction(uint(seqNum))
			if txn == nil {
				err := errors.New("transaction with such sequence is not recorded")
				formatter.JSON(w, http.StatusNotFound, errorString{err.Error()})
				return
			}

			formatter.Text(w, http.StatusOK, txn.StringWithOpts(false, 0))
			return
		}

		// parse optional *until* argument
		if untilStr, withUntil := args[untilArg]; withUntil && len(untilStr) == 1 {
			var err error
			until, err = stringToTime(untilStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		// parse optional *since* argument
		if sinceStr, withSince := args[sinceArg]; withSince && len(sinceStr) == 1 {
			var err error
			since, err = stringToTime(sinceStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		txnHistory := scheduler.getTransactionHistory(since, until)
		formatter.Text(w, http.StatusOK, txnHistory.StringWithOpts(false, 0))
	}
}

// keyTimelineGetHandler is the GET handler for "key-timeline" API.
func (scheduler *Scheduler) keyTimelineGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()

		// parse mandatory *key* argument
		if keys, withKey := args[keyArg]; withKey && len(keys) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			timeline := graphR.GetNodeTimeline(keys[0])
			formatter.JSON(w, http.StatusOK, timeline)
			return
		}

		err := errors.New("missing key argument")
		formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
		return
	}
}

// graphSnapshotGetHandler is the GET handler for "graph-snapshot" API.
func (scheduler *Scheduler) graphSnapshotGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		timeVal := time.Now()
		args := req.URL.Query()

		// parse optional *time* argument
		if timeStr, withTime := args[timeArg]; withTime && len(timeStr) == 1 {
			var err error
			timeVal, err = stringToTime(timeStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		snapshot := graphR.GetSnapshot(timeVal)
		formatter.JSON(w, http.StatusOK, snapshot)
	}
}

// flagStatsGetHandler is the GET handler for "flag-stats" API.
func (scheduler *Scheduler) flagStatsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()
		var prefixes []string

		// parse repeated *prefix* argument
		prefixes, _ = args[prefixArg]

		if flags, withFlag := args[flagArg]; withFlag && len(flags) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			stats := graphR.GetFlagStats(flags[0], func(key string) bool {
				if len(prefixes) == 0 {
					return true
				}
				for _, prefix := range prefixes {
					if strings.HasPrefix(key, prefix) {
						return true
					}
				}
				return false
			})
			formatter.JSON(w, http.StatusOK, stats)
			return
		}

		err := errors.New("missing flag argument")
		formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
		return
	}
}

// downstreamResyncPostHandler is the POST handler for "downstream-resync" API.
func (scheduler *Scheduler) downstreamResyncPostHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		// parse optional *retry* argument
		args := req.URL.Query()
		retry := false
		if retryStr, withRetry := args[retryArg]; withRetry && len(retryStr) == 1 {
			retryVal := retryStr[0]
			if retryVal == "true" || retryVal == "1" {
				retry = true
			}
		}

		ctx := context.Background()
		ctx = WithDownstreamResync(ctx)
		if retry {
			ctx = WithRetry(ctx, time.Second, true)
		}
		kvErrors, txnError := scheduler.StartNBTransaction().Commit(ctx)
		if txnError != nil {
			formatter.JSON(w, http.StatusInternalServerError, errorString{txnError.Error()})
			return
		}
		if len(kvErrors) > 0 {
			kvErrorMap := make(map[string]errorString)
			for _, keyWithError := range kvErrors {
				kvErrorMap[keyWithError.Key] = errorString{keyWithError.Error.Error()}
			}
			formatter.JSON(w, http.StatusInternalServerError, kvErrorMap)
			return
		}
		formatter.Text(w, http.StatusOK, "SB was successfully synchronized with KVScheduler\n")
		return
	}
}

// dumpGetHandler is the GET handler for "dump" API.
func (scheduler *Scheduler) dumpGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()

		// parse mandatory *descriptor* argument
		descriptors, withDescriptor := args[descriptorArg]
		if !withDescriptor {
			err := errors.New("missing descriptor argument")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		if len(descriptors) != 1 {
			err := errors.New("descriptor argument listed more than once")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		descriptor := descriptors[0]

		// parse optional *state* argument (default = SB)
		state := SB
		if stateStr, withState := args[stateArg]; withState && len(stateStr) == 1 {
			state = stateStr[0]
			if state != SB && state != NB && state != internalState {
				err := errors.New("unrecognized system state")
				formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
				return
			}
		}

		// pause transaction processing
		if state == SB {
			scheduler.txnLock.Lock()
			defer scheduler.txnLock.Unlock()
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		if state == NB {
			// dump the requested state
			var kvPairs []KVWithMetadata
			nbNodes := graphR.GetNodes(nil,
					graph.WithFlags(&DescriptorFlag{descriptor}, &OriginFlag{FromNB}),
					graph.WithoutFlags(&DerivedFlag{}))

			for _, node := range nbNodes {
				lastChange := getNodeLastChange(node)
				if lastChange.value == nil {
					// value requested to be deleted
					continue
				}
				kvPairs = append(kvPairs, KVWithMetadata{
					Key:      node.GetKey(),
					Value:    lastChange.value,
					Origin:   FromNB,
				})
			}
		}

		/* internal/SB: */

		// dump from the in-memory graph first (for SB Dump it is used for correlation)
		inMemNodes := nodesToKVPairsWithMetadata(
			graphR.GetNodes(nil,
				graph.WithFlags(&DescriptorFlag{descriptor}),
				graph.WithoutFlags(&PendingFlag{}, &DerivedFlag{})))

		if state == SB {
			// return the scheduler's view of SB for the given descriptor
			formatter.JSON(w, http.StatusOK, inMemNodes)
			return
		}

		// obtain Dump handler from the descriptor
		kvDescriptor := scheduler.registry.GetDescriptor(descriptor)
		if kvDescriptor == nil {
			err := errors.New("descriptor is not registered")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		if kvDescriptor.Dump == nil {
			err := errors.New("descriptor does not support Dump operation")
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}

		// dump the state directly from SB via descriptor
		dump, err := kvDescriptor.Dump(inMemNodes)
		if err != nil {
			formatter.JSON(w, http.StatusInternalServerError, errorString{err.Error()})
			return
		}
		formatter.JSON(w, http.StatusOK, dump)
		return
	}
}

// stringToTime converts Unix timestamp from string to time.Time.
func stringToTime(s string) (time.Time, error) {
	sec, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return time.Time{}, err
	}
	return time.Unix(sec, 0), nil
}
<|endoftext|>


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

/*  Filename:    postkr.go
 *  Author:      Homin Lee <homin.lee@suapapa.net>
 *  Created:     2012-07-06 20:49:03.265118 +0900 KST
 *  Description: Main source file in postkr
 */

// Package postkr does ....
package postkr

import (
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	iconv "github.com/djimenez/iconv-go"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

type serverError struct {
	XMLName xml.Name `xml:"error"`
	Message string   `xml:"message"`
	Code    string   `xml:"error_code"`
}

type zipcodeList struct {
	XMLName xml.Name  `xml:"post"`
	Items   []Zipcode `xml:"itemlist>item"`
}

type Zipcode struct {
	XMLName xml.Name `xml:"item"`
	Address string   `xml:"address"`
	Code    string   `xml:"postcd"`
}

func (p *Zipcode) String() string {
	if p == nil {
		return "nil"
	}
	return p.Code + ":" + p.Address
}

var queryFmtStr string = "http://biz.epost.go.kr/KpostPortal/openapied?" +
	"regkey=%s&target=%s&query=%s"

type Service struct {
	regkey       string // 사용신청을 통해 받은 인증 key 스트링(30자리)
	lastQueryUrl string
}

func (s *Service) queryUrl(str string, target string) string {
	iconvUtf8ToCp949, err := iconv.NewConverter("utf8", "cp949")
	if err != nil {
		log.Println("failed create iconv converter: ", err)
		return ""
	}
	defer iconvUtf8ToCp949.Close()

	qs, err := iconvUtf8ToCp949.ConvertString(str)
	if err != nil {
		log.Println("iconv failed: ", err)
		return ""
	}

	query := url.QueryEscape(qs)
	s.lastQueryUrl = fmt.Sprintf(queryFmtStr, s.regkey, target, query)

	return s.lastQueryUrl
}

func unmarshalCp949(data []byte, v interface{}) error {
	d := xml.NewDecoder(bytes.NewBuffer(data))
	d.CharsetReader = func(c string, i io.Reader) (io.Reader, error) {
		if c != "euc-kr" && c != "cp949" {
			return nil, errors.New("unexpect charset: " + c)
		}
		return iconv.NewReader(i, "cp949", "utf8")
	}

	return d.Decode(v)
}

func (s *Service) SerchZipCode(key string) ([]Zipcode, error) {
	url := s.queryUrl(key, "post")
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Accept-Language", "ko")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	var l zipcodeList
	if err := unmarshalCp949(body, &l); err != nil {
		var e serverError
		if err := unmarshalCp949(body, &e); err == nil {
			errStr := fmt.Sprintf("(%s) %s", e.Code, e.Message)
			return nil, errors.New(errStr)
		}
		return nil, err
	}

	return l.Items, nil
}

func NewService(regkey string) *Service {
	s := new(Service)
	s.regkey = regkey
	return s
}
<commit_msg>add Error() to serverError<commit_after>// Copyright 2012, Homin Lee. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*  Filename:    postkr.go
 *  Author:      Homin Lee <homin.lee@suapapa.net>
 *  Created:     2012-07-06 20:49:03.265118 +0900 KST
 *  Description: Main source file in postkr
 */

// Package postkr does ....
package postkr

import (
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	iconv "github.com/djimenez/iconv-go"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

type serverError struct {
	XMLName xml.Name `xml:"error"`
	Message string   `xml:"message"`
	Code    string   `xml:"error_code"`
}

func (e *serverError) String() string {
	return fmt.Sprintf("(%s) %s", e.Code, e.Message)
}

func (e *serverError) Error() error {
	return errors.New(e.String())
}

type zipcodeList struct {
	XMLName xml.Name  `xml:"post"`
	Items   []Zipcode `xml:"itemlist>item"`
}

type Zipcode struct {
	XMLName xml.Name `xml:"item"`
	Address string   `xml:"address"`
	Code    string   `xml:"postcd"`
}

func (p *Zipcode) String() string {
	if p == nil {
		return "nil"
	}
	return p.Code + ":" + p.Address
}

var queryFmtStr string = "http://biz.epost.go.kr/KpostPortal/openapied?" +
	"regkey=%s&target=%s&query=%s"

type Service struct {
	regkey       string // 사용신청을 통해 받은 인증 key 스트링(30자리)
	lastQueryUrl string
}

func (s *Service) queryUrl(str string, target string) string {
	iconvUtf8ToCp949, err := iconv.NewConverter("utf8", "cp949")
	if err != nil {
		log.Println("failed create iconv converter: ", err)
		return ""
	}
	defer iconvUtf8ToCp949.Close()

	qs, err := iconvUtf8ToCp949.ConvertString(str)
	if err != nil {
		log.Println("iconv failed: ", err)
		return ""
	}

	query := url.QueryEscape(qs)
	s.lastQueryUrl = fmt.Sprintf(queryFmtStr, s.regkey, target, query)

	return s.lastQueryUrl
}

func unmarshalCp949(data []byte, v interface{}) error {
	d := xml.NewDecoder(bytes.NewBuffer(data))
	d.CharsetReader = func(c string, i io.Reader) (io.Reader, error) {
		if c != "euc-kr" && c != "cp949" {
			return nil, errors.New("unexpect charset: " + c)
		}
		return iconv.NewReader(i, "cp949", "utf8")
	}

	return d.Decode(v)
}

func (s *Service) SerchZipCode(key string) ([]Zipcode, error) {
	url := s.queryUrl(key, "post")
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Accept-Language", "ko")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	var l zipcodeList
	if err := unmarshalCp949(body, &l); err != nil {
		var e serverError
		if err := unmarshalCp949(body, &e); err == nil {
			return nil, e.Error()
		}
		return nil, err
	}

	return l.Items, nil
}

func NewService(regkey string) *Service {
	s := new(Service)
	s.regkey = regkey
	return s
}
<|endoftext|>


<commit_before>package fish

import (
    "bytes"
    "code.google.com/p/go.crypto/blowfish"
    "strings"
)

func pad(src []byte, mod int) []byte {
    remainder := len(src) % mod
    if remainder != 0 {
        return append(src, bytes.Repeat([]byte{0}, mod-remainder)...)
    }
    return src
}

func blowfishEncrypt(key string, src []byte) ([]byte, error) {
    cipher, err := blowfish.NewCipher([]byte(key))
    if err != nil {
        return nil, err
    }
    const bs = blowfish.BlockSize
    dst := make([]byte, len(src))
    for i := 0; i < len(src); i += bs {
        cipher.Encrypt(dst[i:i+bs], src[i:i+bs])
    }
    return dst, nil
}

func blowfishDecrypt(key string, src []byte) ([]byte, error) {
    cipher, err := blowfish.NewCipher([]byte(key))
    if err != nil {
        return nil, err
    }
    const bs = blowfish.BlockSize
    dst := make([]byte, len(src))
    for i := 0; i < len(src); i += bs {
        cipher.Decrypt(dst[i:i+bs], src[i:i+bs])
    }
    return bytes.TrimRight(dst, "\x00"), nil
}

func Base64Encode(src []byte) string {
    charset := "./0123456789abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    // Ensure src is padded to a multiple of 8
    src = pad(src, 8)

    buf := make([]byte, len(src)/2*3)
    left := 0
    right := 0
    k := -1
    var v int

    n := 0
    for k < len(src)-1 {
        for _, count := range []uint8{24, 16, 8, 0} {
            k++
            v = int(src[k])
            left += v << count
        }
        for _, count := range []uint8{24, 16, 8, 0} {
            k++
            v = int(src[k])
            right += v << count
        }
        for i := 0; i < 6; i++ {
            buf[n] = charset[right&0x3F]
            n++
            right >>= 6
        }
        for i := 0; i < 6; i++ {
            buf[n] = charset[left&0x3F]
            n++
            left >>= 6
        }
    }
    return string(buf)
}

func Base64Decode(src []byte) []byte {
    charset := []byte("./0123456789abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

    buf := make([]byte, len(src)/3*2)
    k := -1

    n := 0
    for k < len(src)-1 {
        left := 0
        right := 0
        var v int
        var w int
        var z int
        for i := uint8(0); i < 6; i++ {
            k++
            v = bytes.IndexByte(charset, src[k])
            right |= v << (i * 6)
        }
        for i := uint8(0); i < 6; i++ {
            k++
            v = bytes.IndexByte(charset, src[k])
            left |= v << (i * 6)
        }
        for i := uint8(0); i < 4; i++ {
            w = (left & (0xFF << ((3 - i) * 8)))
            z = w >> ((3 - i) * 8)
            buf[n] = byte(z)
            n++
        }
        for i := uint8(0); i < 4; i++ {
            w = (right & (0xFF << ((3 - i) * 8)))
            z = w >> ((3 - i) * 8)
            buf[n] = byte(z)
            n++
        }
    }
    return buf
}

func Encrypt(key string, message string) (string, error) {
    enc, err := blowfishEncrypt(key, pad([]byte(message), 8))
    if err != nil {
        return "", nil
    }
    return "+OK " + Base64Encode(enc), nil
}

func IsEncrypted(s string) bool {
    return strings.HasPrefix(s, "+OK ") || strings.HasPrefix(s, "mcps ")
}

func Decrypt(key string, message string) (string, error) {
    if strings.HasPrefix(message, "+OK ") {
        message = message[4:]
    } else if strings.HasPrefix(message, "mcps ") {
        message = message[5:]
    } else {
        return message, nil
    }
    dec, err := blowfishDecrypt(key, Base64Decode([]byte(message)))
    if err != nil {
        return "", err
    }
    return string(dec), nil
}
<commit_msg>Return err on error<commit_after>package fish

import (
    "bytes"
    "code.google.com/p/go.crypto/blowfish"
    "strings"
)

func pad(src []byte, mod int) []byte {
    remainder := len(src) % mod
    if remainder != 0 {
        return append(src, bytes.Repeat([]byte{0}, mod-remainder)...)
    }
    return src
}

func blowfishEncrypt(key string, src []byte) ([]byte, error) {
    cipher, err := blowfish.NewCipher([]byte(key))
    if err != nil {
        return nil, err
    }
    const bs = blowfish.BlockSize
    dst := make([]byte, len(src))
    for i := 0; i < len(src); i += bs {
        cipher.Encrypt(dst[i:i+bs], src[i:i+bs])
    }
    return dst, nil
}

func blowfishDecrypt(key string, src []byte) ([]byte, error) {
    cipher, err := blowfish.NewCipher([]byte(key))
    if err != nil {
        return nil, err
    }
    const bs = blowfish.BlockSize
    dst := make([]byte, len(src))
    for i := 0; i < len(src); i += bs {
        cipher.Decrypt(dst[i:i+bs], src[i:i+bs])
    }
    return bytes.TrimRight(dst, "\x00"), nil
}

func Base64Encode(src []byte) string {
    charset := "./0123456789abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    // Ensure src is padded to a multiple of 8
    src = pad(src, 8)

    buf := make([]byte, len(src)/2*3)
    left := 0
    right := 0
    k := -1
    var v int

    n := 0
    for k < len(src)-1 {
        for _, count := range []uint8{24, 16, 8, 0} {
            k++
            v = int(src[k])
            left += v << count
        }
        for _, count := range []uint8{24, 16, 8, 0} {
            k++
            v = int(src[k])
            right += v << count
        }
        for i := 0; i < 6; i++ {
            buf[n] = charset[right&0x3F]
            n++
            right >>= 6
        }
        for i := 0; i < 6; i++ {
            buf[n] = charset[left&0x3F]
            n++
            left >>= 6
        }
    }
    return string(buf)
}

func Base64Decode(src []byte) []byte {
    charset := []byte("./0123456789abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

    buf := make([]byte, len(src)/3*2)
    k := -1

    n := 0
    for k < len(src)-1 {
        left := 0
        right := 0
        var v int
        var w int
        var z int
        for i := uint8(0); i < 6; i++ {
            k++
            v = bytes.IndexByte(charset, src[k])
            right |= v << (i * 6)
        }
        for i := uint8(0); i < 6; i++ {
            k++
            v = bytes.IndexByte(charset, src[k])
            left |= v << (i * 6)
        }
        for i := uint8(0); i < 4; i++ {
            w = (left & (0xFF << ((3 - i) * 8)))
            z = w >> ((3 - i) * 8)
            buf[n] = byte(z)
            n++
        }
        for i := uint8(0); i < 4; i++ {
            w = (right & (0xFF << ((3 - i) * 8)))
            z = w >> ((3 - i) * 8)
            buf[n] = byte(z)
            n++
        }
    }
    return buf
}

func Encrypt(key string, message string) (string, error) {
    enc, err := blowfishEncrypt(key, pad([]byte(message), 8))
    if err != nil {
        return "", err
    }
    return "+OK " + Base64Encode(enc), nil
}

func IsEncrypted(s string) bool {
    return strings.HasPrefix(s, "+OK ") || strings.HasPrefix(s, "mcps ")
}

func Decrypt(key string, message string) (string, error) {
    if strings.HasPrefix(message, "+OK ") {
        message = message[4:]
    } else if strings.HasPrefix(message, "mcps ") {
        message = message[5:]
    } else {
        return message, nil
    }
    dec, err := blowfishDecrypt(key, Base64Decode([]byte(message)))
    if err != nil {
        return "", err
    }
    return string(dec), nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"net/http/httptest"
	"net"
	"strconv"
)

type HttpRequestPredicate func(request *http.Request) bool

type RequestRecordingServer struct {
	requests []*http.Request
	port     int
	server   *httptest.Server
}

func CreateRequestRecordingServer(port int) *RequestRecordingServer {
	return &RequestRecordingServer{
		requests: []*http.Request{},
		port: port,
	}
}

func (instance *RequestRecordingServer) Start() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		instance.requests = append(instance.requests, r)
	})
	instance.server = httptest.NewUnstartedServer(handler)
	instance.server.Listener, _ = net.Listen("tcp", ":"+strconv.Itoa(instance.port))
	instance.server.Start()
}

func (instance *RequestRecordingServer) Stop() {
	instance.server.Close()
}

func (instance *RequestRecordingServer) Contains(predicate HttpRequestPredicate) bool {
	for _, request := range instance.requests {
		if predicate(request) {
			return true
		}
	}
	return false
}

func RequestWithPath(path string) HttpRequestPredicate {
	return HttpRequestPredicate(func(request *http.Request) bool {
		return request.URL.Path == path
	})
}
<commit_msg>Changed the Contains function to accept variable number of predicates for which all need to be true to return a truthy result<commit_after>package main

import (
	"net"
	"net/http"
	"net/http/httptest"
	"strconv"
)

type HttpRequestPredicate func(request *http.Request) bool

type RequestRecordingServer struct {
	requests []*http.Request
	port     int
	server   *httptest.Server
}

func CreateRequestRecordingServer(port int) *RequestRecordingServer {
	return &RequestRecordingServer{
		requests: []*http.Request{},
		port:     port,
	}
}

func (instance *RequestRecordingServer) Start() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		instance.requests = append(instance.requests, r)
	})
	instance.server = httptest.NewUnstartedServer(handler)
	instance.server.Listener, _ = net.Listen("tcp", ":"+strconv.Itoa(instance.port))
	instance.server.Start()
}

func (instance *RequestRecordingServer) Stop() {
	instance.server.Close()
}

func (instance *RequestRecordingServer) Contains(predicates ...HttpRequestPredicate) bool {

	for _, request := range instance.requests {
		requestResult := false
		for _, predicate := range predicates {
			requestResult = predicate(request)
			if !requestResult {
				break
			}
		}
		if requestResult {
			return true
		}
	}
	return false

}

func RequestWithPath(path string) HttpRequestPredicate {
	return HttpRequestPredicate(func(request *http.Request) bool {
		return request.URL.Path == path
	})
}
<|endoftext|>


<commit_before>package db

import (
	"testing"

	// For testing the storage of password hashes
	"code.google.com/p/go.crypto/bcrypt"
)

const (
	listname     = "testlist"
	setname      = "testset"
	hashmapname  = "testhashmap"
	keyvaluename = "testkeyvalue"
	testdata1    = "abc123"
	testdata2    = "def456"
	testdata3    = "ghi789"
)

func TestLocalConnection(t *testing.T) {
	Verbose = true

	//err := TestConnection() // locally
	err := TestConnectionHost("travis:@127.0.0.1/") // for travis-ci
	//err := TestConnectionHost("go:go@/main") // laptop
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestList(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	list := NewList(host, listname)
	list.Clear()
	if err := list.Add(testdata1); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	items, err := list.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving list! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != testdata1) {
		t.Errorf("Error, wrong list contents! %v", items)
	}
	if err := list.Add(testdata2); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	if err := list.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	return
	items, err = list.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving list! %s", err.Error())
	}
	if len(items) != 3 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	item, err := list.GetLast()
	if err != nil {
		t.Errorf("Error, could not get last item from list! %s", err.Error())
	}
	if item != testdata3 {
		t.Errorf("Error, expected %s, got %s with GetLast()!", testdata3, item)
	}
	items, err = list.GetLastN(2)
	if err != nil {
		t.Errorf("Error, could not get last N items from list! %s", err.Error())
	}
	if len(items) != 2 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	if items[0] != testdata2 {
		t.Errorf("Error, expected %s, got %s with GetLast()!", testdata2, items[0])
	}
	err = list.Remove()
	if err != nil {
		t.Errorf("Error, could not remove list! %s", err.Error())
	}

	// Check that list qualifies for the IList interface
	var _ IList = list
}

func TestSet(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	set := NewSet(host, setname)
	set.Clear()
	if err := set.Add(testdata1); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	items, err := set.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving set! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong set length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != testdata1) {
		t.Errorf("Error, wrong set contents! %v", items)
	}
	if err := set.Add(testdata2); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	if err := set.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	// Add an element twice. This is a set, so the element should only appear once.
	if err := set.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	items, err = set.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving set! %s", err.Error())
	}
	if len(items) != 3 {
		t.Errorf("Error, wrong set length! %v", len(items))
	}
	err = set.Remove()
	if err != nil {
		t.Errorf("Error, could not remove set! %s", err.Error())
	}

	// Check that set qualifies for the ISet interface
	var _ ISet = set
}

func TestHashMap(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	hashmap := NewHashMap(host, hashmapname)
	hashmap.Clear()

	username := "bob"
	key := "password"
	value := "hunter1"

	// Get key that doesn't exist yet
	item, err := hashmap.Get("ownerblabla", "keyblabla")
	if err == nil {
		t.Errorf("Key found, when it should be missing! %s", err.Error())
	}

	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	// Once more, with the same data
	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	items, err := hashmap.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving elements! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong element length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != username) {
		t.Errorf("Error, wrong elementid! %v", items)
	}
	item, err = hashmap.Get(username, key)
	if err != nil {
		t.Errorf("Error, could not fetch value from hashmap! %s", err.Error())
	}
	if item != value {
		t.Errorf("Error, expected %s, got %s!", value, item)
	}
	err = hashmap.Remove()
	if err != nil {
		t.Errorf("Error, could not remove hashmap! %s", err.Error())
	}

	// Check that hashmap qualifies for the IHashMap interface
	var _ IHashMap = hashmap
}

func TestKeyValue(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	keyvalue := NewKeyValue(host, keyvaluename)
	keyvalue.Clear()

	key := "password"
	value := "hunter1"

	if err := keyvalue.Set(key, value); err != nil {
		t.Errorf("Error, could not set value in keyvalue! %s", err.Error())
	}
	// Twice
	if err := keyvalue.Set(key, value); err != nil {
		t.Errorf("Error, could not set value in keyvalue! %s", err.Error())
	}
	item, err := keyvalue.Get(key)
	if err != nil {
		t.Errorf("Error, could not fetch value from keyvalue! %s", err.Error())
	}
	if item != value {
		t.Errorf("Error, expected %s, got %s!", value, item)
	}
	err = keyvalue.Remove()
	if err != nil {
		t.Errorf("Error, could not remove keyvalue! %s", err.Error())
	}
	// Check that keyvalue qualifies for the IKeyValue interface
	var _ IKeyValue = keyvalue
}

func TestHashStorage(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	hashmap := NewHashMap(host, hashmapname)
	hashmap.Clear()

	username := "bob"
	key := "password"
	password := "hunter1"
	passwordHash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	value := string(passwordHash)

	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	item, err := hashmap.Get(username, key)
	if err != nil {
		t.Errorf("Unable to retrieve from hashmap! %s\n", err.Error())
	}

	if item != value {
		t.Errorf("Error, got a different value back! %s != %s\n", value, item)
	}
	err = hashmap.Remove()
	if err != nil {
		t.Errorf("Error, could not remove hashmap! %s", err.Error())
	}
}

func TestTwoFields(t *testing.T) {
	test, test23, ok := twoFields("test1@test2@test3", "@")
	if ok && ((test != "test1") || (test23 != "test2@test3")) {
		t.Error("Error in twoFields functions")
	}
}
<commit_msg>Added a test that fails (storing sha256 hashes)<commit_after>package db

import (
	"testing"

	// For testing the storage of bcrypt password hashes
	"code.google.com/p/go.crypto/bcrypt"
	"github.com/xyproto/permissions2"
	"crypto/sha256"
	"io"
)

const (
	listname     = "testlist"
	setname      = "testset"
	hashmapname  = "testhashmap"
	keyvaluename = "testkeyvalue"
	testdata1    = "abc123"
	testdata2    = "def456"
	testdata3    = "ghi789"
)

func TestLocalConnection(t *testing.T) {
	Verbose = true

	//err := TestConnection() // locally
	err := TestConnectionHost("travis:@127.0.0.1/") // for travis-ci
	//err := TestConnectionHost("go:go@/main") // laptop
	if err != nil {
		t.Errorf(err.Error())
	}
}

func TestList(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	list := NewList(host, listname)
	list.Clear()
	if err := list.Add(testdata1); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	items, err := list.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving list! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != testdata1) {
		t.Errorf("Error, wrong list contents! %v", items)
	}
	if err := list.Add(testdata2); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	if err := list.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to list! %s", err.Error())
	}
	return
	items, err = list.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving list! %s", err.Error())
	}
	if len(items) != 3 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	item, err := list.GetLast()
	if err != nil {
		t.Errorf("Error, could not get last item from list! %s", err.Error())
	}
	if item != testdata3 {
		t.Errorf("Error, expected %s, got %s with GetLast()!", testdata3, item)
	}
	items, err = list.GetLastN(2)
	if err != nil {
		t.Errorf("Error, could not get last N items from list! %s", err.Error())
	}
	if len(items) != 2 {
		t.Errorf("Error, wrong list length! %v", len(items))
	}
	if items[0] != testdata2 {
		t.Errorf("Error, expected %s, got %s with GetLast()!", testdata2, items[0])
	}
	err = list.Remove()
	if err != nil {
		t.Errorf("Error, could not remove list! %s", err.Error())
	}

	// Check that list qualifies for the IList interface
	var _ IList = list
}

func TestSet(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	set := NewSet(host, setname)
	set.Clear()
	if err := set.Add(testdata1); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	items, err := set.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving set! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong set length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != testdata1) {
		t.Errorf("Error, wrong set contents! %v", items)
	}
	if err := set.Add(testdata2); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	if err := set.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	// Add an element twice. This is a set, so the element should only appear once.
	if err := set.Add(testdata3); err != nil {
		t.Errorf("Error, could not add item to set! %s", err.Error())
	}
	items, err = set.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving set! %s", err.Error())
	}
	if len(items) != 3 {
		t.Errorf("Error, wrong set length! %v", len(items))
	}
	err = set.Remove()
	if err != nil {
		t.Errorf("Error, could not remove set! %s", err.Error())
	}

	// Check that set qualifies for the ISet interface
	var _ ISet = set
}

func TestHashMap(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	hashmap := NewHashMap(host, hashmapname)
	hashmap.Clear()

	username := "bob"
	key := "password"
	value := "hunter1"

	// Get key that doesn't exist yet
	item, err := hashmap.Get("ownerblabla", "keyblabla")
	if err == nil {
		t.Errorf("Key found, when it should be missing! %s", err.Error())
	}

	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	// Once more, with the same data
	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	items, err := hashmap.GetAll()
	if err != nil {
		t.Errorf("Error when retrieving elements! %s", err.Error())
	}
	if len(items) != 1 {
		t.Errorf("Error, wrong element length! %v", len(items))
	}
	if (len(items) > 0) && (items[0] != username) {
		t.Errorf("Error, wrong elementid! %v", items)
	}
	item, err = hashmap.Get(username, key)
	if err != nil {
		t.Errorf("Error, could not fetch value from hashmap! %s", err.Error())
	}
	if item != value {
		t.Errorf("Error, expected %s, got %s!", value, item)
	}
	err = hashmap.Remove()
	if err != nil {
		t.Errorf("Error, could not remove hashmap! %s", err.Error())
	}

	// Check that hashmap qualifies for the IHashMap interface
	var _ IHashMap = hashmap
}

func TestKeyValue(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	keyvalue := NewKeyValue(host, keyvaluename)
	keyvalue.Clear()

	key := "password"
	value := "hunter1"

	if err := keyvalue.Set(key, value); err != nil {
		t.Errorf("Error, could not set value in keyvalue! %s", err.Error())
	}
	// Twice
	if err := keyvalue.Set(key, value); err != nil {
		t.Errorf("Error, could not set value in keyvalue! %s", err.Error())
	}
	item, err := keyvalue.Get(key)
	if err != nil {
		t.Errorf("Error, could not fetch value from keyvalue! %s", err.Error())
	}
	if item != value {
		t.Errorf("Error, expected %s, got %s!", value, item)
	}
	err = keyvalue.Remove()
	if err != nil {
		t.Errorf("Error, could not remove keyvalue! %s", err.Error())
	}
	// Check that keyvalue qualifies for the IKeyValue interface
	var _ IKeyValue = keyvalue
}

func TestHashStorage(t *testing.T) {
	Verbose = true

	//host := New() // locally
	host := NewHost("travis:@127.0.0.1/") // for travis-ci
	//host := NewHost("go:go@/main") // laptop

	defer host.Close()
	hashmap := NewHashMap(host, hashmapname)
	hashmap.Clear()

	username := "bob"
	key := "password"
	password := "hunter1"

	// bcrypt test

	passwordHash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	value := string(passwordHash)

	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	item, err := hashmap.Get(username, key)
	if err != nil {
		t.Errorf("Unable to retrieve from hashmap! %s\n", err.Error())
	}
	if item != value {
		t.Errorf("Error, got a different value back (bcrypt)! %s != %s\n", value, item)
	}

	// sha256 test

	hasher := sha256.New()
	io.WriteString(hasher, password + permissions.RandomCookieFriendlyString(30) + username)
	passwordHash = hasher.Sum(nil)
	value = string(passwordHash)

	if err := hashmap.Set(username, key, value); err != nil {
		t.Errorf("Error, could not set value in hashmap! %s", err.Error())
	}
	item, err = hashmap.Get(username, key)
	if err != nil {
		t.Errorf("Unable to retrieve from hashmap! %s\n", err.Error())
	}
	if item != value {
		t.Errorf("Error, got a different value back (sha256)! %s != %s\n", value, item)
	}

	err = hashmap.Remove()
	if err != nil {
		t.Errorf("Error, could not remove hashmap! %s", err.Error())
	}
}

func TestTwoFields(t *testing.T) {
	test, test23, ok := twoFields("test1@test2@test3", "@")
	if ok && ((test != "test1") || (test23 != "test2@test3")) {
		t.Error("Error in twoFields functions")
	}
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd Authors.

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

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

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

package driver

import (
	"os"

	"github.com/containerd/continuity/sysx"
)

func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error {
	return &os.PathError{Op: "mknod", Path: path, Err: ErrNotSupported}
}

func (d *driver) Mkfifo(path string, mode os.FileMode) error {
	return &os.PathError{Op: "mkfifo", Path: path, Err: ErrNotSupported}
}

// Lchmod changes the mode of an file not following symlinks.
func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
	// TODO: Use Window's equivalent
	return os.Chmod(path, mode)
}

// Readlink is forked in order to support Volume paths which are used
// in container layers.
func (d *driver) Readlink(p string) (string, error) {
	return sysx.Readlink(p)
}
<commit_msg>driver: fail to build on Windows with go < 1.13<commit_after>/*
   Copyright The containerd Authors.

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

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

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

// +build go1.13

// Go 1.13 is the minimally supported version for Windows.
// Earlier golang releases have bug in os.Readlink
// (see https://github.com/golang/go/issues/30463).

package driver

import (
	"os"

	"github.com/containerd/continuity/sysx"
)

func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error {
	return &os.PathError{Op: "mknod", Path: path, Err: ErrNotSupported}
}

func (d *driver) Mkfifo(path string, mode os.FileMode) error {
	return &os.PathError{Op: "mkfifo", Path: path, Err: ErrNotSupported}
}

// Lchmod changes the mode of an file not following symlinks.
func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
	// TODO: Use Window's equivalent
	return os.Chmod(path, mode)
}

// Readlink is forked in order to support Volume paths which are used
// in container layers.
func (d *driver) Readlink(p string) (string, error) {
	return sysx.Readlink(p)
}
<|endoftext|>