forked from abiosoft/caddy-hugo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhugo.go
173 lines (141 loc) · 4.63 KB
/
hugo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//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 assets -o assets/assets.go templates/ assets/css/ assets/js/ assets/fonts/
// Package hugo makes the bridge between the static website generator Hugo
// and the webserver Caddy, also providing an administrative user interface.
package hugo
import (
"log"
"mime"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/hacdias/caddy-hugo/assets"
"github.com/hacdias/caddy-hugo/browse"
"github.com/hacdias/caddy-hugo/config"
"github.com/hacdias/caddy-hugo/editor"
"github.com/hacdias/caddy-hugo/utils"
"github.com/mholt/caddy/caddy/setup"
"github.com/mholt/caddy/middleware"
"github.com/spf13/cobra"
"github.com/spf13/hugo/commands"
)
// Setup is the init function of Caddy plugins and it configures the whole
// middleware thing.
func Setup(c *setup.Controller) (middleware.Middleware, error) {
config, _ := config.ParseHugo(c)
// Checks if there is an Hugo website in the path that is provided.
// If not, a new website will be created.
create := false
if _, err := os.Stat(config.Path + "config.yaml"); os.IsNotExist(err) {
create = true
}
if _, err := os.Stat(config.Path + "config.json"); os.IsNotExist(err) {
create = true
}
if _, err := os.Stat(config.Path + "config.toml"); os.IsNotExist(err) {
create = true
}
if create {
cmd := &cobra.Command{}
cmd.Flags().Bool("force", true, "")
commands.NewSite(cmd, []string{config.Path})
}
// Generates the Hugo website for the first time the plugin is activated.
utils.Run(config)
return func(next middleware.Handler) middleware.Handler {
return &CaddyHugo{Next: next, Config: config}
}, nil
}
// CaddyHugo contais the next middleware to be run and the configuration
// of the current one.
type CaddyHugo struct {
Next middleware.Handler
Config *config.Config
}
// ServeHTTP is the main function of the whole plugin that routes every single
// request to its function.
func (h CaddyHugo) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Only handle /admin path
if middleware.Path(r.URL.Path).Matches("/admin") {
var err error
var page string
code := 404
// If the length of the components string is less than one, the variable
// page will always be "admin"
if len(utils.ParseComponents(r)) > 1 {
page = utils.ParseComponents(r)[1]
} else {
page = utils.ParseComponents(r)[0]
}
// If the page isn't "assets" neither "edit", it should always put a
// trailing slash in the path
if page != "assets" && page != "edit" {
if r.URL.Path[len(r.URL.Path)-1] != '/' {
http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect)
return 0, nil
}
}
// If the current page is only "/admin/", redirect to "/admin/browse/content/"
if r.URL.Path == "/admin/" {
http.Redirect(w, r, "/admin/browse/content/", http.StatusTemporaryRedirect)
return 0, nil
}
// If the url matches exactly with /admin/settings/ serve that page
// page variable isn't used here to avoid people using URLs like
// "/admin/settings/something".
if r.URL.Path == "/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, "/admin/edit/config."+frontmatter, http.StatusTemporaryRedirect)
return 0, nil
}
// Serve the static assets
if page == "assets" {
return serveAssets(w, r)
}
// Browse page
if page == "browse" {
code, err = browse.ServeHTTP(w, r, h.Config)
}
// Edit page
if page == "edit" {
code, err = editor.ServeHTTP(w, r, h.Config)
}
// Whenever the header "X-Regenerate" is true, the website should be
// regenerated. Used in edit and settings, for example.
if r.Header.Get("X-Regenerate") == "true" {
utils.Run(h.Config)
}
if err != nil {
log.Panic(err)
}
return code, err
}
return h.Next.ServeHTTP(w, r)
}
// serveAssets handles the /admin/assets requests
func serveAssets(w http.ResponseWriter, r *http.Request) (int, error) {
filename := strings.Replace(r.URL.Path, "/admin/", "", 1)
file, err := assets.Asset(filename)
if err != nil {
return 404, nil
}
// Get the file extension ant its mime type
extension := filepath.Ext(filename)
mime := mime.TypeByExtension(extension)
// Write the header with the Content-Type and write the file
// content to the buffer
w.Header().Set("Content-Type", mime)
w.Write(file)
return 200, nil
}