Skip to content

Commit a977cf9

Browse files
authored
Merge pull request #5725 from mpilgrem/lsTools
Add `stack ls tools` subcommand
2 parents fc2ffeb + 22fb59a commit a977cf9

File tree

6 files changed

+83
-18
lines changed

6 files changed

+83
-18
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Other enhancements:
3333
[#809](https://github.com/commercialhaskell/stack/issues/809)
3434
* Add the possibility of a `sh` script to customise fully GHC installation. See
3535
[#5585](https://github.com/commercialhaskell/stack/pull/5585)
36+
* `tools` subcommand added to `stack ls`, to list stack's installed tools.
3637

3738
Bug fixes:
3839

src/Stack/Ls.hs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ module Stack.Ls
1212
import Control.Exception (throw)
1313
import Data.Aeson
1414
import Data.Array.IArray ((//), elems)
15+
import Distribution.Package (mkPackageName)
1516
import Stack.Prelude hiding (Snapshot (..), SnapName (..))
1617
import qualified Data.Aeson.Types as A
1718
import qualified Data.List as L
18-
import Data.Text hiding (pack, intercalate)
19+
import Data.Text hiding (filter, intercalate, pack, reverse)
1920
import qualified Data.Text as T
2021
import qualified Data.Text.IO as T
2122
import qualified Data.Vector as V
@@ -24,17 +25,20 @@ import qualified Options.Applicative as OA
2425
import Options.Applicative (idm)
2526
import Options.Applicative.Builder.Extra (boolFlags)
2627
import Path
28+
import RIO.List (sort)
2729
import RIO.PrettyPrint (useColorL)
2830
import RIO.PrettyPrint.DefaultStyles (defaultStyles)
2931
import RIO.PrettyPrint.Types (StyleSpec)
3032
import RIO.PrettyPrint.StylesUpdate (StylesUpdate (..), stylesUpdateL)
3133
import Stack.Dot
3234
import Stack.Runners
3335
import Stack.Options.DotParser (listDepsOptsParser)
36+
import Stack.Setup.Installed (Tool (..), filterTools, listInstalled, toolString)
3437
import Stack.Types.Config
3538
import System.Console.ANSI.Codes (SGR (Reset), setSGRCode, sgrToCode)
3639
import System.Process.Pager (pageText)
3740
import System.Directory (listDirectory)
41+
import System.IO (putStrLn)
3842

3943
data LsView
4044
= Local
@@ -50,6 +54,7 @@ data LsCmds
5054
= LsSnapshot SnapshotOpts
5155
| LsDependencies ListDepsOpts
5256
| LsStyles ListStylesOpts
57+
| LsTools ListToolsOpts
5358

5459
data SnapshotOpts = SnapshotOpts
5560
{ soptViewType :: LsView
@@ -63,12 +68,17 @@ data ListStylesOpts = ListStylesOpts
6368
, coptExample :: Bool
6469
} deriving (Eq, Ord, Show)
6570

71+
newtype ListToolsOpts = ListToolsOpts
72+
{ toptFilter :: String
73+
}
74+
6675
newtype LsCmdOpts = LsCmdOpts
6776
{ lsView :: LsCmds
6877
}
6978

7079
lsParser :: OA.Parser LsCmdOpts
71-
lsParser = LsCmdOpts <$> OA.hsubparser (lsSnapCmd <> lsDepsCmd <> lsStylesCmd)
80+
lsParser = LsCmdOpts
81+
<$> OA.hsubparser (lsSnapCmd <> lsDepsCmd <> lsStylesCmd <> lsToolsCmd)
7282

7383
lsCmdOptsParser :: OA.Parser LsCmds
7484
lsCmdOptsParser = LsSnapshot <$> lsViewSnapCmd
@@ -79,6 +89,9 @@ lsDepOptsParser = LsDependencies <$> listDepsOptsParser
7989
lsStylesOptsParser :: OA.Parser LsCmds
8090
lsStylesOptsParser = LsStyles <$> listStylesOptsParser
8191

92+
lsToolsOptsParser :: OA.Parser LsCmds
93+
lsToolsOptsParser = LsTools <$> listToolsOptsParser
94+
8295
listStylesOptsParser :: OA.Parser ListStylesOpts
8396
listStylesOptsParser = ListStylesOpts
8497
<$> boolFlags False
@@ -98,6 +111,16 @@ listStylesOptsParser = ListStylesOpts
98111
\report"
99112
idm
100113

114+
listToolsOptsParser :: OA.Parser ListToolsOpts
115+
listToolsOptsParser = ListToolsOpts
116+
<$> OA.strOption
117+
( OA.long "filter"
118+
<> OA.metavar "TOOL_NAME"
119+
<> OA.value ""
120+
<> OA.help "Filter by a tool name (eg 'ghc', 'ghc-git' or 'msys2') \
121+
\- case sensitive. The default is no filter"
122+
)
123+
101124
lsViewSnapCmd :: OA.Parser SnapshotOpts
102125
lsViewSnapCmd =
103126
SnapshotOpts <$>
@@ -135,6 +158,12 @@ lsStylesCmd =
135158
(OA.progDesc "View stack's output styles (alias for \
136159
\'stack-colors')"))
137160

161+
lsToolsCmd :: OA.Mod OA.CommandFields LsCmds
162+
lsToolsCmd =
163+
OA.command
164+
"tools"
165+
(OA.info lsToolsOptsParser (OA.progDesc "View stack's installed tools"))
166+
138167
data Snapshot = Snapshot
139168
{ snapId :: Text
140169
, snapTitle :: Text
@@ -242,6 +271,7 @@ handleLocal lsOpts = do
242271
_ -> liftIO $ displayLocalSnapshot isStdoutTerminal snapData
243272
LsDependencies _ -> return ()
244273
LsStyles _ -> return ()
274+
LsTools _ -> return ()
245275

246276
handleRemote
247277
:: HasRunner env
@@ -266,6 +296,7 @@ handleRemote lsOpts = do
266296
_ -> liftIO $ displaySnapshotData isStdoutTerminal snapData
267297
LsDependencies _ -> return ()
268298
LsStyles _ -> return ()
299+
LsTools _ -> return ()
269300
where
270301
urlInfo = "https://www.stackage.org/snapshots"
271302

@@ -278,6 +309,7 @@ lsCmd lsOpts =
278309
Remote -> handleRemote lsOpts
279310
LsDependencies depOpts -> listDependenciesCmd False depOpts
280311
LsStyles stylesOpts -> withConfig NoReexec $ listStylesCmd stylesOpts
312+
LsTools toolsOpts -> withConfig NoReexec $ listToolsCmd toolsOpts
281313

282314
-- | List the dependencies
283315
listDependenciesCmd :: Bool -> ListDepsOpts -> RIO Runner ()
@@ -325,3 +357,17 @@ listStylesCmd opts = do
325357
example = " " <> ansi <> "Example" <> reset
326358
ansi = fromString $ setSGRCode sgrs
327359
reset = fromString $ setSGRCode [Reset]
360+
361+
-- | List stack's installed tools, sorted (see instance of 'Ord' for 'Tool').
362+
listToolsCmd :: ListToolsOpts -> RIO Config ()
363+
listToolsCmd opts = do
364+
localPrograms <- view $ configL.to configLocalPrograms
365+
installed <- sort <$> listInstalled localPrograms
366+
let wanted = case toptFilter opts of
367+
[] -> installed
368+
"ghc-git" -> [t | t@(ToolGhcGit _ _) <- installed]
369+
pkgName -> filtered pkgName installed
370+
liftIO $ mapM_ (putStrLn . toolString) wanted
371+
where
372+
filtered pkgName installed = Tool <$>
373+
filterTools (mkPackageName pkgName) (const True) installed

src/Stack/Path.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ paths =
158158
, ( "PATH environment variable"
159159
, "bin-path"
160160
, WithoutHaddocks $ T.pack . intercalate [FP.searchPathSeparator] . view exeSearchPathL)
161-
, ( "Install location for GHC and other core tools"
161+
, ( "Install location for GHC and other core tools (see 'stack ls tools' command)"
162162
, "programs"
163163
, WithoutHaddocks $ view (configL.to configLocalPrograms.to toFilePathNoTrailingSep.to T.pack))
164164
, ( "Compiler binary (e.g. ghc)"

src/Stack/Setup.hs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import Data.Conduit.Lazy (lazyConsume)
4444
import qualified Data.Conduit.List as CL
4545
import Data.Conduit.Process.Typed (createSource)
4646
import Data.Conduit.Zlib (ungzip)
47-
import Data.Foldable (maximumBy)
4847
#if !MIN_VERSION_aeson(2,0,0)
4948
import qualified Data.HashMap.Strict as HashMap
5049
#endif
@@ -87,7 +86,10 @@ import Stack.Constants.Config (distRelativeDir)
8786
import Stack.GhcPkg (createDatabase, getGlobalDB, mkGhcPackagePath, ghcPkgPathEnvVar)
8887
import Stack.Prelude hiding (Display (..))
8988
import Stack.SourceMap
90-
import Stack.Setup.Installed
89+
import Stack.Setup.Installed (Tool (..), extraDirs, filterTools,
90+
installDir, getCompilerVersion,
91+
listInstalled, markInstalled, tempInstallDir,
92+
toolString, unmarkInstalled)
9193
import Stack.Storage.User (loadCompilerPaths, saveCompilerPaths)
9294
import Stack.Types.Build
9395
import Stack.Types.Compiler
@@ -1161,18 +1163,8 @@ getInstalledTool :: [Tool] -- ^ already installed
11611163
-> PackageName -- ^ package to find
11621164
-> (Version -> Bool) -- ^ which versions are acceptable
11631165
-> Maybe Tool
1164-
getInstalledTool installed name goodVersion =
1165-
if null available
1166-
then Nothing
1167-
else Just $ Tool $ maximumBy (comparing pkgVersion) available
1168-
where
1169-
available = mapMaybe goodPackage installed
1170-
goodPackage (Tool pi') =
1171-
if pkgName pi' == name &&
1172-
goodVersion (pkgVersion pi')
1173-
then Just pi'
1174-
else Nothing
1175-
goodPackage _ = Nothing
1166+
getInstalledTool installed name goodVersion = Tool <$>
1167+
maximumByMaybe (comparing pkgVersion) (filterTools name goodVersion installed)
11761168

11771169
downloadAndInstallTool :: (HasTerm env, HasBuildConfig env)
11781170
=> Path Abs Dir

src/Stack/Setup/Installed.hs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Stack.Setup.Installed
1515
, toolString
1616
, toolNameString
1717
, parseToolText
18+
, filterTools
1819
, extraDirs
1920
, installDir
2021
, tempInstallDir
@@ -40,6 +41,22 @@ data Tool
4041
| ToolGhcGit !Text !Text -- ^ e.g. ghc-git-COMMIT_ID-FLAVOUR
4142
deriving (Eq)
4243

44+
-- | 'Tool' values are ordered by name (being @ghc-git@, for @ToolGhcGit _ _@)
45+
-- alphabetically and then by version (later versions are ordered before
46+
-- earlier versions, where applicable).
47+
instance Ord Tool where
48+
compare (Tool pkgId1) (Tool pkgId2) = if pkgName1 == pkgName2
49+
then compare pkgVersion2 pkgVersion1 -- Later versions ordered first
50+
else compare pkgName1 pkgName2
51+
where
52+
PackageIdentifier pkgName1 pkgVersion1 = pkgId1
53+
PackageIdentifier pkgName2 pkgVersion2 = pkgId2
54+
compare (Tool pkgId) (ToolGhcGit _ _) = compare (pkgName pkgId) "ghc-git"
55+
compare (ToolGhcGit _ _) (Tool pkgId) = compare "ghc-git" (pkgName pkgId)
56+
compare (ToolGhcGit c1 f1) (ToolGhcGit c2 f2) = if f1 == f2
57+
then compare c1 c2
58+
else compare f1 f2
59+
4360
toolString :: Tool -> String
4461
toolString (Tool ident) = packageIdentifierString ident
4562
toolString (ToolGhcGit commit flavour) = "ghc-git-" ++ T.unpack commit ++ "-" ++ T.unpack flavour
@@ -83,6 +100,15 @@ listInstalled programsPath = do
83100
x <- T.stripSuffix ".installed" $ T.pack $ toFilePath $ filename fp
84101
parseToolText x
85102

103+
filterTools :: PackageName -- ^ package to find
104+
-> (Version -> Bool) -- ^ which versions are acceptable
105+
-> [Tool] -- ^ tools to filter
106+
-> [PackageIdentifier]
107+
filterTools name goodVersion installed =
108+
[ pkgId | Tool pkgId <- installed
109+
, pkgName pkgId == name
110+
, goodVersion (pkgVersion pkgId) ]
111+
86112
getCompilerVersion
87113
:: (HasProcessContext env, HasLogFunc env)
88114
=> WhichCompiler

src/main/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ commandLineHandler currentDir progName isInterpreter = complicatedOptions
242242
Stack.Path.path
243243
Stack.Path.pathParser
244244
addCommand' "ls"
245-
"List command. (Supports snapshots, dependencies and stack's styles)"
245+
"List command. (Supports snapshots, dependencies, stack's styles and installed tools)"
246246
lsCmd
247247
lsParser
248248
addCommand' "unpack"

0 commit comments

Comments
 (0)