Commit 33c932e2 authored by Henrik Tramberend's avatar Henrik Tramberend
Browse files

Working on resource resolution

parent 95c2ea54
{
"version": "0.2.0",
"configurations": [
{
"type": "ghc",
"name": "ghci debug viewer Phoityne",
"request": "launch",
"internalConsoleOptions": "openOnSessionStart",
"workspace": "${workspaceRoot}",
"startup": "${workspaceRoot}/test/Spec.hs",
"logFile": "${workspaceRoot}/.vscode/phoityne.log",
"logLevel": "WARNING",
"ghciPrompt": "H>>= ",
"ghciCmd": "stack ghci --test --no-load --no-build --main-is TARGET",
"ghciEnv": {},
"stopOnEntry": true,
"hackageVersion": "0.0.14.0",
"mainArgs": ""
}
]
}
\ No newline at end of file
2017-06-16 14:34:18 [ThreadId 11] ERROR phoityne - [deleteBreakPointOnGHCi] invalid delete break point. BreakPointData {nameBreakPointData = "Spec", srcPosBreakPointData = SourcePosition {filePathSourcePosition = "/Users/henrik/workspace/decker/test/Spec.hs", startLineNoSourcePosition = 97, startColNoSourcePosition = -1, endLineNoSourcePosition = -1, endColNoSourcePosition = -1}, breakNoBreakPointData = Nothing, conditionBreakPointData = Nothing, hitConditionBreakPointData = Nothing, hitCountBreakPointData = 0}
2017-06-16 14:34:49 [ThreadId 16] ERROR phoityne - load file fail.[/Users/henrik/workspace/decker/test/Spec.hs] file load error. '/Users/henrik/workspace/decker/test/Spec.hs'
2017-06-16 14:36:15 [ThreadId 11] ERROR phoityne - "error: Ambiguous occurrence \8216doesFileExist\8217 It could refer to either \8216Development.Shake.doesFileExist\8217, imported from \8216Development.Shake\8217 at /Users/henrik/workspace/decker/src/Context.hs:10:1-24 (and originally defined in \8216shake-0.15.11:Development.Shake.Rules.Directory\8217) or \8216System.Directory.doesFileExist\8217, imported from \8216System.Directory\8217 at /Users/henrik/workspace/decker/src/Filter.hs:23:1-23"
2017-06-16 14:38:28 [ThreadId 11] ERROR phoityne - "\"extractSourcePosition\" (line 26, column 6):\nunexpected end of input\nexpecting \"Stopped at \" or \"Stopped in \" [INPUT] Resolves a file path to a concrete verified file system path. FAILED [2]\ncacheRemoteFile\n Stores the data behind a URL locally, if possible. Return the local path to the cached file.\ncacheRemoteImages\n Replaces all remote images in the pandoc document with locally caches copies.\nparseStudentData\n Parses student data in YAML format into a nifty data structure.\n\nFailures:\n\n /Users/henrik/workspace/decker/test/Spec.hs:107: \n 1) copyResource Copies an existing resource to the public dir and returns the public URL.\n expected: True\n but got: False\n\n /Users/henrik/workspace/decker/test/Spec.hs:112: \n 2) provisionResource Resolves a file path to a concrete verified file system path.\n expected: True\n but got: False\n\nRandomized with seed 1732182263\n\nFinished in 107.8106 seconds\n10 examples, 2 failures\n*** Exception: ExitFailure 1\nH>>= "
2017-06-16 14:39:38 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: aexists"
2017-06-16 14:39:44 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: aexists"
2017-06-16 14:39:58 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: aexists"
2017-06-16 14:40:20 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: b"
2017-06-16 14:40:23 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: a"
2017-06-16 14:40:32 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: a"
2017-06-16 14:40:32 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: b"
2017-06-16 14:41:01 [ThreadId 11] ERROR phoityne - "error: Ambiguous occurrence \8216doesFileExist\8217 It could refer to either \8216Development.Shake.doesFileExist\8217, imported from \8216Development.Shake\8217 at /Users/henrik/workspace/decker/src/Context.hs:10:1-24 (and originally defined in \8216shake-0.15.11:Development.Shake.Rules.Directory\8217) or \8216System.Directory.doesFileExist\8217, imported from \8216System.Directory\8217 at /Users/henrik/workspace/decker/src/Filter.hs:23:1-23"
2017-06-16 15:24:07 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: a"
2017-06-16 15:24:07 [ThreadId 11] ERROR phoityne - "error: Variable not in scope: b"
2017-06-16 15:26:22 [ThreadId 11] ERROR phoityne - "error: parse error on input \8216then\8217"
2017-06-16 15:26:23 [ThreadId 11] ERROR phoityne - "error: \8226 Variable not in scope: bt \8226 Perhaps you meant one of these: \8216Ghci6.b\8217 (imported from Ghci6), \8216Ghci7.b\8217 (imported from Ghci7), \8216b\8217 (<no location info>)"
......@@ -18,15 +18,16 @@ import qualified Text.Mustache as M ()
import Text.Pandoc ()
import Text.Printf ()
import Utilities
import Project
version = "0.1.0"
main :: IO ()
main = do
projectDir <- calcProjectDirectory
let publicDir = projectDir </> "public"
let cacheDir = projectDir </> "cache"
let supportDir = publicDir </> "support"
dirs <- projectDirectories
let projectDir = (project dirs)
let publicDir = (public dirs)
let supportDir = (support dirs)
-- Find sources. These are formulated as actions in the Action mondad, such
-- that each new iteration rescans all possible source files.
let deckSourcesA = globA "**/*-deck.md"
......@@ -42,16 +43,16 @@ main = do
let handoutsPdfA = deckSourcesA >>= calcTargets "-deck.md" "-handout.pdf"
let pagesA = pageSourcesA >>= calcTargets ".md" ".html"
let pagesPdfA = pageSourcesA >>= calcTargets ".md" ".pdf"
let indexSource = projectDir </> "index.md"
let indexSource = (project dirs) </> "index.md"
let index = publicDir </> "index.html"
let indexA = return [index] :: Action [FilePath]
let everythingA = decksA <++> handoutsA <++> pagesA
let everythingPdfA = decksPdfA <++> handoutsPdfA <++> pagesPdfA
let cruft =
map
(combine projectDir)
(combine (project dirs))
["index.md.generated", "server.log", "//.shake"]
context <- makeActionContext projectDir publicDir cacheDir supportDir
context <- makeActionContext dirs
runShakeInContext context options $
--
do
......@@ -185,22 +186,20 @@ replaceSuffix srcSuffix targetSuffix filename =
-- | Calculates the target pathes from a list of source files.
calcTargets :: String -> String -> [FilePath] -> Action [FilePath]
calcTargets srcSuffix targetSuffix sources = do
projectDir <- getProjectDir
publicDir <- getPublicDir
dirs <- getProjectDirs
return $
map
(replaceSuffix srcSuffix targetSuffix .
combine publicDir . makeRelative projectDir)
combine (public dirs) . makeRelative (project dirs))
sources
-- | Calculate the source file from the target path. Calls need.
calcSource :: String -> String -> FilePath -> Action FilePath
calcSource targetSuffix srcSuffix target = do
projectDir <- getProjectDir
publicDir <- getPublicDir
dirs <- getProjectDirs
let src =
(replaceSuffix targetSuffix srcSuffix .
combine projectDir . makeRelative publicDir)
combine (project dirs) . makeRelative (public dirs))
target
need [src]
return src
......@@ -36,13 +36,15 @@ import Text.Pandoc
import Text.Pandoc.PDF
import Text.Pandoc.Walk
import Utilities
import Project
replaceSuffix srcSuffix targetSuffix filename =
dropSuffix srcSuffix filename ++ targetSuffix
main :: IO ()
main = do
projectDir <- calcProjectDirectory
dirs <- projectDirectories
let projectDir = (project dirs)
let privateDir = projectDir </> "private"
-- Find questions
questionSources <- glob "**/*-quest.yaml"
......@@ -65,7 +67,7 @@ main = do
-- Prepare Mustache templates
let templates = compileTesterTemplates
---
context <- makeActionContext projectDir privateDir "" ""
context <- makeActionContext (ProjectDirs projectDir privateDir "" "")
runShakeInContext context shakeOptions $ do
want ["catalog"]
--
......@@ -205,8 +207,8 @@ compileTemplates disposition = do
compileProjectTemplate :: FilePath -> FilePath -> Action MT.Template
compileProjectTemplate disposition name = do
projectDir <- getProjectDir
let filename = projectDir </> "exams" </> "templates" </> disposition </> name
dirs <- getProjectDirs
let filename = (project dirs) </> "exams" </> "templates" </> disposition </> name
need [filename]
text <- liftIO $ T.readFile filename
let result = M.compileTemplate name (fixMustacheMarkupText text)
......
......@@ -15,7 +15,7 @@ cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules: Watch, Test, Embed, Context, Utilities, Filter, Student, Shuffle, Project
exposed-modules: Watch, Test, Embed, Context, Utilities, Filter, Student, Shuffle, Project, Common
build-depends: base
, aeson
, random
......@@ -53,6 +53,7 @@ library
, vector
, scientific
, transformers
, unix
default-language: Haskell2010
executable decker
......@@ -191,6 +192,7 @@ test-suite slides-test
, text
, neat-interpolation
, bytestring
, directory
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
......
module Common
( DeckerException(..)
) where
import Control.Exception
import Data.Typeable
-- | Tool specific exceptions
data DeckerException
= MustacheException String
| ResourceException String
| GitException String
| PandocException String
| YamlException String
| HttpException String
| RsyncUrlException
| DecktapeException String
deriving (Typeable)
instance Exception DeckerException
instance Show DeckerException where
show (MustacheException e) = e
show (ResourceException e) = e
show (GitException e) = e
show (HttpException e) = e
show (PandocException e) = e
show (YamlException e) = e
show (DecktapeException e) = "decktape.sh failed for reason: " ++ e
show RsyncUrlException =
"attributes 'destinationRsyncHost' or 'destinationRsyncPath' not defined in meta data"
......@@ -2,8 +2,8 @@
module Context
(ActionContext(..), makeActionContext, setActionContext, getFilesToWatch,
setFilesToWatch, getServerHandle, setServerHandle, getProjectDir,
getPublicDir, getCacheDir, getSupportDir, actionContextKey, getActionContext)
setFilesToWatch, getServerHandle, setServerHandle, getProjectDirs,
actionContextKey, getActionContext)
where
import Control.Monad ()
......@@ -15,43 +15,33 @@ import Data.Typeable ()
import qualified Data.HashMap.Lazy as HashMap
import System.Process
import Text.Printf
import Project
data ActionContext =
ActionContext {ctxFilesToWatch :: IORef [FilePath]
,ctxServerHandle :: IORef (Maybe ProcessHandle)
,ctxProjectDir :: FilePath
,ctxPublicDir :: FilePath
,ctxCacheDir :: FilePath
,ctxSupportDir :: FilePath}
deriving (Typeable)
,ctxDirs :: ProjectDirs}
deriving (Typeable, Show)
instance Show ActionContext where
show ctx =
printf "ActionContext {ctxProjectDir = '%s', ctxPublicDir = '%s', ctxCacheDir = '%s', ctxSupportDir = '%s'}"
(ctxProjectDir ctx)
(ctxPublicDir ctx)
(ctxCacheDir ctx)
(ctxSupportDir ctx)
instance Show (IORef a) where
show _ = "IORef"
defaultActionContext :: IO ActionContext
defaultActionContext = do
files <- newIORef []
server <- newIORef Nothing
return $ ActionContext files server "" "" "" ""
return $ ActionContext files server (ProjectDirs "" "" "" "")
actionContextKey :: IO TypeRep
actionContextKey = do
ctx <- liftIO $ defaultActionContext
return $ typeOf ctx
makeActionContext :: FilePath -> FilePath -> FilePath -> FilePath-> IO ActionContext
makeActionContext projectDir publicDir cacheDir supportDir =
makeActionContext :: ProjectDirs -> IO ActionContext
makeActionContext dirs =
do ctx <- defaultActionContext
return $
ctx {ctxProjectDir = projectDir
,ctxPublicDir = publicDir
,ctxCacheDir = cacheDir
,ctxSupportDir = supportDir}
ctx { ctxDirs = dirs }
setActionContext :: ActionContext -> ShakeOptions -> IO ShakeOptions
setActionContext ctx options =
......@@ -91,22 +81,8 @@ setServerHandle handle = do
ctx <- getActionContext
liftIO $ writeIORef (ctxServerHandle ctx) handle
getProjectDir :: Action FilePath
getProjectDir =
getProjectDirs :: Action ProjectDirs
getProjectDirs =
do ctx <- getActionContext
return $ ctxProjectDir ctx
return $ ctxDirs ctx
getPublicDir :: Action FilePath
getPublicDir =
do ctx <- getActionContext
return $ ctxPublicDir ctx
getCacheDir :: Action FilePath
getCacheDir =
do ctx <- getActionContext
return $ ctxCacheDir ctx
getSupportDir :: Action FilePath
getSupportDir =
do ctx <- getActionContext
return $ ctxSupportDir ctx
module Project
( provisionResource
, copyResource
, linkResource
, refResource
, removeCommonPrefix
, isPrefix
, makeRelativeTo
, findProjectDirectory
, projectDirectories
, resolve
, Resource(..)
, Provisioning(..)
, ProjectDirs(..)
) where
import Common
import Control.Monad
import Control.Exception
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Data.Maybe
import Debug.Trace
import Extra
import Network.URI
import System.Directory
import System.FilePath
import System.Posix.Files
data Provisioning
= Copy -- Copy to public and relative link
| SymbolicLink -- Link to public and relative link
| Reference -- Absolute local link
deriving (Eq, Show)
data ResolvedUrl = ResolvedUrl
data Resource = Resource
{ sourceFile :: FilePath -- Absolute Path to source file
, publicFile :: FilePath -- Absolute path to file in public folder
, publicUrl :: FilePath -- Relative URL to served file from base
}
} deriving (Eq, Show)
copyResource :: Resource -> IO (FilePath)
copyResource resource
-- copyFileIfNewer (sourceFile resource) (publicFile resource)
= do
createDirectoryIfMissing True (takeDirectory (publicFile resource))
copyFile (sourceFile resource) (publicFile resource)
return (publicUrl resource)
linkResource :: Resource -> IO (FilePath)
linkResource resource = do
whenM (doesFileExist (publicFile resource)) (removeFile (publicFile resource))
createSymbolicLink (sourceFile resource) (publicFile resource)
return (publicUrl resource)
refResource :: Resource -> IO (FilePath)
refResource resource = do
return $ show $ URI "file" Nothing (sourceFile resource) "" ""
data ProjectDirs = ProjectDirs
{ project :: FilePath
, public :: FilePath
, cache :: FilePath
, support :: FilePath
} deriving (Eq, Show)
-- Find the project directory.
-- The project directory is the first upwards directory that contains a .git directory entry.
calcProjectDirectory :: IO FilePath
calcProjectDirectory = do
findProjectDirectory :: IO FilePath
findProjectDirectory = do
cwd <- getCurrentDirectory
searchGitRoot cwd
where
......@@ -40,25 +81,38 @@ calcProjectDirectory = do
then makeAbsolute path
else searchGitRoot $ takeDirectory path
-- Calculate important absolute project directory pathes
projectDirectories :: IO ProjectDirs
projectDirectories = do
projectDir <- findProjectDirectory
let publicDir = projectDir </> "public"
let cacheDir = publicDir </> "cache"
let supportDir = publicDir </> "support"
return (ProjectDirs projectDir publicDir cacheDir supportDir)
-- Resolves a file path to a concrete verified file system path, or
-- returns Nothing if no file can be found.
resolve :: FilePath -> FilePath -> FilePath -> IO (Maybe FilePath)
resolve project base path = do
let pathes =
resolve :: ProjectDirs -> FilePath -> FilePath -> IO (Maybe Resource)
resolve dirs base path = do
let candidates =
if isAbsolute path
then [project </> makeRelative "/" path, path]
else [base </> path, project </> path]
listToMaybe <$> filterM doesFileExist pathes
then [(project dirs) </> makeRelative "/" path, path]
else [base </> path, (project dirs) </> path]
(listToMaybe . map resolveResource) <$> filterM doesFileExist candidates
where
resolveResource absolute =
let relative = makeRelativeTo (project dirs) absolute
in Resource
{ sourceFile = absolute
, publicFile = (public dirs) </> makeRelativeTo (project dirs) absolute
, publicUrl = makeRelativeTo base absolute
}
resolveUrl :: FilePath -> FilePath -> FilePath -> IO (Maybe ResolvedUrl)
resolveUrl project base url = do
resolveUrl :: ProjectDirs -> FilePath -> FilePath -> IO (Maybe Resource)
resolveUrl dirs base url = do
case parseURI url >>= fileOrRelativeUrl of
Nothing -> return Nothing
Just path -> do
file <- resolve project base path
case file of
Nothing -> return Nothing
Just file -> return $ Just $ ResolvedUrl file "" ""
Just path -> resolve dirs base path
fileOrRelativeUrl :: URI -> Maybe FilePath
fileOrRelativeUrl (URI "file:" Nothing path _ _) = Just path
......@@ -67,31 +121,29 @@ fileOrRelativeUrl _ = Nothing
-- | Determines if a URL can be resolved to a local file. Absolute file URLs
-- are resolved against and copied or linked from
-- - the project root
-- - the local filesystem root
-- 1. the project root
-- 2. the local filesystem root
-- Relative file URLs are resolved against and copied or linked from
-- - the directory path of the referencing file
-- - the project root
-- 1. the directory path of the referencing file
-- 2. the project root
-- Copy and link operations target the public directory in the project root
-- and recreate the source directory structure.
provisionResource ::
Provisioning -> FilePath -> FilePath -> FilePath -> IO FilePath
provisionResource provisioning project base path = do
let pathes =
if isAbsolute path
then [project </> makeRelative "/" path, path]
else [base </> path, project </> path]
resource <- listToMaybe <$> filterM doesFileExist pathes
case resource of
Nothing -> return path
Just resolved -> do
Provisioning -> ProjectDirs -> FilePath -> FilePath -> IO FilePath
provisionResource provisioning dirs base path = do
resolved <- resolve dirs base path
case resolved of
Nothing -> throw $ ResourceException $ "Cannot find local resource: " ++ path
Just resource -> do
case provisioning of
Copy -> return resolved
SymbolicLink -> return resolved
Reference -> return resolved
Copy -> copyResource resource
SymbolicLink -> linkResource resource
Reference -> refResource resource
copyFileChanged :: FilePath -> FilePath -> IO ()
copyFileChanged src dst = do
-- | Copies the src to dst if src is newer or dst does not exist.
-- Creates missing directories while doing so.
copyFileIfNewer :: FilePath -> FilePath -> IO ()
copyFileIfNewer src dst = do
newer <- fileIsNewer src dst
if newer
then do
......@@ -100,13 +152,16 @@ copyFileChanged src dst = do
else return ()
fileIsNewer a b = do
exists <- doesFileExist b
if exists
then do
at <- getModificationTime a
bt <- getModificationTime b
return (at > bt)
else return True
aexists <- doesFileExist a
bexists <- doesFileExist b
if bexists
then if aexists
then do
at <- getModificationTime a
bt <- getModificationTime b
return ((traceShowId at) > (traceShowId bt))
else return True
else return False
-- | Express the second path argument as relative to the first.
-- Both arguments are expected to be absolute pathes.
......
......@@ -85,6 +85,8 @@ import Text.Pandoc
import Text.Pandoc.PDF
import Text.Pandoc.Walk
import Watch
import Project
import Common
-- Find the project directory and change current directory to there.
-- The project directory is the first upwards directory that contains a .git directory entry.
......@@ -107,16 +109,16 @@ calcProjectDirectory = do
-- Returns absolute pathes.
globA :: FilePattern -> Action [FilePath]
globA pat = do
projectDir <- getProjectDir
liftIO $ globDir1 (compile pat) projectDir
dirs <- getProjectDirs
liftIO $ globDir1 (compile pat) (project dirs)
-- | Globs for files under the project dir in the Action monad.
-- Returns pathes relative to the project directory.
globRelA :: FilePattern -> Action [FilePath]
globRelA pat = do
projectDir <- getProjectDir
dirs <- getProjectDirs
files <- globA pat
return $ map (makeRelative projectDir) files
return $ map (makeRelative (project dirs)) files
-- Utility functions for shake based apps
spawn :: String -> Action ProcessHandle
......@@ -235,13 +237,13 @@ writeIndex out baseUrl decks handouts pages = do
let decksLinks = map (makeRelative baseUrl) decks
let handoutsLinks = map (makeRelative baseUrl) handouts
let pagesLinks = map (makeRelative baseUrl) pages
projectDir <- getProjectDir
dirs <- getProjectDirs
liftIO $
writeFile out $
unlines
[ "---"
, "title: Generated Index"
, "subtitle: " ++ projectDir
, "subtitle: " ++ (project dirs)
, "---"
, "# Slide decks"
, unlines $ map makeLink $ sort decksLinks
......@@ -263,8 +265,8 @@ readMetaDataForDir :: FilePath -> Action Y.Value
readMetaDataForDir dir = walkUpTo dir
where
walkUpTo dir = do
projectDir <- getProjectDir
if equalFilePath projectDir dir
dirs <- getProjectDirs
if equalFilePath (project dirs) dir
then collectMeta dir
else do
fromAbove <- walkUpTo (takeDirectory dir)
......@@ -308,11 +310,10 @@ substituteMetaData text metaData = do
getRelativeSupportDir :: FilePath -> Action FilePath
getRelativeSupportDir from = do
supportDir <- getSupportDir
publicDir <- getPublicDir
dirs <- getProjectDirs
return $
invertPath (makeRelative publicDir (takeDirectory from)) </>
makeRelative publicDir supportDir
invertPath (makeRelative (public dirs) (takeDirectory from)) </>
makeRelative (public dirs) (support dirs)
invertPath :: FilePath -> FilePath
invertPath fp = joinPath $ map (const "..") $ filter ("." /=) $ splitPath fp
......@@ -356,16 +357,16 @@ getPandocWriter format =
-- template variables and calls need.
readAndPreprocessMarkdown :: FilePath -> Action Pandoc
readAndPreprocessMarkdown markdownFile = do
projectDir <- getProjectDir
dirs <- getProjectDirs
let baseDir = takeDirectory markdownFile
readMetaMarkdown markdownFile >>= processIncludes projectDir baseDir
readMetaMarkdown markdownFile >>= processIncludes (project dirs) baseDir
-- Disable automatic caching of remomte images for a while
-- >>= populateCache
populateCache :: Pandoc -> Action Pandoc
populateCache pandoc = do
cacheDir <- getCacheDir
liftIO $ walkM (cacheRemoteImages cacheDir) pandoc
dirs <- getProjectDirs
liftIO $ walkM (cacheRemoteImages (cache dirs)) pandoc
-- | Write a markdown file to a HTML file using the page template.
markdownToHtmlPage :: FilePath -> FilePath -> Action ()
......@@ -474,8 +475,8 @@ readMetaMarkdown markdownFile = do
let (MetaMap m) = combinedMeta
let pandoc = Pandoc (Meta m) blocks
-- adjust image urls
projectDir <- getProjectDir
return $ walk (adjustImageUrls projectDir (takeDirectory markdownFile)) pandoc
dirs <- getProjectDirs
return $ walk (adjustImageUrls (project dirs) (takeDirectory markdownFile)) pandoc
where
readMarkdownOrThrow opts string =
case readMarkdown opts string of
......@@ -637,28 +638,28 @@ hashURI uri = show (md5 $ L8.pack uri) SF.<.> SF.takeExtension uri
processPandocPage :: String -> Pandoc -> Action Pandoc
processPandocPage format pandoc = do
let f = Just (Format format)
cacheDir <- getCacheDir
dirs <- getProjectDirs
processed <-
liftIO $ processCites' pandoc >>= walkM (useCachedImages cacheDir)
-- processed <- liftIO $ walkM (useCachedImages cacheDir) pandoc
liftIO $ processCites' pandoc >>= walkM (useCachedImages (cache dirs))
-- processed <- liftIO $ walkM (useCachedImages (cache dirs)) pandoc
return $ expandMacros f processed
processPandocDeck :: String -> Pandoc -> Action Pandoc
processPandocDeck format pandoc = do
let f = Just (Format format)
cacheDir <- getCacheDir
dirs <- getProjectDirs
processed <-
liftIO $ processCites' pandoc >>= walkM (useCachedImages cacheDir)
-- processed <- liftIO $ walkM (useCachedImages cacheDir) pandoc
liftIO $ processCites' pandoc >>= walkM (useCachedImages (cache dirs))
-- processed <- liftIO $ walkM (useCachedImages cacheD(cache dirs)ir) pandoc
return $ (makeSlides f . expandMacros f) processed
processPandocHandout :: String -> Pandoc -> Action Pandoc
processPandocHandout format pandoc = do
let f = Just (Format format)
cacheDir <- getCacheDir
dirs <- getProjectDirs