Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
851026d3
Commit
851026d3
authored
Aug 04, 2015
by
Abiola Ibrahim
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Markdown: Watch for file changes. Removed sitegen dependency for links.
parent
32da2ed7
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
205 additions
and
26 deletions
+205
-26
config/setup/markdown.go
config/setup/markdown.go
+25
-6
middleware/markdown/markdown.go
middleware/markdown/markdown.go
+17
-8
middleware/markdown/markdown_test.go
middleware/markdown/markdown_test.go
+27
-10
middleware/markdown/page.go
middleware/markdown/page.go
+37
-0
middleware/markdown/testdata/og/first.md
middleware/markdown/testdata/og/first.md
+4
-0
middleware/markdown/testdata/og_static/og/first.md/index.html
...leware/markdown/testdata/og_static/og/first.md/index.html
+3
-2
middleware/markdown/watcher.go
middleware/markdown/watcher.go
+58
-0
middleware/markdown/watcher_test.go
middleware/markdown/watcher_test.go
+34
-0
No files found.
config/setup/markdown.go
View file @
851026d3
...
@@ -29,14 +29,23 @@ func Markdown(c *Controller) (middleware.Middleware, error) {
...
@@ -29,14 +29,23 @@ func Markdown(c *Controller) (middleware.Middleware, error) {
// For any configs that enabled static site gen, sweep the whole path at startup
// For any configs that enabled static site gen, sweep the whole path at startup
c
.
Startup
=
append
(
c
.
Startup
,
func
()
error
{
c
.
Startup
=
append
(
c
.
Startup
,
func
()
error
{
for
_
,
cfg
:=
range
mdconfigs
{
for
i
:=
range
mdconfigs
{
if
cfg
.
StaticDir
==
""
{
cfg
:=
&
mdconfigs
[
i
]
continue
}
if
err
:=
markdown
.
GenerateLinks
(
md
,
&
cfg
);
err
!=
nil
{
// Links generation.
if
err
:=
markdown
.
GenerateLinks
(
md
,
cfg
);
err
!=
nil
{
return
err
return
err
}
}
// Watch file changes for links generation.
if
cfg
.
Development
{
markdown
.
Watch
(
md
,
cfg
,
0
)
}
else
{
markdown
.
Watch
(
md
,
cfg
,
markdown
.
DefaultInterval
)
}
if
cfg
.
StaticDir
==
""
{
continue
}
// If generated site already exists, clear it out
// If generated site already exists, clear it out
_
,
err
:=
os
.
Stat
(
cfg
.
StaticDir
)
_
,
err
:=
os
.
Stat
(
cfg
.
StaticDir
)
...
@@ -68,7 +77,7 @@ func Markdown(c *Controller) (middleware.Middleware, error) {
...
@@ -68,7 +77,7 @@ func Markdown(c *Controller) (middleware.Middleware, error) {
// Generate the static file
// Generate the static file
ctx
:=
middleware
.
Context
{
Root
:
md
.
FileSys
}
ctx
:=
middleware
.
Context
{
Root
:
md
.
FileSys
}
_
,
err
=
md
.
Process
(
cfg
,
reqPath
,
body
,
ctx
)
_
,
err
=
md
.
Process
(
*
cfg
,
reqPath
,
body
,
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -155,6 +164,16 @@ func markdownParse(c *Controller) ([]markdown.Config, error) {
...
@@ -155,6 +164,16 @@ func markdownParse(c *Controller) ([]markdown.Config, error) {
// only 1 argument allowed
// only 1 argument allowed
return
mdconfigs
,
c
.
ArgErr
()
return
mdconfigs
,
c
.
ArgErr
()
}
}
case
"development"
:
if
c
.
NextArg
()
{
md
.
Development
=
strings
.
ToLower
(
c
.
Val
())
==
"true"
}
else
{
md
.
Development
=
true
}
if
c
.
NextArg
()
{
// only 1 argument allowed
return
mdconfigs
,
c
.
ArgErr
()
}
default
:
default
:
return
mdconfigs
,
c
.
Err
(
"Expected valid markdown configuration property"
)
return
mdconfigs
,
c
.
Err
(
"Expected valid markdown configuration property"
)
}
}
...
...
middleware/markdown/markdown.go
View file @
851026d3
...
@@ -4,7 +4,6 @@ package markdown
...
@@ -4,7 +4,6 @@ package markdown
import
(
import
(
"io/ioutil"
"io/ioutil"
"log"
"net/http"
"net/http"
"os"
"os"
"strings"
"strings"
...
@@ -69,12 +68,29 @@ type Config struct {
...
@@ -69,12 +68,29 @@ type Config struct {
// Links to all markdown pages ordered by date.
// Links to all markdown pages ordered by date.
Links
[]
PageLink
Links
[]
PageLink
// Stores a directory hash to check for changes.
linksHash
string
// Directory to store static files
// Directory to store static files
StaticDir
string
StaticDir
string
// If in development mode. i.e. Actively editing markdown files.
Development
bool
sync
.
RWMutex
sync
.
RWMutex
}
}
// IsValidExt checks to see if an extension is a valid markdown extension
// for config.
func
(
c
Config
)
IsValidExt
(
ext
string
)
bool
{
for
_
,
e
:=
range
c
.
Extensions
{
if
e
==
ext
{
return
true
}
}
return
false
}
// ServeHTTP implements the http.Handler interface.
// ServeHTTP implements the http.Handler interface.
func
(
md
Markdown
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
func
(
md
Markdown
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
for
i
:=
range
md
.
Configs
{
for
i
:=
range
md
.
Configs
{
...
@@ -122,13 +138,6 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
...
@@ -122,13 +138,6 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
}
}
}
}
if
m
.
StaticDir
!=
""
{
// Markdown modified or new. Update links.
if
err
:=
GenerateLinks
(
md
,
m
);
err
!=
nil
{
log
.
Println
(
err
)
}
}
body
,
err
:=
ioutil
.
ReadAll
(
f
)
body
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
return
http
.
StatusInternalServerError
,
err
...
...
middleware/markdown/markdown_test.go
View file @
851026d3
package
markdown
package
markdown
import
(
import
(
"bufio"
"log"
"log"
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
...
@@ -102,7 +103,7 @@ func getTrue() bool {
...
@@ -102,7 +103,7 @@ func getTrue() bool {
</body>
</body>
</html>
</html>
`
`
if
respBody
!=
expectedBody
{
if
!
equalStrings
(
respBody
,
expectedBody
)
{
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
}
}
...
@@ -143,10 +144,7 @@ func getTrue() bool {
...
@@ -143,10 +144,7 @@ func getTrue() bool {
</body>
</body>
</html>`
</html>`
replacer
:=
strings
.
NewReplacer
(
"
\r
"
,
""
,
"
\n
"
,
""
)
if
!
equalStrings
(
respBody
,
expectedBody
)
{
respBody
=
replacer
.
Replace
(
respBody
)
expectedBody
=
replacer
.
Replace
(
expectedBody
)
if
respBody
!=
expectedBody
{
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
}
}
...
@@ -177,19 +175,24 @@ func getTrue() bool {
...
@@ -177,19 +175,24 @@ func getTrue() bool {
</body>
</body>
</html>`
</html>`
respBody
=
replacer
.
Replace
(
respBody
)
expectedBody
=
replacer
.
Replace
(
expectedBody
)
if
!
equalStrings
(
respBody
,
expectedBody
)
{
if
respBody
!=
expectedBody
{
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
}
}
expectedLinks
:=
[]
string
{
expectedLinks
:=
[]
string
{
"/blog/test.md"
,
"/blog/test.md"
,
"/log/test.md"
,
"/log/test.md"
,
"/og/first.md"
,
}
}
for
i
,
c
:=
range
md
.
Configs
{
for
i
:=
range
md
.
Configs
{
c
:=
&
md
.
Configs
[
i
]
if
err
:=
GenerateLinks
(
md
,
c
);
err
!=
nil
{
t
.
Fatalf
(
"Error: %v"
,
err
)
}
}
for
i
,
c
:=
range
md
.
Configs
[
:
2
]
{
log
.
Printf
(
"Test number: %d, configuration links: %v, config: %v"
,
i
,
c
.
Links
,
c
)
log
.
Printf
(
"Test number: %d, configuration links: %v, config: %v"
,
i
,
c
.
Links
,
c
)
if
c
.
Links
[
0
]
.
URL
!=
expectedLinks
[
i
]
{
if
c
.
Links
[
0
]
.
URL
!=
expectedLinks
[
i
]
{
t
.
Fatalf
(
"Expected %v got %v"
,
expectedLinks
[
i
],
c
.
Links
[
0
]
.
URL
)
t
.
Fatalf
(
"Expected %v got %v"
,
expectedLinks
[
i
],
c
.
Links
[
0
]
.
URL
)
...
@@ -219,3 +222,17 @@ func getTrue() bool {
...
@@ -219,3 +222,17 @@ func getTrue() bool {
}
}
}
}
func
equalStrings
(
s1
,
s2
string
)
bool
{
s1
=
strings
.
TrimSpace
(
s1
)
s2
=
strings
.
TrimSpace
(
s2
)
in
:=
bufio
.
NewScanner
(
strings
.
NewReader
(
s1
))
for
in
.
Scan
()
{
txt
:=
strings
.
TrimSpace
(
in
.
Text
())
if
!
strings
.
HasPrefix
(
strings
.
TrimSpace
(
s2
),
txt
)
{
return
false
}
s2
=
strings
.
Replace
(
s2
,
txt
,
""
,
1
)
}
return
true
}
middleware/markdown/page.go
View file @
851026d3
...
@@ -2,7 +2,11 @@ package markdown
...
@@ -2,7 +2,11 @@ package markdown
import
(
import
(
"bytes"
"bytes"
"crypto/sha1"
"encoding/hex"
"fmt"
"io/ioutil"
"io/ioutil"
"log"
"os"
"os"
"path/filepath"
"path/filepath"
"sort"
"sort"
...
@@ -79,6 +83,15 @@ func (l *linkGen) generateLinks(md Markdown, cfg *Config) {
...
@@ -79,6 +83,15 @@ func (l *linkGen) generateLinks(md Markdown, cfg *Config) {
return
return
}
}
hash
,
err
:=
computeDirHash
(
md
,
*
cfg
)
// same hash, return.
if
err
==
nil
&&
hash
==
cfg
.
linksHash
{
return
}
else
if
err
!=
nil
{
log
.
Println
(
"Error:"
,
err
)
}
cfg
.
Links
=
[]
PageLink
{}
cfg
.
Links
=
[]
PageLink
{}
cfg
.
Lock
()
cfg
.
Lock
()
...
@@ -138,6 +151,8 @@ func (l *linkGen) generateLinks(md Markdown, cfg *Config) {
...
@@ -138,6 +151,8 @@ func (l *linkGen) generateLinks(md Markdown, cfg *Config) {
// sort by newest date
// sort by newest date
sort
.
Sort
(
byDate
(
cfg
.
Links
))
sort
.
Sort
(
byDate
(
cfg
.
Links
))
cfg
.
linksHash
=
hash
cfg
.
Unlock
()
cfg
.
Unlock
()
l
.
Lock
()
l
.
Lock
()
...
@@ -176,3 +191,25 @@ func GenerateLinks(md Markdown, cfg *Config) error {
...
@@ -176,3 +191,25 @@ func GenerateLinks(md Markdown, cfg *Config) error {
g
.
discardWaiters
()
g
.
discardWaiters
()
return
g
.
lastErr
return
g
.
lastErr
}
}
// computeDirHash computes an hash on static directory of c.
func
computeDirHash
(
md
Markdown
,
c
Config
)
(
string
,
error
)
{
dir
:=
filepath
.
Join
(
md
.
Root
,
c
.
PathScope
)
if
_
,
err
:=
os
.
Stat
(
dir
);
err
!=
nil
{
return
""
,
err
}
hashString
:=
""
err
:=
filepath
.
Walk
(
dir
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
if
!
info
.
IsDir
()
&&
c
.
IsValidExt
(
filepath
.
Ext
(
path
))
{
hashString
+=
fmt
.
Sprintf
(
"%v%v%v%v"
,
info
.
ModTime
(),
info
.
Name
(),
info
.
Size
(),
path
)
}
return
nil
})
if
err
!=
nil
{
return
""
,
err
}
sum
:=
sha1
.
Sum
([]
byte
(
hashString
))
return
hex
.
EncodeToString
(
sum
[
:
]),
nil
}
middleware/markdown/testdata/og/first.md
View file @
851026d3
---
title
:
first_post
sitename
:
title
---
# Test h1
# Test h1
middleware/markdown/testdata/og_static/og/first.md/index.html
View file @
851026d3
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
<title>
first_post
</title>
<title>
first_post
</title>
</head>
</head>
<body>
<body>
<h1>
Header title
</h1>
<h1>
Header title
</h1>
...
...
middleware/markdown/watcher.go
0 → 100644
View file @
851026d3
package
markdown
import
"time"
const
(
DefaultInterval
=
time
.
Second
*
60
DevInterval
=
time
.
Second
*
1
)
// Watch monitors the configured markdown directory for changes. It calls GenerateLinks
// when there are changes.
func
Watch
(
md
Markdown
,
c
*
Config
,
interval
time
.
Duration
)
(
stopChan
chan
struct
{})
{
return
TickerFunc
(
interval
,
func
()
{
GenerateLinks
(
md
,
c
)
})
}
// TickerFunc runs f at interval. If interval is <= 0, it loops f. A message to the
// returned channel will stop the executing goroutine.
func
TickerFunc
(
interval
time
.
Duration
,
f
func
())
chan
struct
{}
{
stopChan
:=
make
(
chan
struct
{})
if
interval
>
0
{
ticker
:=
time
.
NewTicker
(
interval
)
go
func
()
{
loop
:
for
{
select
{
case
<-
ticker
.
C
:
f
()
case
<-
stopChan
:
ticker
.
Stop
()
break
loop
}
}
}()
}
else
{
go
func
()
{
loop
:
for
{
m
:=
make
(
chan
struct
{})
go
func
()
{
f
()
m
<-
struct
{}{}
}()
select
{
case
<-
m
:
continue
loop
case
<-
stopChan
:
break
loop
}
time
.
Sleep
(
DevInterval
)
}
}()
}
return
stopChan
}
middleware/markdown/watcher_test.go
0 → 100644
View file @
851026d3
package
markdown
import
(
"fmt"
"strings"
"testing"
"time"
)
func
TestWatcher
(
t
*
testing
.
T
)
{
expected
:=
"12345678"
interval
:=
time
.
Millisecond
*
100
i
:=
0
out
:=
""
stopChan
:=
TickerFunc
(
interval
,
func
()
{
i
++
out
+=
fmt
.
Sprint
(
i
)
})
time
.
Sleep
(
interval
*
8
)
stopChan
<-
struct
{}{}
if
expected
!=
out
{
t
.
Fatalf
(
"Expected %v, found %v"
,
expected
,
out
)
}
out
=
""
i
=
0
stopChan
=
TickerFunc
(
interval
,
func
()
{
i
++
out
+=
fmt
.
Sprint
(
i
)
})
time
.
Sleep
(
interval
*
10
)
if
!
strings
.
HasPrefix
(
out
,
expected
)
||
out
==
expected
{
t
.
Fatalf
(
"expected (%v) must be a proper prefix of out(%v)."
,
expected
,
out
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment