This commit is contained in:
Makis Maropoulos 2016-05-31 11:05:42 +03:00
parent c26668a489
commit 31cbd50fb0
18 changed files with 177 additions and 67 deletions

View File

@ -18,6 +18,10 @@
[Language]: http://golang.org [Language]: http://golang.org
[Platform Widget]: https://img.shields.io/badge/platform-Any--OS-gray.svg?style=flat-square [Platform Widget]: https://img.shields.io/badge/platform-Any--OS-gray.svg?style=flat-square
Iris is 3 months baby which has succeeded to be the fastest go web framework that exists, so far, while providing a robust set of features for building web applications.
- [why v3 has 1 commit ?](https://github.com/kataras/iris/issues/162)
[![Benchmark Wizzard Processing Time Horizontal Graph](https://raw.githubusercontent.com/iris-contrib/website/cf71811e6acb2f9bf1e715e25660392bf090b923/assets/benchmark_horizontal_transparent.png)](#benchmarks) [![Benchmark Wizzard Processing Time Horizontal Graph](https://raw.githubusercontent.com/iris-contrib/website/cf71811e6acb2f9bf1e715e25660392bf090b923/assets/benchmark_horizontal_transparent.png)](#benchmarks)
```sh ```sh

View File

@ -1,6 +1,4 @@
/* // Package bindings source code from https://github.com/monoculum/formame.
File bindings/form.go source code from https://github.com/monoculum/formame.
*/
package bindings package bindings
import ( import (

View File

@ -7,10 +7,14 @@ import (
) )
const ( const (
DefaultBasicAuthRealm = "Authorization Required" // DefaultBasicAuth is "Authorization Required"
DefaultBasicAuthRealm = "Authorization Required"
// DefaultBasicAuthContextKey is the "auth"
// this key is used to do context.Set("auth", theUsernameFromBasicAuth)
DefaultBasicAuthContextKey = "auth" DefaultBasicAuthContextKey = "auth"
) )
// BasicAuth the configs for the basicauth middleware
type BasicAuth struct { type BasicAuth struct {
// Users a map of login and the value (username/password) // Users a map of login and the value (username/password)
Users map[string]string Users map[string]string
@ -27,7 +31,7 @@ func DefaultBasicAuth() BasicAuth {
return BasicAuth{make(map[string]string), DefaultBasicAuthRealm, DefaultBasicAuthContextKey, 0} return BasicAuth{make(map[string]string), DefaultBasicAuthRealm, DefaultBasicAuthContextKey, 0}
} }
// Merge MergeSingle the default with the given config and returns the result // MergeSingle merges the default with the given config and returns the result
func (c BasicAuth) MergeSingle(cfg BasicAuth) (config BasicAuth) { func (c BasicAuth) MergeSingle(cfg BasicAuth) (config BasicAuth) {
config = cfg config = cfg

View File

@ -8,16 +8,28 @@ import (
) )
const ( const (
NoEngine EngineType = -1 // NoEngine is a Template's config for engine type
HTMLEngine EngineType = 0 // when use this, the templates are disabled
PongoEngine EngineType = 1 NoEngine EngineType = -1
// HTMLEngine is a Template's config for engine type
// when use this, the templates are html/template
HTMLEngine EngineType = 0
// PongoEngine is a Template's config for engine type
// when use this, the templates are flosch/pongo2
PongoEngine EngineType = 1
// MarkdownEngine is a Template's config for engine type
// when use this, the templates are .md files
MarkdownEngine EngineType = 2 MarkdownEngine EngineType = 2
JadeEngine EngineType = 3 // JadeEngine is a Template's config for engine type
AmberEngine EngineType = 4 // when use this, the templates are joker/jade
JadeEngine EngineType = 3
// AmberEngine is a Template's config for engine type
// when use this, the templates are eknkc/amber
AmberEngine EngineType = 4
// DefaultEngine is the HTMLEngine
DefaultEngine EngineType = HTMLEngine DefaultEngine EngineType = HTMLEngine
// to disable layout for a particular file // NoLayout to disable layout for a particular template file
NoLayout = "@.|.@iris_no_layout@.|.@" NoLayout = "@.|.@iris_no_layout@.|.@"
) )
@ -51,42 +63,71 @@ type (
MarkdownSanitize bool MarkdownSanitize bool
} }
// EngineType is the type of template engine
EngineType int8 EngineType int8
// Template the configs for templates (template/view engines)
// contains common configs for all template engines
Template struct { Template struct {
// contains common configs for both HTMLTemplate & Pongo // Engine the type of template engine
// default is DefaultEngine (HTMLEngine)
Engine EngineType Engine EngineType
Gzip bool // Gzip enable gzip compression
// default is false
Gzip bool
// Minify minifies the html result, // Minify minifies the html result,
// Note: according to this https://github.com/tdewolff/minify/issues/35, also it removes some </tags> when minify on writer, remove this from Iris until fix. // Note: according to this https://github.com/tdewolff/minify/issues/35, also it removes some </tags> when minify on writer, remove this from Iris until fix.
// Default is false // Default is false
//Minify bool //Minify bool
IsDevelopment bool
Directory string
Extensions []string
ContentType string
Charset string
Asset func(name string) ([]byte, error)
AssetNames func() []string
Layout string
HTMLTemplate HTMLTemplate // contains specific configs for HTMLTemplate standard html/template // IsDevelopment re-builds the templates on each request
Pongo Pongo // contains specific configs for pongo2 // default is false
// Markdown template engine it doesn't supports Layout & binding context IsDevelopment bool
Markdown Markdown // contains specific configs for markdown // Directory the system path which the templates live
Jade Jade // contains specific configs for Jade // default is ./templates
Amber Amber // contains specific configs for Amber Directory string
// Extensions the allowed file extension
// default is []string{".html"}
Extensions []string
// ContentType is the Content-Type response header
// default is text/html but you can change if if needed
ContentType string
// Charset the charset, default is UTF-8
Charset string
// Asset is a func which returns bytes, use it to load the templates by binary
Asset func(name string) ([]byte, error)
// AssetNames should returns the template filenames, look Asset
AssetNames func() []string
// Layout the template file ( with its extension) which is the mother of all
// use it to have it as a root file, and include others with {{ yield }}, refer the docs
Layout string
// HTMLTemplate contains specific configs for HTMLTemplate standard html/template
HTMLTemplate HTMLTemplate
// Pongo contains specific configs for for pongo2
Pongo Pongo
// Markdown contains specific configs for for markdown
// this doesn't supports Layout & binding context
Markdown Markdown
// Jade contains specific configs for jade
Jade Jade
// Amber contains specific configs for amber
Amber Amber
} }
// HTMLTemplate the configs for HTMLEngine
HTMLTemplate struct { HTMLTemplate struct {
// RequirePartials default is false
RequirePartials bool RequirePartials bool
// Delims // Delims
Left string // Left delimeter, default is {{
Left string
// Right delimeter, default is }}
Right string Right string
// Funcs for HTMLTemplate html/template // Funcs for HTMLTemplate html/template
Funcs template.FuncMap Funcs template.FuncMap
} }
// Pongo the configs for PongoEngine
Pongo struct { Pongo struct {
// Filters for pongo2, map[name of the filter] the filter function . The filters are auto register // Filters for pongo2, map[name of the filter] the filter function . The filters are auto register
Filters map[string]pongo2.FilterFunction Filters map[string]pongo2.FilterFunction
@ -94,15 +135,18 @@ type (
Globals map[string]interface{} Globals map[string]interface{}
} }
// Markdown the configs for MarkdownEngine
Markdown struct { Markdown struct {
Sanitize bool // if true then returns safe html, default is false Sanitize bool // if true then returns safe html, default is false
} }
// Jade the configs for JadeEngine
// Jade empty for now // Jade empty for now
// stay tuned // stay tuned
Jade struct { Jade struct {
} }
// Amber the configs for AmberEngine
Amber struct { Amber struct {
// Funcs for the html/template result, amber default funcs are not overrided so use it without worries // Funcs for the html/template result, amber default funcs are not overrided so use it without worries
Funcs template.FuncMap Funcs template.FuncMap
@ -147,6 +191,7 @@ func (c Rest) MergeSingle(cfg Rest) (config Rest) {
return return
} }
// DefaultTemplate returns the default template configs
func DefaultTemplate() Template { func DefaultTemplate() Template {
return Template{ return Template{
Engine: DefaultEngine, //or HTMLTemplate Engine: DefaultEngine, //or HTMLTemplate

View File

@ -68,12 +68,19 @@ type (
NoImplicitUseStrict bool `json:"noImplicitUseStrict"` NoImplicitUseStrict bool `json:"noImplicitUseStrict"`
} }
// Typescript the configs for the Typescript plugin
Typescript struct { Typescript struct {
Bin string // Bin the path of the tsc binary file
Dir string // if empty then the plugin tries to find it
Ignore string Bin string
// Dir the client side directory, which typescript (.ts) files are live
Dir string
// Ignore ignore folders, default is /node_modules/
Ignore string
// Tsconfig the typescript build configs, including the compiler's options
Tsconfig Tsconfig Tsconfig Tsconfig
Editor Editor // Editor the Editor plugin
Editor Editor
} }
) )

View File

@ -42,6 +42,7 @@ const (
) )
type ( type (
// Map is just a conversion for a map[string]interface{}
Map map[string]interface{} Map map[string]interface{}
// Context is resetting every time a request is coming to the server // Context is resetting every time a request is coming to the server
// it is not good practice to use this object in goroutines, for these cases use the .Clone() // it is not good practice to use this object in goroutines, for these cases use the .Clone()

View File

@ -95,12 +95,12 @@ func (ctx *Context) PostFormValue(name string) string {
return string(ctx.RequestCtx.PostArgs().Peek(name)) return string(ctx.RequestCtx.PostArgs().Peek(name))
} }
/* Credits to Manish Singh @kryptodev for URLEncode */
// URLEncode returns the path encoded as url // URLEncode returns the path encoded as url
// useful when you want to pass something to a database and be valid to retrieve it via context.Param // useful when you want to pass something to a database and be valid to retrieve it via context.Param
// use it only for special cases, when the default behavior doesn't suits you. // use it only for special cases, when the default behavior doesn't suits you.
// //
// http://www.blooberry.com/indexdot/html/topics/urlencoding.htm // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
/* Credits to Manish Singh @kryptodev for URLEncode */
func URLEncode(path string) string { func URLEncode(path string) string {
if path == "" { if path == "" {
return "" return ""

View File

@ -134,7 +134,7 @@ func (ctx *Context) SetFlashBytes(key string, value []byte) {
fasthttp.ReleaseCookie(c) fasthttp.ReleaseCookie(c)
} }
// Sessionreturns the current session store, returns nil if provider is "" // Session returns the current session store, returns nil if provider is ""
func (ctx *Context) Session() store.IStore { func (ctx *Context) Session() store.IStore {
if ctx.station.sessionManager == nil || ctx.station.config.Sessions.Provider == "" { //the second check can be changed on runtime, users are able to turn off the sessions by setting provider to "" if ctx.station.sessionManager == nil || ctx.station.config.Sessions.Provider == "" { //the second check can be changed on runtime, users are able to turn off the sessions by setting provider to ""
return nil return nil

View File

@ -9,9 +9,11 @@ var (
// It seems to be a +type Points to: +pointer.' // It seems to be a +type Points to: +pointer.'
ErrHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a %T Points to: %v.") ErrHandler = errors.New("Passed argument is not func(*Context) neither an object which implements the iris.Handler with Serve(ctx *Context)\n It seems to be a %T Points to: %v.")
// ErrHandleAnnotated returns an error with message: 'HandleAnnotated parse: +specific error(s)' // ErrHandleAnnotated returns an error with message: 'HandleAnnotated parse: +specific error(s)'
ErrHandleAnnotated = errors.New("HandleAnnotated parse: %s") ErrHandleAnnotated = errors.New("HandleAnnotated parse: %s")
// ErrControllerContextNotFound returns an error with message: 'Context *iris.Context could not be found, the Controller won't be registed.'
ErrControllerContextNotFound = errors.New("Context *iris.Context could not be found, the Controller won't be registed.") ErrControllerContextNotFound = errors.New("Context *iris.Context could not be found, the Controller won't be registed.")
ErrDirectoryFileNotFound = errors.New("Directory or file %s couldn't found. Trace: %s") // ErrDirectoryFileNotFound returns an errir with message: 'Directory or file %s couldn't found. Trace: +error trace'
ErrDirectoryFileNotFound = errors.New("Directory or file %s couldn't found. Trace: %s")
// Plugin // Plugin
// ErrPluginAlreadyExists returns an error with message: 'Cannot activate the same plugin again, plugin '+plugin name[+plugin description]' is already exists' // ErrPluginAlreadyExists returns an error with message: 'Cannot activate the same plugin again, plugin '+plugin name[+plugin description]' is already exists'

24
iris.go
View File

@ -19,7 +19,9 @@ import (
"github.com/kataras/iris/render/template" "github.com/kataras/iris/render/template"
"github.com/kataras/iris/server" "github.com/kataras/iris/server"
"github.com/kataras/iris/sessions" "github.com/kataras/iris/sessions"
// memory loads the memory session provider
_ "github.com/kataras/iris/sessions/providers/memory" _ "github.com/kataras/iris/sessions/providers/memory"
// _ redis loads the redis session provider
_ "github.com/kataras/iris/sessions/providers/redis" _ "github.com/kataras/iris/sessions/providers/redis"
"github.com/kataras/iris/utils" "github.com/kataras/iris/utils"
"github.com/kataras/iris/websocket" "github.com/kataras/iris/websocket"
@ -27,6 +29,7 @@ import (
) )
const ( const (
// Version of the iris
Version = "v3.0.0-beta" Version = "v3.0.0-beta"
banner = ` _____ _ banner = ` _____ _
|_ _| (_) |_ _| (_)
@ -41,14 +44,21 @@ const (
/* for conversion */ /* for conversion */
var ( var (
HTMLEngine = config.HTMLEngine // HTMLEngine conversion for config.HTMLEngine
PongoEngine = config.PongoEngine HTMLEngine = config.HTMLEngine
// PongoEngine conversion for config.PongoEngine
PongoEngine = config.PongoEngine
// MarkdownEngine conversion for config.MarkdownEngine
MarkdownEngine = config.MarkdownEngine MarkdownEngine = config.MarkdownEngine
JadeEngine = config.JadeEngine // JadeEngine conversion for config.JadeEngine
AmberEngine = config.AmberEngine JadeEngine = config.JadeEngine
// AmberEngine conversion for config.AmberEngine
AmberEngine = config.AmberEngine
// DefaultEngine conversion for config.DefaultEngine
DefaultEngine = config.DefaultEngine DefaultEngine = config.DefaultEngine
NoEngine = config.NoEngine // NoEngine conversion for config.NoEngine
NoEngine = config.NoEngine
// //
NoLayout = config.NoLayout NoLayout = config.NoLayout
@ -104,7 +114,7 @@ func (s *Iris) newContextPool() sync.Pool {
} }
func (s *Iris) initTemplates() { func (s *Iris) initTemplates() {
if s.templates == nil { // because if .Templates() called before server's listen, s.templates != nil if s.templates == nil { // because if .Templates() called before server's listen, s.templates != nil when PreListen
// init the templates // init the templates
s.templates = template.New(s.config.Render.Template) s.templates = template.New(s.config.Render.Template)
} }
@ -295,7 +305,7 @@ func (s *Iris) Logger() *logger.Logger {
return s.logger return s.logger
} }
// Render returns the rest render // Rest returns the rest render
func (s *Iris) Rest() *rest.Render { func (s *Iris) Rest() *rest.Render {
return s.rest return s.rest
} }

View File

@ -14,13 +14,17 @@ import (
) )
const ( const (
PackagesURL = "https://github.com/iris-contrib/iris-command-assets/archive/master.zip" // PackagesURL the url to download all the packages
PackagesURL = "https://github.com/iris-contrib/iris-command-assets/archive/master.zip"
// PackagesExportedName the folder created after unzip
PackagesExportedName = "iris-command-assets-master" PackagesExportedName = "iris-command-assets-master"
) )
var ( var (
app *cli.App app *cli.App
SuccessPrint = color.New(color.FgGreen).Add(color.Bold).PrintfFunc() // SuccessPrint prints with a green color
SuccessPrint = color.New(color.FgGreen).Add(color.Bold).PrintfFunc()
// InfoPrint prints with the cyan color
InfoPrint = color.New(color.FgHiCyan).Add(color.Bold).PrintfFunc() InfoPrint = color.New(color.FgHiCyan).Add(color.Bold).PrintfFunc()
packagesInstallDir = os.Getenv("GOPATH") + utils.PathSeparator + "src" + utils.PathSeparator + "github.com" + utils.PathSeparator + "kataras" + utils.PathSeparator + "iris" + utils.PathSeparator + "iris" + utils.PathSeparator packagesInstallDir = os.Getenv("GOPATH") + utils.PathSeparator + "src" + utils.PathSeparator + "github.com" + utils.PathSeparator + "kataras" + utils.PathSeparator + "iris" + utils.PathSeparator + "iris" + utils.PathSeparator
packagesDir = packagesInstallDir + PackagesExportedName + utils.PathSeparator packagesDir = packagesInstallDir + PackagesExportedName + utils.PathSeparator
@ -63,15 +67,15 @@ func create(flags cli.Flags) (err error) {
} }
func downloadPackages() { func downloadPackages() {
_, err := utils.Install("https://github.com/iris-contrib/iris-command-assets/archive/master.zip", packagesInstallDir) _, err := utils.Install(PackagesURL, packagesInstallDir)
if err != nil { if err != nil {
app.Printf("\nProblem while downloading the assets from the internet for the first time. Trace: %s", err.Error()) app.Printf("\nProblem while downloading the assets from the internet for the first time. Trace: %s", err.Error())
} }
} }
func createPackage(packageName string, targetDir string) error { func createPackage(packageName string, targetDir string) error {
basicDir := packagesDir + packageName packageDir := packagesDir + packageName
err := utils.CopyDir(basicDir, targetDir) err := utils.CopyDir(packageDir, targetDir)
if err != nil { if err != nil {
app.Printf("\nProblem while copying the %s package to the %s. Trace: %s", packageName, targetDir, err.Error()) app.Printf("\nProblem while copying the %s package to the %s. Trace: %s", packageName, targetDir, err.Error())
return err return err
@ -79,7 +83,7 @@ func createPackage(packageName string, targetDir string) error {
InfoPrint("\n%s package was installed successfully", packageName) InfoPrint("\n%s package was installed successfully", packageName)
//run the server // build & run the server
// go build // go build
buildCmd := utils.CommandBuilder("go", "build") buildCmd := utils.CommandBuilder("go", "build")
@ -94,7 +98,8 @@ func createPackage(packageName string, targetDir string) error {
} }
buildCmd.Wait() buildCmd.Wait()
println("\n") println("\n")
// run backend/backend.exe
// run backend/backend(.exe)
executable := "backend" executable := "backend"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {

View File

@ -221,10 +221,12 @@ func DefaultCors() *Cors {
return Default() return Default()
} }
// Conflicts used by the router optimizer
func (c *Cors) Conflicts() string { func (c *Cors) Conflicts() string {
return "httpmethod" return "httpmethod"
} }
// Serve serves the middleware
func (c *Cors) Serve(ctx *iris.Context) { func (c *Cors) Serve(ctx *iris.Context) {
if ctx.MethodString() == "OPTIONS" { if ctx.MethodString() == "OPTIONS" {
c.logf("Serve: Preflight request") c.logf("Serve: Preflight request")

View File

@ -1,11 +1,12 @@
package logger package logger
import ( import (
"strconv"
"time"
"github.com/kataras/iris" "github.com/kataras/iris"
"github.com/kataras/iris/config" "github.com/kataras/iris/config"
"github.com/kataras/iris/logger" "github.com/kataras/iris/logger"
"strconv"
"time"
) )
// Options are the options of the logger middlweare // Options are the options of the logger middlweare
@ -13,11 +14,16 @@ import (
// Latency, Status, IP, Method, Path // Latency, Status, IP, Method, Path
// if set to true then these will print // if set to true then these will print
type Options struct { type Options struct {
// Latency displays latency (bool)
Latency bool Latency bool
Status bool // Status displays status code (bool)
IP bool Status bool
Method bool // IP displays request's remote address (bool)
Path bool IP bool
// Method displays the http method (bool)
Method bool
// Path displays the request path (bool)
Path bool
} }
// DefaultOptions returns an options which all properties are true // DefaultOptions returns an options which all properties are true
@ -30,7 +36,7 @@ type loggerMiddleware struct {
options Options options Options
} }
// a poor and ugly implementation of a logger but no need to worry about this at the moment // Serve serves the middleware
func (l *loggerMiddleware) Serve(ctx *iris.Context) { func (l *loggerMiddleware) Serve(ctx *iris.Context) {
//all except latency to string //all except latency to string
var date, status, ip, method, path string var date, status, ip, method, path string

View File

@ -49,6 +49,7 @@ func New(c config.Template) *Engine {
return &Engine{Config: &c} return &Engine{Config: &c}
} }
// BuildTemplates builds the templates
func (s *Engine) BuildTemplates() error { func (s *Engine) BuildTemplates() error {
if s.Config.Asset == nil || s.Config.AssetNames == nil { if s.Config.Asset == nil || s.Config.AssetNames == nil {
@ -218,6 +219,7 @@ func (s *Engine) layoutFuncsFor(name string, binding interface{}) {
} }
} }
// ExecuteWriter executes a templates and write its results to the out writer
func (s *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error { func (s *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error {
if layout != "" && layout != config.NoLayout { if layout != "" && layout != config.NoLayout {
s.layoutFuncsFor(name, binding) s.layoutFuncsFor(name, binding)

View File

@ -6,10 +6,12 @@ import (
"github.com/kataras/iris/render/template/engine/html" "github.com/kataras/iris/render/template/engine/html"
) )
// Engine the JadeEngine
type Engine struct { type Engine struct {
*html.Engine *html.Engine
} }
// new creates and returns a new JadeEngine with its configs
func New(cfg config.Template) *Engine { func New(cfg config.Template) *Engine {
underline := &Engine{Engine: html.New(cfg)} underline := &Engine{Engine: html.New(cfg)}

View File

@ -19,17 +19,37 @@ import (
) )
type ( type (
// Engine the interface that all template engines must inheritance
Engine interface { Engine interface {
// BuildTemplates builds the templates for a directory
BuildTemplates() error BuildTemplates() error
// ExecuteWriter finds and execute a template and write its result to the out writer
ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error
} }
// Template the internal configs for the common configs for the template engines
Template struct { Template struct {
Engine Engine // Engine the type of the Engine
IsDevelopment bool Engine Engine
Gzip bool // Gzip enable gzip compression
ContentType string // default is false
Layout string Gzip bool
// IsDevelopment re-builds the templates on each request
// default is false
IsDevelopment bool
// Directory the system path which the templates live
// default is ./templates
Directory string
// Extensions the allowed file extension
// default is []string{".html"}
Extensions []string
// ContentType is the Content-Type response header
// default is text/html but you can change if if needed
ContentType string
// Layout the template file ( with its extension) which is the mother of all
// use it to have it as a root file, and include others with {{ yield }}, refer the docs
Layout string
buffer *utils.BufferPool // this is used only for RenderString buffer *utils.BufferPool // this is used only for RenderString
gzipWriterPool sync.Pool gzipWriterPool sync.Pool
} }
@ -77,6 +97,7 @@ func New(c config.Template) *Template {
} }
// Render renders a template using the context's writer
func (t *Template) Render(ctx context.IContext, name string, binding interface{}, layout ...string) (err error) { func (t *Template) Render(ctx context.IContext, name string, binding interface{}, layout ...string) (err error) {
if t == nil { // No engine was given but .Render was called if t == nil { // No engine was given but .Render was called
@ -120,6 +141,7 @@ func (t *Template) Render(ctx context.IContext, name string, binding interface{}
return return
} }
// RenderString executes a template and returns its contents result (string)
func (t *Template) RenderString(name string, binding interface{}, layout ...string) (result string, err error) { func (t *Template) RenderString(name string, binding interface{}, layout ...string) (result string, err error) {
if t == nil { // No engine was given but .Render was called if t == nil { // No engine was given but .Render was called

View File

@ -12,6 +12,7 @@ func init() {
} }
var ( var (
// Provider the memory provider
Provider = sessions.NewProvider("memory") Provider = sessions.NewProvider("memory")
) )

View File

@ -202,8 +202,7 @@ func CopyFile(source string, destination string) error {
return nil return nil
} }
// CopyDir // CopyDir recursively copies a directory tree, attempting to preserve permissions.
// Recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist. // Source directory must exist.
// //
// Note: the CopyDir function was not written by me, but its working well // Note: the CopyDir function was not written by me, but its working well