Skip to content

Commit

Permalink
Exposed unsafeExecCompiler + more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jhmcstanton committed Oct 16, 2020
1 parent e8b6561 commit 94c15d4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 15 deletions.
23 changes: 21 additions & 2 deletions README.md
Expand Up @@ -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
```
2 changes: 1 addition & 1 deletion 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`.
Expand Down
48 changes: 36 additions & 12 deletions src/Hakyll/Process.hs
@@ -1,10 +1,16 @@
{-|
Module : Hakyll.Process
Description : Common compilers and helpers for external executables.
Stability : experimental
-}
module Hakyll.Process
(
newExtension
, newExtOutFilePath
, execName
, execCompiler
, execCompilerWith
, unsafeExecCompiler
, CompilerOut(..)
, ExecutableArg(..)
, ExecutableArgs
Expand Down Expand Up @@ -46,19 +52,23 @@ 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
-- Note: like hakyll, assumes that no "." is present in the extension
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

Expand All @@ -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
Expand Down

0 comments on commit 94c15d4

Please sign in to comment.