Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added VFS and Single binary build packaging feature #180

Merged
merged 2 commits into from May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -11,7 +11,7 @@ branches:

go:
- 1.9.x
- 1.10.x
- 1.x
- tip

go_import_path: aahframework.org/aah.v0
Expand Down
58 changes: 44 additions & 14 deletions aah.go
Expand Up @@ -28,6 +28,7 @@ import (
"aahframework.org/log.v0"
"aahframework.org/router.v0"
"aahframework.org/security.v0"
"aahframework.org/vfs.v0"
"aahframework.org/ws.v0"
"golang.org/x/crypto/acme/autocert"
)
Expand Down Expand Up @@ -57,7 +58,8 @@ type BuildInfo struct {

func newApp() *app {
aahApp := &app{
mu: new(sync.Mutex),
vfs: new(vfs.VFS),
mu: new(sync.Mutex),
}

aahApp.he = &HTTPEngine{
Expand All @@ -82,7 +84,8 @@ func newApp() *app {
// app struct represents aah application.
type app struct {
physicalPathMode bool
isPackaged bool
packagedMode bool
embeddedMode bool
serverHeaderEnabled bool
requestIDEnabled bool
gzipEnabled bool
Expand All @@ -97,7 +100,6 @@ type app struct {
multipartMaxMemory int64
maxBodyBytes int64
name string
appType string
importPath string
baseDir string
envProfile string
Expand All @@ -114,6 +116,7 @@ type app struct {
defaultContentType *ahttp.ContentType

cfg *config.Config
vfs *vfs.VFS
tlsCfg *tls.Config
he *HTTPEngine
wse *ws.Engine
Expand Down Expand Up @@ -235,6 +238,10 @@ func (a *app) BaseDir() string {
return a.baseDir
}

func (a *app) VirtualBaseDir() string {
return "/app"
}

func (a *app) ImportPath() string {
return a.importPath
}
Expand All @@ -260,11 +267,20 @@ func (a *app) SetBuildInfo(bi *BuildInfo) {
}

func (a *app) IsPackaged() bool {
return a.isPackaged
return a.packagedMode
}

// TODO remove pack parameter
func (a *app) SetPackaged(pack bool) {
a.isPackaged = pack
a.packagedMode = pack
}

func (a *app) IsEmbeddedMode() bool {
return a.embeddedMode
}

func (a *app) SetEmbeddedMode() {
a.embeddedMode = true
}

func (a *app) Profile() string {
Expand Down Expand Up @@ -349,14 +365,14 @@ func (a *app) WSEngine() *ws.Engine {
return a.wse
}

func (a *app) VFS() *vfs.VFS {
return a.vfs
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// app Unexported methods
//______________________________________________________________________________

func (a *app) configDir() string {
return filepath.Join(a.BaseDir(), "config")
}

func (a *app) logsDir() string {
return filepath.Join(a.BaseDir(), "logs")
}
Expand All @@ -371,6 +387,16 @@ func (a *app) showDeprecatedMsg(msg string, v ...interface{}) {
}

func (a *app) initPath() (err error) {
defer func() {
er := a.VFS().AddMount(a.VirtualBaseDir(), a.BaseDir())
if er != nil && er.(*os.PathError).Err == vfs.ErrMountExists {
// Update app-base-dir to infered base directory
if m, er := a.VFS().FindMount(a.VirtualBaseDir()); er == nil {
m.Proot = a.BaseDir()
}
}
}()

if goPath, err = ess.GoPath(); err != nil && !a.IsPackaged() {
return
}
Expand All @@ -390,26 +416,30 @@ func (a *app) initPath() (err error) {
// import path mode
goSrcDir = filepath.Join(goPath, "src")
a.baseDir = filepath.Join(goSrcDir, filepath.FromSlash(a.ImportPath()))
if a.isPackaged {
if a.IsPackaged() {
ep, er := os.Executable()
if er != nil {
err = er
return
}
a.baseDir = filepath.Clean(filepath.Dir(filepath.Dir(ep)))

if a.embeddedMode {
a.baseDir = filepath.Dir(ep)
} else {
a.baseDir = filepath.Dir(filepath.Dir(ep))
}
a.baseDir = filepath.Clean(a.baseDir)
}

if !ess.IsFileExists(a.BaseDir()) {
err = fmt.Errorf("import path does not exists: %s", a.ImportPath())
}

return
}

func (a *app) initConfigValues() (err error) {
cfg := a.Config()
a.name = cfg.StringDefault("name", filepath.Base(a.BaseDir()))
a.appType = strings.ToLower(cfg.StringDefault("type", ""))

a.envProfile = cfg.StringDefault("env.active", defaultEnvProfile)
if err = a.SetProfile(a.Profile()); err != nil {
Expand Down Expand Up @@ -447,7 +477,7 @@ func (a *app) initConfigValues() (err error) {
return err
}

if a.appType != "websocket" {
if a.Type() != "websocket" {
maxBodySizeStr := cfg.StringDefault("request.max_body_size", "5mb")
if a.maxBodyBytes, err = ess.StrToBytes(maxBodySizeStr); err != nil {
return errors.New("'request.max_body_size' value is not a valid size unit")
Expand Down
53 changes: 16 additions & 37 deletions aah_test.go
Expand Up @@ -251,6 +251,9 @@ func newTestServer(t *testing.T, importPath string) (*testServer, error) {
Version: "1.0.0",
})

err := ts.app.VFS().AddMount(ts.app.VirtualBaseDir(), importPath)
assert.FailOnError(t, err, "not expecting any error")

if err := ts.app.Init(importPath); err != nil {
return nil, err
}
Expand Down Expand Up @@ -301,63 +304,39 @@ func (ts *testServer) manualInit() {

// adding controller
ts.app.AddController((*testSiteController)(nil), []*ainsp.Method{
{
Name: "Index",
Parameters: []*ainsp.Parameter{},
},
{
Name: "Text",
Parameters: []*ainsp.Parameter{},
},
{Name: "Index"},
{Name: "Text"},
{
Name: "Redirect",
Parameters: []*ainsp.Parameter{
&ainsp.Parameter{Name: "mode", Type: reflect.TypeOf((*string)(nil))},
{Name: "mode", Type: reflect.TypeOf((*string)(nil))},
},
},
{
Name: "FormSubmit",
Parameters: []*ainsp.Parameter{
&ainsp.Parameter{Name: "id", Type: reflect.TypeOf((*int)(nil))},
&ainsp.Parameter{Name: "info", Type: reflect.TypeOf((**sample)(nil))},
{Name: "id", Type: reflect.TypeOf((*int)(nil))},
{Name: "info", Type: reflect.TypeOf((**sample)(nil))},
},
},
{
Name: "CreateRecord",
Parameters: []*ainsp.Parameter{
&ainsp.Parameter{Name: "info", Type: reflect.TypeOf((**sampleJSON)(nil))},
{Name: "info", Type: reflect.TypeOf((**sampleJSON)(nil))},
},
},
{
Name: "XML",
Parameters: []*ainsp.Parameter{},
},
{Name: "XML"},
{
Name: "JSONP",
Parameters: []*ainsp.Parameter{
&ainsp.Parameter{Name: "callback", Type: reflect.TypeOf((*string)(nil))},
{Name: "callback", Type: reflect.TypeOf((*string)(nil))},
},
},
{
Name: "SecureJSON",
Parameters: []*ainsp.Parameter{},
},
{
Name: "TriggerPanic",
Parameters: []*ainsp.Parameter{},
},
{
Name: "BinaryBytes",
Parameters: []*ainsp.Parameter{},
},
{
Name: "SendFile",
Parameters: []*ainsp.Parameter{},
},
{
Name: "Cookies",
Parameters: []*ainsp.Parameter{},
},
{Name: "SecureJSON"},
{Name: "TriggerPanic"},
{Name: "BinaryBytes"},
{Name: "SendFile"},
{Name: "Cookies"},
})

// reset controller namespace and key
Expand Down
5 changes: 2 additions & 3 deletions config.go
Expand Up @@ -8,7 +8,7 @@ import (
"fmt"
"os"
"os/signal"
"path/filepath"
"path"
"syscall"

"aahframework.org/config.v0"
Expand All @@ -27,8 +27,7 @@ func (a *app) Config() *config.Config {
//______________________________________________________________________________

func (a *app) initConfig() error {
aahConf := filepath.Join(a.configDir(), "aah.conf")
cfg, err := config.LoadFile(aahConf)
cfg, err := config.VFSLoadFile(a.VFS(), path.Join(a.VirtualBaseDir(), "config", "aah.conf"))
if err != nil {
return fmt.Errorf("aah.conf: %s", err)
}
Expand Down
36 changes: 30 additions & 6 deletions default.go
Expand Up @@ -15,6 +15,7 @@ import (
"aahframework.org/router.v0"
"aahframework.org/security.v0"
"aahframework.org/security.v0/session"
"aahframework.org/vfs.v0"
"aahframework.org/view.v0"
"aahframework.org/ws.v0"
)
Expand Down Expand Up @@ -49,14 +50,22 @@ func AppProfile() string {
return defaultApp.Profile()
}

// AppBaseDir method returns the application base or binary current directory
// AppBaseDir method returns the application base or binary's base directory
// For e.g.:
// $GOPATH/src/github.com/user/myproject
// <app/binary/path/base/directory>
func AppBaseDir() string {
return defaultApp.BaseDir()
}

// AppVirtualBaseDir method returns "/app". In `v0.11.0` Virtual FileSystem (VFS)
// introduced in aah to provide single binary build package and also provides
// seamless experience Read-Only access to application directory and its sub-tree
// across OS platform via `aah.AppVFS()`.
func AppVirtualBaseDir() string {
return defaultApp.VirtualBaseDir()
}

// AppImportPath method returns the application Go import path.
func AppImportPath() string {
return defaultApp.ImportPath()
Expand Down Expand Up @@ -115,10 +124,25 @@ func SetAppBuildInfo(bi *BuildInfo) {
}

// SetAppPackaged method sets the info of binary is packaged or not.
//
// It is used by framework during application startup. IT'S NOT FOR AAH USER(S).
func SetAppPackaged(pack bool) {
defaultApp.SetPackaged(pack)
}

// AppIsEmbeddedMode method returns true if application VFS is running embeded mode,
// otherwise false. It means aah VFS embeds the mounted files within binary.
func AppIsEmbeddedMode() bool {
return defaultApp.embeddedMode
}

// AppSetEmbeddedMode method sets the application VFS mode to embeded state.
//
// It is used by framework during VFS setup. IT'S NOT FOR AAH USER(S).
func AppSetEmbeddedMode() {
defaultApp.SetEmbeddedMode()
}

// NewChildLogger method create a child logger from aah application default logger.
func NewChildLogger(fields log.Fields) log.Loggerer {
return defaultApp.NewChildLogger(fields)
Expand Down Expand Up @@ -218,6 +242,11 @@ func AppWSEngine() *ws.Engine {
return defaultApp.WSEngine()
}

// AppVFS method returns aah Virtual FileSystem instance.
func AppVFS() *vfs.VFS {
return defaultApp.VFS()
}

// AddController method adds given controller into controller registory.
func AddController(c interface{}, methods []*ainsp.Method) {
defaultApp.AddController(c, methods)
Expand Down Expand Up @@ -258,11 +287,6 @@ func SetErrorHandler(handlerFunc ErrorHandlerFunc) {
defaultApp.errorMgr.SetHandler(handlerFunc)
}

// Middlewares method adds given middleware into middleware stack
func Middlewares(middlewares ...MiddlewareFunc) {
defaultApp.he.Middlewares(middlewares...)
}

// AddLoggerHook method adds given logger into aah application default logger.
func AddLoggerHook(name string, hook log.HookFunc) error {
return defaultApp.AddLoggerHook(name, hook)
Expand Down
3 changes: 1 addition & 2 deletions default_test.go
Expand Up @@ -62,6 +62,7 @@ func TestDefaultApp(t *testing.T) {
assert.NotNil(t, AppViewEngine())
assert.NotNil(t, AppSecurityManager())
assert.NotNil(t, AppSessionManager())
assert.NotNil(t, AppVFS())

// Default App Start and Shutdown
t.Log("Default App Start and Shutdown")
Expand Down Expand Up @@ -90,8 +91,6 @@ func TestDefaultApp(t *testing.T) {
return true
})

Middlewares(ToMiddleware(thirdPartyMiddleware1))

AddLoggerHook("testhook", func(e log.Entry) {
t.Log("test logger hook")
})
Expand Down