@@ -30,7 +30,7 @@ import qualified Data.Text.Encoding as Text
30
30
import Control.Monad
31
31
import Control.Monad.Catch (Handler (.. )) -- would be nice if retry exported this itself
32
32
import Stack.Prelude hiding (Handler (.. ))
33
- import Control.Retry (recovering ,limitRetries ,RetryPolicy ,constantDelay )
33
+ import Control.Retry (recovering ,limitRetries ,RetryPolicy ,constantDelay , RetryStatus ( .. ) )
34
34
import Crypto.Hash
35
35
import Crypto.Hash.Conduit (sinkHash )
36
36
import Data.ByteArray as Mem (convert )
@@ -45,6 +45,8 @@ import Network.HTTP.Client (getUri, path)
45
45
import Network.HTTP.Simple (Request , HttpException , httpSink , getResponseHeaders )
46
46
import Network.HTTP.Types.Header (hContentLength , hContentMD5 )
47
47
import Path
48
+ import Stack.Types.Runner
49
+ import Stack.PrettyPrint
48
50
import System.Directory
49
51
import qualified System.FilePath as FP ((<.>) )
50
52
import System.IO (hFileSize )
@@ -179,21 +181,39 @@ hashChecksToZipSink :: MonadThrow m => Request -> [HashCheck] -> ZipSink ByteStr
179
181
hashChecksToZipSink req = traverse_ (ZipSink . sinkCheckHash req)
180
182
181
183
-- 'Control.Retry.recovering' customized for HTTP failures
182
- recoveringHttp :: MonadUnliftIO m
184
+ recoveringHttp :: ( MonadUnliftIO m , MonadLogger m , HasRunner env , MonadReader env m )
183
185
=> RetryPolicy -> m a -> m a
184
186
recoveringHttp retryPolicy =
185
187
#if MIN_VERSION_retry(0,7,0)
186
- helper $ recovering retryPolicy handlers . const
188
+ helper $ \ run -> recovering retryPolicy ( handlers run) . const
187
189
#else
188
- helper $ recovering retryPolicy handlers
190
+ helper $ \ run -> recovering retryPolicy ( handlers run)
189
191
#endif
190
192
where
191
- helper wrapper action = withRunInIO $ \ run -> wrapper (run action)
192
-
193
- handlers = [const $ Handler alwaysRetryHttp,const $ Handler retrySomeIO]
194
-
195
- alwaysRetryHttp :: Monad m => HttpException -> m Bool
196
- alwaysRetryHttp _ = return True
193
+ helper :: (MonadUnliftIO m , HasRunner env , MonadReader env m ) => (UnliftIO m -> IO a -> IO a ) -> m a -> m a
194
+ helper wrapper action = withUnliftIO $ \ run -> wrapper run (unliftIO run action)
195
+
196
+ handlers :: (MonadLogger m , HasRunner env , MonadReader env m ) => UnliftIO m -> [RetryStatus -> Handler IO Bool ]
197
+ handlers run = [Handler . alwaysRetryHttp (unliftIO run),const $ Handler retrySomeIO]
198
+
199
+ alwaysRetryHttp :: (MonadLogger m' , Monad m , HasRunner env , MonadReader env m' ) => (m' () -> m () ) -> RetryStatus -> HttpException -> m Bool
200
+ alwaysRetryHttp run rs _ = do
201
+ run $
202
+ prettyWarn $ vcat
203
+ [ flow $ unwords
204
+ [ " Retry number"
205
+ , show (rsIterNumber rs)
206
+ , " after a total delay of"
207
+ , show (rsCumulativeDelay rs)
208
+ , " us"
209
+ ]
210
+ , flow $ unwords
211
+ [ " If you see this warning and stack fails to download,"
212
+ , " but running the command again solves the problem,"
213
+ , " please report here: https://github.com/commercialhaskell/stack/issues/3510"
214
+ ]
215
+ ]
216
+ return True
197
217
198
218
retrySomeIO :: Monad m => IOException -> m Bool
199
219
retrySomeIO e = return $ case ioe_type e of
@@ -215,7 +235,7 @@ recoveringHttp retryPolicy =
215
235
-- Throws VerifiedDownloadException.
216
236
-- Throws IOExceptions related to file system operations.
217
237
-- Throws HttpException.
218
- verifiedDownload :: (MonadIO m , MonadLogger m )
238
+ verifiedDownload :: (MonadUnliftIO m , MonadLogger m , HasRunner env , MonadReader env m )
219
239
=> DownloadRequest
220
240
-> Path Abs File -- ^ destination
221
241
-> (Maybe Integer -> Sink ByteString IO () ) -- ^ custom hook to observe progress
@@ -224,12 +244,11 @@ verifiedDownload DownloadRequest{..} destpath progressSink = do
224
244
let req = drRequest
225
245
whenM' (liftIO getShouldDownload) $ do
226
246
logDebug $ " Downloading " <> decodeUtf8With lenientDecode (path req)
227
- liftIO $ do
228
- createDirectoryIfMissing True dir
229
- recoveringHttp drRetryPolicy $
230
- withBinaryFile fptmp WriteMode $ \ h ->
231
- httpSink req (go h)
232
- renameFile fptmp fp
247
+ liftIO $ createDirectoryIfMissing True dir
248
+ recoveringHttp drRetryPolicy $ liftIO $
249
+ withBinaryFile fptmp WriteMode $ \ h ->
250
+ httpSink req (go h)
251
+ liftIO $ renameFile fptmp fp
233
252
where
234
253
whenM' mp m = do
235
254
p <- mp
0 commit comments