Skip to content

Commit

Permalink
#156 Added VFS and Single binary build packaging feature (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed May 16, 2018
1 parent 1b6c5ff commit 17731b1
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 102 deletions.
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

0 comments on commit 17731b1

Please sign in to comment.