@@ -158,6 +158,75 @@ public boolean changesSince(@CheckForNull SCMRevision revision, @NonNull OutputS
158158 throw new UnsupportedOperationException ();
159159 }
160160
161+ /**
162+ * Given a {@link SCM} this method will try to retrieve a corresponding {@link SCMFileSystem} instance.
163+ *
164+ * @param build the build of the {@link SCM}
165+ * @param scm the {@link SCM}.
166+ * @return the corresponding {@link SCMFileSystem} or {@code null} if there is none.
167+ * @throws IOException if the attempt to create a {@link SCMFileSystem} failed due to an IO error
168+ * (such as the remote system being unavailable)
169+ * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted.
170+ */
171+ @ CheckForNull
172+ public static SCMFileSystem of (@ NonNull Run build , @ NonNull SCM scm ) throws IOException , InterruptedException {
173+ return of (build , scm , null );
174+ }
175+
176+ /**
177+ * Given a {@link SCM} this method will try to retrieve a corresponding {@link SCMFileSystem} instance that
178+ * reflects the content at the specified {@link SCMRevision}.
179+ *
180+ * @param build the build of the {@link SCM}
181+ * @param scm the {@link SCM}.
182+ * @param rev the specified {@link SCMRevision}.
183+ * @return the corresponding {@link SCMFileSystem} or {@code null} if there is none.
184+ * @throws IOException if the attempt to create a {@link SCMFileSystem} failed due to an IO error
185+ * (such as the remote system being unavailable)
186+ * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted.
187+ */
188+ @ CheckForNull
189+ public static SCMFileSystem of (@ NonNull Run build , @ NonNull SCM scm , @ CheckForNull SCMRevision rev )
190+ throws IOException , InterruptedException {
191+ Objects .requireNonNull (scm );
192+ SCMFileSystem fallBack = null ;
193+ Throwable failure = null ;
194+ for (Builder b : ExtensionList .lookup (Builder .class )) {
195+ if (b .supports (scm )) {
196+ try {
197+ SCMFileSystem inspector = b .build (build , scm , rev );
198+ if (inspector != null ) {
199+ if (inspector .isFixedRevision ()) {
200+ return inspector ;
201+ }
202+ if (fallBack == null ) {
203+ fallBack = inspector ;
204+ }
205+ }
206+ } catch (IOException | InterruptedException | RuntimeException e ) {
207+ if (failure == null ) {
208+ failure = e ;
209+ } else {
210+ failure .addSuppressed (e );
211+ }
212+ }
213+ }
214+ }
215+ if (fallBack == null ) {
216+ if (failure instanceof IOException ) {
217+ throw (IOException ) failure ;
218+ }
219+ if (failure instanceof InterruptedException ) {
220+ throw (InterruptedException ) failure ;
221+ }
222+ //noinspection ConstantConditions
223+ if (failure instanceof RuntimeException ) {
224+ throw (RuntimeException ) failure ;
225+ }
226+ }
227+ return fallBack ;
228+ }
229+
161230 /**
162231 * Given a {@link SCM} this method will try to retrieve a corresponding {@link SCMFileSystem} instance.
163232 *
@@ -483,6 +552,25 @@ public final boolean supports(SCMSourceDescriptor descriptor) {
483552 */
484553 protected abstract boolean supportsDescriptor (SCMSourceDescriptor descriptor );
485554
555+ /**
556+ * Given a {@link SCM} this should try to build a corresponding {@link SCMFileSystem} instance that
557+ * reflects the content at the specified {@link SCMRevision}. If the {@link SCM} is supported but not
558+ * for a fixed revision, best effort is acceptable as the most capable {@link SCMFileSystem} will be returned
559+ * to the caller.
560+ *
561+ * @param build the build of the {@link SCM}
562+ * @param scm the {@link SCM}.
563+ * @param rev the specified {@link SCMRevision}.
564+ * @return the corresponding {@link SCMFileSystem} or {@code null} if this builder cannot create a {@link
565+ * SCMFileSystem} for the specified {@link SCM}.
566+ * @throws IOException if the attempt to create a {@link SCMFileSystem} failed due to an IO error
567+ * (such as the remote system being unavailable)
568+ * @throws InterruptedException if the attempt to create a {@link SCMFileSystem} was interrupted.
569+ */
570+ @ CheckForNull
571+ public abstract SCMFileSystem build (@ NonNull Run build , @ NonNull SCM scm , @ CheckForNull SCMRevision rev )
572+ throws IOException , InterruptedException ;
573+
486574 /**
487575 * Given a {@link SCM} this should try to build a corresponding {@link SCMFileSystem} instance that
488576 * reflects the content at the specified {@link SCMRevision}. If the {@link SCM} is supported but not
0 commit comments