1+ using Semmle . Util ;
12using Semmle . Util . Logging ;
23using System ;
34using System . Collections . Generic ;
@@ -238,6 +239,8 @@ protected Autobuilder(IBuildActions actions, TAutobuildOptions options)
238239 TrapDir = RequireEnvironmentVariable ( EnvVars . TrapDir ( this . Options . Language ) ) ;
239240 SourceArchiveDir = RequireEnvironmentVariable ( EnvVars . SourceArchiveDir ( this . Options . Language ) ) ;
240241 DiagnosticsDir = RequireEnvironmentVariable ( EnvVars . DiagnosticDir ( this . Options . Language ) ) ;
242+
243+ this . diagnostics = DiagnosticsStream . ForFile ( Path . Combine ( DiagnosticsDir , $ "autobuilder-{ DateTime . UtcNow : yyyyMMddHHmm} .jsonc") ) ;
241244 }
242245
243246 /// <summary>
@@ -263,6 +266,8 @@ protected string RequireEnvironmentVariable(string name)
263266
264267 private readonly ILogger logger = new ConsoleLogger ( Verbosity . Info ) ;
265268
269+ private readonly DiagnosticsStream diagnostics ;
270+
266271 /// <summary>
267272 /// Log a given build event to the console.
268273 /// </summary>
@@ -273,6 +278,15 @@ public void Log(Severity severity, string format, params object[] args)
273278 logger . Log ( severity , format , args ) ;
274279 }
275280
281+ /// <summary>
282+ /// Write <paramref name="diagnostic"/> to the diagnostics file.
283+ /// </summary>
284+ /// <param name="diagnostic">The diagnostics entry to write.</param>
285+ public void Diagnostic ( DiagnosticMessage diagnostic )
286+ {
287+ diagnostics . AddEntry ( diagnostic ) ;
288+ }
289+
276290 /// <summary>
277291 /// Attempt to build this project.
278292 /// </summary>
@@ -304,10 +318,48 @@ void exitCallback(int ret, string msg, bool silent)
304318 /// </summary>
305319 public abstract BuildScript GetBuildScript ( ) ;
306320
321+ /// <summary>
322+ /// Constructs a standard <see cref="DiagnosticMessage.TspSource" /> for some message
323+ /// <see cref="id" /> with a human-friendly <see cref="name" />.
324+ /// </summary>
325+ /// <param name="id">The last part of the message id.</param>
326+ /// <param name="name">The human-friendly description of the message.</param>
327+ /// <returns>The resulting <see cref="DiagnosticMessage.TspSource" />.</returns>
328+ protected DiagnosticMessage . TspSource GetDiagnosticSource ( string id , string name ) =>
329+ new ( $ "{ this . Options . Language . UpperCaseName . ToLower ( ) } /autobuilder/{ id } ", name ) ;
330+
331+ /// <summary>
332+ /// Produces a diagnostic for the tool status page that we were unable to automatically
333+ /// build the user's project and that they can manually specify a build command. This
334+ /// can be overriden to implement more specific messages depending on the origin of
335+ /// the failure.
336+ /// </summary>
337+ protected virtual void AutobuildFailureDiagnostic ( )
338+ {
339+ var message = new DiagnosticMessage ( GetDiagnosticSource ( "autobuild-failure" , "Unable to build project" ) )
340+ {
341+ PlaintextMessage =
342+ "We were unable to automatically build your project. " +
343+ "You can manually specify a suitable build command for your project." ,
344+ Severity = DiagnosticMessage . TspSeverity . Error
345+ } ;
346+
347+ Diagnostic ( message ) ;
348+ }
349+
350+ /// <summary>
351+ /// Returns a build script that can be run upon autobuild failure.
352+ /// </summary>
353+ /// <returns>
354+ /// A build script that reports that we could not automatically detect a suitable build method.
355+ /// </returns>
307356 protected BuildScript AutobuildFailure ( ) =>
308357 BuildScript . Create ( actions =>
309358 {
310359 Log ( Severity . Error , "Could not auto-detect a suitable build method" ) ;
360+
361+ AutobuildFailureDiagnostic ( ) ;
362+
311363 return 1 ;
312364 } ) ;
313365
0 commit comments