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

Fix ShellCmd String arguments #221

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 19 additions & 16 deletions .github/workflows/haskell-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.15.20221225
# version: 0.15.20230128
#
# REGENDATA ("0.15.20221225",["github","shelly.cabal"])
# REGENDATA ("0.15.20230128",["github","shelly.cabal"])
#
name: Haskell-CI
on:
Expand Down Expand Up @@ -72,11 +72,6 @@ jobs:
compilerVersion: 8.2.2
setup-method: hvr-ppa
allow-failure: false
- compiler: ghc-8.0.2
compilerKind: ghc
compilerVersion: 8.0.2
setup-method: hvr-ppa
allow-failure: false
fail-fast: false
steps:
- name: apt
Expand All @@ -87,16 +82,18 @@ jobs:
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.18.0/x86_64-linux-ghcup-0.1.18.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.6.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
"$HOME/.ghcup/bin/ghcup" install cabal 3.9.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
else
apt-add-repository -y 'ppa:hvr/ghc'
apt-get update
apt-get install -y "$HCNAME"
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.18.0/x86_64-linux-ghcup-0.1.18.0 > "$HOME/.ghcup/bin/ghcup"
chmod a+x "$HOME/.ghcup/bin/ghcup"
"$HOME/.ghcup/bin/ghcup" install cabal 3.6.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
"$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 cabal 3.9.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
fi
env:
HCKIND: ${{ matrix.compilerKind }}
Expand All @@ -114,13 +111,13 @@ jobs:
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"
echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.9.0.0 -vnormal+nowrap" >> "$GITHUB_ENV"
else
HC=$HCDIR/bin/$HCKIND
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HCDIR/bin/$HCKIND-pkg" >> "$GITHUB_ENV"
echo "HADDOCK=$HCDIR/bin/haddock" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
echo "CABAL=$HOME/.ghcup/bin/cabal-3.9.0.0 -vnormal+nowrap" >> "$GITHUB_ENV"
fi

HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
Expand Down Expand Up @@ -203,8 +200,8 @@ jobs:
touch cabal.project
touch cabal.project.local
echo "packages: ${PKGDIR_shelly}" >> cabal.project
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package shelly" >> cabal.project ; fi
if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
echo "package shelly" >> cabal.project
echo " ghc-options: -Werror=missing-methods" >> cabal.project
cat >> cabal.project <<EOF
EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(shelly)$/; }' >> cabal.project.local
Expand All @@ -214,8 +211,8 @@ jobs:
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan
- name: cache
uses: actions/cache@v3
- name: restore cache
uses: actions/cache/restore@v3
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
Expand All @@ -239,8 +236,14 @@ jobs:
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
$CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: save cache
uses: actions/cache/save@v3
if: always()
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
12 changes: 12 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 1.12.0

Cunning Defenstrator, 2023-02-12
* Rework ShellCmd and ShellCommand instances to support String arguments.
* Add some tests.
* Remove the IncoherentInstances pragma as it's deprecated.
* Bump the major version as CmdArg and ShellArg have changed. Users must
migrate existing instances by replacing `toTextArg` with `toTextArgs` and
wrapping the old return value in a list.
* Bump the resolver to lts-20.04.
* Bump haskell-ci to 0.15.20230128.

# 1.11.0

Andreas Abel, 2023-01-24
Expand Down
4 changes: 2 additions & 2 deletions shelly.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Name: shelly

Version: 1.11.0
Version: 1.12.0
Synopsis: shell-like (systems) programming in Haskell

Description: Shelly provides convenient systems programming in Haskell,
Expand Down Expand Up @@ -38,7 +38,6 @@ tested-with:
GHC == 8.6.5
GHC == 8.4.4
GHC == 8.2.2
GHC == 8.0.2

-- for the sdist of the test suite
extra-source-files:
Expand Down Expand Up @@ -124,6 +123,7 @@ Test-Suite shelly-testsuite
Help
LiftedSpec
MoveSpec
PipeSpec
ReadFileSpec
RmSpec
RunSpec
Expand Down
34 changes: 17 additions & 17 deletions src/Shelly.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
Expand Down Expand Up @@ -175,33 +174,34 @@ cmd fp args = run fp $ toTextArgs args

-- | Argument converter for the variadic argument version of 'run' called 'cmd'.
-- Useful for a type signature of a function that uses 'cmd'.
class CmdArg a where toTextArg :: a -> Text
instance CmdArg Text where toTextArg = id
instance CmdArg String where toTextArg = T.pack
class CmdArg a where toTextArgs :: a -> [Text]

instance CmdArg Text where
toTextArgs = (: []) . id

instance CmdArg String where
toTextArgs = (: []) . T.pack

instance {-# OVERLAPPABLE #-} CmdArg a => CmdArg [a] where
toTextArgs = concatMap toTextArgs

-- | For the variadic function 'cmd'.
--
-- Partially applied variadic functions require type signatures.
class ShellCmd t where
cmdAll :: FilePath -> [Text] -> t

instance ShellCmd (Sh Text) where
cmdAll = run
-- This is the only candidate for `_ <- cmd path x y z` so marking it incoherent will return it and
-- terminate the search immediately. This also removes the warning for do { cmd path x y z ; .. }
-- as GHC will infer `Sh ()` instead of `Sh Text` as before.
instance {-# INCOHERENT #-} s ~ () => ShellCmd (Sh s) where
cmdAll = run_

instance (s ~ Text, Show s) => ShellCmd (Sh s) where
instance ShellCmd (Sh Text) where
cmdAll = run

-- note that Sh () actually doesn't work for its case (_<- cmd) when there is no type signature
instance ShellCmd (Sh ()) where
cmdAll = run_

instance (CmdArg arg, ShellCmd result) => ShellCmd (arg -> result) where
cmdAll fp acc x = cmdAll fp (acc ++ [toTextArg x])

instance (CmdArg arg, ShellCmd result) => ShellCmd ([arg] -> result) where
cmdAll fp acc x = cmdAll fp (acc ++ map toTextArg x)


cmdAll fp acc x = cmdAll fp (acc ++ toTextArgs x)

-- | Variadic argument version of 'run'.
-- Please see the documenation for 'run'.
Expand Down
24 changes: 10 additions & 14 deletions src/Shelly/Pipe.hs
Original file line number Diff line number Diff line change
Expand Up @@ -610,27 +610,23 @@ put = sh1 S.put
-- polyvariadic vodoo

-- | Converter for the variadic argument version of 'run' called 'cmd'.
class ShellArg a where toTextArg :: a -> Text
instance ShellArg Text where toTextArg = id
instance ShellArg FilePath where toTextArg = toTextIgnore
class ShellArg a where toTextArgs :: a -> [Text]
instance ShellArg Text where toTextArgs = (: []) . id
instance ShellArg String where toTextArgs = (: []) . T.pack
instance {-# OVERLAPPABLE #-} ShellArg a => ShellArg [a] where
toTextArgs = Prelude.concatMap toTextArgs


-- Voodoo to create the variadic function 'cmd'
class ShellCommand t where
cmdAll :: FilePath -> [Text] -> t

instance ShellCommand (Sh Text) where
cmdAll fp args = run fp args

instance (s ~ Text, Show s) => ShellCommand (Sh s) where
cmdAll fp args = run fp args
instance {-# INCOHERENT #-} s ~ () => ShellCommand (Sh s) where
cmdAll = run_

-- note that Sh () actually doesn't work for its case (_<- cmd) when there is no type signature
instance ShellCommand (Sh ()) where
cmdAll fp args = run_ fp args
instance ShellCommand (Sh Text) where
cmdAll = run

instance (ShellArg arg, ShellCommand result) => ShellCommand (arg -> result) where
cmdAll fp acc = \x -> cmdAll fp (acc ++ [toTextArg x])
cmdAll fp acc x = cmdAll fp (acc ++ toTextArgs x)

-- | see 'S.cmd'
cmd :: (ShellCommand result) => FilePath -> result
Expand Down
4 changes: 2 additions & 2 deletions stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ flags: {}
packages:
- '.'
- shelly-extra/
resolver: lts-18.16
extra-deps: []
resolver: lts-20.04
extra-deps: []
8 changes: 4 additions & 4 deletions stack.yaml.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
packages: []
snapshots:
- completed:
size: 586286
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/16.yaml
sha256: cdead65fca0323144b346c94286186f4969bf85594d649c49c7557295675d8a5
original: lts-18.16
sha256: 3770dfd79f5aed67acdcc65c4e7730adddffe6dba79ea723cfb0918356fc0f94
size: 648660
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/4.yaml
original: lts-20.4
14 changes: 7 additions & 7 deletions test/src/FindSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ findSpec = do
res <- shelly $ cd "test/src" >> ls "."
sort res @?= map toWindowsStyleIfNecessary ["./CopySpec.hs", "./EnvSpec.hs", "./FailureSpec.hs",
"./FindSpec.hs", "./Help.hs", "./LiftedSpec.hs", "./LogWithSpec.hs", "./MoveSpec.hs",
"./ReadFileSpec.hs", "./RmSpec.hs", "./RunSpec.hs", "./SshSpec.hs",
"./PipeSpec.hs", "./ReadFileSpec.hs", "./RmSpec.hs", "./RunSpec.hs", "./SshSpec.hs",
"./TestInit.hs", "./TestMain.hs",
"./WhichSpec.hs", "./WriteSpec.hs", "./sleep.hs"]

it "lists relative files in folder" $ do
res <- shelly $ cd "test" >> ls "src"
sort res @?= map toWindowsStyleIfNecessary ["src/CopySpec.hs", "src/EnvSpec.hs", "src/FailureSpec.hs",
"src/FindSpec.hs", "src/Help.hs", "src/LiftedSpec.hs", "src/LogWithSpec.hs", "src/MoveSpec.hs",
"src/ReadFileSpec.hs", "src/RmSpec.hs", "src/RunSpec.hs", "src/SshSpec.hs",
"src/PipeSpec.hs", "src/ReadFileSpec.hs", "src/RmSpec.hs", "src/RunSpec.hs", "src/SshSpec.hs",
"src/TestInit.hs", "src/TestMain.hs",
"src/WhichSpec.hs", "src/WriteSpec.hs", "src/sleep.hs"]

it "finds relative files" $ do
res <- shelly $ cd "test/src" >> find "."
sort res @?= map toWindowsStyleIfNecessary ["./CopySpec.hs", "./EnvSpec.hs", "./FailureSpec.hs",
"./FindSpec.hs", "./Help.hs", "./LiftedSpec.hs", "./LogWithSpec.hs", "./MoveSpec.hs",
"./ReadFileSpec.hs", "./RmSpec.hs", "./RunSpec.hs", "./SshSpec.hs",
"./PipeSpec.hs", "./ReadFileSpec.hs", "./RmSpec.hs", "./RunSpec.hs", "./SshSpec.hs",
"./TestInit.hs", "./TestMain.hs",
"./WhichSpec.hs", "./WriteSpec.hs", "./sleep.hs"]

Expand All @@ -86,13 +86,13 @@ findSpec = do
if isWindows
then sort res @?= ["test/src\\CopySpec.hs", "test/src\\EnvSpec.hs", "test/src\\FailureSpec.hs",
"test/src\\FindSpec.hs", "test/src\\Help.hs", "test/src\\LiftedSpec.hs",
"test/src\\LogWithSpec.hs", "test/src\\MoveSpec.hs", "test/src\\ReadFileSpec.hs",
"test/src\\LogWithSpec.hs", "test/src\\MoveSpec.hs", "test/src\\PipeSpec.hs", "test/src\\ReadFileSpec.hs",
"test/src\\RmSpec.hs", "test/src\\RunSpec.hs", "test/src\\SshSpec.hs",
"test/src\\TestInit.hs", "test/src\\TestMain.hs", "test/src\\WhichSpec.hs", "test/src\\WriteSpec.hs",
"test/src\\sleep.hs"]
else sort res @?= ["test/src/CopySpec.hs", "test/src/EnvSpec.hs", "test/src/FailureSpec.hs",
"test/src/FindSpec.hs", "test/src/Help.hs", "test/src/LiftedSpec.hs",
"test/src/LogWithSpec.hs", "test/src/MoveSpec.hs", "test/src/ReadFileSpec.hs",
"test/src/LogWithSpec.hs", "test/src/MoveSpec.hs", "test/src/PipeSpec.hs", "test/src/ReadFileSpec.hs",
"test/src/RmSpec.hs", "test/src/RunSpec.hs", "test/src/SshSpec.hs",
"test/src/TestInit.hs", "test/src/TestMain.hs", "test/src/WhichSpec.hs", "test/src/WriteSpec.hs",
"test/src/sleep.hs"]
Expand All @@ -101,8 +101,8 @@ findSpec = do
res <- shelly $ relPath "test/src" >>= find >>= mapM (relativeTo "test/src")
sort res @?= ["CopySpec.hs", "EnvSpec.hs", "FailureSpec.hs", "FindSpec.hs",
"Help.hs", "LiftedSpec.hs", "LogWithSpec.hs", "MoveSpec.hs",
"ReadFileSpec.hs", "RmSpec.hs", "RunSpec.hs", "SshSpec.hs",
"TestInit.hs", "TestMain.hs",
"PipeSpec.hs", "ReadFileSpec.hs", "RmSpec.hs", "RunSpec.hs",
"SshSpec.hs", "TestInit.hs", "TestMain.hs",
"WhichSpec.hs", "WriteSpec.hs", "sleep.hs"]

unless isWindows $ before createSymlinkForTest $ do
Expand Down