-
Notifications
You must be signed in to change notification settings - Fork 848
Introduce new sub command ls #3252
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
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
a1a43d1
Add ls subcommand
psibi 8bec20e
Implement the module implementing the relevant features
psibi 7d87e87
Expose the module
psibi e7910e5
Code cleanup
psibi c8d4bad
More cleanup and some formatting done
psibi 91b0dab
Handle exception scenario
psibi 3e3ce5f
Update to the stackage server url
psibi e4b400c
Improve help messages
psibi 9e50072
Update Changelog
psibi 5798286
Try fixing build error in stack-7.10 yaml environment
psibi bcb7f75
Lower constraint because of process dependency
psibi 0e14de9
Hlint style fixes
psibi 9947d9e
Only export lsCmd and lsParser
psibi ef9aa32
Fix another hlint failure
psibi d517832
Add no warn for unused-top-binds
psibi fa7fb8b
Fix warning at the code level itself
psibi 99edd1b
Also add tls setting add stackage is https
psibi f5f5272
Merge remote-tracking branch 'upstream/master' into stack-ls
psibi 1c92ae5
Have working code based on the feedback.
psibi 7c0e567
Expose Stack.Ls
psibi 1dea318
Cleanup code
psibi 0eb4078
Use pager implementation
psibi fef2443
Remove dead code and do cleanup
psibi 28f11ff
Change help message
psibi 5cd1db7
Fix hlint style issues
psibi a9f9bd1
Merge remote-tracking branch 'upstream/master' into stack-ls
psibi 54e97c7
Merge remote-tracking branch 'upstream/master' into stack-ls
psibi d412dbb
By default, use Local snapshot if none specified
psibi 19d880b
Add pageText to stream Text via pager
psibi 1f8d99b
More changes to ls sub-command
psibi b29dbed
Update changelog
psibi 16e5b25
Fix hlint style issues
psibi 947cbc8
Remove API change from changelog
psibi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,238 @@ | ||
| {-# LANGUAGE OverloadedStrings #-} | ||
| {-# LANGUAGE RecordWildCards #-} | ||
| {-# LANGUAGE ScopedTypeVariables #-} | ||
|
|
||
| module Stack.Ls | ||
| ( lsCmd | ||
| , lsParser | ||
| ) where | ||
|
|
||
| import Control.Exception (Exception, throw) | ||
| import Control.Monad.Catch (MonadThrow) | ||
| import Control.Monad.IO.Class (MonadIO, liftIO) | ||
| import Control.Monad.Reader (MonadReader) | ||
| import Data.Aeson | ||
| import Stack.Types.Runner | ||
| import qualified Data.Aeson.Types as A | ||
| import qualified Data.List as L | ||
| import Data.Monoid | ||
| import Data.Text hiding (pack, intercalate) | ||
| import qualified Data.Text as T | ||
| import qualified Data.Text.IO as T | ||
| import Data.Typeable (Typeable) | ||
| import qualified Data.Vector as V | ||
| import Network.HTTP.Simple | ||
| (addRequestHeader, getResponseBody, httpJSON, parseRequest, | ||
| setRequestManager) | ||
| import Network.HTTP.Types.Header (hAccept) | ||
| import qualified Options.Applicative as OA | ||
| import Options.Applicative ((<|>)) | ||
| import Path | ||
| import Stack.Runners (withBuildConfig) | ||
| import Stack.Types.Config | ||
| import System.Process.PagerEditor (pageText) | ||
| import System.Directory (listDirectory) | ||
| import Network.HTTP.Client.TLS (getGlobalManager) | ||
|
|
||
| data LsView | ||
| = Local | ||
| | Remote | ||
| deriving (Show, Eq, Ord) | ||
|
|
||
| data SnapshotType | ||
| = Lts | ||
| | Nightly | ||
| deriving (Show, Eq, Ord) | ||
|
|
||
| newtype LsCmds = | ||
| LsSnapshot SnapshotOpts | ||
| deriving (Eq, Show, Ord) | ||
|
|
||
| data SnapshotOpts = SnapshotOpts | ||
| { soptViewType :: LsView | ||
| , soptLtsSnapView :: Bool | ||
| , soptNightlySnapView :: Bool | ||
| } deriving (Eq, Show, Ord) | ||
|
|
||
| newtype LsCmdOpts = LsCmdOpts | ||
| { lsView :: LsCmds | ||
| } deriving (Eq, Show, Ord) | ||
|
|
||
| lsParser :: OA.Parser LsCmdOpts | ||
| lsParser = LsCmdOpts <$> OA.hsubparser lsSnapCmd | ||
|
|
||
| lsCmdOptsParser :: OA.Parser LsCmds | ||
| lsCmdOptsParser = fmap LsSnapshot lsViewSnapCmd | ||
|
|
||
| lsViewSnapCmd :: OA.Parser SnapshotOpts | ||
| lsViewSnapCmd = | ||
| SnapshotOpts <$> | ||
| (OA.hsubparser (lsViewRemoteCmd <> lsViewLocalCmd) <|> pure Local) <*> | ||
| OA.switch | ||
| (OA.long "lts" <> OA.short 'l' <> OA.help "Only show lts snapshots") <*> | ||
| OA.switch | ||
| (OA.long "nightly" <> OA.short 'n' <> | ||
| OA.help "Only show nightly snapshots") | ||
|
|
||
| lsSnapCmd :: OA.Mod OA.CommandFields LsCmds | ||
| lsSnapCmd = | ||
| OA.command | ||
| "snapshots" | ||
| (OA.info | ||
| lsCmdOptsParser | ||
| (OA.progDesc "View local snapshot (default option)")) | ||
|
|
||
| data Snapshot = Snapshot | ||
| { snapId :: Text | ||
| , snapTitle :: Text | ||
| , snapTime :: Text | ||
| } deriving (Show, Eq, Ord) | ||
|
|
||
| data SnapshotData = SnapshotData | ||
| { _snapTotalCounts :: Integer | ||
| , snaps :: [[Snapshot]] | ||
| } deriving (Show, Eq, Ord) | ||
|
|
||
| instance FromJSON Snapshot where | ||
| parseJSON o@(Array _) = parseSnapshot o | ||
| parseJSON _ = mempty | ||
|
|
||
| instance FromJSON SnapshotData where | ||
| parseJSON (Object s) = | ||
| SnapshotData <$> s .: "totalCount" <*> s .: "snapshots" | ||
| parseJSON _ = mempty | ||
|
|
||
| toSnapshot :: [Value] -> Snapshot | ||
| toSnapshot [String sid, String stitle, String stime] = | ||
| Snapshot | ||
| { snapId = sid | ||
| , snapTitle = stitle | ||
| , snapTime = stime | ||
| } | ||
| toSnapshot val = throw $ ParseFailure val | ||
|
|
||
| newtype LsException = | ||
| ParseFailure [Value] | ||
| deriving (Show, Typeable) | ||
|
|
||
| instance Exception LsException | ||
|
|
||
| parseSnapshot :: Value -> A.Parser Snapshot | ||
| parseSnapshot = A.withArray "array of snapshot" (return . toSnapshot . V.toList) | ||
|
|
||
| displayTime :: Snapshot -> [Text] | ||
| displayTime Snapshot {..} = [snapTime] | ||
|
|
||
| displaySnap :: Snapshot -> [Text] | ||
| displaySnap Snapshot {..} = | ||
| ["Resolver name: " <> snapId, "\n" <> snapTitle <> "\n\n"] | ||
|
|
||
| displaySingleSnap :: [Snapshot] -> Text | ||
| displaySingleSnap snapshots = | ||
| case snapshots of | ||
| [] -> mempty | ||
| (x:xs) -> | ||
| let snaps = | ||
| displayTime x <> ["\n\n"] <> displaySnap x <> | ||
| L.concatMap displaySnap xs | ||
| in T.concat snaps | ||
|
|
||
| renderData :: Bool -> Text -> IO () | ||
| renderData True content = pageText content | ||
| renderData False content = T.putStr content | ||
|
|
||
| displaySnapshotData :: Bool -> SnapshotData -> IO () | ||
| displaySnapshotData term sdata = | ||
| case L.reverse $ snaps sdata of | ||
| [] -> return () | ||
| xs -> | ||
| let snaps = T.concat $ L.map displaySingleSnap xs | ||
| in renderData term snaps | ||
|
|
||
| filterSnapshotData :: SnapshotData -> SnapshotType -> SnapshotData | ||
| filterSnapshotData sdata stype = | ||
| sdata | ||
| { snaps = filterSnapData | ||
| } | ||
| where | ||
| snapdata = snaps sdata | ||
| filterSnapData = | ||
| case stype of | ||
| Lts -> L.map (L.filter (\x -> "lts" `isPrefixOf` snapId x)) snapdata | ||
| Nightly -> | ||
| L.map (L.filter (\x -> "nightly" `isPrefixOf` snapId x)) snapdata | ||
|
|
||
| displayLocalSnapshot :: Bool -> [String] -> IO () | ||
| displayLocalSnapshot term xs = renderData term (localSnaptoText xs) | ||
|
|
||
| localSnaptoText :: [String] -> Text | ||
| localSnaptoText xs = T.intercalate "\n" $ L.map T.pack xs | ||
|
|
||
| handleLocal | ||
| :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env) | ||
| => LsCmdOpts -> m () | ||
| handleLocal lsOpts = do | ||
| (instRoot :: Path Abs Dir) <- installationRootDeps | ||
| isStdoutTerminal <- view terminalL | ||
| let snapRootDir = parent $ parent instRoot | ||
| snapData' <- liftIO $ listDirectory $ toFilePath snapRootDir | ||
| let snapData = L.sort snapData' | ||
| case lsView lsOpts of | ||
| LsSnapshot SnapshotOpts {..} -> | ||
| case (soptLtsSnapView, soptNightlySnapView) of | ||
| (True, False) -> | ||
| liftIO $ | ||
| displayLocalSnapshot isStdoutTerminal $ | ||
| L.filter (L.isPrefixOf "lts") snapData | ||
| (False, True) -> | ||
| liftIO $ | ||
| displayLocalSnapshot isStdoutTerminal $ | ||
| L.filter (L.isPrefixOf "night") snapData | ||
| _ -> liftIO $ displayLocalSnapshot isStdoutTerminal snapData | ||
|
|
||
| handleRemote | ||
| :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env) | ||
| => LsCmdOpts -> m () | ||
| handleRemote lsOpts = do | ||
| req <- liftIO $ parseRequest urlInfo | ||
| mgr <- liftIO getGlobalManager | ||
| isStdoutTerminal <- view terminalL | ||
| let req' = | ||
| setRequestManager mgr $ | ||
| addRequestHeader hAccept "application/json" req | ||
| result <- httpJSON req' | ||
| let snapData = getResponseBody result | ||
| case lsView lsOpts of | ||
| LsSnapshot SnapshotOpts {..} -> | ||
| case (soptLtsSnapView, soptNightlySnapView) of | ||
| (True, False) -> | ||
| liftIO $ | ||
| displaySnapshotData isStdoutTerminal $ | ||
| filterSnapshotData snapData Lts | ||
| (False, True) -> | ||
| liftIO $ | ||
| displaySnapshotData isStdoutTerminal $ | ||
| filterSnapshotData snapData Nightly | ||
| _ -> liftIO $ displaySnapshotData isStdoutTerminal snapData | ||
| where | ||
| urlInfo = "https://www.stackage.org/snapshots" | ||
|
|
||
| lsCmd :: LsCmdOpts -> GlobalOpts -> IO () | ||
| lsCmd lsOpts go = | ||
| case lsView lsOpts of | ||
| LsSnapshot SnapshotOpts {..} -> | ||
| case soptViewType of | ||
| Local -> withBuildConfig go (handleLocal lsOpts) | ||
| Remote -> withBuildConfig go (handleRemote lsOpts) | ||
|
|
||
| lsViewLocalCmd :: OA.Mod OA.CommandFields LsView | ||
| lsViewLocalCmd = | ||
| OA.command | ||
| "local" | ||
| (OA.info (pure Local) (OA.progDesc "View local snapshot")) | ||
|
|
||
| lsViewRemoteCmd :: OA.Mod OA.CommandFields LsView | ||
| lsViewRemoteCmd = | ||
| OA.command | ||
| "remote" | ||
| (OA.info (pure Remote) (OA.progDesc "View remote snapshot")) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be
list-snapshots. There is already some precedent here, withlist-dependencies.How about the default for
stack list-snapshotsfirst displaying the remote snapshots, and then displaying the local snapshots. Then, can havestack list-snapshots remoteandstack list-snapshots local, particularly useful for when a script wants to access this info.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgsloan As mentioned by Harendra here,
lsis the umberlla command.dependencieswill be made to work under this interface ( I can work on this - after the PR get's merged)Display
remotesnapshots involves an HTTP call and I want to avoid doing that by default. By default, I'm planning to show thelocalsnapshots and then have different options for displaying each of them. Let me know if you think otherwise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I had not read those comments recently. Ok, I am fine with doing it that way.