forked from simonmichael/hledger
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Shake.hs
executable file
·331 lines (277 loc) · 12.6 KB
/
Shake.hs
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#!/usr/bin/env stack
{- stack exec
--verbosity=info
--package base-prelude
--package directory
--package extra
--package safe
--package shake
--package time
ghc
-}
{-
One of two project scripts files (Makefile, Shake.hs).
This one provides a stronger programming language and more
platform independence than Make. It will build needed packages (above)
on first run and whenever the resolver in stack.yaml changes.
To minimise such startup delays, and reduce sensitivity to git checkout,
compiling is recommended; run the script in interpreted mode to do that.
It requires stack (https://haskell-lang.org/get-started) and
auto-installs the packages above. Also, some rules require:
- runhaskell
- groff
- m4
- makeinfo
- git
- patch
Usage: see below. Also:
$ find hledger-lib hledger | entr ./Shake website # rebuild web files on changes in these dirs
Shake wishes:
just one shake import
wildcards in phony rules
multiple individually accessible wildcards
not having to write :: Action ExitCode after a non-final cmd
-}
{-# LANGUAGE PackageImports, ScopedTypeVariables #-}
import Prelude ()
import "base-prelude" BasePrelude
import "directory" System.Directory as S (getDirectoryContents)
import "extra" Data.List.Extra
import "safe" Safe
import "shake" Development.Shake
import "shake" Development.Shake.FilePath
import "time" Data.Time
usage = unlines
["Usage:"
,"./Shake.hs # compile this script"
,"./Shake # show commands"
,"./Shake manuals # generate the txt/man/info manuals"
,"./Shake website # generate the html manuals and website"
-- ,"./Shake manpages # generate nroff files for man"
-- ,"./Shake txtmanpages # generate text man pages for embedding"
-- ,"./Shake infomanpages # generate info files for info"
-- ,"./Shake webmanpages # generate individual web man pages as markdown"
-- ,"./Shake webmanall # generate all-in-one web manual as markdown"
,"./Shake site/doc/VER/.snapshot # generate and save a versioned web site snapshot"
,"./Shake all # generate everything"
,"./Shake clean # clean generated files"
,"./Shake Clean # clean harder"
,"./Shake --help # show options, eg --color"
]
pandoc = "pandoc" -- assume pandoc from system or user install
makeinfo = "makeinfo"
-- nroff = "nroff"
groff = "groff"
dropDirectory2 = dropDirectory1 . dropDirectory1
main = do
shakeArgs
shakeOptions{
shakeVerbosity=Loud
-- ,shakeReport=[".shake.html"]
} $ do
want ["help"]
phony "help" $ liftIO $ putStrLn usage
-- phony "compile" $ need ["Shake"]
--
-- "Shake" %> \out -> do
-- need [out <.> "hs"]
-- unit $ cmd "./Shake.hs" -- running as stack script installs deps and compiles
-- putLoud "You can now run ./Shake instead of ./Shake.hs"
phony "all" $ need ["manuals", "website"]
-- manuals
let
manpageNames = [ -- in suggested reading order
"hledger.1"
,"hledger-ui.1"
,"hledger-web.1"
,"hledger-api.1"
,"hledger_journal.5"
,"hledger_csv.5"
,"hledger_timeclock.5"
,"hledger_timedot.5"
]
manualNames = map manpageNameToManualName manpageNames
-- hledger.1 -> hledger, hledger_journal.5 -> hledger_journal
manpageNameToManualName = dropNumericSuffix
where
dropNumericSuffix s = reverse $
case reverse s of
c : '.' : cs | isDigit c -> cs
cs -> cs
-- hledger -> hledger.1, hledger_journal -> hledger_journal.5
manualNameToManpageName s
| '_' `elem` s = s <.> "5"
| otherwise = s <.> "1"
-- manuals m4 source; may include other source files (hledger/hledger.m4.md)
m4manpages = [manualDir m </> m <.> "m4.md" | m <- manualNames]
-- manuals rendered to nroff, ready for man (hledger/hledger.1)
nroffmanpages = [manpageDir m </> m | m <- manpageNames]
-- manuals rendered to text, ready for embedding (hledger/hledger.txt)
txtmanpages = [manualDir m </> m <.> "txt" | m <- manualNames]
-- manuals rendered to info, ready for info (hledger/hledger.info)
infomanpages = [manualDir m </> m <.> "info" | m <- manualNames]
-- manuals rendered to markdown, ready for web output by pandoc (site/hledger.md)
webmanpages = ["site" </> manpageNameToUri m <.> "md" | m <- manpageNames]
-- versions of documentation (excluding 0.27)
docversions = [ "1.0" , "1.1" , "1.2" , "1.3" , "1.4" , "1.5" , "1.9", "1.10" ]
-- manuals rendered to html by pandoc
webhtmlpages
= map (normalise . ("site/_site" </>))
$ ( [ prefix </> manpageNameToUri mPage <.> "html"
| prefix <- "" : [ "doc" </> v | v <- docversions ]
, mPage <- manpageNames
]
++ [ mPage <.> "html"
| mPage <- [ "contributors" , "download" , "ledgertips" , "index" , "intro" , "release-notes" ]
]
++ [ prefix </> "manual" <.> "html"
| prefix <- "" : "doc/0.27" : [ "doc" </> v | v <- docversions ]
]
)
-- manuals rendered to markdown and combined, ready for web rendering
webmanall = "site/manual.md"
-- file extensions which should just be copied directly over to the website
webcopyfileexts = ["png", "gif", "cur", "js", "css", "eot", "ttf", "woff", "svg"]
-- hledger.1 -> hledger/doc, hledger_journal.5 -> hledger-lib/doc
manpageDir m
| '_' `elem` m = "hledger-lib"
| otherwise = dropExtension m
-- hledger -> hledger, hledger_journal -> hledger-lib
manualDir m
| '_' `elem` m = "hledger-lib"
| otherwise = m
-- hledger.1 -> hledger, hledger_journal.5 -> journal
manpageNameToUri m | "hledger_" `isPrefixOf` m = dropExtension $ drop 8 m
| otherwise = dropExtension m
-- hledger -> hledger.1, journal -> hledger_journal.5
manpageUriToName u | "hledger" `isPrefixOf` u = u <.> "1"
| otherwise = "hledger_" ++ u <.> "5"
phony "manuals" $ do
need $
nroffmanpages
++ infomanpages
++ txtmanpages
-- man pages
-- use m4 and pandoc to process macros, filter content, and convert to nroff suitable for man output
phony "manpages" $ need nroffmanpages
nroffmanpages |%> \out -> do -- hledger/hledger.1
let src = manpageNameToManualName out <.> "m4.md"
lib = "doc/lib.m4"
dir = takeDirectory out
tmpl = "doc/manpage.nroff"
-- assume all other m4 files in dir are included by this one XXX not true in hledger-lib
deps <- liftIO $ filter (/= src) . filter (".m4.md" `isSuffixOf`) . map (dir </>) <$> S.getDirectoryContents dir
need $ src : lib : tmpl : deps
cmd Shell
"m4 -P -DMAN -I" dir lib src "|"
pandoc "-f markdown -s --template" tmpl
"--lua-filter tools/pandoc-drop-html-blocks.lua"
"--lua-filter tools/pandoc-drop-html-inlines.lua"
"--lua-filter tools/pandoc-drop-links.lua"
"-o" out
-- render man page nroffs to fixed-width text for embedding in executables, with nroff
phony "txtmanpages" $ need txtmanpages
txtmanpages |%> \out -> do -- hledger/hledger.txt
let src = manualNameToManpageName $ dropExtension out
need [src]
cmd Shell groff "-t -e -mandoc -Tascii" src "| col -bx >" out -- http://www.tldp.org/HOWTO/Man-Page/q10.html
-- use m4 and pandoc to process macros, filter content, and convert to info, suitable for info viewing
phony "infomanpages" $ need infomanpages
infomanpages |%> \out -> do -- hledger/hledger.info
let src = out -<.> "m4.md"
lib = "doc/lib.m4"
dir = takeDirectory out
-- assume all other m4 files in dir are included by this one XXX not true in hledger-lib
deps <- liftIO $ filter (/= src) . filter (".m4.md" `isSuffixOf`) . map (dir </>) <$> S.getDirectoryContents dir
need $ src : lib : deps
cmd Shell
"m4 -P -I" dir lib src "|"
pandoc "-f markdown"
"--lua-filter tools/pandoc-drop-html-blocks.lua"
"--lua-filter tools/pandoc-drop-html-inlines.lua"
"--lua-filter tools/pandoc-drop-links.lua"
"-t texinfo |"
makeinfo "--force --no-split -o" out
-- web site
phony "website" $ do
need $ [ "website-copy" , "website-render" ]
-- use m4 and pandoc to process macros and filter content, leaving markdown suitable for web output
phony "webmanpages" $ need webmanpages
webmanpages |%> \out -> do -- site/hledger.md
let manpage = manpageUriToName $ dropExtension $ takeFileName out -- hledger
manual = manpageNameToManualName manpage
dir = manpageDir manpage
src = dir </> manual <.> "m4.md"
lib = "doc/lib.m4"
heading = let h = manual
in if "hledger_" `isPrefixOf` h
then drop 8 h ++ " format"
else h
-- assume all other m4 files in dir are included by this one XXX not true in hledger-lib
deps <- liftIO $ filter (/= src) . filter (".m4.md" `isSuffixOf`) . map (dir </>) <$> S.getDirectoryContents dir
need $ src : lib : deps
liftIO $ writeFile out $ "# " ++ heading ++ "\n\n"
cmd Shell
"m4 -P -DMAN -DWEB -I" dir lib src "|"
pandoc "-f markdown -t markdown-fenced_divs --atx-headers"
"--lua-filter tools/pandoc-demote-headers.lua"
">>" out
-- adjust and combine man page mds for single-page web output, using pandoc
phony "webmanall" $ need [ webmanall ]
webmanall %> \out -> do
need webmanpages
liftIO $ writeFile webmanall "\\$toc\\$" -- # Big Manual\n\n -- TOC style is better without main heading,
forM_ webmanpages $ \f -> do -- site/hledger.md, site/journal.md
cmd Shell ("printf '\\n\\n' >>") webmanall :: Action ExitCode
cmd Shell pandoc f "-t markdown-fenced_divs --atx-headers"
"--lua-filter tools/pandoc-drop-toc.lua"
"--lua-filter tools/pandoc-demote-headers.lua"
">>" webmanall :: Action ExitCode
-- adjust and combine recipe mds for single-page web output, using pandoc
-- build the currently checked out web docs and save as a named snapshot
"site/doc/*/.snapshot" %> \out -> do
need [ webmanall ]
let snapshot = takeDirectory out
cmd Shell "mkdir -p" snapshot :: Action ExitCode
forM_ webmanpages $ \f -> do -- site/hledger.md, site/journal.md
cmd Shell "cp" f (snapshot </> takeFileName f) :: Action ExitCode
cmd Shell "cp" "site/manual.md" snapshot :: Action ExitCode
cmd Shell "cp -r site/images" snapshot :: Action ExitCode
cmd Shell "touch" out -- :: Action ExitCode
phony "website-copy" $ do
orig_files <- getDirectoryFiles "site" (map ("//*" <.>) webcopyfileexts)
need [ "site/_site" </> file
| file <- "files/README" : orig_files
, not ("_site//*" ?== file)
]
phony "website-render" $ do
need webhtmlpages
"site/_site/files/README" : [ "site/_site//*" <.> ext | ext <- webcopyfileexts ] |%> \out -> do
let input = "site" </> dropDirectory2 out
copyFile' input out
"site/_site//*.html" %> \out -> do
let source = "site" </> dropDirectory2 out -<.> "md"
pageTitle = takeBaseName out
template = "site/site.tmpl"
siteRoot = if "site/_site/doc//*" ?== out then "../.." else "."
need [source, template]
cmd Shell pandoc "--from markdown --to html" source
"--template" template
("--metadata=siteRoot:" ++ siteRoot)
("--metadata=title:" ++ pageTitle)
"--lua-filter" "tools/pandoc-site.lua"
"--output" out
-- cleanup
phony "clean" $ do
putNormal "Cleaning generated files"
removeFilesAfter "." webmanpages
removeFilesAfter "." [webmanall]
phony "Clean" $ do
need ["clean"]
putNormal "Cleaning all site generated files"
removeFilesAfter "site" ["_*"]
putNormal "Cleaning object files" -- also forces rebuild of executables
removeFilesAfter "tools" ["*.o","*.p_o","*.hi"]
removeFilesAfter "site" ["*.o","*.p_o","*.hi"]
putNormal "Cleaning shake build files"
removeFilesAfter ".shake" ["//*"]