Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not apply Mustache to large files (fixes #4133) #4134

Merged
merged 1 commit into from
Jul 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Behavior changes:
[help file](https://github.com/commercialhaskell/stack-templates/blob/master/STACK_HELP.md)
with more information on how to discover templates. See:
[#4039](https://github.com/commercialhaskell/stack/issues/4039)
* Mustache templating is not applied to large files (over 50kb) to
avoid performance degredation. See:
[#4133](https://github.com/commercialhaskell/stack/issues/4133).

Other enhancements:

Expand Down
42 changes: 29 additions & 13 deletions src/Stack/New.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ module Stack.New

import Stack.Prelude
import Control.Monad.Trans.Writer.Strict
import qualified Data.ByteString as SB
import qualified Data.ByteString.Lazy as LB
import Data.Conduit
import Data.List
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Encoding as T
import qualified Data.Text.Encoding.Error as T (lenientDecode)
import qualified Data.Text.Lazy.Encoding as TLE
import Data.Time.Calendar
import Data.Time.Clock
import Network.HTTP.Download
Expand Down Expand Up @@ -140,7 +140,7 @@ loadTemplate name logIt = do
<> "\"")
exists <- doesFileExist path
if exists
then liftIO (fmap (T.decodeUtf8With T.lenientDecode) (SB.readFile (toFilePath path)))
then readFileUtf8 (toFilePath path)
else throwM (FailedToLoadTemplate name (toFilePath path))
relRequest :: Path Rel File -> Maybe Request
relRequest rel = do
Expand Down Expand Up @@ -195,17 +195,9 @@ applyTemplate project template nonceParams dir templateText = do
, ("name-as-module", nameAsModule) ]
configParams = configTemplateParams config
yearParam = M.singleton "year" currentYear
etemplateCompiled = Mustache.compileTemplate (T.unpack (templateName template)) templateText
templateCompiled <- case etemplateCompiled of
Left e -> throwM $ InvalidTemplate template (show e)
Right t -> return t
let (substitutionErrors, applied) = Mustache.checkedSubstitute templateCompiled context
missingKeys = S.fromList $ concatMap onlyMissingKeys substitutionErrors
unless (S.null missingKeys)
(logInfo ("\n" <> displayShow (MissingParameters project template missingKeys (configUserConfigPath config)) <> "\n"))
files :: Map FilePath LB.ByteString <-
catch (execWriterT $ runConduit $
yield (T.encodeUtf8 applied) .|
yield (T.encodeUtf8 templateText) .|
unpackTemplate receiveMem id
)
(\(e :: ProjectTemplateException) ->
Expand All @@ -217,12 +209,36 @@ applyTemplate project template nonceParams dir templateText = do
unless (any isPkgSpec . M.keys $ files) $
throwM (InvalidTemplate template "Template does not contain a .cabal \
\or package.yaml file")

-- Apply Mustache templating to a single file within the project
-- template.
let applyMustache bytes
-- Workaround for performance problems with mustache and
-- large files, applies to Yesod templates with large
-- bootstrap CSS files. See
-- https://github.com/commercialhaskell/stack/issues/4133.
| LB.length bytes < 50000
, Right text <- TLE.decodeUtf8' bytes = do
let etemplateCompiled = Mustache.compileTemplate (T.unpack (templateName template)) $ TL.toStrict text
templateCompiled <- case etemplateCompiled of
Left e -> throwM $ InvalidTemplate template (show e)
Right t -> return t
let (substitutionErrors, applied) = Mustache.checkedSubstitute templateCompiled context
missingKeys = S.fromList $ concatMap onlyMissingKeys substitutionErrors
unless (S.null missingKeys)
(logInfo ("\n" <> displayShow (MissingParameters project template missingKeys (configUserConfigPath config)) <> "\n"))
pure $ LB.fromStrict $ encodeUtf8 applied

-- Too large or too binary
| otherwise = pure bytes

liftM
M.fromList
(mapM
(\(fp,bytes) ->
do path <- parseRelFile fp
return (dir </> path, bytes))
bytes' <- applyMustache bytes
return (dir </> path, bytes'))
(M.toList files))
where
onlyMissingKeys (Mustache.VariableNotFound ks) = map T.unpack ks
Expand Down