Skip to content

Commit dba035e

Browse files
authored
Add freeze command (#486)
Implement the freeze command (#437) Takes input from stdin or file and updates all imports with hashes
1 parent da8b540 commit dba035e

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

dhall.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ Library
209209
Dhall.Core,
210210
Dhall.Diff,
211211
Dhall.Format,
212+
Dhall.Freeze,
212213
Dhall.Hash,
213214
Dhall.Import,
214215
Dhall.Lint,

src/Dhall/Freeze.hs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
3+
module Dhall.Freeze (
4+
freeze
5+
, hashImport
6+
) where
7+
8+
import Dhall.Core
9+
import Dhall.Import (load, hashExpression)
10+
import Dhall.Parser (exprAndHeaderFromText, Src)
11+
import Dhall.Pretty (annToAnsiStyle)
12+
13+
import System.Console.ANSI (hSupportsANSI)
14+
import Data.Monoid ((<>))
15+
import Data.Maybe (fromMaybe)
16+
import Data.Text
17+
18+
import qualified Data.Text.Prettyprint.Doc as Pretty
19+
import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty
20+
import qualified Control.Exception
21+
import qualified Data.Text.IO
22+
import qualified System.IO
23+
24+
opts :: Pretty.LayoutOptions
25+
opts =
26+
Pretty.defaultLayoutOptions
27+
{ Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }
28+
29+
readInput :: Maybe FilePath -> IO Text
30+
readInput = maybe fromStdin Data.Text.IO.readFile
31+
where
32+
fromStdin = System.IO.hSetEncoding System.IO.stdin System.IO.utf8 >> Data.Text.IO.getContents
33+
34+
hashImport :: Import -> IO Import
35+
hashImport import_ = do
36+
expression <- Dhall.Import.load (Embed import_)
37+
let expressionHash = Just (Dhall.Import.hashExpression expression)
38+
let newImportHashed = (importHashed import_) { hash = expressionHash }
39+
return $ import_ { importHashed = newImportHashed }
40+
41+
parseExpr :: String -> Text -> IO (Text, Expr Src Import)
42+
parseExpr src txt =
43+
case exprAndHeaderFromText src txt of
44+
Left err -> Control.Exception.throwIO err
45+
Right x -> return x
46+
47+
freezeExpr :: (Text, Expr s Import) -> IO (Text, Expr s Import)
48+
freezeExpr (t, e) = do
49+
e' <- traverse hashImport e
50+
return (t, e')
51+
52+
writeExpr :: Maybe FilePath -> (Text, Expr s Import) -> IO ()
53+
writeExpr inplace (header, expr) = do
54+
let doc = Pretty.pretty header <> Pretty.pretty expr
55+
let layoutOptions = opts
56+
let stream = Pretty.layoutSmart layoutOptions doc
57+
58+
case inplace of
59+
Just f ->
60+
System.IO.withFile f System.IO.WriteMode (\h ->
61+
Pretty.renderIO h (annToAnsiStyle <$> stream))
62+
63+
Nothing -> do
64+
supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout
65+
if supportsANSI
66+
then
67+
Pretty.renderIO System.IO.stdout (annToAnsiStyle <$> Pretty.layoutSmart opts doc)
68+
else
69+
Pretty.renderIO System.IO.stdout (Pretty.layoutSmart opts (Pretty.unAnnotate doc))
70+
71+
freeze :: Maybe FilePath -> IO ()
72+
freeze inplace = do
73+
expr <- readInput inplace
74+
parseExpr srcInfo expr >>= freezeExpr >>= writeExpr inplace
75+
where
76+
srcInfo = fromMaybe "(stdin)" inplace

src/Dhall/Main.hs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import qualified Dhall
3636
import qualified Dhall.Core
3737
import qualified Dhall.Diff
3838
import qualified Dhall.Format
39+
import qualified Dhall.Freeze
3940
import qualified Dhall.Hash
4041
import qualified Dhall.Lint
4142
import qualified Dhall.Parser
@@ -59,6 +60,7 @@ data Mode
5960
| Normalize
6061
| Repl
6162
| Format (Maybe FilePath)
63+
| Freeze (Maybe FilePath)
6264
| Hash
6365
| Diff Text Text
6466
| Lint (Maybe FilePath)
@@ -98,6 +100,7 @@ parseMode =
98100
<|> subcommand "hash" "Compute semantic hashes for Dhall expressions" (pure Hash)
99101
<|> subcommand "lint" "Improve Dhall code" parseLint
100102
<|> formatSubcommand
103+
<|> freezeSubcommand
101104
<|> pure Default
102105
where
103106
subcommand name description modeParser =
@@ -139,6 +142,10 @@ parseMode =
139142
parserWithHelper = Options.Applicative.helper <*> parser
140143
parser = Format <$> optional parseInplace
141144

145+
freezeSubcommand = subcommand "freeze" "Add hashes to all import statements of an expression" parseFreeze
146+
where
147+
parseFreeze = Freeze <$> optional parseInplace
148+
142149
opts :: Pretty.LayoutOptions
143150
opts =
144151
Pretty.defaultLayoutOptions
@@ -279,6 +286,9 @@ command (Options {..}) = do
279286
Format inplace -> do
280287
Dhall.Format.format inplace
281288

289+
Freeze inplace -> do
290+
Dhall.Freeze.freeze inplace
291+
282292
Hash -> do
283293
Dhall.Hash.hash
284294

src/Dhall/Tutorial.hs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1551,7 +1551,26 @@ import Dhall
15511551
-- behavior-preserving. This provides an easy way to detect refactoring errors
15521552
-- that you might accidentally introduce. The hash not only protects you
15531553
-- from attackers, but also protects against human error, too!
1554-
1554+
--
1555+
-- If you have a file which either doesn't already use hashed imports,
1556+
-- or you changed some of the imports and want to update the hashes you can use the
1557+
-- freeze command to either add or update hashes:
1558+
--
1559+
-- > cat foo.dhall
1560+
-- ''
1561+
-- let replicate =
1562+
-- https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate
1563+
--
1564+
-- in replicate 5
1565+
-- ''
1566+
-- > dhall freeze --inplace ./foo.dhall
1567+
-- > cat ./foo.dhall
1568+
-- ''
1569+
-- let replicate =
1570+
-- https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
1571+
-- in replicate 5
1572+
-- ''
1573+
--
15551574
-- $rawText
15561575
--
15571576
-- Sometimes you want to import the contents of a raw text file as a Dhall

0 commit comments

Comments
 (0)