summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjhmcstanton <>2020-10-16 18:39:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2020-10-16 18:39:00 (GMT)
commit5b372100642d3254275adaa8d6c5b39fdf838f62 (patch)
tree12bc2ff2a8f73205d66cb307e5cf48a0b665b209
parent1e9f1be6943c4d421c3c86aab21e97b0841a831d (diff)
version 0.0.2.0HEAD0.0.2.0master
-rw-r--r--README.md23
-rw-r--r--hakyll-process.cabal2
-rw-r--r--src/Hakyll/Process.hs48
3 files changed, 58 insertions, 15 deletions
diff --git a/README.md b/README.md
index 9c67beb..369b0e2 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,36 @@
Hakyll compilers for passing Hakyll items to external processes. This is useful for tools that do not have
Haskell bindings or may not make sense to have Haskell bindings, like Typescript or LaTex compilers.
-## Example Usage:
+## Common Usage
+
+There are a few main entry points for this library:
+
+- `execCompilerWith` is the most common. This allows the caller to declaratively run an external process
+ and includes support for passing arguments.
+- `execCompiler` is an aliased version of `execCompilerWith` that provides no arguments to the external executable/process.
+- `unsafeExecCompiler` is the less type safe and more manual method to calling external executables. This provides
+ no helper functionality but may be useful if you are already manually building out a compiler in your site generator.
+
+### Example
This example shows how this library can be used to include latex files in your
site source and include the output pdf in your target site.
```haskell
+import qualified Data.ByteString.Lazy.Char8 as B
import Hakyll.Process
main = do
hakyll $ do
match "resume/*.tex" $ do
route $ setExtension "pdf"
- compile $ execCompilerWith (execName "xelatex") [ProcArg "-output-directory=resume/", HakFilePath] (newExtOutFilePath ("pdf"))
+ compile $ execCompilerWith (execName "xelatex") [ProcArg "-output-directory=resume/", HakFilePath] (newExtOutFilePath "pdf")
+
+ -- alternative, manual method, using unsafeExecCompiler
+ match "resume/*.tex" $ do
+ route $ setExtension "pdf"
+ compile $ do
+ input <- getResourceFilePath
+ let outputReader _ = B.readFile (newExtension "pdf" input)
+ unsafeExecCompiler (execName "xelatex") ["-output-directory=resume/", input] outputReader
```
diff --git a/hakyll-process.cabal b/hakyll-process.cabal
index aab8cd3..98b1891 100644
--- a/hakyll-process.cabal
+++ b/hakyll-process.cabal
@@ -1,5 +1,5 @@
name: hakyll-process
-version: 0.0.1.0
+version: 0.0.2.0
synopsis: Hakyll compiler for arbitrary external processes.
description: Exposes Hakyll compilers for passing file paths to external processes.
Transformed results are made available as Hakyll `Items`.
diff --git a/src/Hakyll/Process.hs b/src/Hakyll/Process.hs
index 1dd4dea..fb9aa33 100644
--- a/src/Hakyll/Process.hs
+++ b/src/Hakyll/Process.hs
@@ -1,3 +1,8 @@
+{-|
+Module : Hakyll.Process
+Description : Common compilers and helpers for external executables.
+Stability : experimental
+-}
module Hakyll.Process
(
newExtension
@@ -5,6 +10,7 @@ module Hakyll.Process
, execName
, execCompiler
, execCompilerWith
+ , unsafeExecCompiler
, CompilerOut(..)
, ExecutableArg(..)
, ExecutableArgs
@@ -46,7 +52,10 @@ type ExecutableArgs = [ExecutableArg]
-- | Helper function to indicate that the output file name is the same as the input file name with a new extension
-- Note: like hakyll, assumes that no "." is present in the extension
-newExtension :: String -> FilePath -> FilePath
+newExtension ::
+ String -- ^ New file extension, excluding the leading "."
+ -> FilePath -- ^ Original FilePath
+ -> FilePath
newExtension ext f = (reverse . dropWhile (/= '.') . reverse $ f) <> ext
-- | Helper function to indicate that the output file name is the same as the input file name with a new extension
@@ -54,11 +63,12 @@ newExtension ext f = (reverse . dropWhile (/= '.') . reverse $ f) <> ext
newExtOutFilePath :: String -> CompilerOut
newExtOutFilePath ext = COutFile $ RelativePath (newExtension ext)
-execName :: String -> ExecutableName
+execName :: String -> ExecutableName
execName = ExecutableName
-- | Calls the external compiler with no arguments. Returns the output contents as a 'B.ByteString'.
-- If an error occurs this raises an exception.
+-- May be useful if you already have build scripts for artifacts in your repository.
execCompiler :: ExecutableName -> CompilerOut -> Compiler (Item B.ByteString)
execCompiler name out = execCompilerWith name [] out
@@ -68,22 +78,36 @@ execCompilerWith :: ExecutableName -> ExecutableArgs -> CompilerOut -> Compiler
execCompilerWith name exArgs out = do
input <- getResourceFilePath
let args = fmap (hargToArg input) exArgs
- results <- unsafeCompiler $ runExecutable name args out input
- -- just using this to get at the item
- oldBody <- getResourceString
- pure $ itemSetBody results oldBody
+ let outputReader = cOutToFileContents input out
+ unsafeExecCompiler name args outputReader
-runExecutable :: ExecutableName -> [String] -> CompilerOut -> FilePath -> IO B.ByteString
-runExecutable (ExecutableName exName) args compilerOut inputFile = withProcessWait procConf waitOutput where
+-- | Primarily for internal use, occasionally useful when already building a compiler imperatively.
+-- Allows the caller to opt out of the declarative components of 'execCompiler' and 'execCompilerWith'.
+unsafeExecCompiler ::
+ ExecutableName -- ^ Name or filepath of the executable
+ -> [String] -- ^ Arguments to pass to the executable
+ -> (B.ByteString -> IO B.ByteString) -- ^ Action to read the output of the compiler. Input is the stdout of the process.
+ -> Compiler (Item B.ByteString)
+unsafeExecCompiler (ExecutableName exName) args outputReader =
+ do
+ results <- unsafeCompiler $ procResults
+ -- just using this to get at the item
+ oldBody <- getResourceString
+ pure $ itemSetBody results oldBody
+ where
+ procResults = withProcessWait procConf waitOutput
procConf = setStdout byteStringOutput . proc exName $ args
waitOutput process = do
let stmProc = getStdout process
out <- atomically stmProc
checkExitCode process
- case compilerOut of
- CStdOut -> pure out
- COutFile (SpecificPath f) -> B.readFile f
- COutFile (RelativePath f) -> B.readFile (f inputFile)
+ outputReader out
+
+-- input fpath stdout contents
+cOutToFileContents :: FilePath -> CompilerOut -> B.ByteString -> IO B.ByteString
+cOutToFileContents _ CStdOut out = pure out
+cOutToFileContents _ (COutFile (SpecificPath f)) _ = B.readFile f
+cOutToFileContents input (COutFile (RelativePath f)) _ = B.readFile (f input)
hargToArg :: FilePath -> ExecutableArg -> String
hargToArg _ (ProcArg s) = s