From 40951c103f709cd47f520cee2db36b9dc597a631 Mon Sep 17 00:00:00 2001 From: mpl Date: Fri, 16 Aug 2013 18:25:14 +0200 Subject: [PATCH] appengine: fix the UI -dev-appengine populates the default sourceRoot. -app.yaml filters out the go files from the static resources -the UI handler warns that sourceRoot is required Change-Id: I816456a882ff4b0573bc8962cce85139d8a0f611 --- dev-appengine | 21 +++++++++++++++++++- pkg/server/publish.go | 1 + pkg/server/ui.go | 19 +++++++++++++++++- server/camlistored/ui/fileembed.go | 7 ++++++- server/camlistored/ui/fileembed_appengine.go | 13 ++---------- website/content/docs/server-config | 15 ++++++++++++++ 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/dev-appengine b/dev-appengine index 18f0c6fc7..0e2da15cb 100755 --- a/dev-appengine +++ b/dev-appengine @@ -38,8 +38,27 @@ if ($opt_port) { push @args, @ARGV; chdir "$Bin/server/appengine" or die "$!"; -push @args, "."; +my $sourceRoot = "$Bin/server/appengine/source_root"; +# import in the appengine dir all the static files, so they get uploaded +# TODO(mpl): do a smarter mirroring when we convert this to go +unless (-d $sourceRoot) { + # copy ui files + system("mkdir", "-p", $sourceRoot) and die "Failed to create $sourceRoot.\n"; + my $dest = "$sourceRoot/server/camlistored"; + system("mkdir", "-p", $dest) and die "Failed to create uiDir.\n"; + system("cp", "-a", "$Bin/server/camlistored/ui", $dest) and die "Failed to cp uiDir.\n"; + # copy closure files + $dest = "$sourceRoot/third_party/closure/lib"; + system("mkdir", "-p", $dest) and die "Failed to create closureDir.\n"; + system("cp", "-a", "$Bin/third_party/closure/lib/closure", $dest) and die "Failed to cp uiDir.\n"; + # copy favicon.ico + $dest = "$sourceRoot/pkg/server"; + system("mkdir", "-p", $dest) and die "Failed to create pkg/server.\n"; + system("cp", "$Bin/pkg/server/favicon.ico", $dest) and die "Failed to cp favicon.ico.\n"; +} + +push @args, "."; print "\$ @args\n"; exec(@args); diff --git a/pkg/server/publish.go b/pkg/server/publish.go index bf76d2bd5..8f29ef732 100644 --- a/pkg/server/publish.go +++ b/pkg/server/publish.go @@ -159,6 +159,7 @@ func newPublishFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Han } } + // TODO(mpl): check that it works on appengine too. if ph.sourceRoot == "" { ph.sourceRoot = os.Getenv("CAMLI_DEV_CAMLI_ROOT") } diff --git a/pkg/server/ui.go b/pkg/server/ui.go index 01f48b026..3498d1477 100644 --- a/pkg/server/ui.go +++ b/pkg/server/ui.go @@ -158,6 +158,19 @@ func uiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, er if ui.sourceRoot == "" { ui.sourceRoot = os.Getenv("CAMLI_DEV_CAMLI_ROOT") + if uistatic.IsAppEngine { + if _, err = os.Stat(filepath.Join(uistatic.GaeSourceRoot, + filepath.FromSlash("server/camlistored/ui/index.html"))); err != nil { + hint := fmt.Sprintf("\"sourceRoot\" was not specified in the config,"+ + " and the default sourceRoot dir %v does not exist or does not contain"+ + " \"server/camlistored/ui/index.html\". dev-appengine can do that for you.", + uistatic.GaeSourceRoot) + log.Print(hint) + return nil, errors.New("No sourceRoot found; UI not available.") + } + log.Printf("Using the default \"%v\" as the sourceRoot for AppEngine", uistatic.GaeSourceRoot) + ui.sourceRoot = uistatic.GaeSourceRoot + } } if ui.sourceRoot != "" { ui.uiDir = filepath.Join(ui.sourceRoot, filepath.FromSlash("server/camlistored/ui")) @@ -168,6 +181,10 @@ func uiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, er uistatic.Files = &fileembed.Files{ DirFallback: ui.uiDir, Listable: true, + // In dev_appserver, allow edit-and-reload without + // restarting. In production, though, it's faster to just + // slurp it in. + SlurpToMemory: uistatic.IsProdAppEngine, } } @@ -202,7 +219,7 @@ func (ui *UIHandler) makeClosureHandler(root string) (http.Handler, error) { // 3) a path on disk to the root of camlistore's source (which // contains the necessary subset of Closure files) func makeClosureHandler(root, handlerName string) (http.Handler, error) { - // devcam server environment variable takes precendence: + // devcam server environment variable takes precedence: if d := os.Getenv("CAMLI_DEV_CLOSURE_DIR"); d != "" { log.Printf("%v: serving Closure from devcam server's $CAMLI_DEV_CLOSURE_DIR: %v", handlerName, d) return http.FileServer(http.Dir(d)), nil diff --git a/server/camlistored/ui/fileembed.go b/server/camlistored/ui/fileembed.go index 237e21af2..7b5c15e80 100644 --- a/server/camlistored/ui/fileembed.go +++ b/server/camlistored/ui/fileembed.go @@ -23,4 +23,9 @@ import ( "camlistore.org/pkg/fileembed" ) -var Files *fileembed.Files +const GaeSourceRoot = "source_root" + +var ( + Files *fileembed.Files + IsAppEngine, IsProdAppEngine bool +) diff --git a/server/camlistored/ui/fileembed_appengine.go b/server/camlistored/ui/fileembed_appengine.go index 78d514c3c..de57dbbb5 100644 --- a/server/camlistored/ui/fileembed_appengine.go +++ b/server/camlistored/ui/fileembed_appengine.go @@ -19,19 +19,10 @@ limitations under the License. package ui import ( - "camlistore.org/pkg/fileembed" - "appengine" ) func init() { - Files = &fileembed.Files{ - DirFallback: "uistatic", - - // In dev_appserver, allow edit-and-reload without - // restarting. In production, though, it's faster to just - // slurp it in. - SlurpToMemory: !appengine.IsDevAppServer(), - Listable: true, - } + IsAppEngine = true + IsProdAppEngine = !appengine.IsDevAppServer() } diff --git a/website/content/docs/server-config b/website/content/docs/server-config index 168d187a3..8935d2bd3 100644 --- a/website/content/docs/server-config +++ b/website/content/docs/server-config @@ -84,3 +84,18 @@ to use the App Engine Blobstore and Datastore, as well as App Engine's user auth mechanisms. But as of 2013-06-12 we don't yet recommend running on App Engine; there are still some sharp corners.

+ +

+The UI requires some static resources that are not included by default in the App Engine application directory (server/appengine/). You can define that directory in the server configuration file (server/appengine/config.json), with the sourceRoot parameter, like so: +

+  "/ui/": {
+    "handler": "ui",
+    "handlerArgs": {
+      "sourceRoot": "dir_name",
+      "jsonSignRoot": "/sighelper/"
+    }
+  },
+
+You will then have to populate that directory with all the necessary resources (UI static files and closure library files).
+Alternatively, you can run ./dev-appengine once, which will create and populate the default directory (server/appengine/source_root). +