Added externela dependencies
This commit is contained in:
Родитель
2766c87cee
Коммит
0983ca9310
|
@ -0,0 +1,2 @@
|
|||
inject
|
||||
inject.test
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Jeremy Saenz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,92 @@
|
|||
# inject
|
||||
--
|
||||
import "github.com/codegangsta/inject"
|
||||
|
||||
Package inject provides utilities for mapping and injecting dependencies in
|
||||
various ways.
|
||||
|
||||
Language Translations:
|
||||
* [简体中文](translations/README_zh_cn.md)
|
||||
|
||||
## Usage
|
||||
|
||||
#### func InterfaceOf
|
||||
|
||||
```go
|
||||
func InterfaceOf(value interface{}) reflect.Type
|
||||
```
|
||||
InterfaceOf dereferences a pointer to an Interface type. It panics if value is
|
||||
not an pointer to an interface.
|
||||
|
||||
#### type Applicator
|
||||
|
||||
```go
|
||||
type Applicator interface {
|
||||
// Maps dependencies in the Type map to each field in the struct
|
||||
// that is tagged with 'inject'. Returns an error if the injection
|
||||
// fails.
|
||||
Apply(interface{}) error
|
||||
}
|
||||
```
|
||||
|
||||
Applicator represents an interface for mapping dependencies to a struct.
|
||||
|
||||
#### type Injector
|
||||
|
||||
```go
|
||||
type Injector interface {
|
||||
Applicator
|
||||
Invoker
|
||||
TypeMapper
|
||||
// SetParent sets the parent of the injector. If the injector cannot find a
|
||||
// dependency in its Type map it will check its parent before returning an
|
||||
// error.
|
||||
SetParent(Injector)
|
||||
}
|
||||
```
|
||||
|
||||
Injector represents an interface for mapping and injecting dependencies into
|
||||
structs and function arguments.
|
||||
|
||||
#### func New
|
||||
|
||||
```go
|
||||
func New() Injector
|
||||
```
|
||||
New returns a new Injector.
|
||||
|
||||
#### type Invoker
|
||||
|
||||
```go
|
||||
type Invoker interface {
|
||||
// Invoke attempts to call the interface{} provided as a function,
|
||||
// providing dependencies for function arguments based on Type. Returns
|
||||
// a slice of reflect.Value representing the returned values of the function.
|
||||
// Returns an error if the injection fails.
|
||||
Invoke(interface{}) ([]reflect.Value, error)
|
||||
}
|
||||
```
|
||||
|
||||
Invoker represents an interface for calling functions via reflection.
|
||||
|
||||
#### type TypeMapper
|
||||
|
||||
```go
|
||||
type TypeMapper interface {
|
||||
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
|
||||
Map(interface{}) TypeMapper
|
||||
// Maps the interface{} value based on the pointer of an Interface provided.
|
||||
// This is really only useful for mapping a value as an interface, as interfaces
|
||||
// cannot at this time be referenced directly without a pointer.
|
||||
MapTo(interface{}, interface{}) TypeMapper
|
||||
// Provides a possibility to directly insert a mapping based on type and value.
|
||||
// This makes it possible to directly map type arguments not possible to instantiate
|
||||
// with reflect like unidirectional channels.
|
||||
Set(reflect.Type, reflect.Value) TypeMapper
|
||||
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
|
||||
// the Type has not been mapped.
|
||||
Get(reflect.Type) reflect.Value
|
||||
}
|
||||
```
|
||||
|
||||
TypeMapper represents an interface for mapping interface{} values based on type.
|
|
@ -0,0 +1,187 @@
|
|||
// Package inject provides utilities for mapping and injecting dependencies in various ways.
|
||||
package inject
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Injector represents an interface for mapping and injecting dependencies into structs
|
||||
// and function arguments.
|
||||
type Injector interface {
|
||||
Applicator
|
||||
Invoker
|
||||
TypeMapper
|
||||
// SetParent sets the parent of the injector. If the injector cannot find a
|
||||
// dependency in its Type map it will check its parent before returning an
|
||||
// error.
|
||||
SetParent(Injector)
|
||||
}
|
||||
|
||||
// Applicator represents an interface for mapping dependencies to a struct.
|
||||
type Applicator interface {
|
||||
// Maps dependencies in the Type map to each field in the struct
|
||||
// that is tagged with 'inject'. Returns an error if the injection
|
||||
// fails.
|
||||
Apply(interface{}) error
|
||||
}
|
||||
|
||||
// Invoker represents an interface for calling functions via reflection.
|
||||
type Invoker interface {
|
||||
// Invoke attempts to call the interface{} provided as a function,
|
||||
// providing dependencies for function arguments based on Type. Returns
|
||||
// a slice of reflect.Value representing the returned values of the function.
|
||||
// Returns an error if the injection fails.
|
||||
Invoke(interface{}) ([]reflect.Value, error)
|
||||
}
|
||||
|
||||
// TypeMapper represents an interface for mapping interface{} values based on type.
|
||||
type TypeMapper interface {
|
||||
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
|
||||
Map(interface{}) TypeMapper
|
||||
// Maps the interface{} value based on the pointer of an Interface provided.
|
||||
// This is really only useful for mapping a value as an interface, as interfaces
|
||||
// cannot at this time be referenced directly without a pointer.
|
||||
MapTo(interface{}, interface{}) TypeMapper
|
||||
// Provides a possibility to directly insert a mapping based on type and value.
|
||||
// This makes it possible to directly map type arguments not possible to instantiate
|
||||
// with reflect like unidirectional channels.
|
||||
Set(reflect.Type, reflect.Value) TypeMapper
|
||||
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
|
||||
// the Type has not been mapped.
|
||||
Get(reflect.Type) reflect.Value
|
||||
}
|
||||
|
||||
type injector struct {
|
||||
values map[reflect.Type]reflect.Value
|
||||
parent Injector
|
||||
}
|
||||
|
||||
// InterfaceOf dereferences a pointer to an Interface type.
|
||||
// It panics if value is not an pointer to an interface.
|
||||
func InterfaceOf(value interface{}) reflect.Type {
|
||||
t := reflect.TypeOf(value)
|
||||
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
if t.Kind() != reflect.Interface {
|
||||
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// New returns a new Injector.
|
||||
func New() Injector {
|
||||
return &injector{
|
||||
values: make(map[reflect.Type]reflect.Value),
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke attempts to call the interface{} provided as a function,
|
||||
// providing dependencies for function arguments based on Type.
|
||||
// Returns a slice of reflect.Value representing the returned values of the function.
|
||||
// Returns an error if the injection fails.
|
||||
// It panics if f is not a function
|
||||
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
|
||||
t := reflect.TypeOf(f)
|
||||
|
||||
var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func
|
||||
for i := 0; i < t.NumIn(); i++ {
|
||||
argType := t.In(i)
|
||||
val := inj.Get(argType)
|
||||
if !val.IsValid() {
|
||||
return nil, fmt.Errorf("Value not found for type %v", argType)
|
||||
}
|
||||
|
||||
in[i] = val
|
||||
}
|
||||
|
||||
return reflect.ValueOf(f).Call(in), nil
|
||||
}
|
||||
|
||||
// Maps dependencies in the Type map to each field in the struct
|
||||
// that is tagged with 'inject'.
|
||||
// Returns an error if the injection fails.
|
||||
func (inj *injector) Apply(val interface{}) error {
|
||||
v := reflect.ValueOf(val)
|
||||
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil // Should not panic here ?
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
structField := t.Field(i)
|
||||
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
|
||||
ft := f.Type()
|
||||
v := inj.Get(ft)
|
||||
if !v.IsValid() {
|
||||
return fmt.Errorf("Value not found for type %v", ft)
|
||||
}
|
||||
|
||||
f.Set(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
|
||||
// It returns the TypeMapper registered in.
|
||||
func (i *injector) Map(val interface{}) TypeMapper {
|
||||
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
|
||||
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
|
||||
return i
|
||||
}
|
||||
|
||||
// Maps the given reflect.Type to the given reflect.Value and returns
|
||||
// the Typemapper the mapping has been registered in.
|
||||
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
|
||||
i.values[typ] = val
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *injector) Get(t reflect.Type) reflect.Value {
|
||||
val := i.values[t]
|
||||
|
||||
if val.IsValid() {
|
||||
return val
|
||||
}
|
||||
|
||||
// no concrete types found, try to find implementors
|
||||
// if t is an interface
|
||||
if t.Kind() == reflect.Interface {
|
||||
for k, v := range i.values {
|
||||
if k.Implements(t) {
|
||||
val = v
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still no type found, try to look it up on the parent
|
||||
if !val.IsValid() && i.parent != nil {
|
||||
val = i.parent.Get(t)
|
||||
}
|
||||
|
||||
return val
|
||||
|
||||
}
|
||||
|
||||
func (i *injector) SetParent(parent Injector) {
|
||||
i.parent = parent
|
||||
}
|
85
vendor/github.com/codegangsta/inject/translations/README_zh_cn.md
сгенерированный
поставляемый
Normal file
85
vendor/github.com/codegangsta/inject/translations/README_zh_cn.md
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,85 @@
|
|||
# inject
|
||||
--
|
||||
import "github.com/codegangsta/inject"
|
||||
|
||||
inject包提供了多种对实体的映射和依赖注入方式。
|
||||
|
||||
## 用法
|
||||
|
||||
#### func InterfaceOf
|
||||
|
||||
```go
|
||||
func InterfaceOf(value interface{}) reflect.Type
|
||||
```
|
||||
函数InterfaceOf返回指向接口类型的指针。如果传入的value值不是指向接口的指针,将抛出一个panic异常。
|
||||
|
||||
#### type Applicator
|
||||
|
||||
```go
|
||||
type Applicator interface {
|
||||
// 在Type map中维持对结构体中每个域的引用并用'inject'来标记
|
||||
// 如果注入失败将会返回一个error.
|
||||
Apply(interface{}) error
|
||||
}
|
||||
```
|
||||
|
||||
Applicator接口表示到结构体的依赖映射关系。
|
||||
|
||||
#### type Injector
|
||||
|
||||
```go
|
||||
type Injector interface {
|
||||
Applicator
|
||||
Invoker
|
||||
TypeMapper
|
||||
// SetParent用来设置父injector. 如果在当前injector的Type map中找不到依赖,
|
||||
// 将会继续从它的父injector中找,直到返回error.
|
||||
SetParent(Injector)
|
||||
}
|
||||
```
|
||||
|
||||
Injector接口表示对结构体、函数参数的映射和依赖注入。
|
||||
|
||||
#### func New
|
||||
|
||||
```go
|
||||
func New() Injector
|
||||
```
|
||||
New创建并返回一个Injector.
|
||||
|
||||
#### type Invoker
|
||||
|
||||
```go
|
||||
type Invoker interface {
|
||||
// Invoke尝试将interface{}作为一个函数来调用,并基于Type为函数提供参数。
|
||||
// 它将返回reflect.Value的切片,其中存放原函数的返回值。
|
||||
// 如果注入失败则返回error.
|
||||
Invoke(interface{}) ([]reflect.Value, error)
|
||||
}
|
||||
```
|
||||
|
||||
Invoker接口表示通过反射进行函数调用。
|
||||
|
||||
#### type TypeMapper
|
||||
|
||||
```go
|
||||
type TypeMapper interface {
|
||||
// 基于调用reflect.TypeOf得到的类型映射interface{}的值。
|
||||
Map(interface{}) TypeMapper
|
||||
// 基于提供的接口的指针映射interface{}的值。
|
||||
// 该函数仅用来将一个值映射为接口,因为接口无法不通过指针而直接引用到。
|
||||
MapTo(interface{}, interface{}) TypeMapper
|
||||
// 为直接插入基于类型和值的map提供一种可能性。
|
||||
// 它使得这一类直接映射成为可能:无法通过反射直接实例化的类型参数,如单向管道。
|
||||
Set(reflect.Type, reflect.Value) TypeMapper
|
||||
// 返回映射到当前类型的Value. 如果Type没被映射,将返回对应的零值。
|
||||
Get(reflect.Type) reflect.Value
|
||||
}
|
||||
```
|
||||
|
||||
TypeMapper接口用来表示基于类型到接口值的映射。
|
||||
|
||||
|
||||
## 译者
|
||||
|
||||
张强 (qqbunny@yeah.net)
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
go get github.com/robertkrimen/godocdown/godocdown
|
||||
godocdown > README.md
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
Copyright 2014 Outbrain Inc.
|
||||
|
||||
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 log
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/syslog"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LogLevel indicates the severity of a log entry
|
||||
type LogLevel int
|
||||
|
||||
func (this LogLevel) String() string {
|
||||
switch this {
|
||||
case FATAL:
|
||||
return "FATAL"
|
||||
case CRITICAL:
|
||||
return "CRITICAL"
|
||||
case ERROR:
|
||||
return "ERROR"
|
||||
case WARNING:
|
||||
return "WARNING"
|
||||
case NOTICE:
|
||||
return "NOTICE"
|
||||
case INFO:
|
||||
return "INFO"
|
||||
case DEBUG:
|
||||
return "DEBUG"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func LogLevelFromString(logLevelName string) (LogLevel, error) {
|
||||
switch logLevelName {
|
||||
case "FATAL":
|
||||
return FATAL, nil
|
||||
case "CRITICAL":
|
||||
return CRITICAL, nil
|
||||
case "ERROR":
|
||||
return ERROR, nil
|
||||
case "WARNING":
|
||||
return WARNING, nil
|
||||
case "NOTICE":
|
||||
return NOTICE, nil
|
||||
case "INFO":
|
||||
return INFO, nil
|
||||
case "DEBUG":
|
||||
return DEBUG, nil
|
||||
}
|
||||
return 0, fmt.Errorf("Unknown LogLevel name: %+v", logLevelName)
|
||||
}
|
||||
|
||||
const (
|
||||
FATAL LogLevel = iota
|
||||
CRITICAL
|
||||
ERROR
|
||||
WARNING
|
||||
NOTICE
|
||||
INFO
|
||||
DEBUG
|
||||
)
|
||||
|
||||
const TimeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
// globalLogLevel indicates the global level filter for all logs (only entries with level equals or higher
|
||||
// than this value will be logged)
|
||||
var globalLogLevel LogLevel = DEBUG
|
||||
var printStackTrace bool = false
|
||||
|
||||
// syslogWriter is optional, and defaults to nil (disabled)
|
||||
var syslogLevel LogLevel = ERROR
|
||||
var syslogWriter *syslog.Writer
|
||||
|
||||
// SetPrintStackTrace enables/disables dumping the stack upon error logging
|
||||
func SetPrintStackTrace(shouldPrintStackTrace bool) {
|
||||
printStackTrace = shouldPrintStackTrace
|
||||
}
|
||||
|
||||
// SetLevel sets the global log level. Only entries with level equals or higher than
|
||||
// this value will be logged
|
||||
func SetLevel(logLevel LogLevel) {
|
||||
globalLogLevel = logLevel
|
||||
}
|
||||
|
||||
// GetLevel returns current global log level
|
||||
func GetLevel() LogLevel {
|
||||
return globalLogLevel
|
||||
}
|
||||
|
||||
// EnableSyslogWriter enables, if possible, writes to syslog. These will execute _in addition_ to normal logging
|
||||
func EnableSyslogWriter(tag string) (err error) {
|
||||
syslogWriter, err = syslog.New(syslog.LOG_ERR, tag)
|
||||
if err != nil {
|
||||
syslogWriter = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SetSyslogLevel sets the minimal syslog level. Only entries with level equals or higher than
|
||||
// this value will be logged. However, this is also capped by the global log level. That is,
|
||||
// messages with lower level than global-log-level will be discarded at any case.
|
||||
func SetSyslogLevel(logLevel LogLevel) {
|
||||
syslogLevel = logLevel
|
||||
}
|
||||
|
||||
// logFormattedEntry nicely formats and emits a log entry
|
||||
func logFormattedEntry(logLevel LogLevel, message string, args ...interface{}) string {
|
||||
if logLevel > globalLogLevel {
|
||||
return ""
|
||||
}
|
||||
msgArgs := fmt.Sprintf(message, args...)
|
||||
entryString := fmt.Sprintf("%s %s %s", time.Now().Format(TimeFormat), logLevel, msgArgs)
|
||||
fmt.Fprintln(os.Stderr, entryString)
|
||||
|
||||
if syslogWriter != nil {
|
||||
go func() error {
|
||||
if logLevel > syslogLevel {
|
||||
return nil
|
||||
}
|
||||
switch logLevel {
|
||||
case FATAL:
|
||||
return syslogWriter.Emerg(msgArgs)
|
||||
case CRITICAL:
|
||||
return syslogWriter.Crit(msgArgs)
|
||||
case ERROR:
|
||||
return syslogWriter.Err(msgArgs)
|
||||
case WARNING:
|
||||
return syslogWriter.Warning(msgArgs)
|
||||
case NOTICE:
|
||||
return syslogWriter.Notice(msgArgs)
|
||||
case INFO:
|
||||
return syslogWriter.Info(msgArgs)
|
||||
case DEBUG:
|
||||
return syslogWriter.Debug(msgArgs)
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
}
|
||||
return entryString
|
||||
}
|
||||
|
||||
// logEntry emits a formatted log entry
|
||||
func logEntry(logLevel LogLevel, message string, args ...interface{}) string {
|
||||
entryString := message
|
||||
for _, s := range args {
|
||||
entryString += fmt.Sprintf(" %s", s)
|
||||
}
|
||||
return logFormattedEntry(logLevel, entryString)
|
||||
}
|
||||
|
||||
// logErrorEntry emits a log entry based on given error object
|
||||
func logErrorEntry(logLevel LogLevel, err error) error {
|
||||
if err == nil {
|
||||
// No error
|
||||
return nil
|
||||
}
|
||||
entryString := fmt.Sprintf("%+v", err)
|
||||
logEntry(logLevel, entryString)
|
||||
if printStackTrace {
|
||||
debug.PrintStack()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Debug(message string, args ...interface{}) string {
|
||||
return logEntry(DEBUG, message, args...)
|
||||
}
|
||||
|
||||
func Debugf(message string, args ...interface{}) string {
|
||||
return logFormattedEntry(DEBUG, message, args...)
|
||||
}
|
||||
|
||||
func Info(message string, args ...interface{}) string {
|
||||
return logEntry(INFO, message, args...)
|
||||
}
|
||||
|
||||
func Infof(message string, args ...interface{}) string {
|
||||
return logFormattedEntry(INFO, message, args...)
|
||||
}
|
||||
|
||||
func Notice(message string, args ...interface{}) string {
|
||||
return logEntry(NOTICE, message, args...)
|
||||
}
|
||||
|
||||
func Noticef(message string, args ...interface{}) string {
|
||||
return logFormattedEntry(NOTICE, message, args...)
|
||||
}
|
||||
|
||||
func Warning(message string, args ...interface{}) error {
|
||||
return errors.New(logEntry(WARNING, message, args...))
|
||||
}
|
||||
|
||||
func Warningf(message string, args ...interface{}) error {
|
||||
return errors.New(logFormattedEntry(WARNING, message, args...))
|
||||
}
|
||||
|
||||
func Error(message string, args ...interface{}) error {
|
||||
return errors.New(logEntry(ERROR, message, args...))
|
||||
}
|
||||
|
||||
func Errorf(message string, args ...interface{}) error {
|
||||
return errors.New(logFormattedEntry(ERROR, message, args...))
|
||||
}
|
||||
|
||||
func Errore(err error) error {
|
||||
return logErrorEntry(ERROR, err)
|
||||
}
|
||||
|
||||
func Critical(message string, args ...interface{}) error {
|
||||
return errors.New(logEntry(CRITICAL, message, args...))
|
||||
}
|
||||
|
||||
func Criticalf(message string, args ...interface{}) error {
|
||||
return errors.New(logFormattedEntry(CRITICAL, message, args...))
|
||||
}
|
||||
|
||||
func Criticale(err error) error {
|
||||
return logErrorEntry(CRITICAL, err)
|
||||
}
|
||||
|
||||
// Fatal emits a FATAL level entry and exists the program
|
||||
func Fatal(message string, args ...interface{}) error {
|
||||
logEntry(FATAL, message, args...)
|
||||
os.Exit(1)
|
||||
return errors.New(logEntry(CRITICAL, message, args...))
|
||||
}
|
||||
|
||||
// Fatalf emits a FATAL level entry and exists the program
|
||||
func Fatalf(message string, args ...interface{}) error {
|
||||
logFormattedEntry(FATAL, message, args...)
|
||||
os.Exit(1)
|
||||
return errors.New(logFormattedEntry(CRITICAL, message, args...))
|
||||
}
|
||||
|
||||
// Fatale emits a FATAL level entry and exists the program
|
||||
func Fatale(err error) error {
|
||||
logErrorEntry(FATAL, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Copyright 2014 Shlomi Noach.
|
||||
|
||||
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 math
|
||||
|
||||
func MinInt(i1, i2 int) int {
|
||||
if i1 < i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MaxInt(i1, i2 int) int {
|
||||
if i1 > i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MinInt64(i1, i2 int64) int64 {
|
||||
if i1 < i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MaxInt64(i1, i2 int64) int64 {
|
||||
if i1 > i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MinUInt(i1, i2 uint) uint {
|
||||
if i1 < i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MaxUInt(i1, i2 uint) uint {
|
||||
if i1 > i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MinUInt64(i1, i2 uint64) uint64 {
|
||||
if i1 < i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MaxUInt64(i1, i2 uint64) uint64 {
|
||||
if i1 > i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MinString(i1, i2 string) string {
|
||||
if i1 < i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
func MaxString(i1, i2 string) string {
|
||||
if i1 > i2 {
|
||||
return i1
|
||||
}
|
||||
return i2
|
||||
}
|
||||
|
||||
// TernaryString acts like a "? :" C-style ternary operator for strings
|
||||
func TernaryString(condition bool, resTrue string, resFalse string) string {
|
||||
if condition {
|
||||
return resTrue
|
||||
}
|
||||
return resFalse
|
||||
}
|
||||
|
||||
// TernaryString acts like a "? :" C-style ternary operator for ints
|
||||
func TernaryInt(condition bool, resTrue int, resFalse int) int {
|
||||
if condition {
|
||||
return resTrue
|
||||
}
|
||||
return resFalse
|
||||
}
|
||||
|
||||
// AbsInt is an ABS function for int type
|
||||
func AbsInt(i int) int {
|
||||
if i >= 0 {
|
||||
return i
|
||||
}
|
||||
return -i
|
||||
}
|
||||
|
||||
// AbsInt64 is an ABS function for int64 type
|
||||
func AbsInt64(i int64) int64 {
|
||||
if i >= 0 {
|
||||
return i
|
||||
}
|
||||
return -i
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
Copyright 2014 Outbrain Inc.
|
||||
|
||||
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 sqlutils
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/outbrain/golib/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// RowMap represents one row in a result set. Its objective is to allow
|
||||
// for easy, typed getters by column name.
|
||||
type RowMap map[string]CellData
|
||||
|
||||
// Cell data is the result of a single (atomic) column in a single row
|
||||
type CellData sql.NullString
|
||||
|
||||
func (this *CellData) MarshalJSON() ([]byte, error) {
|
||||
if this.Valid {
|
||||
return json.Marshal(this.String)
|
||||
} else {
|
||||
return json.Marshal(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *CellData) NullString() *sql.NullString {
|
||||
return (*sql.NullString)(this)
|
||||
}
|
||||
|
||||
// RowData is the result of a single row, in positioned array format
|
||||
type RowData []CellData
|
||||
|
||||
// MarshalJSON will marshal this map as JSON
|
||||
func (this *RowData) MarshalJSON() ([]byte, error) {
|
||||
cells := make([](*CellData), len(*this), len(*this))
|
||||
for i, val := range *this {
|
||||
d := CellData(val)
|
||||
cells[i] = &d
|
||||
}
|
||||
return json.Marshal(cells)
|
||||
}
|
||||
|
||||
// ResultData is an ordered row set of RowData
|
||||
type ResultData []RowData
|
||||
|
||||
var EmptyResultData = ResultData{}
|
||||
|
||||
func (this *RowMap) GetString(key string) string {
|
||||
return (*this)[key].String
|
||||
}
|
||||
|
||||
// GetStringD returns a string from the map, or a default value if the key does not exist
|
||||
func (this *RowMap) GetStringD(key string, def string) string {
|
||||
if cell, ok := (*this)[key]; ok {
|
||||
return cell.String
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func (this *RowMap) GetInt64(key string) int64 {
|
||||
res, _ := strconv.ParseInt(this.GetString(key), 10, 0)
|
||||
return res
|
||||
}
|
||||
|
||||
func (this *RowMap) GetNullInt64(key string) sql.NullInt64 {
|
||||
i, err := strconv.ParseInt(this.GetString(key), 10, 0)
|
||||
if err == nil {
|
||||
return sql.NullInt64{Int64: i, Valid: true}
|
||||
} else {
|
||||
return sql.NullInt64{Valid: false}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *RowMap) GetInt(key string) int {
|
||||
res, _ := strconv.Atoi(this.GetString(key))
|
||||
return res
|
||||
}
|
||||
|
||||
func (this *RowMap) GetIntD(key string, def int) int {
|
||||
res, err := strconv.Atoi(this.GetString(key))
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (this *RowMap) GetUint(key string) uint {
|
||||
res, _ := strconv.Atoi(this.GetString(key))
|
||||
return uint(res)
|
||||
}
|
||||
|
||||
func (this *RowMap) GetUintD(key string, def uint) uint {
|
||||
res, err := strconv.Atoi(this.GetString(key))
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return uint(res)
|
||||
}
|
||||
|
||||
func (this *RowMap) GetBool(key string) bool {
|
||||
return this.GetInt(key) != 0
|
||||
}
|
||||
|
||||
// knownDBs is a DB cache by uri
|
||||
var knownDBs map[string]*sql.DB = make(map[string]*sql.DB)
|
||||
var knownDBsMutex = &sync.Mutex{}
|
||||
|
||||
// GetDB returns a DB instance based on uri.
|
||||
// bool result indicates whether the DB was returned from cache; err
|
||||
func GetDB(mysql_uri string) (*sql.DB, bool, error) {
|
||||
knownDBsMutex.Lock()
|
||||
defer func() {
|
||||
knownDBsMutex.Unlock()
|
||||
}()
|
||||
|
||||
var exists bool
|
||||
if _, exists = knownDBs[mysql_uri]; !exists {
|
||||
if db, err := sql.Open("mysql", mysql_uri); err == nil {
|
||||
knownDBs[mysql_uri] = db
|
||||
} else {
|
||||
return db, exists, err
|
||||
}
|
||||
}
|
||||
return knownDBs[mysql_uri], exists, nil
|
||||
}
|
||||
|
||||
// RowToArray is a convenience function, typically not called directly, which maps a
|
||||
// single read database row into a NullString
|
||||
func RowToArray(rows *sql.Rows, columns []string) []CellData {
|
||||
buff := make([]interface{}, len(columns))
|
||||
data := make([]CellData, len(columns))
|
||||
for i, _ := range buff {
|
||||
buff[i] = data[i].NullString()
|
||||
}
|
||||
rows.Scan(buff...)
|
||||
return data
|
||||
}
|
||||
|
||||
// ScanRowsToArrays is a convenience function, typically not called directly, which maps rows
|
||||
// already read from the databse into arrays of NullString
|
||||
func ScanRowsToArrays(rows *sql.Rows, on_row func([]CellData) error) error {
|
||||
columns, _ := rows.Columns()
|
||||
for rows.Next() {
|
||||
arr := RowToArray(rows, columns)
|
||||
err := on_row(arr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rowToMap(row []CellData, columns []string) map[string]CellData {
|
||||
m := make(map[string]CellData)
|
||||
for k, data_col := range row {
|
||||
m[columns[k]] = data_col
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// ScanRowsToMaps is a convenience function, typically not called directly, which maps rows
|
||||
// already read from the databse into RowMap entries.
|
||||
func ScanRowsToMaps(rows *sql.Rows, on_row func(RowMap) error) error {
|
||||
columns, _ := rows.Columns()
|
||||
err := ScanRowsToArrays(rows, func(arr []CellData) error {
|
||||
m := rowToMap(arr, columns)
|
||||
err := on_row(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// QueryRowsMap is a convenience function allowing querying a result set while poviding a callback
|
||||
// function activated per read row.
|
||||
func QueryRowsMap(db *sql.DB, query string, on_row func(RowMap) error, args ...interface{}) error {
|
||||
var err error
|
||||
defer func() {
|
||||
if derr := recover(); derr != nil {
|
||||
err = errors.New(fmt.Sprintf("QueryRowsMap unexpected error: %+v", derr))
|
||||
}
|
||||
}()
|
||||
|
||||
rows, err := db.Query(query, args...)
|
||||
defer rows.Close()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return log.Errore(err)
|
||||
}
|
||||
err = ScanRowsToMaps(rows, on_row)
|
||||
return err
|
||||
}
|
||||
|
||||
// queryResultData returns a raw array of rows for a given query, optionally reading and returning column names
|
||||
func queryResultData(db *sql.DB, query string, retrieveColumns bool, args ...interface{}) (ResultData, []string, error) {
|
||||
var err error
|
||||
defer func() {
|
||||
if derr := recover(); derr != nil {
|
||||
err = errors.New(fmt.Sprintf("QueryRowsMap unexpected error: %+v", derr))
|
||||
}
|
||||
}()
|
||||
|
||||
columns := []string{}
|
||||
rows, err := db.Query(query, args...)
|
||||
defer rows.Close()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return EmptyResultData, columns, log.Errore(err)
|
||||
}
|
||||
if retrieveColumns {
|
||||
// Don't pay if you don't want to
|
||||
columns, _ = rows.Columns()
|
||||
}
|
||||
resultData := ResultData{}
|
||||
err = ScanRowsToArrays(rows, func(rowData []CellData) error {
|
||||
resultData = append(resultData, rowData)
|
||||
return nil
|
||||
})
|
||||
return resultData, columns, err
|
||||
}
|
||||
|
||||
// QueryResultData returns a raw array of rows
|
||||
func QueryResultData(db *sql.DB, query string, args ...interface{}) (ResultData, error) {
|
||||
resultData, _, err := queryResultData(db, query, false, args...)
|
||||
return resultData, err
|
||||
}
|
||||
|
||||
// QueryResultDataNamed returns a raw array of rows, with column names
|
||||
func QueryResultDataNamed(db *sql.DB, query string, args ...interface{}) (ResultData, []string, error) {
|
||||
return queryResultData(db, query, true, args...)
|
||||
}
|
||||
|
||||
// QueryRowsMapBuffered reads data from the database into a buffer, and only then applies the given function per row.
|
||||
// This allows the application to take its time with processing the data, albeit consuming as much memory as required by
|
||||
// the result set.
|
||||
func QueryRowsMapBuffered(db *sql.DB, query string, on_row func(RowMap) error, args ...interface{}) error {
|
||||
resultData, columns, err := queryResultData(db, query, true, args...)
|
||||
if err != nil {
|
||||
// Already logged
|
||||
return err
|
||||
}
|
||||
for _, row := range resultData {
|
||||
err = on_row(rowToMap(row, columns))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecNoPrepare executes given query using given args on given DB, without using prepared statements.
|
||||
func ExecNoPrepare(db *sql.DB, query string, args ...interface{}) (sql.Result, error) {
|
||||
var err error
|
||||
defer func() {
|
||||
if derr := recover(); derr != nil {
|
||||
err = errors.New(fmt.Sprintf("ExecNoPrepare unexpected error: %+v", derr))
|
||||
}
|
||||
}()
|
||||
|
||||
var res sql.Result
|
||||
res, err = db.Exec(query, args...)
|
||||
if err != nil {
|
||||
log.Errore(err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// ExecQuery executes given query using given args on given DB. It will safele prepare, execute and close
|
||||
// the statement.
|
||||
func execInternal(silent bool, db *sql.DB, query string, args ...interface{}) (sql.Result, error) {
|
||||
var err error
|
||||
defer func() {
|
||||
if derr := recover(); derr != nil {
|
||||
err = errors.New(fmt.Sprintf("execInternal unexpected error: %+v", derr))
|
||||
}
|
||||
}()
|
||||
|
||||
stmt, err := db.Prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
var res sql.Result
|
||||
res, err = stmt.Exec(args...)
|
||||
if err != nil && !silent {
|
||||
log.Errore(err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Exec executes given query using given args on given DB. It will safele prepare, execute and close
|
||||
// the statement.
|
||||
func Exec(db *sql.DB, query string, args ...interface{}) (sql.Result, error) {
|
||||
return execInternal(false, db, query, args...)
|
||||
}
|
||||
|
||||
// ExecSilently acts like Exec but does not report any error
|
||||
func ExecSilently(db *sql.DB, query string, args ...interface{}) (sql.Result, error) {
|
||||
return execInternal(true, db, query, args...)
|
||||
}
|
||||
|
||||
func InClauseStringValues(terms []string) string {
|
||||
quoted := []string{}
|
||||
for _, s := range terms {
|
||||
quoted = append(quoted, fmt.Sprintf("'%s'", strings.Replace(s, ",", "''", -1)))
|
||||
}
|
||||
return strings.Join(quoted, ", ")
|
||||
}
|
||||
|
||||
// Convert variable length arguments into arguments array
|
||||
func Args(args ...interface{}) []interface{} {
|
||||
return args
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Spec is an access point to test Expections
|
||||
type Spec struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
// S generates a spec. You will want to use it once in a test file, once in a test or once per each check
|
||||
func S(t *testing.T) *Spec {
|
||||
return &Spec{t: t}
|
||||
}
|
||||
|
||||
// ExpectNil expects given value to be nil, or errors
|
||||
func (spec *Spec) ExpectNil(actual interface{}) {
|
||||
if actual == nil {
|
||||
return
|
||||
}
|
||||
spec.t.Errorf("Expected %+v to be nil", actual)
|
||||
}
|
||||
|
||||
// ExpectNotNil expects given value to be not nil, or errors
|
||||
func (spec *Spec) ExpectNotNil(actual interface{}) {
|
||||
if actual != nil {
|
||||
return
|
||||
}
|
||||
spec.t.Errorf("Expected %+v to be not nil", actual)
|
||||
}
|
||||
|
||||
// ExpectEquals expects given values to be equal (comparison via `==`), or errors
|
||||
func (spec *Spec) ExpectEquals(actual, value interface{}) {
|
||||
if actual == value {
|
||||
return
|
||||
}
|
||||
spec.t.Errorf("Expected %+v, got %+v", value, actual)
|
||||
}
|
||||
|
||||
// ExpectNotEquals expects given values to be nonequal (comparison via `==`), or errors
|
||||
func (spec *Spec) ExpectNotEquals(actual, value interface{}) {
|
||||
if !(actual == value) {
|
||||
return
|
||||
}
|
||||
spec.t.Errorf("Expected not %+v", value)
|
||||
}
|
||||
|
||||
// ExpectEqualsAny expects given actual to equal (comparison via `==`) at least one of given values, or errors
|
||||
func (spec *Spec) ExpectEqualsAny(actual interface{}, values ...interface{}) {
|
||||
for _, value := range values {
|
||||
if actual == value {
|
||||
return
|
||||
}
|
||||
}
|
||||
spec.t.Errorf("Expected %+v to equal any of given values", actual)
|
||||
}
|
||||
|
||||
// ExpectNotEqualsAny expects given actual to be nonequal (comparison via `==`)tp any of given values, or errors
|
||||
func (spec *Spec) ExpectNotEqualsAny(actual interface{}, values ...interface{}) {
|
||||
for _, value := range values {
|
||||
if actual == value {
|
||||
spec.t.Errorf("Expected not %+v", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectFalse expects given values to be false, or errors
|
||||
func (spec *Spec) ExpectFalse(actual interface{}) {
|
||||
spec.ExpectEquals(actual, false)
|
||||
}
|
||||
|
||||
// ExpectTrue expects given values to be true, or errors
|
||||
func (spec *Spec) ExpectTrue(actual interface{}) {
|
||||
spec.ExpectEquals(actual, true)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2015 Shlomi Noach.
|
||||
|
||||
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 util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ParseSimpleTime parses input in the format 7s, 55m, 3h, 31d, 4w (second, minute, hour, day, week)
|
||||
// The time.ParseDuration() function should have done this, but it does not support "d" and "w" extensions.
|
||||
func SimpleTimeToSeconds(simpleTime string) (int, error) {
|
||||
if matched, _ := regexp.MatchString("^[0-9]+s$", simpleTime); matched {
|
||||
i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
|
||||
return i, nil
|
||||
}
|
||||
if matched, _ := regexp.MatchString("^[0-9]+m$", simpleTime); matched {
|
||||
i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
|
||||
return i * 60, nil
|
||||
}
|
||||
if matched, _ := regexp.MatchString("^[0-9]+h$", simpleTime); matched {
|
||||
i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
|
||||
return i * 60 * 60, nil
|
||||
}
|
||||
if matched, _ := regexp.MatchString("^[0-9]+d$", simpleTime); matched {
|
||||
i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
|
||||
return i * 60 * 60 * 24, nil
|
||||
}
|
||||
if matched, _ := regexp.MatchString("^[0-9]+w$", simpleTime); matched {
|
||||
i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
|
||||
return i * 60 * 60 * 24 * 7, nil
|
||||
}
|
||||
return 0, errors.New(fmt.Sprintf("Cannot parse simple time: %s", simpleTime))
|
||||
}
|
Загрузка…
Ссылка в новой задаче