hledger/Shake.hs

299 lines
11 KiB
Haskell
Raw Normal View History

#!/usr/bin/env stack
{- stack runghc --verbosity info
--package base-prelude
--package directory
--package extra
2016-10-28 21:15:10 +03:00
--package pandoc
--package safe
--package shake
--package time
-}
{-
2016-10-28 21:15:10 +03:00
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: ./Shake.hs compile
It requires stack (https://haskell-lang.org/get-started) and
auto-installs the packages above. Also, some rules require:
2016-10-29 19:45:59 +03:00
- site/hakyll-std/hakyll-std
- runhaskell
2016-10-28 21:15:10 +03:00
- groff
- m4
- makeinfo
2016-10-29 19:45:59 +03:00
- git
- patch
2016-10-28 21:15:10 +03:00
Usage: see below.
2016-10-28 21:15:10 +03:00
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 "extra" Data.List.Extra
import "safe" Safe
import "shake" Development.Shake
import "shake" Development.Shake.FilePath
import "time" Data.Time
import "directory" System.Directory as S (getDirectoryContents)
2016-10-28 21:15:10 +03:00
usage = unlines
["Usage:"
,"./Shake.hs compile # compile this script (recommended)"
,"./Shake # show commands"
,"./Shake all # generate everything"
,"./Shake docs # generate general docs"
,"./Shake website # generate the web site"
,"./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 web man pages for hakyll"
,"./Shake webmanual # generate combined web man page for hakyll"
,"./Shake clean # clean generated files"
,"./Shake Clean # clean harder"
,"./Shake --help # show options, eg --color"
]
2016-04-19 03:54:55 +03:00
pandoc = "pandoc" -- pandoc from PATH (faster)
-- "stack exec -- pandoc" -- pandoc from project's stackage snapshot
hakyllstd = "site/hakyll-std/hakyll-std"
2016-04-19 03:54:55 +03:00
makeinfo = "makeinfo"
-- nroff = "nroff"
groff = "groff"
main = do
pandocFilters <-
2016-04-06 01:46:44 +03:00
map ("doc" </>). nub . sort . map (-<.> "") . filter ("pandoc-" `isPrefixOf`)
<$> S.getDirectoryContents "doc"
shakeArgs
shakeOptions{
2016-04-13 06:32:01 +03:00
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 --version" -- install libs via shebang line
unit $ cmd "stack ghc Shake.hs"
2016-10-28 21:15:10 +03:00
putLoud "You can now run ./Shake instead of ./Shake.hs"
phony "all" $ need ["docs", "website"]
-- docs
let
manpageNames = [ -- in suggested reading order
"hledger.1"
,"hledger-ui.1"
,"hledger-web.1"
,"hledger-api.1"
,"hledger_journal.5"
,"hledger_csv.5"
2016-04-13 07:10:02 +03:00
,"hledger_timeclock.5"
,"hledger_timedot.5"
]
-- manuals m4 source, may include other files (hledger/doc/hledger.1.m4.md)
m4manpages = [manpageDir m </> m <.> "m4.md" | m <- manpageNames]
-- manuals rendered to nroff, ready for man (hledger/doc/hledger.1)
nroffmanpages = [manpageDir m </> m | m <- manpageNames]
-- manuals rendered to text, ready for embedding (hledger/doc/hledger.1.txt)
txtmanpages = [manpageDir m </> m <.> "txt" | m <- manpageNames]
2016-10-17 18:53:38 +03:00
-- manuals rendered to info, ready for info (hledger/doc/hledger.1.info)
2016-04-19 03:54:55 +03:00
infomanpages = [manpageDir m </> m <.> "info" | m <- manpageNames]
-- manuals rendered to markdown, ready for web output by hakyll (site/hledger.md)
webmanpages = ["site" </> manpageNameToUri m <.>"md" | m <- manpageNames]
-- manuals rendered to markdown and combined, ready for web output by hakyll
webmanual = "site/manual.md"
-- hledger.1 -> hledger/doc, hledger_journal.5 -> hledger-lib/doc
manpageDir m
| '_' `elem` m = "hledger-lib" </> "doc"
| otherwise = dropExtension m </> "doc"
-- 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 "docs" $ do
need $
nroffmanpages
2016-04-19 03:54:55 +03:00
++ infomanpages
++ txtmanpages
-- compile pandoc helpers
phony "pandocfilters" $ need pandocFilters
pandocFilters |%> \out -> do
need [out <.> "hs"]
cmd ("stack ghc") out
-- 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/doc/hledger.1
let src = 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 ++ pandocFilters
cmd Shell
"m4 -P -DMAN -I" dir lib src "|"
pandoc "-f markdown -s --template" tmpl
-- "--filter doc/pandoc-drop-web-blocks"
2016-04-06 01:46:44 +03:00
"--filter doc/pandoc-drop-html-blocks"
"--filter doc/pandoc-drop-html-inlines"
"--filter doc/pandoc-drop-links"
"--filter doc/pandoc-drop-notes"
"-o" out
-- render man page nroffs to fixed-width text for embedding in executables, with nroff
phony "txtmanpages" $ need txtmanpages
txtmanpages |%> \out -> do -- hledger/doc/hledger.1.txt
let src = dropExtension out
need [src]
cmd Shell groff "-t -e -mandoc -Tascii" src "| col -bx >" out -- http://www.tldp.org/HOWTO/Man-Page/q10.html
2016-04-19 03:54:55 +03:00
-- use m4 and pandoc to process macros, filter content, and convert to info, suitable for info viewing
phony "infomanpages" $ need infomanpages
2016-10-17 18:53:38 +03:00
infomanpages |%> \out -> do -- hledger/doc/hledger.1.info
2016-04-19 03:54:55 +03:00
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 ++ pandocFilters
cmd Shell
"m4 -P -I" dir lib src "|"
pandoc "-f markdown"
-- "--filter doc/pandoc-drop-web-blocks"
"--filter doc/pandoc-drop-html-blocks"
"--filter doc/pandoc-drop-html-inlines"
"--filter doc/pandoc-drop-links"
"--filter doc/pandoc-drop-notes"
"-t texinfo |"
makeinfo "--force --no-split -o" out
-- web site
phony "website" $ do
2016-10-28 21:15:10 +03:00
need $
webmanpages ++
[webmanual
,"releasemanual"
,hakyllstd
]
cmd Shell (Cwd "site") "hakyll-std/hakyll-std" "build"
-- 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 m = manpageUriToName $ dropExtension $ takeFileName out -- hledger.1
dir = manpageDir m
src = dir </> m <.> "m4.md"
lib = "doc/lib.m4"
2016-04-09 23:36:48 +03:00
heading = let h = dropExtension m
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 ++ pandocFilters
2016-04-09 23:36:48 +03:00
liftIO $ writeFile out $ "# " ++ heading ++ "\n\n"
cmd Shell
"m4 -P -DMAN -DWEB -I" dir lib src "|"
pandoc "-f markdown -t markdown --atx-headers"
"--filter doc/pandoc-demote-headers"
-- "--filter doc/pandoc-add-toc"
-- "--filter doc/pandoc-drop-man-blocks"
2016-04-09 23:36:48 +03:00
">>" out
-- adjust and combine man page mds for single-page web output, using pandoc
phony "webmanual" $ need [ webmanual ]
2016-10-28 21:15:10 +03:00
webmanual %> \out -> do
need webmanpages
2016-04-16 15:52:20 +03:00
liftIO $ writeFile webmanual "* toc\n\n"
forM_ webmanpages $ \f -> do -- site/hledger.md, site/journal.md
2016-04-09 23:36:48 +03:00
cmd Shell ("printf '\\n\\n' >>") webmanual :: Action ExitCode
cmd Shell "pandoc" f "-t markdown --atx-headers"
2016-04-09 23:36:48 +03:00
-- "--filter doc/pandoc-drop-man-blocks"
"--filter doc/pandoc-drop-toc"
-- "--filter doc/pandoc-capitalize-headers"
"--filter doc/pandoc-demote-headers"
">>" webmanual :: Action ExitCode
-- check out and render manual pages for the current release also
phony "releasemanual" $ need [ "releasemanual0.27" ]
phony "releasemanual0.27" $ do
-- XXX under doc so hakyll-std will render it
cmd "mkdir -p site/doc/0.27" :: Action ExitCode
cmd Shell "git show 0.27:doc/manual.md >site/doc/0.27/manual.md" :: Action ExitCode
cmd Shell "patch site/doc/0.27/manual.md doc/manual0.27.diff "
-- build standard hakyll script used for site rendering
hakyllstd %> \out -> do
let dir = takeDirectory out
need [out <.> "hs", dir </> "TableOfContents.hs"] -- XXX hard-coded dep
-- install libs via shebang line
-- XXX 2016/10/29 why has this started giving
-- "./hakyll-std.hs: createProcess: runInteractiveProcess: exec: does not exist (No such file or directory))"
unit $ liftIO $
cmd (Cwd dir) "./hakyll-std.hs --version"
`catch` (\(e::IOException) -> putStr $ unlines $
["I could not run ./hakyll-std.hs in "++dir++" to install Hakyll."
,"If you see a hakyll-std build error after this, please do it manually:"
,"$ (cd site/hakyll-std; ./hakyll-std.hs --version)"
,"and try again."
])
-- compile
cmd (Cwd dir) "stack ghc hakyll-std"
2016-04-06 01:40:59 +03:00
-- cleanup
phony "clean" $ do
putNormal "Cleaning generated files"
removeFilesAfter "." webmanpages
removeFilesAfter "." [webmanual]
phony "Clean" $ do
need ["clean"]
putNormal "Cleaning all hakyll generated files"
removeFilesAfter "site" ["_*"]
putNormal "Cleaning executables"
removeFilesAfter "." $ hakyllstd : pandocFilters
2016-10-29 19:45:59 +03:00
putNormal "Cleaning object files" -- also forces rebuild of executables
removeFilesAfter "doc" ["*.o","*.p_o","*.hi"]
removeFilesAfter "site" ["*.o","*.p_o","*.hi"]
putNormal "Cleaning shake build files"
2016-04-13 06:32:01 +03:00
removeFilesAfter ".shake" ["//*"]