Work on implementing new static resource plan, as documented in the big TODO item.

Change-Id: I79d7665a24633630c39cceb5e1ab49cbb0300150
This commit is contained in:
Brad Fitzpatrick 2013-06-12 10:10:24 -07:00
parent 299b4cc0c8
commit 5761b57d69
4 changed files with 61 additions and 32 deletions

3
TODO
View File

@ -4,6 +4,9 @@ There are two TODO lists. This file (good for airplanes) and the online bug trac
Offline list:
-- add camliRoot & closureRoot to pkg/genconfig high-level config &
the docs
-- website: remove the "Installation" heading for /cmd/*, since
they're misleading and people should use "go run make.go" in the
general case.

View File

@ -52,6 +52,8 @@
"/ui/": {
"handler": "ui",
"handlerArgs": {
"camliRoot": ["_env", "${CAMLI_DEV_CAMLI_ROOT}", ""],
"closureRoot": ["_env", "${CAMLI_DEV_CLOSURE_ROOT}", ""],
"jsonSignRoot": "/sighelper/",
"cache": "/cache/",
"scaledImage": "lrucache",

View File

@ -26,7 +26,6 @@ my $opt_offline; # don't use the network ("airplane mode")
my $opt_staticres; # use static resources, not those on disk
my $opt_tls;
my $opt_wipe;
my $opt_closure; # run the Closure compiler
my $opt_verbose;
# keep indexes in memory only. often used with --wipe, but not
@ -51,7 +50,6 @@ GetOptions("wipe" => \$opt_wipe,
"fast" => \$opt_fast,
"verbose" => \$opt_verbose,
"hostname=s" => \$opt_hostname,
"compile-js" => \$opt_closure,
)
or usage();
@ -181,7 +179,6 @@ if ($opt_wipe && -d $templatedir) {
# To use resources from disk, instead of the copies linked into the
# binary:
unless ($opt_staticres) {
$ENV{CAMLI_DEV_UI_FILES} = "$FindBin::Bin/server/camlistored/ui"; # set in server/camlistored/ui/fileembed.go
unless ($opt_offline) {
if (-e "$Bin/tmp/closure-lib/.svn") {
system("rm", "-rf", "$Bin/tmp/closure-lib") and die "Failed to remove the svn checkout of the closure-lib.\n";
@ -190,10 +187,13 @@ unless ($opt_staticres) {
get_closure_compiler();
chdir $Bin or die;
}
if ($opt_closure) {
$ENV{CAMLI_USE_COMPILED_JS} = 1;
system("make", "minijs") and die "Failed to compress javascript with closure compiler.\n";
}
$ENV{CAMLI_DEV_CAMLI_ROOT} = $Bin;
$ENV{CAMLI_DEV_CLOSURE_ROOT} = "$Bin/tmp/closure-lib";
# TODO: delete CAMLI_DEV_UI_FILES here and in
# server/ui/fileembed_normal.go, once ui.go is updated to use
# camliRoot. This is just here transitionally:
$ENV{CAMLI_DEV_UI_FILES} = "$Bin/server/camlistored/ui";
}
print "Starting dev server on $base/ui/ with password \"pass$port\"\n";

View File

@ -38,12 +38,9 @@ import (
"camlistore.org/pkg/httputil"
"camlistore.org/pkg/jsonconfig"
"camlistore.org/pkg/jsonsign/signhandler"
"camlistore.org/pkg/osutil"
uistatic "camlistore.org/server/camlistored/ui"
)
var _ = log.Printf
var (
staticFilePattern = regexp.MustCompile(`^([a-zA-Z0-9\-\_]+\.(html|js|css|png|jpg|gif))$`)
identOrDotPattern = regexp.MustCompile(`^[a-zA-Z\_]+(\.[a-zA-Z\_]+)*$`)
@ -52,7 +49,8 @@ var (
// $1: blobref (checked in download handler)
// $2: optional "/filename" to be sent as recommended download name,
// if sane looking
downloadPattern = regexp.MustCompile(`^download/([^/]+)(/.*)?$`)
downloadPattern = regexp.MustCompile(`^download/([^/]+)(/.*)?$`)
thumbnailPattern = regexp.MustCompile(`^thumbnail/([^/]+)(/.*)?$`)
treePattern = regexp.MustCompile(`^tree/([^/]+)(/.*)?$`)
closurePattern = regexp.MustCompile(`^closure/(([^/]+)(/.*)?)$`)
@ -79,6 +77,13 @@ type UIHandler struct {
Cache blobserver.Storage // or nil
sc ScaledImage // cache for scaled images, optional
// camliRoot optionally specifies the path to root of Camlistore's
// source. If empty, the UI files must be compiled in to the
// binary (with go run make.go). This comes from the "camliRoot"
// ui handler config option.
// TODO: not yet implemented.
camliRoot string
// closureHandler serves the Closure JS files.
closureHandler http.Handler
}
@ -91,7 +96,9 @@ func uiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, er
ui := &UIHandler{
prefix: ld.MyPrefix(),
JSONSignRoot: conf.OptionalString("jsonSignRoot", ""),
camliRoot: conf.OptionalString("camliRoot", ""),
}
closureRoot := conf.OptionalString("closureRoot", "")
pubRoots := conf.OptionalList("publishRoots")
cachePrefix := conf.OptionalString("cache", "")
scType := conf.OptionalString("scaledImage", "")
@ -151,23 +158,9 @@ func uiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, er
}
}
// In development mode, serve the Closure files from disk directly.
isDevServer := os.Getenv("CAMLI_DEV_UI_FILES") != "" // and not in --staticres mode
if isDevServer {
camliRootPath, err := osutil.GoPackagePath("camlistore.org")
if err == nil {
closureDir := filepath.Join(camliRootPath, "tmp", "closure-lib", "closure")
fi, err := os.Stat(closureDir)
if err == nil && fi.IsDir() {
ui.closureHandler = http.FileServer(http.Dir(closureDir))
}
} else {
log.Printf("Package camlistore.org not found in $GOPATH (or $GOPATH not defined)." +
" Online closure from " + closureBaseURL + " will be used.")
}
}
if ui.closureHandler == nil {
ui.closureHandler = closureRedirector{}
ui.closureHandler, err = ui.makeClosureHandler(closureRoot)
if err != nil {
return nil, fmt.Errorf(`Invalid "closureRoot" value of %q: %v"`, closureRoot, err)
}
rootPrefix, _, err := ld.FindHandlerByType("root")
@ -184,17 +177,48 @@ func uiFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (h http.Handler, er
return ui, nil
}
const closureBaseURL = "https://closure-library.googlecode.com/git"
// makeClosureHandler returns a handler to serve Closure files.
// root is either:
// 1) empty: use the Closure files compiled in to the binar (if available), else redirect to the Internet.
// 2) a URL prefix: base of Closure to redirect to
// 3) a path on disk to serve files from
func (ui *UIHandler) makeClosureHandler(root string) (http.Handler, error) {
// In development mode, serve the Closure files from disk directly.
if root == "" {
// TODO: see if they're compiled in, and serve from that.
// But for now, assume a redirector to their current location
// on the web.
return closureBaseURL, nil
}
if strings.HasPrefix(root, "http") {
return closureRedirector(root), nil
}
fi, err := os.Stat(root)
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, errors.New("not a directory")
}
_, err = os.Stat(filepath.Join(root, "closure", "goog", "base.js"))
if err != nil {
return nil, fmt.Errorf("directory doesn't contain closure/goog/base.js; wrong directory?")
}
return http.FileServer(http.Dir(filepath.Join(root, "closure"))), nil
}
const closureBaseURL closureRedirector = "https://closure-library.googlecode.com/git"
// closureRedirector is a hack to redirect requests for Closure's million *.js files
// to https://closure-library.googlecode.com/git.
// TODO: this doesn't work when offline. We need to run genjsdeps over all of the Camlistore
// UI to figure out which Closure *.js files to fileembed and generate zembed. Then this
// type can be deleted.
type closureRedirector struct{}
type closureRedirector string
func (closureRedirector) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
newURL := closureBaseURL + "/" + path.Clean(httputil.PathSuffix(req))
func (base closureRedirector) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
newURL := string(base) + "/" + path.Clean(httputil.PathSuffix(req))
http.Redirect(rw, req, newURL, http.StatusTemporaryRedirect)
}