fileembed: extend environment-variable mode to hard-coded directory loading.

also, slurp to memory mode.  for App Engine.

Change-Id: Ib6de390231e4669e7a6145a8d40b646744fd028c
This commit is contained in:
Brad Fitzpatrick 2011-10-18 11:10:02 -07:00
parent c38d9f6bc7
commit 916073b87b
1 changed files with 37 additions and 5 deletions

View File

@ -17,8 +17,9 @@ limitations under the License.
package fileembed package fileembed
import ( import (
"http"
"fmt" "fmt"
"http"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
@ -30,6 +31,13 @@ type Files struct {
// Optional environment variable key to override // Optional environment variable key to override
OverrideEnv string OverrideEnv string
// Optional fallback directory to check, if not in memory.
DirFallback string
// SlurpToMemory controls whether on first access the file is
// slurped into memory. It's intended for use with DirFallback.
SlurpToMemory bool
lk sync.Mutex lk sync.Mutex
file map[string]string file map[string]string
} }
@ -38,6 +46,11 @@ type Files struct {
func (f *Files) Add(filename, body string) { func (f *Files) Add(filename, body string) {
f.lk.Lock() f.lk.Lock()
defer f.lk.Unlock() defer f.lk.Unlock()
f.add(filename, body)
}
// f.lk must be locked
func (f *Files) add(filename, body string) {
if f.file == nil { if f.file == nil {
f.file = make(map[string]string) f.file = make(map[string]string)
} }
@ -50,16 +63,35 @@ func (f *Files) Open(filename string) (http.File, os.Error) {
} }
f.lk.Lock() f.lk.Lock()
defer f.lk.Unlock() defer f.lk.Unlock()
if f.file == nil {
return nil, os.ENOENT
}
s, ok := f.file[filename] s, ok := f.file[filename]
if !ok { if !ok {
return nil, os.ENOENT return f.openFallback(filename)
} }
return &file{name: filename, s: s}, nil return &file{name: filename, s: s}, nil
} }
// f.lk is held
func (f *Files) openFallback(filename string) (http.File, os.Error) {
if f.DirFallback == "" {
return nil, os.ENOENT
}
of, err := os.Open(filepath.Join(f.DirFallback, filename))
switch {
case err != nil:
return nil, err
case f.SlurpToMemory:
defer of.Close()
bs, err := ioutil.ReadAll(of)
if err != nil {
return nil, err
}
s := string(bs)
f.add(filename, s)
return &file{name: filename, s: s}, nil
}
return of, nil
}
type file struct { type file struct {
name string name string
s string s string