From 72c7abe469f03eba4db0dceeb76669c540ab80a4 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 21 Jun 2016 16:01:46 +0100 Subject: [PATCH] updates and restructure --- _stuff/LICENSE.md | 201 -------------- _stuff/README.md | 37 --- _stuff/git.go | 66 ----- _stuff/hugo.go | 98 ------- _stuff/page.go | 119 -------- _stuff/response.go | 28 -- _stuff/run.go | 29 -- _stuff/setup.go | 145 ---------- _stuff/templates.go | 0 _stuff/tools/commands/commands.go | 15 - _stuff/tools/installer/hashes.go | 25 -- _stuff/tools/installer/installer.go | 216 --------------- _stuff/tools/server/response.go | 30 -- _stuff/tools/server/url.go | 26 -- _stuff/tools/templates/templates.go | 73 ----- _stuff/tools/templates/templates_test.go | 39 --- _stuff/tools/variables/strings.go | 10 - _stuff/tools/variables/transform.go | 42 --- _stuff/tools/variables/transform_test.go | 31 --- _stuff/tools/variables/types.go | 13 - _stuff/tools/variables/variables.go | 37 --- _stuff/tools/variables/variables_test.go | 41 --- _stuff/utilities.go | 24 -- assets/templates/editor.tmpl | 58 ++++ assets/templates/frontmatter.tmpl | 44 +++ binary.go | 260 ++++++++++++++++++ _stuff/editor.go => editor.go | 88 +++--- .../frontmatter.go => frontmatter.go | 7 +- hugo.go | 4 + 29 files changed, 416 insertions(+), 1390 deletions(-) delete mode 100644 _stuff/LICENSE.md delete mode 100644 _stuff/README.md delete mode 100644 _stuff/git.go delete mode 100644 _stuff/hugo.go delete mode 100644 _stuff/page.go delete mode 100644 _stuff/response.go delete mode 100644 _stuff/run.go delete mode 100644 _stuff/setup.go delete mode 100644 _stuff/templates.go delete mode 100644 _stuff/tools/commands/commands.go delete mode 100644 _stuff/tools/installer/hashes.go delete mode 100644 _stuff/tools/installer/installer.go delete mode 100644 _stuff/tools/server/response.go delete mode 100644 _stuff/tools/server/url.go delete mode 100644 _stuff/tools/templates/templates.go delete mode 100644 _stuff/tools/templates/templates_test.go delete mode 100644 _stuff/tools/variables/strings.go delete mode 100644 _stuff/tools/variables/transform.go delete mode 100644 _stuff/tools/variables/transform_test.go delete mode 100644 _stuff/tools/variables/types.go delete mode 100644 _stuff/tools/variables/variables.go delete mode 100644 _stuff/tools/variables/variables_test.go delete mode 100644 _stuff/utilities.go create mode 100644 assets/templates/editor.tmpl create mode 100644 assets/templates/frontmatter.tmpl create mode 100644 binary.go rename _stuff/editor.go => editor.go (61%) rename _stuff/tools/frontmatter/frontmatter.go => frontmatter.go (96%) diff --git a/_stuff/LICENSE.md b/_stuff/LICENSE.md deleted file mode 100644 index 5e0fd33c..00000000 --- a/_stuff/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "{}" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright {yyyy} {name of copyright owner} - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/_stuff/README.md b/_stuff/README.md deleted file mode 100644 index fa050b4a..00000000 --- a/_stuff/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# hugo - a caddy plugin - -[![Build](https://img.shields.io/travis/hacdias/caddy-hugo.svg?style=flat-square)](https://travis-ci.org/hacdias/caddy-hugo) -[![community](https://img.shields.io/badge/community-forum-ff69b4.svg?style=flat-square)](https://forum.caddyserver.com) -[![Documentation](https://img.shields.io/badge/caddy-doc-F06292.svg?style=flat-square)](https://caddyserver.com/docs/hugo) -[![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/hacdias/caddy-hugo) - -[Hugo](http://gohugo.io/) is an easy to use and fast command line static website generator, while [Caddy](http://caddyserver.com) is a lightweight, fast, general-purpose, cross-platform HTTP/2 web server with automatic HTTPS. This extension is able to bring a web interface to Caddy to manage Hugo generated websites. This plugin provides you an web interface to manage your websites made with Hugo. - -**If you're not developer go to the [documentation](https://caddyserver.com/docs/hugo)**. - -## Build from source - -Requirements: - -+ [Go 1.6 or higher][1] -+ [caddydev][2] -+ [go-bindata][3] -+ [Node.js w/ npm][4] (optional) - -Instructions: - -1. ```go get github.com/hacdias/caddy-hugo``` -2. ```cd $GOPATH/github.com/hacdias/caddy-hugo``` - 1. If you want to modify the CSS/JS: - 2. Change the third comment to ```//go:generate go-bindata -debug -pkg assets -o assets/assets.go templates/ assets/css/ assets/js/ assets/fonts/``` - 3. ```npm install``` - 4. ```grunt watch``` -3. ```go generate``` -4. ```cd $YOUR_WEBSITE_PATH``` -5. ```caddydev --source $GOPATH/github.com/hacdias/caddy-hugo hugo``` -6. Go to ```http://domain:port``` - -[1]: https://golang.org/dl/ -[2]: https://github.com/caddyserver/caddydev -[3]: https://github.com/jteeuwen/go-bindata -[4]: https://nodejs.org diff --git a/_stuff/git.go b/_stuff/git.go deleted file mode 100644 index 5e918f88..00000000 --- a/_stuff/git.go +++ /dev/null @@ -1,66 +0,0 @@ -package hugo - -import ( - "bytes" - "encoding/json" - "net/http" - "os/exec" - "strings" -) - -// HandleGit handles the POST method on GIT page which is only an API. -func HandleGit(w http.ResponseWriter, r *http.Request, c *Config) (int, error) { - response := &Response{ - Code: http.StatusOK, - Err: nil, - Content: "OK", - } - - // Check if git is installed on the computer - if _, err := exec.LookPath("git"); err != nil { - response.Code = http.StatusNotImplemented - response.Content = "Git is not installed on your computer." - return response.Send(w) - } - - // Get the JSON information sent using a buffer - buff := new(bytes.Buffer) - buff.ReadFrom(r.Body) - - // Creates the raw file "map" using the JSON - var info map[string]interface{} - json.Unmarshal(buff.Bytes(), &info) - - // Check if command was sent - if _, ok := info["command"]; !ok { - response.Code = http.StatusBadRequest - response.Content = "Command not specified." - return response.Send(w) - } - - command := info["command"].(string) - args := strings.Split(command, " ") - - if len(args) > 0 && args[0] == "git" { - args = append(args[:0], args[1:]...) - } - - if len(args) == 0 { - response.Code = http.StatusBadRequest - response.Content = "Command not specified." - return response.Send(w) - } - - cmd := exec.Command("git", args...) - cmd.Dir = c.Path - output, err := cmd.CombinedOutput() - - if err != nil { - response.Code = http.StatusInternalServerError - response.Content = err.Error() - return response.Send(w) - } - - response.Content = string(output) - return response.Send(w) -} diff --git a/_stuff/hugo.go b/_stuff/hugo.go deleted file mode 100644 index 187064a9..00000000 --- a/_stuff/hugo.go +++ /dev/null @@ -1,98 +0,0 @@ -// Package hugo makes the bridge between the static website generator Hugo -// and the webserver Caddy, also providing an administrative user interface. -package hugo - -import ( - "net/http" - "net/url" - "os" - "path/filepath" - "strings" - - "github.com/hacdias/caddy-filemanager" - "github.com/mholt/caddy/caddyhttp/httpserver" -) - -// Hugo contais the next middleware to be run and the configuration -// of the current one. -type Hugo struct { - FileManager *filemanager.FileManager - Next httpserver.Handler - Config *Config -} - -// 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.Admin) { - // 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 h.FileManager.ServeHTTP(w, r) - } - - if val, ok := query["download"]; ok && val[0] == "true" { - return h.FileManager.ServeHTTP(w, r) - } - - // If the url matches exactly with /{admin}/settings/, redirect - // to the page of the configuration file - if r.URL.Path == h.Config.Admin+"/settings/" { - var frontmatter string - - if _, err := os.Stat(h.Config.Path + "config.yaml"); err == nil { - frontmatter = "yaml" - } - - if _, err := os.Stat(h.Config.Path + "config.json"); err == nil { - frontmatter = "json" - } - - if _, err := os.Stat(h.Config.Path + "config.toml"); err == nil { - frontmatter = "toml" - } - - http.Redirect(w, r, h.Config.Admin+"/config."+frontmatter, http.StatusTemporaryRedirect) - return 0, nil - } - - filename := strings.Replace(r.URL.Path, c.Admin+"/edit/", "", 1) - filename = c.Path + filename - - if strings.HasPrefix(r.URL.Path, h.Config.Admin+"/api/git/") && r.Method == http.MethodPost { - return HandleGit(w, r, h.Config) - } - - if h.ShouldHandle(r.URL) { - // return editor - return 0, nil - } - - 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", -} - -// ShouldHandle checks if this extension should be handled by this plugin -func (h Hugo) ShouldHandle(url *url.URL) bool { - extension := strings.TrimPrefix(filepath.Ext(url.Path), ".") - - for _, ext := range extensions { - if ext == extension { - return true - } - } - - return false -} diff --git a/_stuff/page.go b/_stuff/page.go deleted file mode 100644 index 12cf60b1..00000000 --- a/_stuff/page.go +++ /dev/null @@ -1,119 +0,0 @@ -package hugo - -import ( - "encoding/json" - "html/template" - "log" - "net/http" - "strings" -) - -// Page contains the informations and functions needed to show the page -type Page struct { - Info *PageInfo -} - -// PageInfo contains the information of a page -type PageInfo struct { - Name string - Path string - IsDir bool - Config *Config - Data interface{} -} - -// BreadcrumbMap returns p.Path where every element is a map -// of URLs and path segment names. -func (p PageInfo) BreadcrumbMap() map[string]string { - result := map[string]string{} - - if len(p.Path) == 0 { - return result - } - - // skip trailing slash - lpath := p.Path - if lpath[len(lpath)-1] == '/' { - lpath = lpath[:len(lpath)-1] - } - - parts := strings.Split(lpath, "/") - for i, part := range parts { - if i == 0 && part == "" { - // Leading slash (root) - result["/"] = "/" - continue - } - result[strings.Join(parts[:i+1], "/")] = part - } - - return result -} - -// PreviousLink returns the path of the previous folder -func (p PageInfo) PreviousLink() string { - parts := strings.Split(strings.TrimSuffix(p.Path, "/"), "/") - if len(parts) <= 1 { - return "" - } - - if parts[len(parts)-2] == "" { - if p.Config.BaseURL == "" { - return "/" - } - return p.Config.BaseURL - } - - return parts[len(parts)-2] -} - -// PrintAsHTML formats the page in HTML and executes the template -func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, error) { - templates = append(templates, "actions", "base") - var tpl *template.Template - - // For each template, add it to the the tpl variable - for i, t := range templates { - // Get the template from the assets - page, err := Asset("templates/" + t + ".tmpl") - - // Check if there is some error. If so, the template doesn't exist - if err != nil { - log.Print(err) - return http.StatusInternalServerError, err - } - - // If it's the first iteration, creates a new template and add the - // functions map - if i == 0 { - tpl, err = template.New(t).Parse(string(page)) - } else { - tpl, err = tpl.Parse(string(page)) - } - - if err != nil { - log.Print(err) - return http.StatusInternalServerError, err - } - } - - w.Header().Set("Content-Type", "text/html; charset=utf-8") - err := tpl.Execute(w, p.Info) - - if err != nil { - return http.StatusInternalServerError, err - } - - return http.StatusOK, nil -} - -// PrintAsJSON prints the current page infromation in JSON -func (p Page) PrintAsJSON(w http.ResponseWriter) (int, error) { - marsh, err := json.Marshal(p.Info.Data) - if err != nil { - return http.StatusInternalServerError, err - } - - w.Header().Set("Content-Type", "application/json; charset=utf-8") - return w.Write(marsh) -} diff --git a/_stuff/response.go b/_stuff/response.go deleted file mode 100644 index 7bde4863..00000000 --- a/_stuff/response.go +++ /dev/null @@ -1,28 +0,0 @@ -package hugo - -import ( - "encoding/json" - "net/http" -) - -// Response conta -type Response struct { - Code int - Err error - Content string -} - -// Send used to send JSON responses to the web server -func (r *Response) Send(w http.ResponseWriter) (int, error) { - content := map[string]string{"message": r.Content} - msg, msgErr := json.Marshal(content) - - if msgErr != nil { - return 500, msgErr - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(r.Code) - w.Write(msg) - return 0, r.Err -} diff --git a/_stuff/run.go b/_stuff/run.go deleted file mode 100644 index 38ab10a0..00000000 --- a/_stuff/run.go +++ /dev/null @@ -1,29 +0,0 @@ -package hugo - -import ( - "log" - "os" - - "github.com/hacdias/caddy-hugo/tools/commands" - "github.com/hacdias/caddy-hugo/tools/variables" -) - -// Run is used to run the static website generator -func Run(c *Config, force bool) { - os.RemoveAll(c.Path + "public") - - // 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 - } - - if len(c.Args) == pos+1 { - return - } - } - - if err := commands.Run(c.Hugo, c.Args, c.Path); err != nil { - log.Panic(err) - } -} diff --git a/_stuff/setup.go b/_stuff/setup.go deleted file mode 100644 index 8c4634f2..00000000 --- a/_stuff/setup.go +++ /dev/null @@ -1,145 +0,0 @@ -package hugo - -import ( - "log" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/hacdias/caddy-filemanager" - "github.com/hacdias/caddy-hugo/tools/commands" - "github.com/hacdias/caddy-hugo/tools/installer" - "github.com/mholt/caddy" - "github.com/mholt/caddy/caddyhttp/httpserver" -) - -func init() { - caddy.RegisterPlugin("hugo", caddy.Plugin{ - ServerType: "http", - Action: setup, - }) -} - -// Setup is the init function of Caddy plugins and it configures the whole -// middleware thing. -func setup(c *caddy.Controller) error { - cnf := httpserver.GetConfig(c.Key) - conf, _ := ParseHugo(c, cnf.Root) - - // Checks if there is an Hugo website in the path that is provided. - // If not, a new website will be created. - create := true - - if _, err := os.Stat(conf.Path + "config.yaml"); err == nil { - create = false - } - - if _, err := os.Stat(conf.Path + "config.json"); err == nil { - create = false - } - - if _, err := os.Stat(conf.Path + "config.toml"); err == nil { - create = false - } - - if create { - err := commands.Run(conf.Hugo, []string{"new", "site", conf.Path, "--force"}, ".") - if err != nil { - log.Panic(err) - } - } - - // Generates the Hugo website for the first time the plugin is activated. - go Run(conf, true) - - mid := func(next httpserver.Handler) httpserver.Handler { - return &Hugo{ - Next: next, - FileManager: &filemanager.FileManager{ - Next: next, - Configs: []filemanager.Config{ - filemanager.Config{ - PathScope: conf.Path, - Root: http.Dir(conf.Path), - BaseURL: conf.Admin, - }, - }, - }, - Config: conf, - } - } - - cnf.AddMiddleware(mid) - return nil -} - -// Config is the add-on configuration set on Caddyfile -type Config struct { - Public string // Public content path - Path string // Hugo files path - Styles string // Admin styles path - Args []string // Hugo arguments - Hugo string // Hugo executable path - Admin string // Hugo admin URL - Git bool // Is this site a git repository -} - -// ParseHugo parses the configuration file -func ParseHugo(c *caddy.Controller, root string) (*Config, error) { - conf := &Config{ - Public: strings.Replace(root, "./", "", -1), - Admin: "/admin", - Path: "./", - Git: false, - } - - conf.Hugo = installer.GetPath() - - for c.Next() { - args := c.RemainingArgs() - - switch len(args) { - case 1: - conf.Path = args[0] - conf.Path = strings.TrimSuffix(conf.Path, "/") - conf.Path += "/" - } - - for c.NextBlock() { - switch c.Val() { - case "styles": - if !c.NextArg() { - return nil, c.ArgErr() - } - conf.Styles = c.Val() - // Remove the beginning slash if it exists or not - conf.Styles = strings.TrimPrefix(conf.Styles, "/") - // Add a beginning slash to make a - conf.Styles = "/" + conf.Styles - case "admin": - if !c.NextArg() { - return nil, c.ArgErr() - } - conf.Admin = c.Val() - conf.Admin = strings.TrimPrefix(conf.Admin, "/") - conf.Admin = "/" + conf.Admin - default: - key := "--" + c.Val() - value := "true" - - if c.NextArg() { - value = c.Val() - } - - conf.Args = append(conf.Args, key+"="+value) - } - } - } - - if _, err := os.Stat(filepath.Join(conf.Path, ".git")); err == nil { - conf.Git = true - } - - return conf, nil -} diff --git a/_stuff/templates.go b/_stuff/templates.go deleted file mode 100644 index e69de29b..00000000 diff --git a/_stuff/tools/commands/commands.go b/_stuff/tools/commands/commands.go deleted file mode 100644 index 2e8626d4..00000000 --- a/_stuff/tools/commands/commands.go +++ /dev/null @@ -1,15 +0,0 @@ -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/_stuff/tools/installer/hashes.go b/_stuff/tools/installer/hashes.go deleted file mode 100644 index f28106ab..00000000 --- a/_stuff/tools/installer/hashes.go +++ /dev/null @@ -1,25 +0,0 @@ -package installer - -var ( - sha256Hash = map[string]string{ - "hugo_0.16_darwin-arm32.tgz": "683d5d4b4e0ac03a183ca5eb9019981ba696569445c7d6d1efc7e6706bd273a5", - "hugo_0.16_dragonfly-64bit.tgz": "63a3ee9a36d4d2166c77b96bb8bf39b2239affe118e44a83b3d0a44374a8921d", - "hugo_0.16_freebsd-32bit.tgz": "ea3f84900feeeb9d89573dea49a4349753116e70de561eeec4858f7ffc74f8f9", - "hugo_0.16_freebsd-64bit.tgz": "8d9320bb660090a77a4f922ca30b1582593bc6d87c3fd8bd6f5ecbe49cf1d2f2", - "hugo_0.16_freebsd-arm32.tgz": "b4c21296e01ea68709ac50d7eb1d314b738f1c8408ff2be223d06ae76604dbea", - "hugo_0.16_linux-32bit.tgz": "aed82d156f01a4562c39bd1af41aa81699009140da965e0369c370ba874725c9", - "hugo_0.16_linux-64bit.tgz": "13e299dc45bea4fad5bdf8c2640305a5926e2acd02c3aa03b7864403e513920e", - "hugo_0.16_linux-arm32.tgz": "bc836def127d93e2457da9994f9c09b0100523e46d61074cd724ef092b11714f", - "hugo_0.16_linux-arm64.tgz": "d04486918f43f89f1e0359eebedd8a05d96f7ca40f93e7fd8d7c3f2dac115a8d", - "hugo_0.16_netbsd-32bit.tgz": "cb578eebec5b6364b0afd5bb208d94317acab0a3e033b81f04b1511af0669b63", - "hugo_0.16_netbsd-64bit.tgz": "d3c766d9800d7fdd268ffd2f28b7af451f13a4de63901bfdae2ee5c96528b8cc", - "hugo_0.16_netbsd-arm32.tgz": "51162b2637e71b786582af715a44b778f62bdc62a9a354ccc4a7c8384afe194c", - "hugo_0.16_openbsd-32bit.tgz": "2d1e112a7346850897ea77da868c0d987ef90efb7f49c917659437a5a67f89f8", - "hugo_0.16_openbsd-64bit.tgz": "7b33ff2565df5a6253c3e4308813d947e34af04c633fb4e01cac83751066e16e", - "hugo_0.16_osx-32bit.tgz": "6155dda548bbd1e26c26a4a00472e4c0e55fad9fcd46991ce90987385bd5fd0a", - "hugo_0.16_osx-64bit.tgz": "b0cba8f6996946ef34a664184d6461567d79fc2a3e793145d34379902eda0ad9", - "hugo_0.16_solaris-64bit.tgz": "af9557403af5e16eb7faf965c04540417a70699efbbbc4e0a7ae4c4703ad1ae8", - "hugo_0.16_windows-32bit.zip": "1c72d06843fe02cb62348660d87a523c885ed684a683271fc8762e7234c4210b", - "hugo_0.16_windows-64bit.zip": "a3fda0bd30592e4eb3bdde85c8a8ce23a7433073536466d16fd0e97bf7794067", - } -) diff --git a/_stuff/tools/installer/installer.go b/_stuff/tools/installer/installer.go deleted file mode 100644 index 4a075124..00000000 --- a/_stuff/tools/installer/installer.go +++ /dev/null @@ -1,216 +0,0 @@ -package installer - -import ( - "crypto/sha256" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - - "github.com/hacdias/caddy-hugo/tools/files" - "github.com/mitchellh/go-homedir" - "github.com/pivotal-golang/archiver/extractor" -) - -const ( - version = "0.16" - baseurl = "https://github.com/spf13/hugo/releases/download/v" + version + "/" -) - -var caddy, bin, temp, hugo, tempfile, zipname, exename string - -// GetPath retrives the Hugo path for the user or install it if it's not found -func GetPath() string { - initializeVariables() - - var err error - - // Check if Hugo is already on $PATH - if hugo, err = exec.LookPath("hugo"); err == nil { - if checkVersion() { - return hugo - } - } - - // Check if Hugo is on $HOME/.caddy/bin - if _, err = os.Stat(hugo); err == nil { - if checkVersion() { - return hugo - } - } - - fmt.Println("Unable to find Hugo on your computer.") - - // Create the neccessary folders - os.MkdirAll(caddy, 0774) - os.Mkdir(bin, 0774) - - if temp, err = ioutil.TempDir("", "caddy-hugo"); err != nil { - fmt.Println(err) - os.Exit(-1) - } - - downloadHugo() - checkSHA256() - - fmt.Print("Unzipping... ") - - // Unzip or Ungzip the file - switch runtime.GOOS { - case "darwin", "windows": - zp := extractor.NewZip() - err = zp.Extract(tempfile, temp) - default: - gz := extractor.NewTgz() - err = gz.Extract(tempfile, temp) - } - - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - fmt.Println("done.") - - var exetorename string - - err = filepath.Walk(temp, func(path string, f os.FileInfo, err error) error { - if f.Name() == exename { - exetorename = path - } - - return nil - }) - - // Copy the file - fmt.Print("Moving Hugo executable... ") - err = files.CopyFile(exetorename, hugo) - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - err = os.Chmod(hugo, 0755) - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - fmt.Println("done.") - fmt.Println("Hugo installed at " + hugo) - defer os.RemoveAll(temp) - return hugo -} - -func initializeVariables() { - var arch string - switch runtime.GOARCH { - case "amd64": - arch = "64bit" - case "386": - arch = "32bit" - case "arm": - arch = "arm32" - default: - arch = runtime.GOARCH - } - - var ops = runtime.GOOS - if runtime.GOOS == "darwin" && runtime.GOARCH != "arm" { - ops = "osx" - } - - exename = "hugo" - zipname = "hugo_" + version + "_" + ops + "-" + arch - - homedir, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - caddy = filepath.Join(homedir, ".caddy") - bin = filepath.Join(caddy, "bin") - hugo = filepath.Join(bin, "hugo") - - switch runtime.GOOS { - case "windows": - zipname += ".zip" - exename += ".exe" - hugo += ".exe" - default: - zipname += ".tgz" - } -} - -func checkVersion() bool { - out, _ := exec.Command("hugo", "version").Output() - - r := regexp.MustCompile(`v\d\.\d{2}`) - v := r.FindStringSubmatch(string(out))[0] - v = v[1:len(v)] - - return (v == version) -} - -func downloadHugo() { - tempfile = filepath.Join(temp, zipname) - - fmt.Print("Downloading Hugo from GitHub releases... ") - - // Create the file - out, err := os.Create(tempfile) - out.Chmod(0774) - if err != nil { - defer os.RemoveAll(temp) - fmt.Println(err) - os.Exit(-1) - } - defer out.Close() - - // Get the data - resp, err := http.Get(baseurl + zipname) - if err != nil { - fmt.Println("An error ocurred while downloading. If this error persists, try downloading Hugo from \"https://github.com/spf13/hugo/releases/\" and put the executable in " + bin + " and rename it to 'hugo' or 'hugo.exe' if you're on Windows.") - fmt.Println(err) - os.Exit(-1) - } - defer resp.Body.Close() - - // Writer the body to file - _, err = io.Copy(out, resp.Body) - if err != nil { - fmt.Println(err) - os.Exit(-1) - } - - fmt.Println("downloaded.") -} - -func checkSHA256() { - fmt.Print("Checking SHA256...") - - hasher := sha256.New() - f, err := os.Open(tempfile) - if err != nil { - log.Fatal(err) - } - defer f.Close() - if _, err := io.Copy(hasher, f); err != nil { - log.Fatal(err) - } - - if hex.EncodeToString(hasher.Sum(nil)) != sha256Hash[zipname] { - fmt.Println("can't verify SHA256.") - os.Exit(-1) - } - - fmt.Println("checked!") -} diff --git a/_stuff/tools/server/response.go b/_stuff/tools/server/response.go deleted file mode 100644 index 97fa55df..00000000 --- a/_stuff/tools/server/response.go +++ /dev/null @@ -1,30 +0,0 @@ -package server - -import ( - "encoding/json" - "net/http" -) - -type Response struct { - Code int - Err error - Content interface{} -} - -// RespondJSON used to send JSON responses to the web server -func RespondJSON(w http.ResponseWriter, r *Response) (int, error) { - if r.Content == nil { - r.Content = map[string]string{} - } - - msg, msgErr := json.Marshal(r.Content) - - if msgErr != nil { - return 500, msgErr - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(r.Code) - w.Write(msg) - return 0, r.Err -} diff --git a/_stuff/tools/server/url.go b/_stuff/tools/server/url.go deleted file mode 100644 index e88d8b04..00000000 --- a/_stuff/tools/server/url.go +++ /dev/null @@ -1,26 +0,0 @@ -package server - -import ( - "net/http" - "strings" -) - -// ParseURLComponents parses the components of an URL creating an array -func ParseURLComponents(r *http.Request) []string { - //The URL that the user queried. - path := r.URL.Path - path = strings.TrimSpace(path) - //Cut off the leading and trailing forward slashes, if they exist. - //This cuts off the leading forward slash. - if strings.HasPrefix(path, "/") { - path = path[1:] - } - //This cuts off the trailing forward slash. - if strings.HasSuffix(path, "/") { - cutOffLastCharLen := len(path) - 1 - path = path[:cutOffLastCharLen] - } - //We need to isolate the individual components of the path. - components := strings.Split(path, "/") - return components -} diff --git a/_stuff/tools/templates/templates.go b/_stuff/tools/templates/templates.go deleted file mode 100644 index d8d09ceb..00000000 --- a/_stuff/tools/templates/templates.go +++ /dev/null @@ -1,73 +0,0 @@ -package templates - -import ( - "log" - "net/http" - "strings" - "text/template" - - "github.com/hacdias/caddy-hugo/routes/assets" -) - -// CanBeEdited checks if the extension of a file is supported by the editor -func CanBeEdited(filename string) bool { - extensions := [...]string{ - "md", "markdown", "mdown", "mmark", - "asciidoc", "adoc", "ad", - "rst", - ".json", ".toml", ".yaml", - ".css", ".sass", ".scss", - ".js", - ".html", - ".txt", - } - - for _, extension := range extensions { - if strings.HasSuffix(filename, extension) { - return true - } - } - - return false -} - -// Get is used to get a ready to use template based on the url and on -// other sent templates -func Get(r *http.Request, functions template.FuncMap, templates ...string) (*template.Template, error) { - // If this is a pjax request, use the minimal template to send only - // the main content - if r.Header.Get("X-PJAX") == "true" { - templates = append(templates, "base_minimal") - } else { - templates = append(templates, "base_full") - } - - var tpl *template.Template - - // For each template, add it to the the tpl variable - for i, t := range templates { - // Get the template from the assets - page, err := assets.Asset("templates/" + t + ".tmpl") - - // Check if there is some error. If so, the template doesn't exist - if err != nil { - log.Print(err) - return new(template.Template), err - } - - // If it's the first iteration, creates a new template and add the - // functions map - if i == 0 { - tpl, err = template.New(t).Funcs(functions).Parse(string(page)) - } else { - tpl, err = tpl.Parse(string(page)) - } - - if err != nil { - log.Print(err) - return new(template.Template), err - } - } - - return tpl, nil -} diff --git a/_stuff/tools/templates/templates_test.go b/_stuff/tools/templates/templates_test.go deleted file mode 100644 index 54d3ef05..00000000 --- a/_stuff/tools/templates/templates_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package templates - -import "testing" - -type canBeEdited struct { - file string - result bool -} - -var canBeEditedPairs = []canBeEdited{ - {"file.markdown", true}, - {"file.md", true}, - {"file.json", true}, - {"file.toml", true}, - {"file.yaml", true}, - {"file.css", true}, - {"file.sass", true}, - {"file.scss", true}, - {"file.js", true}, - {"file.html", true}, - {"file.git", false}, - {"file.log", false}, - {"file.sh", false}, - {"file.png", false}, - {"file.jpg", false}, -} - -func TestCanBeEdited(t *testing.T) { - for _, pair := range canBeEditedPairs { - v := CanBeEdited(pair.file) - if v != pair.result { - t.Error( - "For", pair.file, - "expected", pair.result, - "got", v, - ) - } - } -} diff --git a/_stuff/tools/variables/strings.go b/_stuff/tools/variables/strings.go deleted file mode 100644 index cd29ee59..00000000 --- a/_stuff/tools/variables/strings.go +++ /dev/null @@ -1,10 +0,0 @@ -package variables - -func StringInSlice(a string, list []string) (bool, int) { - for i, b := range list { - if b == a { - return true, i - } - } - return false, 0 -} diff --git a/_stuff/tools/variables/transform.go b/_stuff/tools/variables/transform.go deleted file mode 100644 index 3307b7a3..00000000 --- a/_stuff/tools/variables/transform.go +++ /dev/null @@ -1,42 +0,0 @@ -package variables - -import ( - "strings" - "unicode" -) - -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 -} diff --git a/_stuff/tools/variables/transform_test.go b/_stuff/tools/variables/transform_test.go deleted file mode 100644 index 1a0c2fbf..00000000 --- a/_stuff/tools/variables/transform_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package variables - -import "testing" - -type testSplitCapitalize struct { - name string - result string -} - -var testSplitCapitalizeCases = []testSplitCapitalize{ - {"loremIpsum", "Lorem ipsum"}, - {"LoremIpsum", "Lorem ipsum"}, - {"loremipsum", "Loremipsum"}, - {"YouTube", "YouTube"}, - {"GitHub", "GitHub"}, - {"GooglePlus", "Google Plus"}, - {"Facebook", "Facebook"}, -} - -func TestSplitCapitalize(t *testing.T) { - for _, pair := range testSplitCapitalizeCases { - v := SplitCapitalize(pair.name) - if v != pair.result { - t.Error( - "For", pair.name, - "expected", pair.result, - "got", v, - ) - } - } -} diff --git a/_stuff/tools/variables/types.go b/_stuff/tools/variables/types.go deleted file mode 100644 index ee43dad3..00000000 --- a/_stuff/tools/variables/types.go +++ /dev/null @@ -1,13 +0,0 @@ -package variables - -import "reflect" - -// 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 -} diff --git a/_stuff/tools/variables/variables.go b/_stuff/tools/variables/variables.go deleted file mode 100644 index 9d60dabf..00000000 --- a/_stuff/tools/variables/variables.go +++ /dev/null @@ -1,37 +0,0 @@ -package variables - -import ( - "errors" - "log" - "reflect" -) - -// 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 -} diff --git a/_stuff/tools/variables/variables_test.go b/_stuff/tools/variables/variables_test.go deleted file mode 100644 index ec76d459..00000000 --- a/_stuff/tools/variables/variables_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package variables - -import "testing" - -type testDefinedData struct { - f1 string - f2 bool - f3 int - f4 func() -} - -type testDefined struct { - data interface{} - field string - result bool -} - -var testDefinedCases = []testDefined{ - {testDefinedData{}, "f1", true}, - {testDefinedData{}, "f2", true}, - {testDefinedData{}, "f3", true}, - {testDefinedData{}, "f4", true}, - {testDefinedData{}, "f5", false}, - {[]string{}, "", false}, - {map[string]int{"oi": 4}, "", false}, - {"asa", "", false}, - {"int", "", false}, -} - -func TestDefined(t *testing.T) { - for _, pair := range testDefinedCases { - v := Defined(pair.data, pair.field) - if v != pair.result { - t.Error( - "For", pair.data, - "expected", pair.result, - "got", v, - ) - } - } -} diff --git a/_stuff/utilities.go b/_stuff/utilities.go deleted file mode 100644 index 5bd088d0..00000000 --- a/_stuff/utilities.go +++ /dev/null @@ -1,24 +0,0 @@ -package hugo - -import ( - "encoding/json" - "net/http" -) - -// RespondJSON used to send JSON responses to the web server -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/assets/templates/editor.tmpl b/assets/templates/editor.tmpl new file mode 100644 index 00000000..8916a5d4 --- /dev/null +++ b/assets/templates/editor.tmpl @@ -0,0 +1,58 @@ +{{ define "content" }} +
+ {{ if eq .Class "complete" }} +

+ {{ end }} +
+
+ {{ if not (eq .Class "complete") }} +

{{ .Name }}

+ {{ end }} + + {{ if eq .Class "frontmatter-only" }} +
+ {{ template "frontmatter" .FrontMatter }} +

+ +

+
+ {{ else if eq .Class "content-only" }} +
+
+ +
+ {{ else }} +
+
+ {{ template "frontmatter" .FrontMatter }} +
+ +

+ +

+
+ +
+ {{ if eq .Mode "markdown" }} + + {{ end}} +
+ +
+
+ {{ end }} + +

+ + + {{ if and (eq .Class "complete") ( .IsPost ) }} {{ end }} + + +

+
+
+
+{{ end }} diff --git a/assets/templates/frontmatter.tmpl b/assets/templates/frontmatter.tmpl new file mode 100644 index 00000000..f00f6af5 --- /dev/null +++ b/assets/templates/frontmatter.tmpl @@ -0,0 +1,44 @@ +{{ define "frontmatter" }} +{{ range $key, $value := . }} + + {{ if or (eq $value.Type "object") (eq $value.Type "array") }} +
+

{{ SplitCapitalize $value.Title }}

+ + + + + {{ template "frontmatter" $value.Content }} +
+ {{ else }} + + {{ if not (eq $value.Parent.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 new file mode 100644 index 00000000..b616926e --- /dev/null +++ b/binary.go @@ -0,0 +1,260 @@ +// Code generated by go-bindata. +// sources: +// assets/templates/editor.tmpl +// assets/templates/frontmatter.tmpl +// DO NOT EDIT! + +package hugo + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _templatesEditorTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x56\x4d\x6f\xdc\x38\x0c\xbd\x07\xc8\x7f\xe0\xea\x94\x3d\x8c\x8d\xbd\x7b\xbc\x58\xec\x6e\x8b\x1e\xd2\x0e\x30\x01\x7a\xd6\x58\x9c\x58\x88\x6d\xb9\x12\x3d\xd3\x41\x90\xff\x5e\xca\xf2\x97\x32\xcd\x07\x82\xa0\xf5\xc9\x96\xc8\xc7\x47\xf2\x51\xf2\xfd\x3d\x28\xdc\xeb\x06\x41\x14\xa6\x21\x6c\x48\xc0\xc3\xc3\xe5\x45\xa6\xf4\x01\x8a\x4a\x3a\xb7\x16\xa8\x34\x19\x0b\x7e\x5f\xb2\xa5\x05\x76\x4a\xfe\xf5\x7b\x6c\x2a\xf2\xcb\x0b\xf0\x2b\x7a\x0f\xf8\x6d\x5c\x67\xb0\xba\xad\x90\x30\xa0\x01\x64\xe5\x5f\x79\x46\xf8\x9d\xa4\x45\x09\x5a\xad\x85\xd3\x84\x2b\xd2\x54\xa1\xc8\x3d\xe0\x67\x59\x23\x1b\x67\xe9\x68\x95\x67\x29\x3b\x0d\xe8\xd8\xa8\x11\x69\x6f\x6c\x0d\x35\x52\x69\x18\x65\xf3\x65\x7b\x23\x40\x16\xa4\x4d\xb3\x16\x81\x0c\xdb\xd4\x4c\x74\x78\x1f\xc9\x35\x86\xe0\xea\x67\x0c\xff\x1c\x80\xc3\xc3\x44\x9f\xa7\x37\x70\x1a\x80\x47\x5e\x71\xac\x45\x98\xbd\xe5\xb2\xd5\x92\x08\xed\xca\x34\xd5\x49\x2c\xa2\x2d\x8b\xbc\xb0\x83\x5d\x65\x8a\x3b\x27\xf2\x99\x15\xc3\x12\x32\x5f\x49\x18\x41\x0a\x48\x3e\xf8\xaf\xeb\xe0\x18\x25\xd2\x8e\xd0\xa1\x3a\x11\x1e\x6f\xef\x3a\x22\xd3\x4c\x36\x4a\x89\xfc\x1f\xa5\x60\xaf\xb1\x52\x59\x1a\x76\x17\x1e\x59\xda\x4e\x5f\x59\xca\xc4\xa3\x2a\x54\x0e\xcf\x04\xd0\xab\xe9\xd9\x9c\x47\xc5\x2d\xc3\xf8\x6d\x5f\xff\x20\xba\x95\x33\x9d\x2d\x58\x45\x4a\x92\x5c\xd5\x46\xe1\x5a\xf8\x6e\x5c\xf3\x5b\x2f\xbe\x98\x0a\xfb\x4f\x1a\x6b\xb8\x61\x8b\x10\xbd\x66\xc3\x47\xac\xb2\xe7\x93\x7a\xb1\x59\x67\xe4\x07\x93\xf7\xe9\xe1\xc0\xe9\x97\x76\xf5\x95\x9d\x9a\x95\xde\x37\x43\xd4\xd2\xde\x29\x73\x6c\x44\x9c\x41\x23\x0f\x31\xc3\x61\xfa\x11\xa7\xde\x2e\x12\x3a\xf0\xb4\x65\x7a\x2a\xb3\x84\xbd\x5c\x15\x0c\xef\x1b\xad\x73\xd8\xf6\x1e\x59\x2a\x9f\x82\x6c\x2d\x1e\x34\x1e\xcf\x41\xf0\x34\x62\x6c\x82\x49\x0c\x92\xa5\x31\xcf\x30\xd9\x51\x22\xbf\x4d\x98\xe7\xb1\xe7\x2c\xa3\x20\xe7\x0a\x7e\x74\x38\xcd\xe2\x21\x63\xaa\x9d\x8c\xc5\xab\x9b\xb6\x23\xa0\x53\xcb\xec\x5c\xb7\xab\x35\x0d\xd9\x85\xa5\xe8\xd0\x0f\x1b\x16\x6f\x91\xef\x03\x16\xb4\x2f\x33\x8f\xcb\xb0\xee\x8a\x12\x55\x57\xcd\xab\x43\x95\xd0\x39\x79\x1b\xa0\x5e\x3e\x24\x6f\x4a\x0c\xb2\x75\x70\x44\x8b\xe0\xc9\xb1\xb2\xa9\x44\x6d\xe1\x28\x4f\xc9\xeb\xce\x9d\xff\x0f\x68\x4f\xb0\x3b\xf1\xd0\x1d\xa5\x03\x27\x0f\xa8\x92\x79\xba\x37\xc6\x51\x58\x84\xa3\xa6\x12\x5a\xbe\x15\x40\x72\xdd\x0a\x6d\x8b\xae\x76\x24\x9b\x02\x93\xa9\x96\x02\x0e\xb2\xea\x38\x85\xad\xf4\x52\x5d\x54\xcf\xb5\x72\x1a\x3b\xab\x6f\x4b\x8a\x07\x33\xa4\xec\x81\x9f\xb8\x83\xae\x20\xf9\xe4\x7a\x36\xfe\x3e\x7a\x43\x33\xe6\xa2\x93\xed\xf0\x85\x0e\x4d\xad\x08\xf9\x0f\xae\x2a\xe1\x56\x8d\x09\x0e\x6b\x22\x8f\xaf\xdf\x77\x92\xcb\x82\xe3\x99\x5a\xde\x20\x96\x6d\xdf\x41\x5f\xde\x39\x88\x7a\xa5\x42\xfe\x33\x0d\x26\xf0\xb5\x94\x04\xca\xc0\xc9\x74\x2c\x14\x9e\xc5\xda\x58\xfc\xfb\x91\x50\xda\x6e\x57\x69\xc7\x74\x13\xf8\x68\xfa\x70\xae\xe4\x59\x05\x4d\x7f\x2c\x24\x32\xa8\x80\xff\xab\x64\x57\xd1\x24\x99\x4d\x70\x8e\x54\x93\x7a\xd9\x2c\x06\x78\x3c\x8d\xb3\x74\xfa\x83\xc9\x52\xff\xc3\xc3\xaf\xe3\x78\x2f\xda\xf1\x23\x00\x00\xff\xff\x32\x91\x30\x45\xbe\x09\x00\x00") + +func templatesEditorTmplBytes() ([]byte, error) { + return bindataRead( + _templatesEditorTmpl, + "templates/editor.tmpl", + ) +} + +func templatesEditorTmpl() (*asset, error) { + bytes, err := templatesEditorTmplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/editor.tmpl", size: 2494, mode: os.FileMode(438), modTime: time.Unix(1466520293, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _templatesFrontmatterTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x54\xdd\x6e\xd3\x4c\x10\xbd\xaf\xd4\x77\x18\xed\x57\x7d\x02\x09\xc7\x69\x5a\x7e\x14\x1c\xdf\x54\x42\x5c\x00\x42\x22\x2f\xb0\xb1\xc7\xb0\x74\xb3\x6b\xd6\x93\x8a\x50\xf5\xdd\x19\xaf\xbd\xa9\xb1\x9d\xca\xad\x10\x77\x59\x9f\xd9\xd9\x73\xce\xcc\xc9\xed\x2d\xe4\x58\x28\x83\x20\x0a\x67\x0d\x6d\x25\x11\x3a\x01\x77\x77\xa7\x27\x8c\x39\x69\xbe\x22\x9c\x5d\xe3\xfe\x05\x9c\xdd\x48\xbd\x43\x58\xae\x60\xe6\xe1\xd3\x13\x00\x2e\x51\x05\x58\x07\xcf\xf0\x47\x5b\x30\x5b\xef\x4b\xee\x66\x37\xdf\x31\x23\xf1\x7c\x88\x48\xe7\xe4\x9e\x81\xba\x07\x40\x52\x28\xd4\x79\x85\x04\x2a\x5f\x09\xee\xd7\xd6\x7e\x92\x5b\xe4\x12\x01\xb9\x24\x19\x11\xdf\xec\xa2\xbe\x13\xa3\x69\xdd\x82\x9b\x7c\xbb\x48\x19\xfc\x52\x6a\x45\x57\xb2\x54\x24\xb5\xfa\x85\x87\x62\x45\xba\xae\x4e\x62\x2e\x6b\x2f\x54\xa5\x34\x90\x69\x59\x55\x2b\x21\x33\x52\xd6\x54\xa1\x19\xa3\x9b\x1d\x91\xbd\xc7\xf3\x5c\xa4\xff\xff\x77\x79\xf1\x36\x89\x1b\xe4\x58\x65\x8e\x1a\x09\xeb\xe2\x37\xaf\x17\x8b\x7e\x79\x12\xd7\xaf\xb6\x07\xa6\x4b\xb8\x2d\xb5\xa4\xbe\xf5\x2d\xeb\x2b\xfe\x84\x86\x82\x4d\x71\xf0\x29\x6d\x7d\x47\x5d\x61\x6f\x0e\xc6\x52\xd7\xee\xcf\xd2\x71\x83\x71\xd7\x73\x75\x13\x48\x6f\xb4\xcd\xae\x85\xb7\xdf\xff\x8c\x8e\x0d\x21\x6b\x18\x8d\x4d\x29\x28\xd4\x72\x83\x1a\x0a\xeb\x46\x8b\xa6\x8c\xc8\x77\x78\xca\x94\x26\x7a\x1f\xdc\x33\x79\xcf\xbc\x07\x7d\xeb\xda\x36\xba\xa7\xde\x34\x8e\x49\x7f\x65\xfd\xf5\x48\xf1\xa8\x45\x3a\xe1\xe9\xf7\xeb\x8f\x1f\x9a\x77\x09\x7f\x12\xf3\x90\x87\xa7\xc3\x87\xa0\xb7\xca\x9c\xd5\x5a\x80\x61\x02\x23\x84\x96\xc3\xb0\x3c\x98\xb0\xd2\x8b\x1e\x04\xad\xeb\x45\x3b\xc2\xc1\x7e\x26\x71\xe0\xf6\xc7\x6e\x1e\x11\xc6\xaf\x21\xa9\x2d\x1e\x84\x29\x53\xee\xe8\x2f\xc8\xf0\xc7\x2e\xd2\x32\x9c\xbd\xb3\x8e\xb3\x05\x62\x31\x9f\xbf\x8a\xe6\xe7\xd1\x7c\xb1\x3e\x7f\xb9\x9c\x5f\x0a\x7f\xad\x51\x1c\x58\x45\x9c\x00\xa9\x1f\xe7\x49\x12\x7b\x09\x83\x60\xfe\x03\x6d\x1d\x05\xf7\xd8\xc1\xeb\xc7\x0e\xb7\x2f\x64\xb0\xa8\xd3\xfe\x60\x92\x98\x63\x92\x3e\x3d\x64\xa3\xa9\x9f\x98\xf6\x36\xe7\x0d\x85\x81\x8e\xce\x61\xfc\xe7\xef\x00\x00\x00\xff\xff\x30\xc2\x3e\x0c\x0f\x07\x00\x00") + +func templatesFrontmatterTmplBytes() ([]byte, error) { + return bindataRead( + _templatesFrontmatterTmpl, + "templates/frontmatter.tmpl", + ) +} + +func templatesFrontmatterTmpl() (*asset, error) { + bytes, err := templatesFrontmatterTmplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/frontmatter.tmpl", size: 1807, mode: os.FileMode(438), modTime: time.Unix(1466520317, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// 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. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "templates/editor.tmpl": templatesEditorTmpl, + "templates/frontmatter.tmpl": templatesFrontmatterTmpl, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} +var _bintree = &bintree{nil, map[string]*bintree{ + "templates": &bintree{nil, map[string]*bintree{ + "editor.tmpl": &bintree{templatesEditorTmpl, map[string]*bintree{}}, + "frontmatter.tmpl": &bintree{templatesFrontmatterTmpl, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + diff --git a/_stuff/editor.go b/editor.go similarity index 61% rename from _stuff/editor.go rename to editor.go index 5295d209..5947ab2e 100644 --- a/_stuff/editor.go +++ b/editor.go @@ -2,17 +2,14 @@ package hugo import ( "bytes" - "errors" + "html/template" "io/ioutil" "net/http" "os" "path/filepath" "strings" - "text/template" - "github.com/hacdias/caddy-hugo/tools/frontmatter" - "github.com/hacdias/caddy-hugo/tools/templates" - "github.com/hacdias/caddy-hugo/tools/variables" + "github.com/hacdias/caddy-filemanager" "github.com/spf13/hugo/parser" ) @@ -23,17 +20,10 @@ type editor struct { Mode string Content string FrontMatter interface{} - Config *Config } // GET handles the GET method on editor page -func GET(w http.ResponseWriter, r *http.Request, c *Config, filename string) (int, error) { - // Check if the file format is supported. If not, send a "Not Acceptable" - // header and an error - if !templates.CanBeEdited(filename) { - return http.StatusNotAcceptable, errors.New("File format not supported.") - } - +func (h Hugo) GET(w http.ResponseWriter, r *http.Request, c *Config, filename string) (int, error) { // Check if the file exists. if _, err := os.Stat(filename); os.IsNotExist(err) { return http.StatusNotFound, err @@ -51,51 +41,56 @@ func GET(w http.ResponseWriter, r *http.Request, c *Config, filename string) (in return http.StatusInternalServerError, err } + page := &filemanager.Page{ + Info: &filemanager.PageInfo{ + IsDir: false, + Config: &h.FileManager.Configs[0], + Name: strings.Replace(filename, c.Root, "", 1), + }, + } + // Create a new editor variable and set the extension - page := new(editor) - page.Mode = strings.TrimPrefix(filepath.Ext(filename), ".") - page.Name = strings.Replace(filename, c.Path, "", 1) - page.Config = c - page.IsPost = false + data := new(editor) + data.Mode = strings.TrimPrefix(filepath.Ext(filename), ".") + data.Name = strings.Replace(filename, c.Root, "", 1) + data.IsPost = false + data.Mode = sanitizeMode(data.Mode) - // Sanitize the extension - page.Mode = sanitizeMode(page.Mode) - - var ppage parser.Page + var parserPage parser.Page // Handle the content depending on the file extension - switch page.Mode { + 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) - ppage, err = parser.ReadFrom(buffer) + parserPage, err = parser.ReadFrom(buffer) if err != nil { return http.StatusInternalServerError, err } - if strings.Contains(string(ppage.FrontMatter()), "date") { - page.IsPost = true + if strings.Contains(string(parserPage.FrontMatter()), "date") { + data.IsPost = true } // Parses the page content and the frontmatter - page.Content = strings.TrimSpace(string(ppage.Content())) - page.FrontMatter, page.Name, err = frontmatter.Pretty(ppage.FrontMatter()) - page.Class = "complete" + 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 - page.Class = "content-only" - page.Content = string(file) + data.Class = "content-only" + data.Content = string(file) } case "json", "toml", "yaml": // Defines the class and declares an error - page.Class = "frontmatter-only" + data.Class = "frontmatter-only" // Checks if the file already has the frontmatter rune and parses it if hasFrontMatterRune(file) { - page.FrontMatter, _, err = frontmatter.Pretty(file) + data.FrontMatter, _, err = Pretty(file) } else { - page.FrontMatter, _, err = frontmatter.Pretty(appendFrontMatterRune(file, page.Mode)) + data.FrontMatter, _, err = Pretty(appendFrontMatterRune(file, data.Mode)) } // Check if there were any errors @@ -104,24 +99,35 @@ func GET(w http.ResponseWriter, r *http.Request, c *Config, filename string) (in } default: // The editor will handle only content - page.Class = "content-only" - page.Content = string(file) + 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": variables.SplitCapitalize, - "Defined": variables.Defined, + "SplitCapitalize": SplitCapitalize, + "Defined": Defined, } - tpl, err := templates.Get(r, functions, "editor", "frontmatter") + var code int + + page.Info.Data = data + code, err = page.AddTemplate("base", filemanager.Asset, functions) if err != nil { - return http.StatusInternalServerError, err + return code, err } - return http.StatusOK, tpl.Execute(w, page) + templates := []string{"listing", "actions"} + for _, t := range templates { + code, err = page.AddTemplate(t, Asset, nil) + if err != nil { + return code, err + } + } + + return page.PrintAsHTML(w) } func hasFrontMatterRune(file []byte) bool { diff --git a/_stuff/tools/frontmatter/frontmatter.go b/frontmatter.go similarity index 96% rename from _stuff/tools/frontmatter/frontmatter.go rename to frontmatter.go index dd618457..5fb3090e 100644 --- a/_stuff/tools/frontmatter/frontmatter.go +++ b/frontmatter.go @@ -1,4 +1,4 @@ -package frontmatter +package hugo import ( "log" @@ -6,7 +6,6 @@ import ( "sort" "strings" - "github.com/hacdias/caddy-hugo/tools/variables" "github.com/spf13/cast" "github.com/spf13/hugo/parser" ) @@ -64,9 +63,9 @@ func rawToPretty(config interface{}, parent *frontmatter) interface{} { } for name, element := range cnf { - if variables.IsMap(element) { + if IsMap(element) { objects = append(objects, handleObjects(element, parent, name)) - } else if variables.IsSlice(element) { + } else if IsSlice(element) { arrays = append(arrays, handleArrays(element, parent, name)) } else { if name == "title" && parent.Name == mainName { diff --git a/hugo.go b/hugo.go index 51a7d828..c907c370 100644 --- a/hugo.go +++ b/hugo.go @@ -1,3 +1,7 @@ +//go:generate go get github.com/jteeuwen/go-bindata +//go:generate go install github.com/jteeuwen/go-bindata/go-bindata +//go:generate go-bindata -pkg hugo -prefix "assets" -o binary.go assets/... + // Package hugo makes the bridge between the static website generator Hugo // and the webserver Caddy, also providing an administrative user interface. package hugo