-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
382 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# EditorConfig: https://EditorConfig.org | ||
|
||
root = true | ||
|
||
[*] | ||
end_of_line = lf | ||
insert_final_newline = true | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
indent_size = 2 | ||
indent_style = space | ||
|
||
[*.go] | ||
indent_style = tab | ||
indent_size = 8 | ||
|
||
[Makefile] | ||
indent_style = tab | ||
|
||
[*.{json, yml, yaml}] | ||
indent_style = space | ||
indent_size = 2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Created by .ignore support plugin (hsz.mobi) | ||
### JetBrains template | ||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm | ||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
|
||
# User-specific stuff | ||
.idea/**/workspace.xml | ||
.idea/**/tasks.xml | ||
.idea/**/usage.statistics.xml | ||
.idea/**/dictionaries | ||
.idea/**/shelf | ||
|
||
# Generated files | ||
.idea/**/contentModel.xml | ||
|
||
# Sensitive or high-churn files | ||
.idea/**/dataSources/ | ||
.idea/**/dataSources.ids | ||
.idea/**/dataSources.local.xml | ||
.idea/**/sqlDataSources.xml | ||
.idea/**/dynamic.xml | ||
.idea/**/uiDesigner.xml | ||
.idea/**/dbnavigator.xml | ||
|
||
# Gradle | ||
.idea/**/gradle.xml | ||
.idea/**/libraries | ||
|
||
# Gradle and Maven with auto-import | ||
# When using Gradle or Maven with auto-import, you should exclude module files, | ||
# since they will be recreated, and may cause churn. Uncomment if using | ||
# auto-import. | ||
# .idea/modules.xml | ||
# .idea/*.iml | ||
# .idea/modules | ||
# *.iml | ||
# *.ipr | ||
|
||
# CMake | ||
cmake-build-*/ | ||
|
||
# Mongo Explorer plugin | ||
.idea/**/mongoSettings.xml | ||
|
||
# File-based project format | ||
*.iws | ||
|
||
# IntelliJ | ||
out/ | ||
|
||
# mpeltonen/sbt-idea plugin | ||
.idea_modules/ | ||
|
||
# JIRA plugin | ||
atlassian-ide-plugin.xml | ||
|
||
# Cursive Clojure plugin | ||
.idea/replstate.xml | ||
|
||
# Crashlytics plugin (for Android Studio and IntelliJ) | ||
com_crashlytics_export_strings.xml | ||
crashlytics.properties | ||
crashlytics-build.properties | ||
fabric.properties | ||
|
||
# Editor-based Rest Client | ||
.idea/httpRequests | ||
|
||
# Android studio 3.1+ serialized cache file | ||
.idea/caches/build_file_checksums.ser | ||
|
||
### Go template | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,23 @@ | ||
# golang-httpfs-template | ||
golang-vfstemplate | ||
======================= | ||
|
||
## Installation | ||
|
||
``` | ||
go get github.com/shakahl/golang-vfstemplate | ||
``` | ||
|
||
## Usage | ||
|
||
Parsing templates by glob pattern: | ||
|
||
``` | ||
template.Must(vfstemplate.ParseGlob(myhttpfs, nil, "/views/*.html") | ||
``` | ||
|
||
Parsing templates by specifying a list of file paths: | ||
|
||
``` | ||
vfstemplate.ParseFiles(myhttpfs, nil, "/views/first.html", "/views/second.html") | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/shakahl/golang-vfstemplate | ||
|
||
go 1.12 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package vfstemplate | ||
|
||
import ( | ||
"net/http" | ||
"os" | ||
"path" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
const separator = "/" | ||
|
||
// Glob returns the names of all files matching pattern or nil | ||
// if there is no matching file. The syntax of patterns is the same | ||
// as in path.Match. The pattern may describe hierarchical names such as | ||
// /usr/*/bin/ed. | ||
// | ||
// Glob ignores file system errors such as I/O errors reading directories. | ||
// The only possible returned error is ErrBadPattern, when pattern | ||
// is malformed. | ||
func Glob(fs http.FileSystem, pattern string) (matches []string, err error) { | ||
if !hasMeta(pattern) { | ||
if _, err = Stat(fs, pattern); err != nil { | ||
return nil, nil | ||
} | ||
return []string{pattern}, nil | ||
} | ||
|
||
dir, file := path.Split(pattern) | ||
switch dir { | ||
case "": | ||
dir = "." | ||
case string(separator): | ||
// nothing | ||
default: | ||
dir = dir[0 : len(dir)-1] // chop off trailing separator | ||
} | ||
|
||
if !hasMeta(dir) { | ||
return glob(fs, dir, file, nil) | ||
} | ||
|
||
var m []string | ||
m, err = Glob(fs, dir) | ||
if err != nil { | ||
return | ||
} | ||
for _, d := range m { | ||
matches, err = glob(fs, d, file, matches) | ||
if err != nil { | ||
return | ||
} | ||
} | ||
return | ||
} | ||
|
||
// glob searches for files matching pattern in the directory dir | ||
// and appends them to matches. If the directory cannot be | ||
// opened, it returns the existing matches. New matches are | ||
// added in lexicographical order. | ||
func glob(fs http.FileSystem, dir, pattern string, matches []string) (m []string, e error) { | ||
m = matches | ||
fi, err := Stat(fs, dir) | ||
if err != nil { | ||
return | ||
} | ||
if !fi.IsDir() { | ||
return | ||
} | ||
fis, err := ReadDir(fs, dir) | ||
if err != nil { | ||
return | ||
} | ||
|
||
sort.Sort(byName(fis)) | ||
|
||
for _, fi := range fis { | ||
n := fi.Name() | ||
matched, err := path.Match(path.Clean(pattern), n) | ||
if err != nil { | ||
return m, err | ||
} | ||
if matched { | ||
m = append(m, path.Join(dir, n)) | ||
} | ||
} | ||
return | ||
} | ||
|
||
// hasMeta reports whether path contains any of the magic characters | ||
// recognized by Match. | ||
func hasMeta(path string) bool { | ||
return strings.ContainsAny(path, "*?[") | ||
} | ||
|
||
// byName implements sort.Interface. | ||
type byName []os.FileInfo | ||
|
||
func (f byName) Len() int { return len(f) } | ||
func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } | ||
func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package vfstemplate | ||
|
||
import ( | ||
"fmt" | ||
"html/template" | ||
"net/http" | ||
"path" | ||
) | ||
|
||
// ParseFiles creates a new Template if t is nil and parses the template definitions from | ||
// the named files. The returned template's name will have the (base) name and | ||
// (parsed) contents of the first file. There must be at least one file. | ||
// If an error occurs, parsing stops and the returned *Template is nil. | ||
func ParseFiles(fs http.FileSystem, t *template.Template, filenames ...string) (*template.Template, error) { | ||
return parseFiles(fs, t, filenames...) | ||
} | ||
|
||
// ParseGlob parses the template definitions in the files identified by the | ||
// pattern and associates the resulting templates with t. The pattern is | ||
// processed by vfspath.Glob and must match at least one file. ParseGlob is | ||
// equivalent to calling t.ParseFiles with the list of files matched by the | ||
// pattern. | ||
func ParseGlob(fs http.FileSystem, t *template.Template, pattern string) (*template.Template, error) { | ||
filenames, err := Glob(fs, pattern) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(filenames) == 0 { | ||
return nil, fmt.Errorf("vfstemplate: pattern matches no files: %#q", pattern) | ||
} | ||
return parseFiles(fs, t, filenames...) | ||
} | ||
|
||
// parseFiles is the helper for the method and function. If the argument | ||
// template is nil, it is created from the first file. | ||
func parseFiles(fs http.FileSystem, t *template.Template, filenames ...string) (*template.Template, error) { | ||
if len(filenames) == 0 { | ||
// Not really a problem, but be consistent. | ||
return nil, fmt.Errorf("vfstemplate: no files named in call to ParseFiles") | ||
} | ||
for _, filename := range filenames { | ||
b, err := ReadFile(fs, filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
s := string(b) | ||
name := path.Base(filename) | ||
// First template becomes return value if not already defined, | ||
// and we use that one for subsequent New calls to associate | ||
// all the templates together. Also, if this file has the same name | ||
// as t, this file becomes the contents of t, so | ||
// t, err := New(name).Funcs(xxx).ParseFiles(name) | ||
// works. Otherwise we create a new template associated with t. | ||
var tmpl *template.Template | ||
if t == nil { | ||
t = template.New(name) | ||
} | ||
if name == t.Name() { | ||
tmpl = t | ||
} else { | ||
tmpl = t.New(name) | ||
} | ||
_, err = tmpl.Parse(s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
return t, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package vfstemplate | ||
|
||
import ( | ||
"io/ioutil" | ||
"net/http" | ||
"os" | ||
) | ||
|
||
// ReadDir reads the contents of the directory associated with file and | ||
// returns a slice of FileInfo values in directory order. | ||
func ReadDir(fs http.FileSystem, name string) ([]os.FileInfo, error) { | ||
f, err := fs.Open(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
return f.Readdir(-1) | ||
} | ||
|
||
// Stat returns the FileInfo structure describing file. | ||
func Stat(fs http.FileSystem, name string) (os.FileInfo, error) { | ||
f, err := fs.Open(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
return f.Stat() | ||
} | ||
|
||
// ReadFile reads the file named by path from fs and returns the contents. | ||
func ReadFile(fs http.FileSystem, path string) ([]byte, error) { | ||
rc, err := fs.Open(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer rc.Close() | ||
return ioutil.ReadAll(rc) | ||
} | ||
|
||
// ReadFileString reads the file named by path from fs and returns the contents. | ||
func ReadFileString(fs http.FileSystem, path string) (string, error) { | ||
buf, err := ReadFile(fs, path) | ||
if err != nil { | ||
return "", err | ||
} | ||
return string(buf), nil | ||
} |