@@ -46,9 +46,10 @@ import Data.Text.Metrics (damerauLevenshteinNorm)
46
46
import Data.Time (UTCTime , defaultTimeLocale , formatTime , readPTime , rfc822DateFormat )
47
47
import Data.Time.Clock.POSIX (getPOSIXTime )
48
48
import Data.Traversable (for )
49
- import Fmt (Buildable (.. ), Builder , fmt , maybeF , nameF )
49
+ import Fmt (Buildable (.. ), Builder , fmt , fmtLn , maybeF , nameF )
50
50
import GHC.Exts qualified as Exts
51
51
import GHC.Read (Read (readPrec ))
52
+ import Network.Connection qualified as N.C
52
53
import Network.FTP.Client
53
54
(FTPException (.. ), FTPResponse (.. ), ResponseStatus (.. ), login , nlst , size , withFTP , withFTPS )
54
55
import Network.HTTP.Client
@@ -107,13 +108,6 @@ data WithReferenceLoc a = WithReferenceLoc
107
108
, wrlItem :: a
108
109
}
109
110
110
- instance (Given ColorMode , Buildable a ) => Buildable (WithReferenceLoc a ) where
111
- build WithReferenceLoc {.. } = [int ||
112
- In file #{styleIfNeeded Faint (styleIfNeeded Bold wrlFile)}
113
- bad #{wrlReference}
114
- #{wrlItem}
115
- |]
116
-
117
111
-- | Contains a name of a domain, examples:
118
112
-- @DomainName "github.com"@,
119
113
-- @DomainName "localhost"@,
@@ -137,6 +131,7 @@ data VerifyError
137
131
| ExternalFtpException FTPException
138
132
| FtpEntryDoesNotExist FilePath
139
133
| ExternalResourceSomeError Text
134
+ | ExternalResourceConnectionFailure
140
135
| RedirectChainCycle RedirectChain
141
136
| RedirectMissingLocation RedirectChain
142
137
| RedirectChainLimit RedirectChain
@@ -147,8 +142,8 @@ data ResponseResult
147
142
= RRDone
148
143
| RRFollow Text
149
144
150
- instance Given ColorMode => Buildable VerifyError where
151
- build = \ case
145
+ pprVerifyErr' :: Given ColorMode => VerifyError -> Builder
146
+ pprVerifyErr' = \ case
152
147
LocalFileDoesNotExist file ->
153
148
[int ||
154
149
File does not exist:
@@ -256,6 +251,11 @@ instance Given ColorMode => Buildable VerifyError where
256
251
#{err}
257
252
|]
258
253
254
+ ExternalResourceConnectionFailure ->
255
+ [int ||
256
+ Connection failure
257
+ |]
258
+
259
259
RedirectChainCycle chain ->
260
260
[int ||
261
261
Cycle found in the following redirect chain:
@@ -304,15 +304,48 @@ incTotalCounter rc = rc {rcTotalRetries = rcTotalRetries rc + 1}
304
304
incTimeoutCounter :: RetryCounter -> RetryCounter
305
305
incTimeoutCounter rc = rc {rcTimeoutRetries = rcTimeoutRetries rc + 1 }
306
306
307
+ pprVerifyErr :: Given ColorMode => WithReferenceLoc VerifyError -> Builder
308
+ pprVerifyErr wrl = hdr <> " \n " <> interpolateIndentF 2 msg
309
+ where
310
+ WithReferenceLoc {wrlFile, wrlReference, wrlItem} = wrl
311
+ Reference {rName, rInfo} = wrlReference
312
+
313
+ hdr , msg :: Builder
314
+ hdr =
315
+ styleIfNeeded Bold (build wrlFile <> " :" <> build (rPos wrlReference) <> " : " ) <>
316
+ colorIfNeeded Red " bad reference:"
317
+ msg =
318
+ " The reference to " <> show rName <> " failed verification.\n " <>
319
+ mconcat (map (\ info -> " - " <> info <> " \n " ) ref_infos) <>
320
+ pprVerifyErr' wrlItem
321
+
322
+ ref_infos :: [Builder ]
323
+ ref_infos = case rInfo of
324
+ RIFile ReferenceInfoFile {.. } ->
325
+ case rifLink of
326
+ FLLocal ->
327
+ case rifAnchor of
328
+ Nothing -> []
329
+ Just anc -> [" anchor " <> paren (styleIfNeeded Faint " file-local" ) <> " : " <> build anc]
330
+ FLRelative link ->
331
+ [" link " <> paren (styleIfNeeded Faint " relative" ) <> " : " <> build link] ++
332
+ (case rifAnchor of
333
+ Nothing -> []
334
+ Just anc -> [" anchor: " <> build anc])
335
+ FLAbsolute link ->
336
+ [" link " <> paren (styleIfNeeded Faint " absolute" ) <> " : " <> build link] ++
337
+ (case rifAnchor of
338
+ Nothing -> []
339
+ Just anc -> [" anchor: " <> build anc])
340
+ RIExternal (ELUrl url) -> [" link " <> paren (styleIfNeeded Faint " external" ) <> " : " <> build url]
341
+ RIExternal (ELOther url) -> [" link: " <> build url]
342
+
307
343
reportVerifyErrs
308
344
:: Given ColorMode => NonEmpty (WithReferenceLoc VerifyError ) -> IO ()
309
- reportVerifyErrs errs = fmt
310
- [int ||
311
- === Invalid references found ===
312
-
313
- #{interpolateIndentF 2 (interpolateBlockListF' "➥ " build errs)}
314
- Invalid references dumped, #{length errs} in total.
315
- |]
345
+ reportVerifyErrs errs = do
346
+ traverse_ (fmtLn . pprVerifyErr) errs
347
+ fmtLn $ colorIfNeeded Red $
348
+ " Invalid references dumped, " <> build (length errs) <> " in total."
316
349
317
350
data RetryAfter = Date UTCTime | Seconds (Time Second )
318
351
deriving stock (Show , Eq )
@@ -708,7 +741,7 @@ checkExternalResource followed config@Config{..} link
708
741
let maxTime = Time @ Second $ unTime ncExternalRefCheckTimeout * timeoutFrac
709
742
710
743
reqRes <- catch (liftIO (timeout maxTime $ reqLink $> RRDone )) $
711
- (Just <$> ) <$> interpretErrors uri
744
+ (Just <$> ) <$> interpretHttpErrors uri
712
745
713
746
case reqRes of
714
747
Nothing -> throwError $ ExternalHttpTimeout $ extractHost uri
@@ -730,9 +763,13 @@ checkExternalResource followed config@Config{..} link
730
763
, (405 == ) -- method mismatch
731
764
]
732
765
733
- interpretErrors uri = \ case
766
+ interpretHttpErrors :: URI -> Network.HTTP.Req. HttpException -> ExceptT VerifyError IO ResponseResult
767
+ interpretHttpErrors uri = \ case
734
768
JsonHttpException _ -> error " External link JSON parse exception"
735
- VanillaHttpException err -> case err of
769
+ VanillaHttpException err -> interpretHttpErrors' uri err
770
+
771
+ interpretHttpErrors' :: URI -> Network.HTTP.Client. HttpException -> ExceptT VerifyError IO ResponseResult
772
+ interpretHttpErrors' uri = \ case
736
773
InvalidUrlException {} -> error " External link URL invalid exception"
737
774
HttpExceptionRequest _ exc -> case exc of
738
775
StatusCodeException resp _
@@ -765,6 +802,12 @@ checkExternalResource followed config@Config{..} link
765
802
redirectLocation = fmap decodeUtf8
766
803
. lookup " Location"
767
804
$ responseHeaders resp
805
+
806
+ ConnectionFailure _ -> throwError ExternalResourceConnectionFailure
807
+ InternalException e
808
+ | Just (N.C. HostCannotConnect _ _) <- fromException e
809
+ -> throwError ExternalResourceConnectionFailure
810
+
768
811
other -> throwError $ ExternalResourceSomeError $ show other
769
812
where
770
813
retryAfterInfo :: Response a -> Maybe RetryAfter
0 commit comments