@@ -20,33 +20,100 @@ private[sbt] object Retry {
2020 try System .getProperty(" sbt.io.retry.limit" , defaultLimit.toString).toInt
2121 catch { case NonFatal (_) => defaultLimit }
2222 }
23+ private final val defaultSleepInMillis = 100
24+
25+ /**
26+ * Retry on all non-fatal exceptions that are NOT listed in
27+ * the excludedExceptions list.
28+ */
2329 private [sbt] def apply [@ specialized T ](f : => T , excludedExceptions : Class [? <: Throwable ]* ): T =
2430 apply(f, limit, excludedExceptions : _* )
31+
32+ /**
33+ * Retry on all non-fatal exceptions that are NOT listed in
34+ * the excludedExceptions list.
35+ */
2536 private [sbt] def apply [@ specialized T ](
2637 f : => T ,
2738 limit : Int ,
2839 excludedExceptions : Class [? <: Throwable ]* ,
29- ): T = apply(f, limit, 100 , excludedExceptions : _* )
40+ ): T = apply(f, limit, defaultSleepInMillis, excludedExceptions : _* )
41+
42+ /**
43+ * Retry on all non-fatal exceptions that are NOT listed in
44+ * the excludedExceptions list.
45+ */
3046 private [sbt] def apply [@ specialized T ](
3147 f : => T ,
3248 limit : Int ,
3349 sleepInMillis : Long ,
3450 excludedExceptions : Class [? <: Throwable ]* ,
3551 ): T = {
36- require(limit >= 1 , " limit must be 1 or higher: was: " + limit)
37- def filter (e : Throwable ): Boolean = excludedExceptions match {
52+ def allowRetry (e : Throwable ): Boolean = excludedExceptions match {
3853 case s if s.nonEmpty =>
3954 ! excludedExceptions.exists(_.isAssignableFrom(e.getClass))
4055 case _ =>
4156 true
4257 }
58+ impl(limit = limit, sleepInMillis = sleepInMillis)(allowRetry)(f)
59+ }
60+
61+ /**
62+ * Retry on all IOExceptions that are NOT listed in
63+ * the excludedExceptions list.
64+ * Non-IOException will immediately throw.
65+ */
66+ private [sbt] def io [@ specialized A1 ](f : => A1 , excludedExceptions : Class [? <: IOException ]* ): A1 =
67+ io(f, limit, excludedExceptions : _* )
68+
69+ /**
70+ * Retry on all IOExceptions that are NOT listed in
71+ * the excludedExceptions list.
72+ * Non-IOException will immediately throw.
73+ */
74+ private [sbt] def io [@ specialized A1 ](
75+ f : => A1 ,
76+ limit : Int ,
77+ excludedExceptions : Class [? <: IOException ]* ,
78+ ): A1 = io(f, limit, defaultSleepInMillis, excludedExceptions : _* )
79+
80+ /**
81+ * Retry on all IOExceptions that are NOT listed in
82+ * the excludedExceptions list.
83+ * Non-IOException will immediately throw.
84+ */
85+ private [sbt] def io [@ specialized A1 ](
86+ f : => A1 ,
87+ limit : Int ,
88+ sleepInMillis : Long ,
89+ excludedExceptions : Class [? <: IOException ]* ,
90+ ): A1 = {
91+ def allowRetry (e : Throwable ): Boolean =
92+ e match {
93+ case ioe : IOException =>
94+ excludedExceptions match {
95+ case s if s.nonEmpty =>
96+ ! excludedExceptions.exists(_.isAssignableFrom(ioe.getClass))
97+ case _ =>
98+ true
99+ }
100+ case _ => false
101+ }
102+ impl(limit = limit, sleepInMillis = sleepInMillis)(allowRetry)(f)
103+ }
104+
105+ private def impl [@ specialized A1 ](
106+ limit : Int ,
107+ sleepInMillis : Long ,
108+ )(allowRetry : Throwable => Boolean )(f : => A1 ): A1 = {
109+ require(limit >= 1 , " limit must be 1 or higher: was: " + limit)
43110 var attempt = 1
44111 var firstException : Throwable = null
45112 while (attempt <= limit) {
46113 try {
47114 return f
48115 } catch {
49- case NonFatal (e) if filter (e) =>
116+ case NonFatal (e) if allowRetry (e) =>
50117 if (firstException == null ) firstException = e
51118 // https://github.com/sbt/io/issues/295
52119 // On Windows, we're seeing java.nio.file.AccessDeniedException with sleep(0).
0 commit comments