diff --git a/cardano-cli/cardano-cli.cabal b/cardano-cli/cardano-cli.cabal index 6f7a689379..d9478620e5 100644 --- a/cardano-cli/cardano-cli.cabal +++ b/cardano-cli/cardano-cli.cabal @@ -317,6 +317,7 @@ test-suite cardano-cli-test other-modules: Test.Cli.CliIntermediateFormat Test.Cli.FilePermissions + Test.Cli.Governance.Hash Test.Cli.ITN Test.Cli.JSON Test.Cli.Pioneers.Exercise1 diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Hash.hs b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Hash.hs index 17c5b3bf67..b517b5a4bc 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Hash.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Commands/Governance/Hash.hs @@ -20,8 +20,9 @@ newtype GovernanceHashCmds era = GovernanceHashCmd (GovernanceHashCmdArgs era) data GovernanceHashCmdArgs era = GovernanceHashCmdArgs { - eon :: !(ConwayEraOnwards era), - toHash :: !GovernanceHashSource + eon :: !(ConwayEraOnwards era) + , toHash :: !GovernanceHashSource + , moutFile :: !(Maybe (File () Out)) -- ^ The output file to which the hash is written } deriving Show data GovernanceHashSource diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Hash.hs b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Hash.hs index 4a0ae4736c..e2ee76e17d 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Hash.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Options/Governance/Hash.hs @@ -25,9 +25,10 @@ pGovernanceHashCmds era = do return $ subParser "hash" $ Opt.info - ( Cmd.GovernanceHashCmd . GovernanceHashCmdArgs eon - <$> pGovernanceHashSource - ) + ( fmap Cmd.GovernanceHashCmd + (GovernanceHashCmdArgs eon + <$> pGovernanceHashSource + <*> optional pOutputFile)) $ Opt.progDesc "Compute the hash to pass to the various --*-hash arguments of governance commands." pGovernanceHashSource :: Parser Cmd.GovernanceHashSource diff --git a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Hash.hs b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Hash.hs index 61298f390d..f7c7e02bc2 100644 --- a/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Hash.hs +++ b/cardano-cli/src/Cardano/CLI/EraBased/Run/Governance/Hash.hs @@ -24,12 +24,10 @@ import Cardano.Ledger.Crypto import Cardano.Ledger.SafeHash (extractHash) import qualified Cardano.Ledger.SafeHash as Ledger -import Control.Monad.IO.Class import Control.Monad.Trans.Except import Control.Monad.Trans.Except.Extra import qualified Data.ByteString as BS import Data.Function -import qualified Data.Text as Text import qualified Data.Text.Encoding as Text import qualified Data.Text.IO as Text @@ -43,7 +41,7 @@ runGovernanceHashCmds (Cmd.GovernanceHashCmd args)= runGovernanceHashCmd :: () => Cmd.GovernanceHashCmdArgs era -> ExceptT GovernanceHashError IO () -runGovernanceHashCmd Cmd.GovernanceHashCmdArgs { toHash } = +runGovernanceHashCmd Cmd.GovernanceHashCmdArgs { toHash, moutFile } = -- TODO @smelc we probably want an option to write the computed hash to a file -- This can be done in a separate PR case toHash of @@ -61,5 +59,9 @@ runGovernanceHashCmd Cmd.GovernanceHashCmdArgs { toHash } = let hash = Ledger.hashAnchorData $ Ledger.AnchorData $ Text.encodeUtf8 text printHash hash where - printHash :: Ledger.SafeHash StandardCrypto i -> ExceptT a IO () - printHash = liftIO . putStr . Text.unpack . hashToTextAsHex . extractHash + printHash :: Ledger.SafeHash StandardCrypto i -> ExceptT GovernanceHashError IO () + printHash hash = do + firstExceptT GovernanceHashWriteFileError $ + newExceptT $ writeTextOutput moutFile text + where + text = hashToTextAsHex . extractHash $ hash diff --git a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceHashError.hs b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceHashError.hs index 914ad52dd9..f65c52453d 100644 --- a/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceHashError.hs +++ b/cardano-cli/src/Cardano/CLI/Types/Errors/GovernanceHashError.hs @@ -8,10 +8,13 @@ import Cardano.Api import Cardano.Prelude (Exception (displayException), IOException) data GovernanceHashError - = GovernanceHashReadFileError FilePath IOException + = GovernanceHashReadFileError !FilePath !IOException + | GovernanceHashWriteFileError !(FileError ()) deriving Show instance Error GovernanceHashError where displayError = \case GovernanceHashReadFileError filepath exc -> "Cannot read " <> filepath <> ": " <> displayException exc + GovernanceHashWriteFileError fileErr -> + displayError fileErr diff --git a/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Action.hs b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Action.hs index d99d27b65a..3b7059da0b 100644 --- a/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Action.hs +++ b/cardano-cli/test/cardano-cli-golden/Test/Golden/Governance/Action.hs @@ -10,6 +10,7 @@ import Test.Cardano.CLI.Util import Hedgehog (Property) import qualified Hedgehog.Extras.Test.Base as H import qualified Hedgehog.Extras.Test.Golden as H +import qualified Hedgehog.Extras as H hprop_golden_governance_action_create_constitution :: Property hprop_golden_governance_action_create_constitution = @@ -53,12 +54,18 @@ hprop_golden_conway_governance_action_view_constitution_json :: Property hprop_golden_conway_governance_action_view_constitution_json = propertyOnce . H.moduleWorkspace "tmp" $ \tempDir -> do stakeAddressVKeyFile <- H.note "test/cardano-cli-golden/files/input/governance/stake-address.vkey" + hashFile <- noteTempFile tempDir "hash.txt" actionFile <- noteTempFile tempDir "action" - proposalHash <- execCardanoCLI + -- We go through a file for the hash, to test --out-file + void $ execCardanoCLI [ "conway", "governance", "hash" - , "--text", "whatever "] + , "--text", "whatever " + , "--out-file", hashFile + ] + + proposalHash <- H.readFile hashFile void $ execCardanoCLI [ "conway", "governance", "action", "create-constitution" diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli index 170dd7dc15..06ad51b7b7 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help.cli @@ -6182,6 +6182,7 @@ Usage: cardano-cli conway governance hash | --file-binary FILE | --file-text FILE ) + [--out-file FILE] Compute the hash to pass to the various --*-hash arguments of governance commands. diff --git a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_hash.cli b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_hash.cli index ba527404ef..6c0be02032 100644 --- a/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_hash.cli +++ b/cardano-cli/test/cardano-cli-golden/files/golden/help/conway_governance_hash.cli @@ -3,6 +3,7 @@ Usage: cardano-cli conway governance hash | --file-binary FILE | --file-text FILE ) + [--out-file FILE] Compute the hash to pass to the various --*-hash arguments of governance commands. @@ -11,4 +12,5 @@ Available options: --text TEXT Text to hash as UTF-8 --file-binary FILE Binary file to hash --file-text FILE Text file to hash + --out-file FILE The output file. -h,--help Show this help text diff --git a/cardano-cli/test/cardano-cli-test/Test/Cli/Governance/Hash.hs b/cardano-cli/test/cardano-cli-test/Test/Cli/Governance/Hash.hs new file mode 100644 index 0000000000..32c3cef9e4 --- /dev/null +++ b/cardano-cli/test/cardano-cli-test/Test/Cli/Governance/Hash.hs @@ -0,0 +1,42 @@ +{- HLINT ignore "Use camelCase" -} + +module Test.Cli.Governance.Hash where + +import Control.Monad (void) + +import Test.Cardano.CLI.Util + +import Hedgehog (Property) +import qualified Hedgehog as H +import qualified Hedgehog.Extras as H + +hprop_governance_hash_trip :: Property +hprop_governance_hash_trip = + propertyOnce $ do + governance_hash_trip_fun "foo" + governance_hash_trip_fun "longerText" + governance_hash_trip_fun "nonAscii: 你好" + governance_hash_trip_fun "nonAscii: à la mode de Cæn" + +-- Test that @cardano-cli conway governance hash --text > file1@ and +-- @cardano-cli conway governance hash --text --out-file file2@ yields +-- similar @file1@ and @file2@ files. +governance_hash_trip_fun :: String -> H.PropertyT IO () +governance_hash_trip_fun input = + H.moduleWorkspace "tmp" $ \tempDir -> do + hashFile <- noteTempFile tempDir "hash.txt" + + hash <- execCardanoCLI + [ "conway", "governance", "hash" + , "--text", input + ] + + void $ execCardanoCLI + [ "conway", "governance", "hash" + , "--text", input + , "--out-file", hashFile + ] + + hashFromFile <- H.readFile hashFile + + H.diff hash (==) hashFromFile