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
7b29568e
Commit
7b29568e
authored
Jul 29, 2015
by
Abiola Ibrahim
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code cleanups.
Fix more race conditions.
parent
e240cd5b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
135 additions
and
40 deletions
+135
-40
middleware/markdown/markdown.go
middleware/markdown/markdown.go
+10
-8
middleware/markdown/markdown_test.go
middleware/markdown/markdown_test.go
+47
-12
middleware/markdown/page.go
middleware/markdown/page.go
+76
-18
middleware/markdown/process.go
middleware/markdown/process.go
+2
-2
No files found.
middleware/markdown/markdown.go
View file @
7b29568e
...
...
@@ -4,13 +4,14 @@ package markdown
import
(
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"sync"
"github.com/mholt/caddy/middleware"
"github.com/russross/blackfriday"
// "log"
)
// Markdown implements a layer of middleware that serves
...
...
@@ -70,11 +71,14 @@ type Config struct {
// Directory to store static files
StaticDir
string
sync
.
RWMutex
}
// ServeHTTP implements the http.Handler interface.
func
(
md
Markdown
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
for
_
,
m
:=
range
md
.
Configs
{
for
i
:=
range
md
.
Configs
{
m
:=
&
md
.
Configs
[
i
]
if
!
middleware
.
Path
(
r
.
URL
.
Path
)
.
Matches
(
m
.
PathScope
)
{
continue
}
...
...
@@ -120,11 +124,9 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
if
m
.
StaticDir
!=
""
{
// Markdown modified or new. Update links.
// go func() {
// if err := GenerateLinks(md, &md.Configs[i]); err != nil {
// log.Println(err)
// }
// }()
if
err
:=
GenerateLinks
(
md
,
m
);
err
!=
nil
{
log
.
Println
(
err
)
}
}
body
,
err
:=
ioutil
.
ReadAll
(
f
)
...
...
@@ -137,7 +139,7 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
Req
:
r
,
URL
:
r
.
URL
,
}
html
,
err
:=
md
.
Process
(
m
,
fpath
,
body
,
ctx
)
html
,
err
:=
md
.
Process
(
*
m
,
fpath
,
body
,
ctx
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
...
...
middleware/markdown/markdown_test.go
View file @
7b29568e
...
...
@@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
"github.com/mholt/caddy/middleware"
...
...
@@ -18,20 +19,24 @@ func TestMarkdown(t *testing.T) {
FileSys
:
http
.
Dir
(
"./testdata"
),
Configs
:
[]
Config
{
Config
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/blog"
,
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{},
Scripts
:
[]
string
{},
Templates
:
templates
,
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/blog"
,
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{},
Scripts
:
[]
string
{},
Templates
:
templates
,
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
Config
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/log"
,
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{
"/resources/css/log.css"
,
"/resources/css/default.css"
},
Scripts
:
[]
string
{
"/resources/js/log.js"
,
"/resources/js/default.js"
},
Templates
:
make
(
map
[
string
]
string
),
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/log"
,
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{
"/resources/css/log.css"
,
"/resources/css/default.css"
},
Scripts
:
[]
string
{
"/resources/js/log.js"
,
"/resources/js/default.js"
},
Templates
:
make
(
map
[
string
]
string
),
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
},
IndexFiles
:
[]
string
{
"index.html"
},
...
...
@@ -123,4 +128,34 @@ func getTrue() bool {
if
respBody
!=
expectedBody
{
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
}
expectedLinks
:=
[]
string
{
"/blog/test.md"
,
"/log/test.md"
,
}
for
i
,
c
:=
range
md
.
Configs
{
if
c
.
Links
[
0
]
.
Url
!=
expectedLinks
[
i
]
{
t
.
Fatalf
(
"Expected %v got %v"
,
expectedLinks
[
i
],
c
.
Links
[
0
]
.
Url
)
}
}
// attempt to trigger race condition
var
w
sync
.
WaitGroup
f
:=
func
()
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
"/log/test.md"
,
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"Could not create HTTP request: %v"
,
err
)
}
rec
:=
httptest
.
NewRecorder
()
md
.
ServeHTTP
(
rec
,
req
)
w
.
Done
()
}
for
i
:=
0
;
i
<
5
;
i
++
{
w
.
Add
(
1
)
go
f
()
}
w
.
Wait
()
}
middleware/markdown/page.go
View file @
7b29568e
...
...
@@ -12,17 +12,15 @@ import (
"github.com/russross/blackfriday"
)
var
(
pagesMutex
sync
.
RWMutex
linksGenerating
bool
)
const
(
// Date format YYYY-MM-DD HH:MM:SS
timeLayout
=
`2006-01-02 15:04:05`
// Length of page summary.
summaryLen
=
150
)
// Page represents a statically generated markdown page.
// Page
Link
represents a statically generated markdown page.
type
PageLink
struct
{
Title
string
Summary
string
...
...
@@ -30,25 +28,51 @@ type PageLink struct {
Url
string
}
// pageLinkSorter sort PageLink by newest date to oldest.
// pageLinkSorter sort
s
PageLink by newest date to oldest.
type
pageLinkSorter
[]
PageLink
func
(
p
pageLinkSorter
)
Len
()
int
{
return
len
(
p
)
}
func
(
p
pageLinkSorter
)
Swap
(
i
,
j
int
)
{
p
[
i
],
p
[
j
]
=
p
[
j
],
p
[
i
]
}
func
(
p
pageLinkSorter
)
Less
(
i
,
j
int
)
bool
{
return
p
[
i
]
.
Date
.
After
(
p
[
j
]
.
Date
)
}
func
GenerateLinks
(
md
Markdown
,
cfg
*
Config
)
error
{
if
linksGenerating
{
return
nil
type
linkGen
struct
{
generating
bool
waiters
int
lastErr
error
sync
.
RWMutex
sync
.
WaitGroup
}
func
(
l
*
linkGen
)
addWaiter
()
{
l
.
WaitGroup
.
Add
(
1
)
l
.
waiters
++
}
func
(
l
*
linkGen
)
discardWaiters
()
{
l
.
Lock
()
defer
l
.
Unlock
()
for
i
:=
0
;
i
<
l
.
waiters
;
i
++
{
l
.
Done
()
}
}
func
(
l
*
linkGen
)
started
()
bool
{
l
.
RLock
()
defer
l
.
RUnlock
()
return
l
.
generating
}
pagesMutex
.
Lock
()
linksGenerating
=
true
func
(
l
*
linkGen
)
generateLinks
(
md
Markdown
,
cfg
*
Config
)
{
l
.
Lock
()
l
.
generating
=
true
l
.
Unlock
()
fp
:=
filepath
.
Join
(
md
.
Root
,
cfg
.
PathScope
)
cfg
.
Links
=
[]
PageLink
{}
err
:=
filepath
.
Walk
(
fp
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
cfg
.
Lock
()
l
.
lastErr
=
filepath
.
Walk
(
fp
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
for
_
,
ext
:=
range
cfg
.
Extensions
{
if
!
info
.
IsDir
()
&&
strings
.
HasSuffix
(
info
.
Name
(),
ext
)
{
// Load the file
...
...
@@ -92,12 +116,46 @@ func GenerateLinks(md Markdown, cfg *Config) error {
}
}
// sort by newest date
sort
.
Sort
(
pageLinkSorter
(
cfg
.
Links
))
return
nil
})
linksGenerating
=
false
pagesMutex
.
Unlock
()
return
err
// sort by newest date
sort
.
Sort
(
pageLinkSorter
(
cfg
.
Links
))
cfg
.
Unlock
()
l
.
Lock
()
l
.
generating
=
false
l
.
Unlock
()
}
type
linkGenerator
struct
{
gens
map
[
*
Config
]
*
linkGen
sync
.
Mutex
}
var
generator
=
linkGenerator
{
gens
:
make
(
map
[
*
Config
]
*
linkGen
)}
// GenerateLinks generates links to all markdown files ordered by newest date.
// This blocks until link generation is done. When called by multiple goroutines,
// the first caller starts the generation and others only wait.
func
GenerateLinks
(
md
Markdown
,
cfg
*
Config
)
error
{
generator
.
Lock
()
// if link generator exists for config and running, wait.
if
g
,
ok
:=
generator
.
gens
[
cfg
];
ok
{
if
g
.
started
()
{
g
.
addWaiter
()
generator
.
Unlock
()
g
.
Wait
()
return
g
.
lastErr
}
}
g
:=
&
linkGen
{}
generator
.
gens
[
cfg
]
=
g
generator
.
Unlock
()
g
.
generateLinks
(
md
,
cfg
)
g
.
discardWaiters
()
return
g
.
lastErr
}
middleware/markdown/process.go
View file @
7b29568e
...
...
@@ -101,9 +101,9 @@ func (md Markdown) processTemplate(c Config, requestPath string, tmpl []byte, me
Links
:
c
.
Links
,
}
pagesMutex
.
RLock
()
c
.
RLock
()
err
=
t
.
Execute
(
b
,
mdData
)
pagesMutex
.
RUnlock
()
c
.
RUnlock
()
if
err
!=
nil
{
return
nil
,
err
...
...
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