-{{ if eq .Mode "markdown" }}
-
-{{ end}}
-
-
-
-
-
-{{ else if eq .Class "content-only" }}
-
-{{ else }}
-
-{{ end }}
-
-
-
-
-{{ end }}
diff --git a/assets/templates/options.tmpl b/assets/templates/options.tmpl
deleted file mode 100644
index e10b039b..00000000
--- a/assets/templates/options.tmpl
+++ /dev/null
@@ -1,50 +0,0 @@
-{{ define "frontmatter" }}
- {{ range $key, $value := . }}
-
- {{ if or (eq $value.Type "object") (eq $value.Type "array") }}
-
-
-
-
- {{ end }}
-
- {{ if eq $value.Parent.Type "array" }}
-
- {{ end }}
-
- {{ if eq $value.HTMLType "textarea" }}
-
- {{ else if eq $value.HTMLType "datetime" }}
-
- {{ else }}
-
- {{ end }}
-
- {{ if not (eq $value.Parent.Type "array") }}
-
- {{ end }}
-
- {{ if eq $value.Parent.Type "array" }}
-
-
- {{ end }}
-
- {{ end }}
- {{ end }}
-{{ end }}
diff --git a/binary.go b/binary.go
index e8011866..3aabdc3e 100644
--- a/binary.go
+++ b/binary.go
@@ -1,9 +1,6 @@
// Code generated by go-bindata.
// sources:
-// assets/public/css/styles.css
// assets/public/js/application.js
-// assets/templates/editor.tmpl
-// assets/templates/options.tmpl
// DO NOT EDIT!
package hugo
@@ -30,24 +27,6 @@ type asset struct {
info os.FileInfo
}
-// publicCssStylesCss reads file data from disk. It returns an error on failure.
-func publicCssStylesCss() (*asset, error) {
- path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\public\\css\\styles.css"
- name := "public/css/styles.css"
- bytes, err := bindataRead(path, name)
- if err != nil {
- return nil, err
- }
-
- fi, err := os.Stat(path)
- if err != nil {
- err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
- }
-
- a := &asset{bytes: bytes, info: fi}
- return a, err
-}
-
// publicJsApplicationJs reads file data from disk. It returns an error on failure.
func publicJsApplicationJs() (*asset, error) {
path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\public\\js\\application.js"
@@ -66,42 +45,6 @@ func publicJsApplicationJs() (*asset, error) {
return a, err
}
-// templatesEditorTmpl reads file data from disk. It returns an error on failure.
-func templatesEditorTmpl() (*asset, error) {
- path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\templates\\editor.tmpl"
- name := "templates/editor.tmpl"
- bytes, err := bindataRead(path, name)
- if err != nil {
- return nil, err
- }
-
- fi, err := os.Stat(path)
- if err != nil {
- err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
- }
-
- a := &asset{bytes: bytes, info: fi}
- return a, err
-}
-
-// templatesOptionsTmpl reads file data from disk. It returns an error on failure.
-func templatesOptionsTmpl() (*asset, error) {
- path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-hugo\\assets\\templates\\options.tmpl"
- name := "templates/options.tmpl"
- bytes, err := bindataRead(path, name)
- if err != nil {
- return nil, err
- }
-
- fi, err := os.Stat(path)
- if err != nil {
- err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err)
- }
-
- a := &asset{bytes: bytes, info: fi}
- return a, err
-}
-
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
@@ -154,10 +97,7 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
- "public/css/styles.css": publicCssStylesCss,
"public/js/application.js": publicJsApplicationJs,
- "templates/editor.tmpl": templatesEditorTmpl,
- "templates/options.tmpl": templatesOptionsTmpl,
}
// AssetDir returns the file names below a certain
@@ -201,17 +141,10 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
"public": &bintree{nil, map[string]*bintree{
- "css": &bintree{nil, map[string]*bintree{
- "styles.css": &bintree{publicCssStylesCss, map[string]*bintree{}},
- }},
"js": &bintree{nil, map[string]*bintree{
"application.js": &bintree{publicJsApplicationJs, map[string]*bintree{}},
}},
}},
- "templates": &bintree{nil, map[string]*bintree{
- "editor.tmpl": &bintree{templatesEditorTmpl, map[string]*bintree{}},
- "options.tmpl": &bintree{templatesOptionsTmpl, map[string]*bintree{}},
- }},
}}
// RestoreAsset restores an asset under the given directory
diff --git a/commands.go b/commands.go
deleted file mode 100644
index 080cc187..00000000
--- a/commands.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package hugo
-
-import (
- "log"
- "os"
- "os/exec"
-)
-
-// Run executes an external command
-func Run(command string, args []string, path string) error {
- cmd := exec.Command(command, args...)
- cmd.Dir = path
- cmd.Stdout = os.Stderr
- cmd.Stderr = os.Stderr
- return cmd.Run()
-}
-
-// RunHugo is used to run the static website generator
-func RunHugo(c *Config, force bool) {
- os.RemoveAll(c.Public)
-
- // Prevent running if watching is enabled
- if b, pos := StringInSlice("--watch", c.Args); b && !force {
- if len(c.Args) > pos && c.Args[pos+1] != "false" {
- return
- }
-
- if len(c.Args) == pos+1 {
- return
- }
- }
-
- if err := Run(c.Hugo, c.Args, c.Root); err != nil {
- log.Panic(err)
- }
-}
diff --git a/frontmatter.go b/frontmatter.go
deleted file mode 100644
index 5fb3090e..00000000
--- a/frontmatter.go
+++ /dev/null
@@ -1,172 +0,0 @@
-package hugo
-
-import (
- "log"
- "reflect"
- "sort"
- "strings"
-
- "github.com/spf13/cast"
- "github.com/spf13/hugo/parser"
-)
-
-const (
- mainName = "#MAIN#"
- objectType = "object"
- arrayType = "array"
-)
-
-var mainTitle = ""
-
-// Pretty creates a new FrontMatter object
-func Pretty(content []byte) (interface{}, string, error) {
- frontType := parser.DetectFrontMatter(rune(content[0]))
- front, err := frontType.Parse(content)
-
- if err != nil {
- return []string{}, mainTitle, err
- }
-
- object := new(frontmatter)
- object.Type = objectType
- object.Name = mainName
-
- return rawToPretty(front, object), mainTitle, nil
-}
-
-type frontmatter struct {
- Name string
- Title string
- Content interface{}
- Type string
- HTMLType string
- Parent *frontmatter
-}
-
-func rawToPretty(config interface{}, parent *frontmatter) interface{} {
- objects := []*frontmatter{}
- arrays := []*frontmatter{}
- fields := []*frontmatter{}
-
- cnf := map[string]interface{}{}
-
- if reflect.TypeOf(config) == reflect.TypeOf(map[interface{}]interface{}{}) {
- for key, value := range config.(map[interface{}]interface{}) {
- cnf[key.(string)] = value
- }
- } else if reflect.TypeOf(config) == reflect.TypeOf([]interface{}{}) {
- for key, value := range config.([]interface{}) {
- cnf[string(key)] = value
- }
- } else {
- cnf = config.(map[string]interface{})
- }
-
- for name, element := range cnf {
- if IsMap(element) {
- objects = append(objects, handleObjects(element, parent, name))
- } else if IsSlice(element) {
- arrays = append(arrays, handleArrays(element, parent, name))
- } else {
- if name == "title" && parent.Name == mainName {
- mainTitle = element.(string)
- }
-
- fields = append(fields, handleFlatValues(element, parent, name))
- }
- }
-
- sort.Sort(sortByTitle(objects))
- sort.Sort(sortByTitle(arrays))
- sort.Sort(sortByTitle(fields))
-
- settings := []*frontmatter{}
- settings = append(settings, fields...)
- settings = append(settings, arrays...)
- settings = append(settings, objects...)
- return settings
-}
-
-type sortByTitle []*frontmatter
-
-func (f sortByTitle) Len() int { return len(f) }
-func (f sortByTitle) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f sortByTitle) Less(i, j int) bool {
- return strings.ToLower(f[i].Name) < strings.ToLower(f[j].Name)
-}
-
-func handleObjects(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
- c.Parent = parent
- c.Type = objectType
- c.Title = name
-
- if parent.Name == mainName {
- c.Name = c.Title
- } else if parent.Type == arrayType {
- c.Name = parent.Name + "[]"
- } else {
- c.Name = parent.Name + "[" + c.Title + "]"
- }
-
- c.Content = rawToPretty(content, c)
- return c
-}
-
-func handleArrays(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
- c.Parent = parent
- c.Type = arrayType
- c.Title = name
-
- if parent.Name == mainName {
- c.Name = name
- } else {
- c.Name = parent.Name + "[" + name + "]"
- }
-
- c.Content = rawToPretty(content, c)
- return c
-}
-
-func handleFlatValues(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
- c.Parent = parent
-
- switch reflect.ValueOf(content).Kind() {
- case reflect.Bool:
- c.Type = "boolean"
- case reflect.Int, reflect.Float32, reflect.Float64:
- c.Type = "number"
- default:
- c.Type = "string"
- }
-
- c.Content = content
-
- switch strings.ToLower(name) {
- case "description":
- c.HTMLType = "textarea"
- case "date", "publishdate":
- c.HTMLType = "datetime"
- c.Content = cast.ToTime(content)
- default:
- c.HTMLType = "text"
- }
-
- if parent.Type == arrayType {
- c.Name = parent.Name + "[]"
- c.Title = content.(string)
- } else if parent.Type == objectType {
- c.Title = name
- c.Name = parent.Name + "[" + name + "]"
-
- if parent.Name == mainName {
- c.Name = name
- }
- } else {
- log.Panic("Parent type not allowed in handleFlatValues.")
- }
-
- return c
-}
diff --git a/get.go b/get.go
deleted file mode 100644
index ac799485..00000000
--- a/get.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package hugo
-
-import (
- "bytes"
- "fmt"
- "html/template"
- "io/ioutil"
- "net/http"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/hacdias/caddy-filemanager"
- "github.com/spf13/hugo/parser"
-)
-
-type editor struct {
- Name string
- Class string
- IsPost bool
- Mode string
- Content string
- BaseURL string
- FrontMatter interface{}
-}
-
-// GET handles the GET method on editor page
-func (h Hugo) GET(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
- // Check if the file exists.
- if _, err := os.Stat(filename); os.IsNotExist(err) {
- return http.StatusNotFound, err
- } else if os.IsPermission(err) {
- return http.StatusForbidden, err
- } else if err != nil {
- return http.StatusInternalServerError, err
- }
-
- // Open the file and check if there was some error while opening
- file, err := ioutil.ReadFile(filename)
- if os.IsPermission(err) {
- return http.StatusForbidden, err
- } else if err != nil {
- return http.StatusInternalServerError, err
- }
-
- // Create a new editor variable and set the extension
- data := new(editor)
- data.Mode = strings.TrimPrefix(filepath.Ext(filename), ".")
- data.Name = strings.Replace(filename, h.Config.Root, "", 1)
- data.IsPost = false
- data.BaseURL = h.Config.BaseURL
- data.Mode = sanitizeMode(data.Mode)
-
- var parserPage parser.Page
-
- // Handle the content depending on the file extension
- switch data.Mode {
- case "markdown", "asciidoc", "rst":
- if hasFrontMatterRune(file) {
- // Starts a new buffer and parses the file using Hugo's functions
- buffer := bytes.NewBuffer(file)
- parserPage, err = parser.ReadFrom(buffer)
- if err != nil {
- return http.StatusInternalServerError, err
- }
-
- if strings.Contains(string(parserPage.FrontMatter()), "date") {
- data.IsPost = true
- }
-
- // Parses the page content and the frontmatter
- data.Content = strings.TrimSpace(string(parserPage.Content()))
- data.FrontMatter, data.Name, err = Pretty(parserPage.FrontMatter())
- data.Class = "complete"
- } else {
- // The editor will handle only content
- data.Class = "content-only"
- data.Content = string(file)
- }
- case "json", "toml", "yaml":
- // Defines the class and declares an error
- data.Class = "frontmatter-only"
-
- // Checks if the file already has the frontmatter rune and parses it
- if hasFrontMatterRune(file) {
- data.FrontMatter, _, err = Pretty(file)
- } else {
- data.FrontMatter, _, err = Pretty(appendFrontMatterRune(file, data.Mode))
- }
-
- // Check if there were any errors
- if err != nil {
- return http.StatusInternalServerError, err
- }
- default:
- // The editor will handle only content
- data.Class = "content-only"
- data.Content = string(file)
- }
-
- // Create the functions map, then the template, check for erros and
- // execute the template if there aren't errors
- functions := template.FuncMap{
- "SplitCapitalize": SplitCapitalize,
- "Defined": Defined,
- }
-
- var code int
-
- page := &filemanager.Page{
- Info: &filemanager.PageInfo{
- IsDir: false,
- Config: &h.FileManager.Configs[0],
- Name: data.Name,
- Data: data,
- },
- }
-
- templates := []string{"options", "editor"}
- for _, t := range templates {
- code, err = page.AddTemplate(t, Asset, functions)
- if err != nil {
- return code, err
- }
- }
-
- templates = []string{"actions", "base"}
- for _, t := range templates {
- code, err = page.AddTemplate(t, filemanager.Asset, nil)
- if err != nil {
- return code, err
- }
- }
-
- code, err = page.PrintAsHTML(w)
- fmt.Println(err)
- return code, err
-}
-
-func hasFrontMatterRune(file []byte) bool {
- return strings.HasPrefix(string(file), "---") ||
- strings.HasPrefix(string(file), "+++") ||
- strings.HasPrefix(string(file), "{")
-}
-
-func appendFrontMatterRune(frontmatter []byte, language string) []byte {
- switch language {
- case "yaml":
- return []byte("---\n" + string(frontmatter) + "\n---")
- case "toml":
- return []byte("+++\n" + string(frontmatter) + "\n+++")
- case "json":
- return frontmatter
- }
-
- return frontmatter
-}
-
-func sanitizeMode(extension string) string {
- switch extension {
- case "md", "markdown", "mdown", "mmark":
- return "markdown"
- case "asciidoc", "adoc", "ad":
- return "asciidoc"
- case "rst":
- return "rst"
- case "html", "htm":
- return "html"
- case "js":
- return "javascript"
- default:
- return extension
- }
-}
diff --git a/hugo.go b/hugo.go
index d282973c..684b3a52 100644
--- a/hugo.go
+++ b/hugo.go
@@ -7,6 +7,7 @@
package hugo
import (
+ "log"
"mime"
"net/http"
"os"
@@ -14,120 +15,54 @@ import (
"strings"
"github.com/hacdias/caddy-filemanager"
+ "github.com/hacdias/caddy-filemanager/utils/variables"
+ "github.com/hacdias/caddy-hugo/utils/commands"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
-// AssetsURL is the base url of the assets
-const AssetsURL = "/_hugointernal"
-
-// Hugo contais the next middleware to be run and the configuration
-// of the current one.
+// Hugo is hugo
type Hugo struct {
- FileManager *filemanager.FileManager
Next httpserver.Handler
Config *Config
+ FileManager *filemanager.FileManager
}
-// ServeHTTP is the main function of the whole plugin that routes every single
-// request to its function.
func (h Hugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
- // Check if the current request if for this plugin
if httpserver.Path(r.URL.Path).Matches(h.Config.BaseURL) {
- // Check if we are asking for the assets
if httpserver.Path(r.URL.Path).Matches(h.Config.BaseURL + AssetsURL) {
- return h.ServeAssets(w, r)
- }
- // If the url matches exactly with /{admin}/settings/, redirect
- // to the page of the configuration file
- if r.URL.Path == h.Config.BaseURL+"/settings/" {
- var frontmatter string
-
- if _, err := os.Stat(h.Config.Root + "config.yaml"); err == nil {
- frontmatter = "yaml"
- }
-
- if _, err := os.Stat(h.Config.Root + "config.json"); err == nil {
- frontmatter = "json"
- }
-
- if _, err := os.Stat(h.Config.Root + "config.toml"); err == nil {
- frontmatter = "toml"
- }
-
- http.Redirect(w, r, h.Config.BaseURL+"/config."+frontmatter, http.StatusTemporaryRedirect)
- return 0, nil
- }
-
- if strings.HasPrefix(r.URL.Path, h.Config.BaseURL+"/api/git/") && r.Method == http.MethodPost {
- //return HandleGit(w, r, h.Config)
- return 0, nil
- }
-
- if h.ShouldHandle(r) {
- filename := strings.Replace(r.URL.Path, h.Config.BaseURL, h.Config.Root, 1)
- switch r.Method {
- case http.MethodGet:
- return h.GET(w, r, filename)
- case http.MethodPost:
- return h.POST(w, r, filename)
- default:
- return h.FileManager.ServeHTTP(w, r)
- }
}
return h.FileManager.ServeHTTP(w, r)
}
+
return h.Next.ServeHTTP(w, r)
}
-var extensions = []string{
- "md", "markdown", "mdown", "mmark",
- "asciidoc", "adoc", "ad",
- "rst",
- "html", "htm",
- "js",
- "toml", "yaml", "json",
-}
+// RunHugo is used to run the static website generator
+func RunHugo(c *Config, force bool) {
+ os.RemoveAll(c.Root + "public")
-// ShouldHandle checks if this extension should be handled by this plugin
-func (h Hugo) ShouldHandle(r *http.Request) bool {
- // Checks if the method is get or post
- if r.Method != http.MethodGet && r.Method != http.MethodPost {
- return false
- }
+ // Prevent running if watching is enabled
+ if b, pos := variables.StringInSlice("--watch", c.Args); b && !force {
+ if len(c.Args) > pos && c.Args[pos+1] != "false" {
+ return
+ }
- // Check if this request is for FileManager assets
- if httpserver.Path(r.URL.Path).Matches(h.Config.BaseURL + filemanager.AssetsURL) {
- return false
- }
-
- // If this request requires a raw file or a download, return the FileManager
- query := r.URL.Query()
- if val, ok := query["raw"]; ok && val[0] == "true" {
- return false
- }
-
- if val, ok := query["download"]; ok && val[0] == "true" {
- return false
- }
-
- // Check by file extension
- extension := strings.TrimPrefix(filepath.Ext(r.URL.Path), ".")
-
- for _, ext := range extensions {
- if ext == extension {
- return true
+ if len(c.Args) == pos+1 {
+ return
}
}
- return false
+ if err := commands.Run(c.Hugo, c.Args, c.Root); err != nil {
+ log.Panic(err)
+ }
}
-// ServeAssets provides the needed assets for the front-end
-func (h Hugo) ServeAssets(w http.ResponseWriter, r *http.Request) (int, error) {
+// serveAssets provides the needed assets for the front-end
+func serveAssets(w http.ResponseWriter, r *http.Request, c *Config) (int, error) {
// gets the filename to be used with Assets function
- filename := strings.Replace(r.URL.Path, h.Config.BaseURL+AssetsURL, "public", 1)
+ filename := strings.Replace(r.URL.Path, c.BaseURL+AssetsURL, "public", 1)
file, err := Asset(filename)
if err != nil {
return http.StatusNotFound, nil
diff --git a/installer/installer.go b/installer/installer.go
index af77bb9b..2dc968dd 100644
--- a/installer/installer.go
+++ b/installer/installer.go
@@ -14,6 +14,7 @@ import (
"regexp"
"runtime"
+ "github.com/hacdias/caddy-hugo/utils/files"
"github.com/mitchellh/go-homedir"
"github.com/pivotal-golang/archiver/extractor"
)
@@ -90,7 +91,7 @@ func GetPath() string {
// Copy the file
fmt.Print("Moving Hugo executable... ")
- err = CopyFile(exetorename, hugo)
+ err = files.CopyFile(exetorename, hugo)
if err != nil {
fmt.Println(err)
os.Exit(-1)
@@ -213,27 +214,3 @@ func checkSHA256() {
fmt.Println("checked!")
}
-
-// CopyFile is used to copy a file
-func CopyFile(old, new string) error {
- // Open the file and create a new one
- r, err := os.Open(old)
- if err != nil {
- return err
- }
- defer r.Close()
-
- w, err := os.Create(new)
- if err != nil {
- return err
- }
- defer w.Close()
-
- // Copy the content
- _, err = io.Copy(w, r)
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/post.go b/post.go
deleted file mode 100644
index ecdf5744..00000000
--- a/post.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package hugo
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/http"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/robfig/cron"
- "github.com/spf13/cast"
- "github.com/spf13/hugo/parser"
-)
-
-type info struct {
- ContentType string
- Schedule bool
- Regenerate bool
- Content map[string]interface{}
-}
-
-type response struct {
- Message string `json:"message"`
-}
-
-// POST handles the POST method on editor page
-func (h Hugo) POST(w http.ResponseWriter, r *http.Request, filename string) (int, error) {
- var data info
-
- // Get the JSON information sent using a buffer
- rawBuffer := new(bytes.Buffer)
- rawBuffer.ReadFrom(r.Body)
- err := json.Unmarshal(rawBuffer.Bytes(), &data)
-
- if err != nil {
- return RespondJSON(w, &response{"Error decrypting json."}, http.StatusInternalServerError, err)
- }
-
- // Initializes the file content to write
- var file []byte
- var code int
-
- switch data.ContentType {
- case "frontmatter-only":
- file, code, err = parseFrontMatterOnlyFile(data, filename)
- if err != nil {
- return RespondJSON(w, &response{err.Error()}, code, err)
- }
- case "content-only":
- // The main content of the file
- mainContent := data.Content["content"].(string)
- mainContent = strings.TrimSpace(mainContent)
-
- file = []byte(mainContent)
- case "complete":
- file, code, err = parseCompleteFile(data, filename, h.Config)
- if err != nil {
- return RespondJSON(w, &response{err.Error()}, code, err)
- }
- default:
- return RespondJSON(w, &response{"Invalid content type."}, http.StatusBadRequest, nil)
- }
-
- // Write the file
- err = ioutil.WriteFile(filename, file, 0666)
-
- if err != nil {
- return RespondJSON(w, &response{err.Error()}, http.StatusInternalServerError, err)
- }
-
- if data.Regenerate {
- go RunHugo(h.Config, false)
- }
-
- return RespondJSON(w, nil, http.StatusOK, nil)
-}
-
-func parseFrontMatterOnlyFile(data info, filename string) ([]byte, int, error) {
- frontmatter := strings.TrimPrefix(filepath.Ext(filename), ".")
- var mark rune
-
- switch frontmatter {
- case "toml":
- mark = rune('+')
- case "json":
- mark = rune('{')
- case "yaml":
- mark = rune('-')
- default:
- return []byte{}, http.StatusBadRequest, errors.New("Can't define the frontmatter.")
- }
-
- f, err := parser.InterfaceToFrontMatter(data.Content, mark)
- fString := string(f)
-
- // If it's toml or yaml, strip frontmatter identifier
- if frontmatter == "toml" {
- fString = strings.TrimSuffix(fString, "+++\n")
- fString = strings.TrimPrefix(fString, "+++\n")
- }
-
- if frontmatter == "yaml" {
- fString = strings.TrimSuffix(fString, "---\n")
- fString = strings.TrimPrefix(fString, "---\n")
- }
-
- f = []byte(fString)
-
- if err != nil {
- return []byte{}, http.StatusInternalServerError, err
- }
-
- return f, http.StatusOK, nil
-}
-
-func parseCompleteFile(data info, filename string, c *Config) ([]byte, int, error) {
- // The main content of the file
- mainContent := data.Content["content"].(string)
- mainContent = "\n\n" + strings.TrimSpace(mainContent) + "\n"
-
- // Removes the main content from the rest of the frontmatter
- delete(data.Content, "content")
-
- if _, ok := data.Content["date"]; ok {
- data.Content["date"] = data.Content["date"].(string) + ":00"
- }
-
- // Schedule the post
- if data.Schedule {
- t := cast.ToTime(data.Content["date"])
-
- scheduler := cron.New()
- scheduler.AddFunc(t.In(time.Now().Location()).Format("05 04 15 02 01 *"), func() {
- // Set draft to false
- data.Content["draft"] = false
-
- // Converts the frontmatter in JSON
- jsonFrontmatter, err := json.Marshal(data.Content)
-
- if err != nil {
- return
- }
-
- // Indents the json
- frontMatterBuffer := new(bytes.Buffer)
- json.Indent(frontMatterBuffer, jsonFrontmatter, "", " ")
-
- // Generates the final file
- f := new(bytes.Buffer)
- f.Write(frontMatterBuffer.Bytes())
- f.Write([]byte(mainContent))
- file := f.Bytes()
-
- // Write the file
- if err = ioutil.WriteFile(filename, file, 0666); err != nil {
- return
- }
-
- go RunHugo(c, false)
- })
- scheduler.Start()
- }
-
- // Converts the frontmatter in JSON
- jsonFrontmatter, err := json.Marshal(data.Content)
-
- if err != nil {
- return []byte{}, http.StatusInternalServerError, err
- }
-
- // Indents the json
- frontMatterBuffer := new(bytes.Buffer)
- json.Indent(frontMatterBuffer, jsonFrontmatter, "", " ")
-
- // Generates the final file
- f := new(bytes.Buffer)
- f.Write(frontMatterBuffer.Bytes())
- f.Write([]byte(mainContent))
- return f.Bytes(), http.StatusOK, nil
-}
-
-func RespondJSON(w http.ResponseWriter, message interface{}, code int, err error) (int, error) {
- if message == nil {
- message = map[string]string{}
- }
-
- msg, msgErr := json.Marshal(message)
-
- if msgErr != nil {
- return 500, msgErr
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(code)
- w.Write(msg)
- return 0, err
-}
diff --git a/setup.go b/setup.go
index 8152cc88..b6f43708 100644
--- a/setup.go
+++ b/setup.go
@@ -5,15 +5,18 @@ import (
"log"
"net/http"
"os"
- "path/filepath"
"strings"
"github.com/hacdias/caddy-filemanager"
+ "github.com/hacdias/caddy-filemanager/config"
"github.com/hacdias/caddy-hugo/installer"
+ "github.com/hacdias/caddy-hugo/utils/commands"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
+const AssetsURL = "/_hugointernal"
+
func init() {
caddy.RegisterPlugin("hugo", caddy.Plugin{
ServerType: "http",
@@ -25,7 +28,7 @@ func init() {
// middleware thing.
func setup(c *caddy.Controller) error {
cnf := httpserver.GetConfig(c)
- conf, _ := ParseHugo(c, cnf.Root)
+ conf, _ := parse(c, cnf.Root)
// Checks if there is an Hugo website in the path that is provided.
// If not, a new website will be created.
@@ -44,7 +47,7 @@ func setup(c *caddy.Controller) error {
}
if create {
- err := Run(conf.Hugo, []string{"new", "site", conf.Root, "--force"}, ".")
+ err := commands.Run(conf.Hugo, []string{"new", "site", conf.Root, "--force"}, ".")
if err != nil {
log.Panic(err)
}
@@ -59,8 +62,8 @@ func setup(c *caddy.Controller) error {
Config: conf,
FileManager: &filemanager.FileManager{
Next: next,
- Configs: []filemanager.Config{
- filemanager.Config{
+ Configs: []config.Config{
+ config.Config{
HugoEnabled: true,
PathScope: conf.Root,
Root: http.Dir(conf.Root),
@@ -76,35 +79,27 @@ func setup(c *caddy.Controller) error {
return nil
}
-// Config contains the configuration of hugo plugin
+// Config is a configuration for managing a particular hugo website.
type Config struct {
- Args []string // Hugo arguments
- Git bool // Is this site a git repository
- BaseURL string // Admin URL to listen on
- Hugo string // Hugo executable path
- Root string // Hugo website path
- Public string // Public content path
- Styles string // Admin stylesheet
+ Public string // Public content path
+ Root string // Hugo files path
+ Hugo string // Hugo executable location
+ Styles string // Admin styles path
+ Args []string // Hugo arguments
+ BaseURL string // BaseURL of admin interface
+ FileManager *filemanager.FileManager
}
-// ParseHugo parses the configuration file
-func ParseHugo(c *caddy.Controller, root string) (*Config, error) {
+// Parse parses the configuration set by the user so it can be
+// used by the middleware
+func parse(c *caddy.Controller, root string) (*Config, error) {
conf := &Config{
Public: strings.Replace(root, "./", "", -1),
BaseURL: "/admin",
Root: "./",
- Git: false,
- Hugo: installer.GetPath(),
}
- stlsbytes, err := Asset("public/css/styles.css")
-
- if err != nil {
- return conf, err
- }
-
- conf.Styles = string(stlsbytes)
-
+ conf.Hugo = installer.GetPath()
for c.Next() {
args := c.RemainingArgs()
@@ -121,19 +116,17 @@ func ParseHugo(c *caddy.Controller, root string) (*Config, error) {
if !c.NextArg() {
return conf, c.ArgErr()
}
- stylesheet, err := ioutil.ReadFile(c.Val())
+ tplBytes, err := ioutil.ReadFile(c.Val())
if err != nil {
return conf, err
}
- conf.Styles += string(stylesheet)
+ conf.Styles = string(tplBytes)
case "admin":
if !c.NextArg() {
- return nil, c.ArgErr()
+ return conf, c.ArgErr()
}
conf.BaseURL = c.Val()
- // Remove the beginning slash if it exists or not
conf.BaseURL = strings.TrimPrefix(conf.BaseURL, "/")
- // Add a beginning slash to make a
conf.BaseURL = "/" + conf.BaseURL
default:
key := "--" + c.Val()
@@ -148,9 +141,5 @@ func ParseHugo(c *caddy.Controller, root string) (*Config, error) {
}
}
- if _, err := os.Stat(filepath.Join(conf.Root, ".git")); err == nil {
- conf.Git = true
- }
-
return conf, nil
}
diff --git a/utils/commands/commands.go b/utils/commands/commands.go
new file mode 100644
index 00000000..2e8626d4
--- /dev/null
+++ b/utils/commands/commands.go
@@ -0,0 +1,15 @@
+package commands
+
+import (
+ "os"
+ "os/exec"
+)
+
+// Run executes an external command
+func Run(command string, args []string, path string) error {
+ cmd := exec.Command(command, args...)
+ cmd.Dir = path
+ cmd.Stdout = os.Stderr
+ cmd.Stderr = os.Stderr
+ return cmd.Run()
+}
diff --git a/utils/files/files.go b/utils/files/files.go
new file mode 100644
index 00000000..084259ca
--- /dev/null
+++ b/utils/files/files.go
@@ -0,0 +1,30 @@
+package files
+
+import (
+ "io"
+ "os"
+)
+
+// CopyFile is used to copy a file
+func CopyFile(old, new string) error {
+ // Open the file and create a new one
+ r, err := os.Open(old)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+
+ w, err := os.Create(new)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+
+ // Copy the content
+ _, err = io.Copy(w, r)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/variables.go b/variables.go
deleted file mode 100644
index e361b612..00000000
--- a/variables.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package hugo
-
-import (
- "errors"
- "log"
- "reflect"
- "strings"
- "unicode"
-)
-
-// Defined checks if variable is defined in a struct
-func Defined(data interface{}, field string) bool {
- t := reflect.Indirect(reflect.ValueOf(data)).Type()
-
- if t.Kind() != reflect.Struct {
- log.Print("Non-struct type not allowed.")
- return false
- }
-
- _, b := t.FieldByName(field)
- return b
-}
-
-// Dict allows to send more than one variable into a template
-func Dict(values ...interface{}) (map[string]interface{}, error) {
- if len(values)%2 != 0 {
- return nil, errors.New("invalid dict call")
- }
- dict := make(map[string]interface{}, len(values)/2)
- for i := 0; i < len(values); i += 2 {
- key, ok := values[i].(string)
- if !ok {
- return nil, errors.New("dict keys must be strings")
- }
- dict[key] = values[i+1]
- }
-
- return dict, nil
-}
-
-// IsMap checks if some variable is a map
-func IsMap(sth interface{}) bool {
- return reflect.ValueOf(sth).Kind() == reflect.Map
-}
-
-// IsSlice checks if some variable is a slice
-func IsSlice(sth interface{}) bool {
- return reflect.ValueOf(sth).Kind() == reflect.Slice
-}
-
-// StringInSlice checks if a slice contains a string
-func StringInSlice(a string, list []string) (bool, int) {
- for i, b := range list {
- if b == a {
- return true, i
- }
- }
- return false, 0
-}
-
-var splitCapitalizeExceptions = map[string]string{
- "youtube": "YouTube",
- "github": "GitHub",
- "googleplus": "Google Plus",
- "linkedin": "LinkedIn",
-}
-
-// SplitCapitalize splits a string by its uppercase letters and capitalize the
-// first letter of the string
-func SplitCapitalize(name string) string {
- if val, ok := splitCapitalizeExceptions[strings.ToLower(name)]; ok {
- return val
- }
-
- var words []string
- l := 0
- for s := name; s != ""; s = s[l:] {
- l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1
- if l <= 0 {
- l = len(s)
- }
- words = append(words, s[:l])
- }
-
- name = ""
-
- for _, element := range words {
- name += element + " "
- }
-
- name = strings.ToLower(name[:len(name)-1])
- name = strings.ToUpper(string(name[0])) + name[1:]
-
- return name
-}