@@ -21,13 +21,16 @@ import (
21
21
"time"
22
22
23
23
"golang.org/x/tools/blog/atom"
24
+ "golang.org/x/tools/godoc/vfs"
25
+ "golang.org/x/tools/godoc/vfs/httpfs"
24
26
"golang.org/x/tools/present"
25
27
)
26
28
27
29
var validJSONPFunc = regexp .MustCompile (`(?i)^[a-z_][a-z0-9_.]*$` )
28
30
29
31
// Config specifies Server configuration values.
30
32
type Config struct {
33
+ RootFS vfs.FileSystem
31
34
ContentPath string // Relative or absolute location of article files and related content.
32
35
TemplatePath string // Relative or absolute location of template files.
33
36
@@ -73,36 +76,47 @@ type Server struct {
73
76
func NewServer (cfg Config ) (* Server , error ) {
74
77
present .PlayEnabled = cfg .PlayEnabled
75
78
76
- root := filepath .Join (cfg .TemplatePath , "root.tmpl" )
77
- parse := func (name string ) (* template.Template , error ) {
78
- t := template .New ("" ).Funcs (funcMap )
79
- return t .ParseFiles (root , filepath .Join (cfg .TemplatePath , name ))
79
+ parse := func (fs vfs.FileSystem , t * template.Template , filenames ... string ) (* template.Template , error ) {
80
+ if t == nil {
81
+ t = template .New (filenames [0 ]).Funcs (funcMap )
82
+ } else {
83
+ t = t .Funcs (funcMap )
84
+ }
85
+ for _ , name := range filenames {
86
+ data , err := vfs .ReadFile (fs , filepath .Join (cfg .TemplatePath , name ))
87
+ if err != nil {
88
+ return nil , err
89
+ }
90
+ if _ , err := t .Parse (string (data )); err != nil {
91
+ return nil , err
92
+ }
93
+ }
94
+ return t , nil
80
95
}
81
96
82
97
s := & Server {cfg : cfg }
83
98
84
99
// Parse templates.
85
100
var err error
86
- s .template .home , err = parse ("home.tmpl" )
101
+ s .template .home , err = parse (s . cfg . RootFS , nil , "root.tmpl" , "home.tmpl" )
87
102
if err != nil {
88
103
return nil , err
89
104
}
90
- s .template .index , err = parse ("index.tmpl" )
105
+ s .template .index , err = parse (s . cfg . RootFS , nil , "root.tmpl" , "index.tmpl" )
91
106
if err != nil {
92
107
return nil , err
93
108
}
94
- s .template .article , err = parse ("article.tmpl" )
109
+ s .template .article , err = parse (s . cfg . RootFS , nil , "root.tmpl" , "article.tmpl" )
95
110
if err != nil {
96
111
return nil , err
97
112
}
98
- p := present .Template ().Funcs (funcMap )
99
- s .template .doc , err = p .ParseFiles (filepath .Join (cfg .TemplatePath , "doc.tmpl" ))
113
+ s .template .doc , err = parse (s .cfg .RootFS , present .Template (), "doc.tmpl" )
100
114
if err != nil {
101
115
return nil , err
102
116
}
103
117
104
118
// Load content.
105
- err = s .loadDocs (filepath . Clean ( cfg .ContentPath ) )
119
+ err = s .loadDocs (s . cfg .ContentPath )
106
120
if err != nil {
107
121
return nil , err
108
122
}
@@ -118,11 +132,23 @@ func NewServer(cfg Config) (*Server, error) {
118
132
}
119
133
120
134
// Set up content file server.
121
- s .content = http .StripPrefix (s .cfg .BasePath , http .FileServer (http .Dir (cfg .ContentPath )))
135
+ s .content = http .StripPrefix (s .cfg .BasePath , http .FileServer (
136
+ httpfs .New (getNameSpace (s .cfg .RootFS , s .cfg .ContentPath )),
137
+ ))
122
138
123
139
return s , nil
124
140
}
125
141
142
+ func getNameSpace (fs vfs.FileSystem , ns string ) vfs.NameSpace {
143
+ newns := make (vfs.NameSpace )
144
+ if ns != "" {
145
+ newns .Bind ("/" , fs , ns , vfs .BindReplace )
146
+ } else {
147
+ newns .Bind ("/" , fs , "/" , vfs .BindReplace )
148
+ }
149
+ return newns
150
+ }
151
+
126
152
var funcMap = template.FuncMap {
127
153
"sectioned" : sectioned ,
128
154
"authors" : authors ,
@@ -171,16 +197,21 @@ func authorName(a present.Author) string {
171
197
func (s * Server ) loadDocs (root string ) error {
172
198
// Read content into docs field.
173
199
const ext = ".article"
174
- fn := func (p string , info os.FileInfo , err error ) error {
200
+ fn := func (fs vfs. FileSystem , p string , info os.FileInfo , err error ) error {
175
201
if filepath .Ext (p ) != ext {
176
202
return nil
177
203
}
178
- f , err := os .Open (p )
204
+ f , err := fs .Open (p )
179
205
if err != nil {
180
206
return err
181
207
}
182
208
defer f .Close ()
183
- d , err := present .Parse (f , p , 0 )
209
+ ctx := & present.Context {
210
+ ReadFile : func (filename string ) ([]byte , error ) {
211
+ return vfs .ReadFile (s .cfg .RootFS , filename )
212
+ },
213
+ }
214
+ d , err := ctx .Parse (f , p , 0 )
184
215
if err != nil {
185
216
return err
186
217
}
@@ -199,7 +230,7 @@ func (s *Server) loadDocs(root string) error {
199
230
})
200
231
return nil
201
232
}
202
- err := filepath . Walk (root , fn )
233
+ err := Walk (s . cfg . RootFS , root , fn )
203
234
if err != nil {
204
235
return err
205
236
}
0 commit comments