user7627: I have a script that is developed in Plutus Playground. It is working well and now I want to deploy it to the Cardano blockchain via cardano-cli.
Following this answer, I have to use cabal to turn my Haskell script (.hs) into a plutus (.plutus) file. And then send it along with a transaction to the blockchain. The answer is vague and provides no details. I especially need to know how to configure .cabal file, dependencies, among other things. I find no other resource/tutorial that shows how it is done.
Question: How to turn (compile) my “script.hs” into “script.plutus”?
I am aware of this example by IOHK. But now I need to apply to own script and configurations.

user1071: You can base your cabal files and project from plutus-apps next-node branch. See here: https://github.com/input-output-hk/plutus-apps/blob/next-node/cabal.project
I have an example repo you can you as guideline here: https://github.com/james-iohk/plutus-scripts

user5523: Take a look at this example: (https://github.com/Apexaverse-metaverse/P2E/blob/main/scripts/mint-token-cli.sh#L22), is a bit clunky but it works:
Using cabal repl. I call writePolicyFile function from https://github.com/Apexaverse-metaverse/P2E/blob/main/src/Deploy.hs#L58. This function builds the policy UPLC using hard-coded params, serialize it to plutus format and save it. Then, in the bash script, the tx is built and submitted using cardano-cli.

user5311: Another way is to use a separate Utils.hs file (remember add it in your your-app.cabal file for config) for utility fucntions, example:
dataToScriptData :: Data -> ScriptData
dataToScriptData (Constr n xs) = ScriptDataConstructor n $ dataToScriptData <$> xs
dataToScriptData (Map xs)      = ScriptDataMap [(dataToScriptData x, dataToScriptData y) | (x, y) <- xs]
dataToScriptData (List xs)     = ScriptDataList $ dataToScriptData <$> xs
dataToScriptData (I n)         = ScriptDataNumber n
dataToScriptData (B bs)        = ScriptDataBytes bs

writeJSON :: PlutusTx.ToData a => FilePath -> a -> IO ()
writeJSON file = LBS.writeFile file . encode . scriptDataToJson ScriptDataJsonDetailedSchema . dataToScriptData . PlutusTx.toData

writeUnit :: IO ()
writeUnit = writeJSON "scripts/unit.json" ()

-- For validator:
writeValidator :: Plutus.Validator -> IO (Either (FileError ()) ())
writeValidator = writeValidator "scripts/demoContract.plutus" . validator

-- For minting policy:
writeMintingPolicy :: Plutus.MintingPolicy -> IO (Either (FileError ()) ())
writeMintingPolicy  = writeFileTextEnvelope @(PlutusScript PlutusScriptV1) "scripts/my-minting-script.plutus" Nothing . PlutusScriptSerialised . SBS.toShort . LBS.toStrict . serialise . Plutus.getMintingPolicy

Then pass your minting policy or validator in the above functions then you would get a script output.
Example of my implementation on a validator:
strToPpkh :: String -> Plutus.PaymentPubKeyHash
strToPpkh = Plutus.PaymentPubKeyHash . Plutus.PubKeyHash . stringToBuiltinByteString 

tupleToAssetClass :: (String, String) -> AssetClass
tupleToAssetClass (cs, tn) = AssetClass (CurrencySymbol $ stringToBuiltinByteString cs, TokenName $ stringToBuiltinByteString tn)

makeParam :: (String, String) -> String -> (String, String) -> AppParam
makeParam ca fc tt = AppParam {
    cContractAsset = tupleToAssetClass ca
    , cFeeCollector  = strToPpkh fc
    , cTT            = tupleToAssetClass tt 
}

writeSimplifiedValidator :: (String, String) -> String -> (String, String) -> IO (Either (FileError ()) ())
writeSimplifiedValidator ca fc tt = writeValidator "scripts/demoContract.plutus" $ Simplified.validator $ makeParam ca fc tt


An excessive import list as below, its from PPP lecture with wallet implementation as well, you could filtered out those not used for your own purposes:
{-# LANGUAGE GADTs            #-}
{-# LANGUAGE TypeApplications #-}

module Utils.Utils where

import           Cardano.Api                 as API
import           Cardano.Api.Shelley         (Address (..), PlutusScript (..))
import           Cardano.Crypto.Hash.Class   (hashToBytes)
import           Cardano.Ledger.Credential   as Ledger
import           Cardano.Ledger.Crypto       (StandardCrypto)
import           Cardano.Ledger.Hashes       (ScriptHash (..))
import           Cardano.Ledger.Keys         (KeyHash (..))
import           Codec.Serialise             (serialise)
import           Data.Aeson                  (decode, encode)
import qualified Data.ByteString.Char8       as BS8
import qualified Data.ByteString.Lazy        as LBS
import qualified Data.ByteString.Short       as SBS
import           Data.Maybe                  (fromJust, fromMaybe)
import           Data.String                 (IsString (..))
import           Data.Text                   (pack)
import           Plutus.PAB.Webserver.Types  (ContractActivationArgs (..))
import           Plutus.V1.Ledger.Credential as Plutus
import           Plutus.V1.Ledger.Crypto     as Plutus
import           Plutus.V1.Ledger.Value      (TokenName (..))
import           PlutusTx                    (Data (..))
import qualified PlutusTx
import           PlutusTx.Builtins           (toBuiltin)
import           PlutusTx.Builtins.Internal  (BuiltinByteString (..))
import qualified Ledger                      as Plutus
import           Ledger.Value              
import           Wallet.Emulator.Wallet      (WalletId (..), Wallet (..))
import           Wallet.Types                (ContractInstanceId (..))
import           PlutusTx.Builtins.Class

import           MyApp.Onchain
import           MyApp.Types
import           MyToken.Onchain


7627: <p>I have a script that is developed in Plutus Playground. It is working well and now I want to deploy it to the Cardano blockchain via cardano-cli.</p>
<p>Following <a href="https://forum.cardano.org/t/compiling-validator-scripts/75626/2" rel="nofollow noreferrer">this</a> answer, I have to use cabal to turn my Haskell script (.hs) into a plutus (.plutus) file. And then send it along with a transaction to the blockchain. The answer is vague and provides no details. I especially need to know how to configure .cabal file, dependencies, among other things. I find no other resource/tutorial that shows how it is done.</p>
<p>Question: How to turn (compile) my “script.hs” into “script.plutus”?</p>
<p>I am aware of <a href="https://docs.cardano.org/plutus/Plutus-transactions" rel="nofollow noreferrer">this</a> example by IOHK. But now I need to apply to own script and configurations.</p>
 1071: <p>You can base your cabal files and project from plutus-apps <code>next-node</code> branch. See here: <a href="https://github.com/input-output-hk/plutus-apps/blob/next-node/cabal.project" rel="nofollow noreferrer">https://github.com/input-output-hk/plutus-apps/blob/next-node/cabal.project</a></p>
<p>I have an example repo you can you as guideline here: <a href="https://github.com/james-iohk/plutus-scripts" rel="nofollow noreferrer">https://github.com/james-iohk/plutus-scripts</a></p>
 5523: <p>Take a look at this example: (<a href="https://github.com/Apexaverse-metaverse/P2E/blob/main/scripts/mint-token-cli.sh#L22" rel="nofollow noreferrer">https://github.com/Apexaverse-metaverse/P2E/blob/main/scripts/mint-token-cli.sh#L22</a>), is a bit clunky but it works:</p>
<p>Using <code>cabal repl</code>. I call <code>writePolicyFile</code> function from <a href="https://github.com/Apexaverse-metaverse/P2E/blob/main/src/Deploy.hs#L58" rel="nofollow noreferrer">https://github.com/Apexaverse-metaverse/P2E/blob/main/src/Deploy.hs#L58</a>. This function builds the policy UPLC using hard-coded params, serialize it to plutus format and save it. Then, in the bash script, the tx is built and submitted using cardano-cli.</p>
 5311: <p>Another way is to use a separate <code>Utils.hs</code> file (remember add it in your <code>your-app.cabal</code> file for config) for utility fucntions, example:</p>
<pre class="lang-haskell prettyprint-override"><code>dataToScriptData :: Data -&gt; ScriptData
dataToScriptData (Constr n xs) = ScriptDataConstructor n $ dataToScriptData &lt;$&gt; xs
dataToScriptData (Map xs)      = ScriptDataMap [(dataToScriptData x, dataToScriptData y) | (x, y) &lt;- xs]
dataToScriptData (List xs)     = ScriptDataList $ dataToScriptData &lt;$&gt; xs
dataToScriptData (I n)         = ScriptDataNumber n
dataToScriptData (B bs)        = ScriptDataBytes bs

writeJSON :: PlutusTx.ToData a =&gt; FilePath -&gt; a -&gt; IO ()
writeJSON file = LBS.writeFile file . encode . scriptDataToJson ScriptDataJsonDetailedSchema . dataToScriptData . PlutusTx.toData

writeUnit :: IO ()
writeUnit = writeJSON &quot;scripts/unit.json&quot; ()

-- For validator:
writeValidator :: Plutus.Validator -&gt; IO (Either (FileError ()) ())
writeValidator = writeValidator &quot;scripts/demoContract.plutus&quot; . validator

-- For minting policy:
writeMintingPolicy :: Plutus.MintingPolicy -&gt; IO (Either (FileError ()) ())
writeMintingPolicy  = writeFileTextEnvelope @(PlutusScript PlutusScriptV1) &quot;scripts/my-minting-script.plutus&quot; Nothing . PlutusScriptSerialised . SBS.toShort . LBS.toStrict . serialise . Plutus.getMintingPolicy
</code></pre>
<p>Then pass your minting policy or validator in the above functions then you would get a script output.</p>
<p>Example of my implementation on a validator:</p>
<pre class="lang-haskell prettyprint-override"><code>strToPpkh :: String -&gt; Plutus.PaymentPubKeyHash
strToPpkh = Plutus.PaymentPubKeyHash . Plutus.PubKeyHash . stringToBuiltinByteString 

tupleToAssetClass :: (String, String) -&gt; AssetClass
tupleToAssetClass (cs, tn) = AssetClass (CurrencySymbol $ stringToBuiltinByteString cs, TokenName $ stringToBuiltinByteString tn)

makeParam :: (String, String) -&gt; String -&gt; (String, String) -&gt; AppParam
makeParam ca fc tt = AppParam {
    cContractAsset = tupleToAssetClass ca
    , cFeeCollector  = strToPpkh fc
    , cTT            = tupleToAssetClass tt 
}

writeSimplifiedValidator :: (String, String) -&gt; String -&gt; (String, String) -&gt; IO (Either (FileError ()) ())
writeSimplifiedValidator ca fc tt = writeValidator &quot;scripts/demoContract.plutus&quot; $ Simplified.validator $ makeParam ca fc tt

</code></pre>
<p>An excessive import list as below, its from PPP lecture with wallet implementation as well, you could filtered out those not used for your own purposes:</p>
<pre class="lang-haskell prettyprint-override"><code>{-# LANGUAGE GADTs            #-}
{-# LANGUAGE TypeApplications #-}

module Utils.Utils where

import           Cardano.Api                 as API
import           Cardano.Api.Shelley         (Address (..), PlutusScript (..))
import           Cardano.Crypto.Hash.Class   (hashToBytes)
import           Cardano.Ledger.Credential   as Ledger
import           Cardano.Ledger.Crypto       (StandardCrypto)
import           Cardano.Ledger.Hashes       (ScriptHash (..))
import           Cardano.Ledger.Keys         (KeyHash (..))
import           Codec.Serialise             (serialise)
import           Data.Aeson                  (decode, encode)
import qualified Data.ByteString.Char8       as BS8
import qualified Data.ByteString.Lazy        as LBS
import qualified Data.ByteString.Short       as SBS
import           Data.Maybe                  (fromJust, fromMaybe)
import           Data.String                 (IsString (..))
import           Data.Text                   (pack)
import           Plutus.PAB.Webserver.Types  (ContractActivationArgs (..))
import           Plutus.V1.Ledger.Credential as Plutus
import           Plutus.V1.Ledger.Crypto     as Plutus
import           Plutus.V1.Ledger.Value      (TokenName (..))
import           PlutusTx                    (Data (..))
import qualified PlutusTx
import           PlutusTx.Builtins           (toBuiltin)
import           PlutusTx.Builtins.Internal  (BuiltinByteString (..))
import qualified Ledger                      as Plutus
import           Ledger.Value              
import           Wallet.Emulator.Wallet      (WalletId (..), Wallet (..))
import           Wallet.Types                (ContractInstanceId (..))
import           PlutusTx.Builtins.Class

import           MyApp.Onchain
import           MyApp.Types
import           MyToken.Onchain
</code></pre>
