Skip to content

Commit

Permalink
go-aah/aah#156 integrated vfs into CLI and aah binary build support a…
Browse files Browse the repository at this point in the history
…dded
  • Loading branch information
jeevatkm committed May 16, 2018
1 parent 6b790a5 commit 26727ba
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 60 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ branches:
- /^v[0-9.]+$/

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

go_import_path: aahframework.org/tools.v0/aah
Expand Down
2 changes: 1 addition & 1 deletion aah/aah.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func main() {
// if panic happens, recover and abort nicely :)
defer func() {
if r := recover(); r != nil {
strace := aruntime.NewStacktrace(r, config.NewEmptyConfig())
strace := aruntime.NewStacktrace(r, config.NewEmpty())
strace.Print(os.Stdout)
exit(2)
}
Expand Down
42 changes: 37 additions & 5 deletions aah/app-template/aah.project.atmpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,20 @@ build {
tags = ""

# AST excludes is used for `aah.Context` inspection and generating aah
# application main Go file. Valid exclude patterns
# refer: https://golang.org/pkg/path/filepath/#Match
# application main Go file.
#
# Valid pattern syntax, refer to https://golang.org/pkg/path/filepath/#Match
ast_excludes = ["*_test.go", ".*", "*.bak", "*.tmp", "vendor"]

# Packing excludes is used to exclude file/directory during aah application
# build archive. Valid exclude patterns
# refer: https://golang.org/pkg/path/filepath/#Match
excludes = ["*.go", "*_test.go", ".*", "*.bak", "*.tmp", "vendor", "app", "build", "tests", "logs"]
# build archive.
#
# Note: It is applicable to aah single binary build. This list excluded from
# embedding.
#
# Valid pattern syntax, refer to https://golang.org/pkg/path/filepath/#Match
excludes = ["*.go", ".*", "*.bak", "*.tmp", "*.pid",
"vendor", "app", "build", "tests", "logs"]
}

# Logger configuration for aah CLI tool.
Expand Down Expand Up @@ -66,3 +72,29 @@ hot_reload {
file_excludes = [".*", "_test.go", "LICENSE", "README.md"]
}
}

# Virtual FileSystem (VFS) configuration
vfs {
# Adding custom mount points. Configured mount points directory sub-tree
# gets embedded into aah binary during a build.
#
# Note: Its applicable for aah single binary build.
mount {
# Choose an unique key name
#my_mount {
# # Mount point (path separator is '/').
# mount_path = "/my_mount"
#
# # Physical FileSystem path.
# # Note: Only absolute path accepted.
# physical_path = "/Users/jeeva/path/to/physical"
#}
}

# This config is speed up the single binary build process.
# Do not spend time to gzip for already compress content.
#
# Even without this config aah does best decision on what to gzip.
no_gzip = [".png", ".jpeg", ".jpg", ".gif", ".bmp", ".tiff", ".tif"
".woff", ".woff2"]
}
19 changes: 15 additions & 4 deletions aah/app-template/app/init.go.atmpl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func init() {
// Executed in the order they are defined. It is recommended; NOT to change
// the order of pre-defined aah framework middleware's.
//__________________________________________________________________________
aah.Middlewares(
aah.AppHTTPEngine().Middlewares(
aah.RouteMiddleware,
aah.CORSMiddleware,
aah.BindMiddleware,{{ if .App.IsWebApp }}
Expand Down Expand Up @@ -123,23 +123,31 @@ func SubscribeHTTPEvents(_ *aah.Event) {
{{ if not .App.IsSecurityEnabled }}//{{ end }} he := aah.AppHTTPEngine()

// Event: OnRequest
//
// Published for each incoming request to the aah go server.
// he.OnRequest(myserverext.OnRequest)

// Event: OnPreReply
//
// Published right before writing an reply on the wire.
// he.OnPreReply(myserverext.OnPreReply)

// Event: OnPostReply
//
// Published right after the reply is written on the wire.
// he.OnPostReply(myserverext.OnPostReply)

// Event: OnPreAuth
//
// Published right before the Authentication by security manager.
// he.OnPreAuth(myserverext.OnPreAuth){{ if .App.IsSecurityEnabled }}

// Event: OnPostAuth
// Published right after the successful Authentication
// Published right after the successful Authentication by security manager.
he.OnPostAuth(security.PostAuthEvent){{ else }}

// Event: OnPostAuth
// Published right after the successful Authentication
// Published right after the successful Authentication by security manager.
// he.OnPostAuth(myserverext.PostAuthEvent){{ end }}
}
{{ end }}{{ if or .App.IsWebSocketApp .App.IsSubTypeWebSocket }}
Expand All @@ -155,6 +163,9 @@ func SubscribeHTTPEvents(_ *aah.Event) {
func SubscribeWebSocketEvents(_ *aah.Event) {
// wse := aah.AppWSEngine()

// Custom ID Generator
// wse.SetIDGenerator(websockets.MyCustomIDGenerator)

// Event: OnPreConnect
//
// Published before connection gets upgraded to WebSocket.
Expand All @@ -180,6 +191,6 @@ func SubscribeWebSocketEvents(_ *aah.Event) {
// WebSocket/WebSocket Action not found, WebSocket Action parameter parse error,
// and WebSocket upgrade fails.
//
//`ctx.ErrorReason()` method can be called to know the reason for the error.
// `ctx.ErrorReason()` method can be called to know the reason for the error.
// wse.OnError(mywebsockets.HandleEvents)
}{{ end }}
125 changes: 100 additions & 25 deletions aah/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ import (
var buildCmd = cli.Command{
Name: "build",
Aliases: []string{"b"},
Usage: "Builds aah application for deployment",
Description: `Builds aah application for deployment.
Usage: "Builds aah application for deployment (single or non-single)",
Description: `Builds aah application for deployment. It supports single and non-single
binary. Its a trade-off learn more https://docs.aahframework.org/build-packaging.html
Artifact naming convention: <appbinaryname>-<appversion>-<goos>-<goarch>.zip
For e.g.: aahwebsite-381eaa8-darwin-amd64.zip
Examples of short and long flags:
aah build
aah build --single
aah build -e dev
aah build -i github.com/user/appname -o /Users/jeeva -e qa
aah build -i github.com/user/appname -o /Users/jeeva/aahwebsite.zip
Expand All @@ -48,24 +50,39 @@ var buildCmd = cli.Command{
Name: "o, output",
Usage: "Output of aah application build artifact; the default is '<appbasedir>/build/<appbinaryname>-<appversion>-<goos>-<goarch>.zip'",
},
cli.BoolFlag{
Name: "s, single",
Usage: "Creates aah single application binary",
},
},
}

func buildAction(c *cli.Context) error {
importPath := appImportPath(c)

if err := aah.Init(importPath); err != nil {
logFatal(err)
}

appBaseDir := aah.AppBaseDir()
projectCfg := aahProjectCfg(appBaseDir)
projectCfg := aahProjectCfg(aah.AppBaseDir())
cliLog = initCLILogger(projectCfg)

cliLog.Infof("Loaded aah project file: %s", filepath.Join(appBaseDir, aahProjectIdentifier))
cliLog.Infof("Loaded aah project file: %s", filepath.Join(aah.AppBaseDir(), aahProjectIdentifier))
cliLog.Infof("Build starts for '%s' [%s]", aah.AppName(), aah.AppImportPath())

appBinay, err := compileApp(&compileArgs{
if c.Bool("s") || c.Bool("single") {
buildSingleBinary(c, projectCfg)
} else {
buildBinary(c, projectCfg)
}

return nil
}

func buildBinary(c *cli.Context, projectCfg *config.Config) {
appBaseDir := aah.AppBaseDir()
cleanupAutoGenVFSFiles(appBaseDir)

appBinary, err := compileApp(&compileArgs{
Cmd: "BuildCmd",
ProjectCfg: projectCfg,
AppPack: true,
Expand All @@ -75,41 +92,73 @@ func buildAction(c *cli.Context) error {
}

appProfile := firstNonEmpty(c.String("e"), c.String("envprofile"), "prod")
buildBaseDir, err := copyFilesToWorkingDir(projectCfg, appBaseDir, appBinay, appProfile)
buildBaseDir, err := copyFilesToWorkingDir(projectCfg, appBaseDir, appBinary, appProfile)
if err != nil {
logFatal(err)
}

outputFile := firstNonEmpty(c.String("o"), c.String("output"))
archiveName := ess.StripExt(filepath.Base(appBinay)) + "-" + getAppVersion(appBaseDir, projectCfg)
archiveName = addTargetBuildInfo(archiveName)
destArchiveFile := createZipArchiveName(c, projectCfg, appBaseDir, appBinary)

var destArchiveFile string
if ess.IsStrEmpty(outputFile) {
destArchiveFile = filepath.Join(appBaseDir, "build", archiveName)
} else {
destArchiveFile, err = filepath.Abs(outputFile)
if err != nil {
logFatal(err)
// Creating app archive
if err = createZipArchive(buildBaseDir, destArchiveFile); err != nil {
logFatal(err)
}

cliLog.Infof("Build successful for '%s' [%s]", aah.AppName(), aah.AppImportPath())
cliLog.Infof("Application artifact is here: %s\n", destArchiveFile)
}

func buildSingleBinary(c *cli.Context, projectCfg *config.Config) {
cliLog.Infof("Embed starts for '%s' [%s]", aah.AppName(), aah.AppImportPath())
appBaseDir := aah.AppBaseDir()
defer cleanupAutoGenVFSFiles(appBaseDir)

excludes, _ := projectCfg.StringList("build.excludes")
noGzipList, _ := projectCfg.StringList("vfs.no_gzip")

// Default mount point
if err := processMount(appBaseDir, "/app", appBaseDir, ess.Excludes(excludes), noGzipList); err != nil {
logFatal(err)
}

// Custom mount points
mountKeys := projectCfg.KeysByPath("vfs.mount")
for _, key := range mountKeys {
vroot := projectCfg.StringDefault("vfs.mount."+key+".mount_path", "")
proot := projectCfg.StringDefault("vfs.mount."+key+".physical_path", "")

if !filepath.IsAbs(proot) {
logErrorf("vfs %s: physical_path is not absolute path, skip mount: %s", proot, vroot)
continue
}

if !strings.HasSuffix(destArchiveFile, ".zip") {
destArchiveFile = filepath.Join(destArchiveFile, archiveName)
if !ess.IsStrEmpty(vroot) && !ess.IsStrEmpty(proot) {
cliLog.Infof("|--- Processing mount: '%s' <== '%s'", vroot, proot)
if err := processMount(appBaseDir, vroot, proot, ess.Excludes(excludes), noGzipList); err != nil {
logFatal(err)
}
}
}
cliLog.Infof("Embed successful for '%s' [%s]", aah.AppName(), aah.AppImportPath())

if !strings.HasSuffix(destArchiveFile, ".zip") {
destArchiveFile = destArchiveFile + ".zip"
appBinary, err := compileApp(&compileArgs{
Cmd: "BuildCmd",
ProjectCfg: projectCfg,
AppPack: true,
AppEmbed: true,
})
if err != nil {
logFatal(err)
}

// Creating app archive
if err = createZipArchive(buildBaseDir, destArchiveFile); err != nil {
destArchiveFile := createZipArchiveName(c, projectCfg, appBaseDir, appBinary)
if err = createZipArchive(appBinary, destArchiveFile); err != nil {
logFatal(err)
}

cliLog.Infof("Build successful for '%s' [%s]", aah.AppName(), aah.AppImportPath())
cliLog.Infof("Your application artifact is here: %s\n", destArchiveFile)
return nil
cliLog.Infof("Application artifact is here: %s\n", destArchiveFile)
}

func copyFilesToWorkingDir(projectCfg *config.Config, appBaseDir, appBinary, appProfile string) (string, error) {
Expand Down Expand Up @@ -190,6 +239,32 @@ func createZipArchive(buildBaseDir, destArchiveFile string) error {
return ess.Zip(destArchiveFile, buildBaseDir)
}

func createZipArchiveName(c *cli.Context, projectCfg *config.Config, appBaseDir, appBinary string) string {
var err error
outputFile := firstNonEmpty(c.String("o"), c.String("output"))
archiveName := ess.StripExt(filepath.Base(appBinary)) + "-" + getAppVersion(appBaseDir, projectCfg)
archiveName = addTargetBuildInfo(archiveName)

var destArchiveFile string
if ess.IsStrEmpty(outputFile) {
destArchiveFile = filepath.Join(appBaseDir, "build", archiveName)
} else {
destArchiveFile, err = filepath.Abs(outputFile)
if err != nil {
logFatal(err)
}

if !strings.HasSuffix(destArchiveFile, ".zip") {
destArchiveFile = filepath.Join(destArchiveFile, archiveName)
}
}

if !strings.HasSuffix(destArchiveFile, ".zip") {
destArchiveFile = destArchiveFile + ".zip"
}
return destArchiveFile
}

const aahBashStartupTemplate = `#!/usr/bin/env bash
# The MIT License (MIT)
Expand Down
10 changes: 2 additions & 8 deletions aah/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@
package main

import (
"path/filepath"

"gopkg.in/urfave/cli.v1"

"aahframework.org/aah.v0"
"aahframework.org/essentials.v0"
)

var cleanCmd = cli.Command{
Expand Down Expand Up @@ -43,11 +40,8 @@ func cleanAction(c *cli.Context) error {
projectCfg := aahProjectCfg(aah.AppBaseDir())
cliLog = initCLILogger(projectCfg)

ess.DeleteFiles(
filepath.Join(aah.AppBaseDir(), "app", "aah.go"),
filepath.Join(aah.AppBaseDir(), "build"),
filepath.Join(aah.AppBaseDir(), aah.AppName()+".pid"),
)
cleanupAutoGenFiles(aah.AppBaseDir())
cleanupAutoGenVFSFiles(aah.AppBaseDir())

cliLog.Infof("Import Path '%v' clean successful.\n", importPath)

Expand Down
Loading

0 comments on commit 26727ba

Please sign in to comment.