diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 8fcbebe..e0d367e 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -8,9 +8,9 @@ # # For more information, see https://github.com/haskell-CI/haskell-ci # -# version: 0.17.20231004 +# version: 0.19.20240708 # -# REGENDATA ("0.17.20231004",["github","cabal.project"]) +# REGENDATA ("0.19.20240708",["github","cabal.project"]) # name: Haskell-CI on: @@ -27,19 +27,29 @@ jobs: timeout-minutes: 60 container: - image: buildpack-deps:bionic + image: buildpack-deps:jammy continue-on-error: ${{ matrix.allow-failure }} strategy: matrix: include: - - compiler: ghc-9.6.3 + - compiler: ghc-9.10.1 compilerKind: ghc - compilerVersion: 9.6.3 + compilerVersion: 9.10.1 setup-method: ghcup allow-failure: false - - compiler: ghc-9.4.7 + - compiler: ghc-9.8.2 compilerKind: ghc - compilerVersion: 9.4.7 + compilerVersion: 9.8.2 + setup-method: ghcup + allow-failure: false + - compiler: ghc-9.6.6 + compilerKind: ghc + compilerVersion: 9.6.6 + setup-method: ghcup + allow-failure: false + - compiler: ghc-9.4.8 + compilerKind: ghc + compilerVersion: 9.4.8 setup-method: ghcup allow-failure: false - compiler: ghc-9.2.8 @@ -64,11 +74,10 @@ jobs: apt-get update apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5 mkdir -p "$HOME/.ghcup/bin" - curl -sL https://downloads.haskell.org/ghcup/0.1.19.5/x86_64-linux-ghcup-0.1.19.5 > "$HOME/.ghcup/bin/ghcup" + curl -sL https://downloads.haskell.org/ghcup/0.1.30.0/x86_64-linux-ghcup-0.1.30.0 > "$HOME/.ghcup/bin/ghcup" chmod a+x "$HOME/.ghcup/bin/ghcup" - "$HOME/.ghcup/bin/ghcup" config add-release-channel https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml; "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false) - "$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + "$HOME/.ghcup/bin/ghcup" install cabal 3.12.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false) env: HCKIND: ${{ matrix.compilerKind }} HCNAME: ${{ matrix.compiler }} @@ -86,7 +95,7 @@ jobs: echo "HC=$HC" >> "$GITHUB_ENV" echo "HCPKG=$HCPKG" >> "$GITHUB_ENV" echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV" - echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV" + echo "CABAL=$HOME/.ghcup/bin/cabal-3.12.1.0 -vnormal+nowrap" >> "$GITHUB_ENV" HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))') echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV" echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV" @@ -134,9 +143,9 @@ jobs: run: | $CABAL v2-update -v - name: cache (tools) - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: - key: ${{ runner.os }}-${{ matrix.compiler }}-tools-2bcd4d44 + key: ${{ runner.os }}-${{ matrix.compiler }}-tools-655fd156 path: ~/.haskell-ci-tools - name: install cabal-plan run: | @@ -149,22 +158,16 @@ jobs: cabal-plan --version - name: install doctest run: | - if [ $((HCNUMVER < 90400)) -ne 0 ] ; then $CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.20' ; fi - if [ $((HCNUMVER < 90400)) -ne 0 ] ; then doctest --version ; fi - - name: install hlint - run: | - if [ $((HCNUMVER >= 90400 && HCNUMVER < 90600)) -ne 0 ] ; then HLINTVER=$(cd /tmp && (${CABAL} v2-install -v $ARG_COMPILER --dry-run hlint --constraint='hlint >=3.3 && <3.6' | perl -ne 'if (/\bhlint-(\d+(\.\d+)*)\b/) { print "$1"; last; }')); echo "HLint version $HLINTVER" ; fi - if [ $((HCNUMVER >= 90400 && HCNUMVER < 90600)) -ne 0 ] ; then if [ ! -e $HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint ]; then echo "Downloading HLint version $HLINTVER"; mkdir -p $HOME/.haskell-ci-tools; curl --write-out 'Status Code: %{http_code} Redirects: %{num_redirects} Total time: %{time_total} Total Dsize: %{size_download}\n' --silent --location --output $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v$HLINTVER/hlint-$HLINTVER-x86_64-linux.tar.gz"; tar -xzv -f $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz -C $HOME/.haskell-ci-tools; fi ; fi - if [ $((HCNUMVER >= 90400 && HCNUMVER < 90600)) -ne 0 ] ; then mkdir -p $CABAL_DIR/bin && ln -sf "$HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint" $CABAL_DIR/bin/hlint ; fi - if [ $((HCNUMVER >= 90400 && HCNUMVER < 90600)) -ne 0 ] ; then hlint --version ; fi + if [ $((HCNUMVER < 91000)) -ne 0 ] ; then $CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.22.0' ; fi + if [ $((HCNUMVER < 91000)) -ne 0 ] ; then doctest --version ; fi - name: save cache (tools) - uses: actions/cache/save@v3 + uses: actions/cache/save@v4 if: always() with: - key: ${{ runner.os }}-${{ matrix.compiler }}-tools-2bcd4d44 + key: ${{ runner.os }}-${{ matrix.compiler }}-tools-655fd156 path: ~/.haskell-ci-tools - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: source - name: initial cabal.project for sdist @@ -192,7 +195,7 @@ jobs: echo " ghc-options: -Werror=missing-methods" >> cabal.project cat >> cabal.project <> cabal.project.local + $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(typed-process-effectful)$/; }' >> cabal.project.local cat cabal.project cat cabal.project.local - name: dump install plan @@ -200,7 +203,7 @@ jobs: $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all cabal-plan - name: restore cache - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} path: ~/.cabal/store @@ -220,11 +223,8 @@ jobs: $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct - name: doctest run: | - if [ $((HCNUMVER < 90400)) -ne 0 ] ; then cd ${PKGDIR_typed_process_effectful} || false ; fi - if [ $((HCNUMVER < 90400)) -ne 0 ] ; then doctest -XHaskell2010 -XDataKinds -XFlexibleContexts -XGADTs -XKindSignatures -XTypeOperators src ; fi - - name: hlint - run: | - if [ $((HCNUMVER >= 90400 && HCNUMVER < 90600)) -ne 0 ] ; then (cd ${PKGDIR_typed_process_effectful} && hlint -XHaskell2010 -XDataKinds -XFlexibleContexts -XGADTs -XKindSignatures -XTypeOperators src) ; fi + if [ $((HCNUMVER < 91000)) -ne 0 ] ; then cd ${PKGDIR_typed_process_effectful} || false ; fi + if [ $((HCNUMVER < 91000)) -ne 0 ] ; then doctest -XHaskell2010 -XDataKinds -XFlexibleContexts -XGADTs -XKindSignatures -XTypeOperators src ; fi - name: cabal check run: | cd ${PKGDIR_typed_process_effectful} || false @@ -237,7 +237,7 @@ jobs: rm -f cabal.project.local $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all - name: save cache - uses: actions/cache/save@v3 + uses: actions/cache/save@v4 if: always() with: key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..0ce8800 --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,43 @@ +name: Linters +on: + - push + - pull_request +jobs: + cabal-gild: + runs-on: ubuntu-latest + + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + + - name: 'Set up cabal-gild' + uses: tfausak/cabal-gild-setup-action@v2 + + - name: 'Run cabal-gild' + run: cabal-gild --mode check --input typed-process-effectful.cabal + + fourmolu: + runs-on: ubuntu-latest + + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + + - name: 'Run fourmolu' + uses: haskell-actions/run-fourmolu@v10 + + hlint: + runs-on: ubuntu-latest + + steps: + - name: 'Checkout repository' + uses: actions/checkout@v4 + + - name: 'Set up hlint' + uses: haskell-actions/hlint-setup@v2 + + - name: 'Run hlint' + uses: haskell-actions/hlint-run@v2 + with: + path: './' + fail-on: suggestion diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a69991..054168c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG +## v1.0.0.2 (????-??-??) +* Bumped upper bounds for bytestring and tasty dependency. + ## v1.0.0.1 (2023-10-07) * Bumped upper bounds for effectful and effectful-core dependency. diff --git a/cabal.haskell-ci b/cabal.haskell-ci index 5aebfa5..437dd40 100644 --- a/cabal.haskell-ci +++ b/cabal.haskell-ci @@ -1,9 +1,6 @@ branches: main -doctest: <9.3 -hlint: True -hlint-job: 9.4.7 -hlint-version: >=3.3 && <3.6 +doctest: <9.9 tests: True benchmarks: True diff --git a/example/Main.hs b/example/Main.hs index f650474..80208d5 100644 --- a/example/Main.hs +++ b/example/Main.hs @@ -4,5 +4,5 @@ import Effectful.Process.Typed main :: IO () main = runEff . runTypedProcess $ true -true :: TypedProcess :> es => Eff es () +true :: (TypedProcess :> es) => Eff es () true = Effectful.Process.Typed.runProcess_ $ shell "true" diff --git a/fourmolu.yaml b/fourmolu.yaml new file mode 100644 index 0000000..4c93b29 --- /dev/null +++ b/fourmolu.yaml @@ -0,0 +1,19 @@ +indentation: 4 +column-limit: none +function-arrows: leading +comma-style: leading +import-export-style: diff-friendly +indent-wheres: true +record-brace-space: false +newlines-between-decls: 1 +haddock-style: single-line +haddock-style-module: null +let-style: newline +in-style: left-align +single-constraint-parens: always +single-deriving-parens: always +unicode: never +respectful: true +fixities: [] +reexports: [] +record-braces: false diff --git a/src/Effectful/Process/Typed.hs b/src/Effectful/Process/Typed.hs index 3fe9e03..106bed9 100644 --- a/src/Effectful/Process/Typed.hs +++ b/src/Effectful/Process/Typed.hs @@ -1,83 +1,74 @@ -{-| -Module : Effectful.Process.Typed -Description : effectful bindings for typed-process -Copyright : (c) 2022 Dominik Peteler -License : BSD-3-Clause -Stability : stable - -This module provides [effectful](https://hackage.haskell.org/package/effectful) -bindings for [typed-process](https://hackage.haskell.org/package/typed-process). --} -{-# OPTIONS_GHC -fno-warn-dodgy-imports #-} -{-# LANGUAGE CPP #-} {-# LANGUAGE TypeFamilies #-} -module Effectful.Process.Typed - ( -- * Process effect - TypedProcess - , runTypedProcess - - -- * Launch a process - , startProcess - , stopProcess - , withProcessWait - , withProcessWait_ - , withProcessTerm - , withProcessTerm_ - , readProcess - , readProcess_ - , runProcess - , runProcess_ - , readProcessStdout - , readProcessStdout_ - , readProcessStderr - , readProcessStderr_ - , readProcessInterleaved - , readProcessInterleaved_ - - -- * Process exit code - , waitExitCode - , getExitCode - , checkExitCode - - -- * Re-exports from "System.Process.Typed" - , module Reexport -#if ! MIN_VERSION_typed_process(0,2,8) - , ExitCode(..) -#endif - ) where - -import System.Process.Typed as Reexport hiding - ( startProcess - , stopProcess - , withProcessWait - , withProcessWait_ - , withProcessTerm - , withProcessTerm_ - , readProcess - , readProcess_ - , runProcess - , runProcess_ - , readProcessStdout - , readProcessStdout_ - , readProcessStderr - , readProcessStderr_ - , readProcessInterleaved - , readProcessInterleaved_ - , waitExitCode - , getExitCode - , checkExitCode - ) + +-- | +-- Module : Effectful.Process.Typed +-- Description : effectful bindings for typed-process +-- Copyright : (c) 2022 Dominik Peteler +-- License : BSD-3-Clause +-- Stability : stable +-- +-- This module provides [effectful](https://hackage.haskell.org/package/effectful) +-- bindings for [typed-process](https://hackage.haskell.org/package/typed-process). +module Effectful.Process.Typed ( + -- * Process effect + TypedProcess, + runTypedProcess, + + -- * Launch a process + startProcess, + stopProcess, + withProcessWait, + withProcessWait_, + withProcessTerm, + withProcessTerm_, + readProcess, + readProcess_, + runProcess, + runProcess_, + readProcessStdout, + readProcessStdout_, + readProcessStderr, + readProcessStderr_, + readProcessInterleaved, + readProcessInterleaved_, + + -- * Process exit code + waitExitCode, + getExitCode, + checkExitCode, + + -- * Re-exports from "System.Process.Typed" + module Reexport, +) where + +import System.Process.Typed as Reexport hiding ( + checkExitCode, + getExitCode, + readProcess, + readProcessInterleaved, + readProcessInterleaved_, + readProcessStderr, + readProcessStderr_, + readProcessStdout, + readProcessStdout_, + readProcess_, + runProcess, + runProcess_, + startProcess, + stopProcess, + waitExitCode, + withProcessTerm, + withProcessTerm_, + withProcessWait, + withProcessWait_, + ) import Data.ByteString.Lazy (ByteString) import qualified System.Process.Typed as PT import Effectful -import qualified Effectful.Process import Effectful.Dispatch.Static - -#if ! MIN_VERSION_typed_process(0,2,8) -import System.Exit (ExitCode(..)) -#endif +import qualified Effectful.Process ---------------------------------------- -- Effect & Handler @@ -90,157 +81,176 @@ type TypedProcess = Effectful.Process.Process -- clashes with 'runProcess', i.e.: -- -- > runTypedProcess = Effectful.Process.runProcess -runTypedProcess :: IOE :> es => Eff (TypedProcess : es) a -> Eff es a +runTypedProcess :: (IOE :> es) => Eff (TypedProcess : es) a -> Eff es a runTypedProcess = Effectful.Process.runProcess ---------------------------------------- -- Launch a process -- | Lifted 'PT.startProcess'. -startProcess :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> Eff es (PT.Process stdin stdout stderr) +startProcess + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> Eff es (PT.Process stdin stdout stderr) startProcess = unsafeEff_ . PT.startProcess -- | Lifted 'PT.stopProcess'. -stopProcess :: TypedProcess :> es => PT.Process stdin stdout stderr -> Eff es () +stopProcess :: (TypedProcess :> es) => PT.Process stdin stdout stderr -> Eff es () stopProcess = unsafeEff_ . PT.stopProcess -- | Lifted 'PT.withProcessWait'. -withProcessWait :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> (PT.Process stdin stdout stderr -> Eff es a) - -> Eff es a +withProcessWait + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> (PT.Process stdin stdout stderr -> Eff es a) + -> Eff es a withProcessWait = liftWithProcess PT.withProcessWait -- | Lifted 'PT.withProcessWait_'. -withProcessWait_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> (PT.Process stdin stdout stderr -> Eff es a) - -> Eff es a +withProcessWait_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> (PT.Process stdin stdout stderr -> Eff es a) + -> Eff es a withProcessWait_ = liftWithProcess PT.withProcessWait_ -- | Lifted 'PT.withProcessTerm'. -withProcessTerm :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> (PT.Process stdin stdout stderr -> Eff es a) - -> Eff es a +withProcessTerm + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> (PT.Process stdin stdout stderr -> Eff es a) + -> Eff es a withProcessTerm = liftWithProcess PT.withProcessTerm -- | Lifted 'PT.withProcessTerm_'. -withProcessTerm_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> (PT.Process stdin stdout stderr -> Eff es a) - -> Eff es a +withProcessTerm_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> (PT.Process stdin stdout stderr -> Eff es a) + -> Eff es a withProcessTerm_ = liftWithProcess PT.withProcessTerm_ -- | Lifted 'PT.readProcess'. -readProcess :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderrIgnored - -> Eff es (ExitCode, ByteString, ByteString) +readProcess + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderrIgnored + -> Eff es (ExitCode, ByteString, ByteString) readProcess = unsafeEff_ . PT.readProcess -- | Lifted 'PT.readProcess_'. -readProcess_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderrIgnored - -> Eff es (ByteString, ByteString) +readProcess_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderrIgnored + -> Eff es (ByteString, ByteString) readProcess_ = unsafeEff_ . PT.readProcess_ -- | Lifted 'PT.runProcess'. -runProcess :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> Eff es ExitCode +runProcess + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> Eff es ExitCode runProcess = unsafeEff_ . PT.runProcess -- | Lifted 'PT.runProcess_'. -runProcess_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderr - -> Eff es () +runProcess_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderr + -> Eff es () runProcess_ = unsafeEff_ . PT.runProcess_ -- | Lifted 'PT.readProcessStdout'. -readProcessStdout :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderr - -> Eff es (ExitCode, ByteString) +readProcessStdout + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderr + -> Eff es (ExitCode, ByteString) readProcessStdout = unsafeEff_ . PT.readProcessStdout -- | Lifted 'PT.readProcessStdout_'. -readProcessStdout_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderr - -> Eff es ByteString +readProcessStdout_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderr + -> Eff es ByteString readProcessStdout_ = unsafeEff_ . PT.readProcessStdout_ -- | Lifted 'PT.readProcessStderr'. -readProcessStderr :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderrIgnored - -> Eff es (ExitCode, ByteString) +readProcessStderr + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderrIgnored + -> Eff es (ExitCode, ByteString) readProcessStderr = unsafeEff_ . PT.readProcessStderr -- | Lifted 'PT.readProcessStderr_'. -readProcessStderr_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdout stderrIgnored - -> Eff es ByteString +readProcessStderr_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdout stderrIgnored + -> Eff es ByteString readProcessStderr_ = unsafeEff_ . PT.readProcessStderr_ -- | Lifted 'PT.readProcessInterleaved'. -readProcessInterleaved :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderrIgnored - -> Eff es (ExitCode, ByteString) +readProcessInterleaved + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderrIgnored + -> Eff es (ExitCode, ByteString) readProcessInterleaved = unsafeEff_ . PT.readProcessInterleaved -- | Lifted 'PT.readProcessInterleaved_'. -readProcessInterleaved_ :: TypedProcess :> es - => PT.ProcessConfig stdin stdoutIgnored stderrIgnored - -> Eff es ByteString +readProcessInterleaved_ + :: (TypedProcess :> es) + => PT.ProcessConfig stdin stdoutIgnored stderrIgnored + -> Eff es ByteString readProcessInterleaved_ = unsafeEff_ . PT.readProcessInterleaved_ ---------------------------------------- -- Process exit code -- | Lifted 'PT.waitExitCode'. -waitExitCode :: TypedProcess :> es - => PT.Process stdin stdout stderr - -> Eff es ExitCode +waitExitCode + :: (TypedProcess :> es) + => PT.Process stdin stdout stderr + -> Eff es ExitCode waitExitCode = unsafeEff_ . PT.waitExitCode ---- | Lifted 'PT.waitExitCodeSTM'. ---waitExitCodeSTM :: TypedProcess :> es +-- waitExitCodeSTM :: TypedProcess :> es -- => PT.Process stdin stdout stderr -- -> Eff es ExitCode ---waitExitCodeSTM = unsafeEff_ . PT.waitExitCode +-- waitExitCodeSTM = unsafeEff_ . PT.waitExitCode -- | Lifted 'PT.getExitCode'. -getExitCode :: TypedProcess :> es - => PT.Process stdin stdout stderr - -> Eff es (Maybe ExitCode) +getExitCode + :: (TypedProcess :> es) + => PT.Process stdin stdout stderr + -> Eff es (Maybe ExitCode) getExitCode = unsafeEff_ . PT.getExitCode ---- | Lifted 'PT.getExitCodeSTM'. ---getExitCodeSTM :: TypedProcess :> es +-- getExitCodeSTM :: TypedProcess :> es -- => PT.Process stdin stdout stderr -- -> Eff es (Maybe ExitCode) ---getExitCodeSTM = unsafeEff_ . PT.getExitCodeSTM +-- getExitCodeSTM = unsafeEff_ . PT.getExitCodeSTM -- | Lifted 'PT.checkExitCode'. -checkExitCode :: TypedProcess :> es - => PT.Process stdin stdout stderr - -> Eff es () +checkExitCode + :: (TypedProcess :> es) + => PT.Process stdin stdout stderr + -> Eff es () checkExitCode = unsafeEff_ . PT.checkExitCode ---- | Lifted 'PT.checkExitCodeSTM'. ---checkExitCodeSTM :: TypedProcess :> es +-- checkExitCodeSTM :: TypedProcess :> es -- => PT.Process stdin stdout stderr -- -> Eff es () ---checkExitCodeSTM = unsafeEff_ . PT.checkExitCodeSTM +-- checkExitCodeSTM = unsafeEff_ . PT.checkExitCodeSTM ---------------------------------------- -- Helpers -liftWithProcess :: TypedProcess :> es - => (PT.ProcessConfig stdin stdout stderr -> (PT.Process stdin stdout stderr -> IO a) -> IO a) - -> PT.ProcessConfig stdin stdout stderr - -> (PT.Process stdin stdout stderr -> Eff es a) - -> Eff es a +liftWithProcess + :: (TypedProcess :> es) + => (PT.ProcessConfig stdin stdout stderr -> (PT.Process stdin stdout stderr -> IO a) -> IO a) + -> PT.ProcessConfig stdin stdout stderr + -> (PT.Process stdin stdout stderr -> Eff es a) + -> Eff es a liftWithProcess k pc f = unsafeEff $ \es -> - seqUnliftIO es $ \runInIO -> - k pc (runInIO . f) + seqUnliftIO es $ \runInIO -> + k pc (runInIO . f) diff --git a/test/Main.hs b/test/Main.hs index 242377c..bbb0c76 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -9,129 +9,154 @@ import System.IO.Error (isDoesNotExistError) import qualified Utils as U import Effectful.Process.Typed -import Test.Tasty.HUnit (Assertion, testCase) import Test.Tasty (defaultMain, testGroup) +import Test.Tasty.HUnit (Assertion, testCase) main :: IO () -main = defaultMain $ testGroup "typed-process-effectful" - [ testCase "Existing executable" testExistingExecutable - , testCase "Non-existent executable" testNonExistentExecutable - , testCase "Continue process execution" testContinueProcessExecution - , testCase "Terminate process" testTerminateProcess - , testCase "Wait for process" testWaitForProcess - , testCase "Helper functions" testHelperFunctions - , testCase "Exit Codes" testExitCodes - ] +main = + defaultMain $ + testGroup + "typed-process-effectful" + [ testCase "Existing executable" testExistingExecutable + , testCase "Non-existent executable" testNonExistentExecutable + , testCase "Continue process execution" testContinueProcessExecution + , testCase "Terminate process" testTerminateProcess + , testCase "Wait for process" testWaitForProcess + , testCase "Helper functions" testHelperFunctions + , testCase "Exit Codes" testExitCodes + ] testExistingExecutable :: Assertion testExistingExecutable = runEff $ do - let pc = proc "/usr/bin/env" ["true"] - action = runTypedProcess $ do - p <- startProcess pc - waitExitCode p - result <- action - U.assertEqual "Executable exists" ExitSuccess result + let + pc = proc "/usr/bin/env" ["true"] + action = runTypedProcess $ do + p <- startProcess pc + waitExitCode p + result <- action + U.assertEqual "Executable exists" ExitSuccess result testNonExistentExecutable :: Assertion testNonExistentExecutable = runEff $ do - let pc = proc "/bin/doesnotexist" [] - let action = runTypedProcess $ do - p <- startProcess pc - waitExitCode p - U.assertException (runEff action) isDoesNotExistError + let + pc = proc "/bin/doesnotexist" [] + let + action = runTypedProcess $ do + p <- startProcess pc + waitExitCode p + U.assertException (runEff action) isDoesNotExistError testContinueProcessExecution :: Assertion testContinueProcessExecution = runEff $ do - let pc = shell "sleep 3" - action = runTypedProcess $ do - p <- startProcess pc - getExitCode p - result <- action - U.assertEqual "" result Nothing + let + pc = shell "sleep 3" + action = runTypedProcess $ do + p <- startProcess pc + getExitCode p + result <- action + U.assertEqual "" result Nothing testTerminateProcess :: Assertion testTerminateProcess = runEff $ do - let action = runTemporary . runTypedProcess $ do - withSystemTempFile "typed-process-effectful-test" $ \fp h -> do - let pc = setStdout (useHandleClose h) - $ shell "sleep 1; printf 'Output'" - withProcessTerm pc (const $ pure ()) - liftIO $ readFile fp - result <- action - U.assertEqual "" "" result + let + action = runTemporary . runTypedProcess $ do + withSystemTempFile "typed-process-effectful-test" $ \fp h -> do + let + pc = + setStdout (useHandleClose h) $ + shell "sleep 1; printf 'Output'" + withProcessTerm pc (const $ pure ()) + liftIO $ readFile fp + result <- action + U.assertEqual "" "" result testWaitForProcess :: Assertion testWaitForProcess = runEff $ do - let action = runTemporary . runTypedProcess $ do - withSystemTempFile "typed-process-effectful-test" $ \fp h -> do - let pc = setStdout (useHandleClose h) - $ shell "sleep 1; printf 'Output'" - withProcessWait pc (const $ pure ()) - liftIO $ readFile fp - result <- action - U.assertEqual "" result "Output" + let + action = runTemporary . runTypedProcess $ do + withSystemTempFile "typed-process-effectful-test" $ \fp h -> do + let + pc = + setStdout (useHandleClose h) $ + shell "sleep 1; printf 'Output'" + withProcessWait pc (const $ pure ()) + liftIO $ readFile fp + result <- action + U.assertEqual "" result "Output" testHelperFunctions :: Assertion testHelperFunctions = runEff $ do - let pc = proc "/usr/bin/env" ["true"] - action = runTypedProcess $ do - runProcess pc - result <- action - U.assertEqual "" result ExitSuccess - - let pc2 = proc "/usr/bin/env" ["true"] - result2 <- runTypedProcess $ do + let + pc = proc "/usr/bin/env" ["true"] + action = runTypedProcess $ do + runProcess pc + result <- action + U.assertEqual "" result ExitSuccess + + let + pc2 = proc "/usr/bin/env" ["true"] + result2 <- runTypedProcess $ do runProcess_ pc2 - U.assertEqual "" result2 () + U.assertEqual "" result2 () - let pc3 = shell "printf 'stdout'; printf 'stderr' >&2" - result3 <- runTypedProcess $ do + let + pc3 = shell "printf 'stdout'; printf 'stderr' >&2" + result3 <- runTypedProcess $ do readProcess pc3 - U.assertEqual "" result3 (ExitSuccess, "stdout", "stderr") + U.assertEqual "" result3 (ExitSuccess, "stdout", "stderr") - let pc4 = shell "printf 'stdout'; printf 'stderr' >&2" - result4 <- runTypedProcess $ do + let + pc4 = shell "printf 'stdout'; printf 'stderr' >&2" + result4 <- runTypedProcess $ do readProcess_ pc4 - U.assertEqual "" result4 ("stdout", "stderr") + U.assertEqual "" result4 ("stdout", "stderr") - let pc5 = shell "printf 'Output'" - result5 <- runTypedProcess $ do + let + pc5 = shell "printf 'Output'" + result5 <- runTypedProcess $ do readProcessStdout pc5 - U.assertEqual "" result5 (ExitSuccess, "Output") + U.assertEqual "" result5 (ExitSuccess, "Output") - let pc6 = shell "printf 'Output'" - result6 <- runTypedProcess $ do + let + pc6 = shell "printf 'Output'" + result6 <- runTypedProcess $ do readProcessStdout pc6 - U.assertEqual "" result6 (ExitSuccess, "Output") + U.assertEqual "" result6 (ExitSuccess, "Output") - let pc7 = shell "printf 'Output'" - result7 <- runTypedProcess $ do + let + pc7 = shell "printf 'Output'" + result7 <- runTypedProcess $ do readProcessStdout_ pc7 - U.assertEqual "" result7 "Output" + U.assertEqual "" result7 "Output" - let pc8 = shell "printf 'Output' >&2" - result8 <- runTypedProcess $ do + let + pc8 = shell "printf 'Output' >&2" + result8 <- runTypedProcess $ do readProcessStderr pc8 - U.assertEqual "" result8 (ExitSuccess, "Output") + U.assertEqual "" result8 (ExitSuccess, "Output") testExitCodes :: Assertion testExitCodes = runEff $ do - let pc = proc "/usr/bin/env" ["false"] - action = runEff . runTypedProcess $ do - runProcess_ pc - U.assertException action (const @_ @ExitCodeException True) - - let pc2 = proc "/usr/bin/env" ["false"] - action2 = runEff . runTypedProcess $ do - readProcess_ pc2 - U.assertException action2 (const @_ @ExitCodeException True) - - let pc3 = proc "/usr/bin/env" ["false"] - action3 = runEff . runTypedProcess $ do - readProcessStdout_ pc3 - U.assertException action3 (const @_ @ExitCodeException True) - - let pc4 = proc "/usr/bin/env" ["false"] - action4 = runEff . runTypedProcess $ do - readProcessStderr_ pc4 - U.assertException action4 (const @_ @ExitCodeException True) + let + pc = proc "/usr/bin/env" ["false"] + action = runEff . runTypedProcess $ do + runProcess_ pc + U.assertException action (const @_ @ExitCodeException True) + + let + pc2 = proc "/usr/bin/env" ["false"] + action2 = runEff . runTypedProcess $ do + readProcess_ pc2 + U.assertException action2 (const @_ @ExitCodeException True) + + let + pc3 = proc "/usr/bin/env" ["false"] + action3 = runEff . runTypedProcess $ do + readProcessStdout_ pc3 + U.assertException action3 (const @_ @ExitCodeException True) + + let + pc4 = proc "/usr/bin/env" ["false"] + action4 = runEff . runTypedProcess $ do + readProcessStderr_ pc4 + U.assertException action4 (const @_ @ExitCodeException True) diff --git a/test/Utils.hs b/test/Utils.hs index ee194e8..7ba1cef 100644 --- a/test/Utils.hs +++ b/test/Utils.hs @@ -1,40 +1,42 @@ {-# LANGUAGE RankNTypes #-} -module Utils - ( assertBool - , assertEqual - , assertFailure - , assertException - ) where + +module Utils ( + assertBool, + assertEqual, + assertFailure, + assertException, +) where import GHC.Stack import qualified Test.Tasty.HUnit as T -import Effectful import Control.Exception +import Effectful assertBool :: (HasCallStack, IOE :> es) => String -> Bool -> Eff es () assertBool msg p = liftIO $ T.assertBool msg p assertEqual - :: (HasCallStack, Eq a, Show a, IOE :> es) - => String - -> a - -> a - -> Eff es () + :: (HasCallStack, Eq a, Show a, IOE :> es) + => String + -> a + -> a + -> Eff es () assertEqual msg expected given = liftIO $ T.assertEqual msg expected given assertFailure :: (HasCallStack, IOE :> es) => String -> Eff es a assertFailure msg = liftIO $ T.assertFailure msg -assertException :: forall e es a - . (HasCallStack, Exception e, IOE :> es) - => IO a - -> (e -> Bool) - -> Eff es () +assertException + :: forall e es a + . (HasCallStack, Exception e, IOE :> es) + => IO a + -> (e -> Bool) + -> Eff es () assertException action expectedClassifier = do - r <- liftIO $ try action - case r of - Right _ -> - assertFailure "The action did not raise an exception" - Left e -> - assertBool "The expected exception doesn't match what was given" (expectedClassifier e) + r <- liftIO $ try action + case r of + Right _ -> + assertFailure "The action did not raise an exception" + Left e -> + assertBool "The expected exception doesn't match what was given" (expectedClassifier e) diff --git a/typed-process-effectful.cabal b/typed-process-effectful.cabal index ebe6d19..6dd061d 100644 --- a/typed-process-effectful.cabal +++ b/typed-process-effectful.cabal @@ -1,6 +1,6 @@ -cabal-version: 3.0 -name: typed-process-effectful -version: 1.0.0.1 +cabal-version: 3.0 +name: typed-process-effectful +version: 1.0.0.1 synopsis: A binding of the typed-process library for the effectful effect system. @@ -12,32 +12,36 @@ description: implementation relies on [typed-process](https://hackage.haskell.org/package/typed-process) instead. -category: System +category: System homepage: https://github.com/haskell-effectful/typed-process-effectful#readme bug-reports: https://github.com/haskell-effectful/typed-process-effectful/issues -author: Dominik Peteler -maintainer: hackage+typed-process-effectful@with-h.at -license: BSD-3-Clause -build-type: Simple +author: Dominik Peteler +maintainer: hackage+typed-process-effectful@with-h.at +license: BSD-3-Clause +build-type: Simple +-- cabal-gild: discover ./ --include=LICENSE --include=*.md extra-doc-files: CHANGELOG.md LICENSE.md README.md -tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.7 || ==9.6.3 +tested-with: ghc ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.6 || ==9.8.2 || ==9.10.1 source-repository head - type: git + type: git location: https://github.com/haskell-effectful/typed-process-effectful common language - ghc-options: -Wall -Wcompat - default-language: Haskell2010 + ghc-options: + -Wall + -Wcompat + + default-language: Haskell2010 default-extensions: DataKinds FlexibleContexts @@ -46,28 +50,34 @@ common language TypeOperators library - import: language - hs-source-dirs: src + import: language + hs-source-dirs: src/ + -- cabal-gild: discover src/ --include=src/**/*.hs exposed-modules: Effectful.Process.Typed build-depends: - , base >=4.14 && <5 - , bytestring <0.12 - , effectful >=2.0 && <2.4 - , effectful-core >=2.0 && <2.4 - , typed-process >=0.2.5 && <0.3 + base >=4.14 && <5, + bytestring <0.13, + effectful >=2.0 && <2.4, + effectful-core >=2.0 && <2.4, + typed-process >=0.2.8 && <0.3, test-suite typed-process-effectful-test - import: language - ghc-options: -rtsopts -threaded -with-rtsopts=-N + import: language + ghc-options: + -rtsopts + -threaded + -with-rtsopts=-N + build-depends: - , base - , effectful - , effectful-core - , tasty >=1.4 && <1.5 - , tasty-hunit >=0.10 && <0.11 - , typed-process-effectful + base, + effectful, + effectful-core, + tasty >=1.4 && <1.6, + tasty-hunit >=0.10 && <0.11, + typed-process-effectful, - hs-source-dirs: test - type: exitcode-stdio-1.0 - main-is: Main.hs - other-modules: Utils + hs-source-dirs: test/ + type: exitcode-stdio-1.0 + main-is: Main.hs + -- cabal-gild: discover test/ --exclude=test/Main.hs --include=test/**/*.hs + other-modules: Utils