Skip to content

Commit

Permalink
Implemented debugging support for roslyn script sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorkstromm committed May 9, 2016
1 parent b7400a6 commit 659c665
Show file tree
Hide file tree
Showing 29 changed files with 778 additions and 39 deletions.
2 changes: 2 additions & 0 deletions src/Cake.Tests/Cake.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<Compile Include="Extensions\StreamReaderExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Fixtures\ArgumentParserFixture.cs" />
<Compile Include="Fixtures\DebugScriptHostFixture.cs" />
<Compile Include="Fixtures\CakeApplicationFixture.cs" />
<Compile Include="Fixtures\MonoScriptProcessorFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand All @@ -79,6 +80,7 @@
<Compile Include="Unit\CakeReportPrinterTests.cs" />
<Compile Include="Unit\Diagnostics\CakeBuildLogTests.cs" />
<Compile Include="Unit\Diagnostics\FormatParserTests.cs" />
<Compile Include="Unit\Scripting\DebugScriptHostTests.cs" />
<Compile Include="Unit\Scripting\BuildScriptHostTests.cs">
<SubType>Code</SubType>
</Compile>
Expand Down
36 changes: 36 additions & 0 deletions src/Cake.Tests/Fixtures/DebugScriptHostFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Cake.Core;
using Cake.Core.Diagnostics;
using Cake.Diagnostics;
using Cake.Scripting;
using NSubstitute;

namespace Cake.Tests.Fixtures
{
internal sealed class DebugScriptHostFixture
{
public ICakeEngine Engine { get; set; }
public ICakeContext Context { get; set; }
public ICakeReportPrinter Printer { get; set; }
public ICakeLog Log { get; set; }
public IDebugger Debugger { get; set; }

public DebugScriptHostFixture()
{
Engine = Substitute.For<ICakeEngine>();
Context = Substitute.For<ICakeContext>();
Printer = Substitute.For<ICakeReportPrinter>();
Log = Substitute.For<ICakeLog>();
Debugger = Substitute.For<IDebugger>();
}

public DebugScriptHost CreateHost()
{
return new DebugScriptHost(Engine, Context, Printer, Log, Debugger);
}

public CakeReport RunTarget(string target)
{
return CreateHost().RunTarget(target);
}
}
}
32 changes: 32 additions & 0 deletions src/Cake.Tests/Unit/Arguments/ArgumentParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,22 @@ public void Can_Parse_Version(string input)
// Then
Assert.Equal(true, result.ShowVersion);
}

[Theory]
[InlineData("-debug")]
[InlineData("-d")]
public void Can_Parse_Debug(string input)
{
// Given
var fixture = new ArgumentParserFixture();
var parser = new ArgumentParser(fixture.Log, fixture.VerbosityParser);

// When
var result = parser.Parse(new[] { "build.csx", input });

// Then
Assert.Equal(true, result.PerformDebug);
}
}

public sealed class WithTwoDashLongArguments
Expand Down Expand Up @@ -467,6 +483,22 @@ public void Can_Parse_Version(string input)
// Then
Assert.Equal(true, result.ShowVersion);
}

[Theory]
[InlineData("--debug")]
[InlineData("-d")]
public void Can_Parse_Debug(string input)
{
// Given
var fixture = new ArgumentParserFixture();
var parser = new ArgumentParser(fixture.Log, fixture.VerbosityParser);

// When
var result = parser.Parse(new[] { "build.csx", input });

// Then
Assert.Equal(true, result.PerformDebug);
}
}
}
}
Expand Down
109 changes: 109 additions & 0 deletions src/Cake.Tests/Unit/Scripting/DebugScriptHostTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using Cake.Core;
using Cake.Core.Diagnostics;
using Cake.Scripting;
using Cake.Tests.Fixtures;
using NSubstitute;
using Xunit;

namespace Cake.Tests.Unit.Scripting
{
public sealed class DebugScriptHostTests
{
public sealed class TheRunTargetMethod
{
[Fact]
public void Should_Proxy_Call_To_Engine()
{
// Given
var fixture = new DebugScriptHostFixture();
var engine = fixture.Engine;
var context = fixture.Context;

// When
fixture.RunTarget("Target");

// Then
engine.Received(1).RunTarget(context, Arg.Any<DefaultExecutionStrategy>(), "Target");
}

[Fact]
public void Should_Print_Report()
{
// Given
var fixture = new DebugScriptHostFixture();
var engine = fixture.Engine;
var context = fixture.Context;
var printer = fixture.Printer;

var report = new CakeReport();
report.Add("Target", TimeSpan.FromSeconds(1));
engine.RunTarget(context, Arg.Any<DefaultExecutionStrategy>(), "Target").Returns(report);

// When
fixture.RunTarget("Target");

// Then
printer.Received(1).Write(report);
}

[Fact]
public void Should_Not_Print_Report_That_Is_Null()
{
// Given
var fixture = new DebugScriptHostFixture();
var engine = fixture.Engine;
var context = fixture.Context;
var printer = fixture.Printer;

var report = new CakeReport();
report.Add("Target", TimeSpan.FromSeconds(1));
engine.RunTarget(context, Arg.Any<DefaultExecutionStrategy>(), "Target").Returns((CakeReport)null);

// When
fixture.RunTarget("Target");

// Then
printer.Received(0).Write(Arg.Any<CakeReport>());
}

[Fact]
public void Should_Not_Print_Report_That_Is_Empty()
{
// Given
var fixture = new DebugScriptHostFixture();
var engine = fixture.Engine;
var context = fixture.Context;
var printer = fixture.Printer;

var report = new CakeReport();
report.Add("Target", TimeSpan.FromSeconds(1));
engine.RunTarget(context, Arg.Any<DefaultExecutionStrategy>(), "Target").Returns(new CakeReport());

// When
fixture.RunTarget("Target");

// Then
printer.Received(0).Write(Arg.Any<CakeReport>());
}

[Fact]
public void Should_Report_Correct_Process_Id()
{
// Given
var fixture = new DebugScriptHostFixture();
var debugger = fixture.Debugger;
var log = fixture.Log;
var pid = 1234567;

debugger.GetProcessId().Returns(pid);

// When
fixture.RunTarget("Target");

// Then
log.Received(1).Information(Verbosity.Quiet, Arg.Any<string>(), pid);
}
}
}
}
6 changes: 6 additions & 0 deletions src/Cake/Arguments/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ private bool ParseOption(string name, string value, CakeOptions options)
options.ShowVersion = true;
}

if (name.Equals("debug", StringComparison.OrdinalIgnoreCase) ||
name.Equals("d", StringComparison.OrdinalIgnoreCase))
{
options.PerformDebug = true;
}

if (options.Arguments.ContainsKey(name))
{
_log.Error("Multiple arguments with the same name ({0}).", name);
Expand Down
3 changes: 3 additions & 0 deletions src/Cake/Autofac/CakeModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,17 @@ protected override void Load(ContainerBuilder builder)
builder.RegisterType<ScriptRunner>().As<IScriptRunner>().SingleInstance();
builder.RegisterType<CakeBuildLog>().As<ICakeLog>().As<IVerbosityAwareLog>().SingleInstance();
builder.RegisterType<VerbosityParser>().SingleInstance();
builder.RegisterType<CakeDebugger>().As<IDebugger>().SingleInstance();

// Register script hosts.
builder.RegisterType<BuildScriptHost>().SingleInstance();
builder.RegisterType<DebugScriptHost>().SingleInstance();
builder.RegisterType<DescriptionScriptHost>().SingleInstance();
builder.RegisterType<DryRunScriptHost>().SingleInstance();

// Register commands.
builder.RegisterType<BuildCommand>().AsSelf().InstancePerDependency();
builder.RegisterType<DebugCommand>().AsSelf().InstancePerDependency();
builder.RegisterType<DescriptionCommand>().AsSelf().InstancePerDependency();
builder.RegisterType<DryRunCommand>().AsSelf().InstancePerDependency();
builder.RegisterType<HelpCommand>().AsSelf().InstancePerDependency();
Expand Down
15 changes: 13 additions & 2 deletions src/Cake/Autofac/ScriptingModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,19 @@ protected override void Load(ContainerBuilder builder)
{
// Roslyn
builder.RegisterType<RoslynScriptEngine>().As<IScriptEngine>().SingleInstance();
builder.RegisterType<RoslynScriptSessionFactory>().SingleInstance();
builder.RegisterType<RoslynNightlyScriptSessionFactory>().SingleInstance();

if (_options.Arguments.ContainsKey("debug"))
{
// Debug
builder.RegisterType<DebugRoslynScriptSessionFactory>().As<RoslynScriptSessionFactory>().SingleInstance();
builder.RegisterType<DebugRoslynNightlyScriptSessionFactory>().As<RoslynNightlyScriptSessionFactory>().SingleInstance();
}
else
{
// Default
builder.RegisterType<DefaultRoslynScriptSessionFactory>().As<RoslynScriptSessionFactory>().SingleInstance();
builder.RegisterType<DefaultRoslynNightlyScriptSessionFactory>().As<RoslynNightlyScriptSessionFactory>().SingleInstance();
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/Cake/Cake.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
<Compile Include="CakeReportPrinter.cs" />
<Compile Include="Commands\BuildCommand.cs" />
<Compile Include="Commands\CommandFactory.cs" />
<Compile Include="Commands\DebugCommand.cs" />
<Compile Include="Commands\DescriptionCommand.cs" />
<Compile Include="Commands\DryRunCommand.cs" />
<Compile Include="Commands\ErrorCommandDecorator.cs" />
Expand All @@ -146,17 +147,20 @@
<Compile Include="Commands\VersionCommand.cs" />
<Compile Include="Diagnostics\CakeBuildLog.cs" />
<Compile Include="Diagnostics\ConsolePalette.cs" />
<Compile Include="Diagnostics\CakeDebugger.cs" />
<Compile Include="Diagnostics\Formatting\FormatParser.cs" />
<Compile Include="Diagnostics\Formatting\FormatToken.cs" />
<Compile Include="Diagnostics\Formatting\LiteralToken.cs" />
<Compile Include="Diagnostics\Formatting\PropertyToken.cs" />
<Compile Include="Diagnostics\IDebugger.cs" />
<Compile Include="Diagnostics\IVerbosityAware.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="..\SolutionInfo.cs">
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="Scripting\BuildScriptHost.cs" />
<Compile Include="Scripting\DebugScriptHost.cs" />
<Compile Include="Scripting\DescriptionScriptHost.cs" />
<Compile Include="Scripting\DryRunExecutionStrategy.cs" />
<Compile Include="Scripting\DryRunScriptHost.cs" />
Expand All @@ -168,12 +172,20 @@
<Compile Include="Scripting\Mono\CodeGen\Parsing\ScriptBlock.cs" />
<Compile Include="Scripting\Mono\CodeGen\Parsing\ScriptParser.cs" />
<Compile Include="Scripting\Mono\CodeGen\MonoScriptProcessor.cs" />
<Compile Include="Scripting\Roslyn\Nightly\DefaultRoslynNightlyScriptSession.cs" />
<Compile Include="Scripting\Roslyn\Nightly\DebugRoslynNightlyScriptSession.cs" />
<Compile Include="Scripting\Roslyn\Nightly\RoslynNightlyScriptSession.cs" />
<Compile Include="Scripting\Roslyn\Nightly\DebugRoslynNightlyScriptSessionFactory.cs" />
<Compile Include="Scripting\Roslyn\Nightly\DefaultRoslynNightlyScriptSessionFactory.cs" />
<Compile Include="Scripting\Roslyn\Nightly\RoslynNightlyScriptSessionFactory.cs" />
<Compile Include="Scripting\Roslyn\RoslynCodeGenerator.cs" />
<Compile Include="Scripting\Roslyn\Stable\RoslynScriptSession.cs" />
<Compile Include="Scripting\Roslyn\Stable\DebugRoslynScriptSession.cs" />
<Compile Include="Scripting\Roslyn\Stable\DefaultRoslynScriptSession.cs" />
<Compile Include="Scripting\Roslyn\RoslynScriptEngine.cs" />
<Compile Include="Scripting\Roslyn\Stable\RoslynScriptSessionFactory.cs" />
<Compile Include="Scripting\Roslyn\Stable\DebugRoslynScriptSessionFactory.cs" />
<Compile Include="Scripting\Roslyn\Stable\DefaultRoslynScriptSessionFactory.cs" />
<Compile Include="Scripting\Mono\MonoScriptSession.cs" />
<Compile Include="Scripting\Mono\MonoScriptEngine.cs" />
<Compile Include="Scripting\Mono\CodeGen\MonoCodeGenerator.cs" />
Expand Down
4 changes: 4 additions & 0 deletions src/Cake/CakeApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ private ICommand CreateCommand(CakeOptions options)
{
return _commandFactory.CreateDescriptionCommand();
}
if (options.PerformDebug)
{
return _commandFactory.CreateDebugCommand();
}

return _commandFactory.CreateBuildCommand();
}
Expand Down
8 changes: 8 additions & 0 deletions src/Cake/CakeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ public IDictionary<string, string> Arguments
/// </value>
public bool PerformDryRun { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to debug script.
/// </summary>
/// <value>
/// <c>true</c> if a debug session should be started; otherwise, <c>false</c>.
/// </value>
public bool PerformDebug { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to show help.
/// </summary>
Expand Down
8 changes: 8 additions & 0 deletions src/Cake/Commands/CommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@
internal sealed class CommandFactory : ICommandFactory
{
private readonly BuildCommand.Factory _buildCommandFactory;
private readonly DebugCommand.Factory _debugCommandFactory;
private readonly DescriptionCommand.Factory _descriptionCommandFactory;
private readonly DryRunCommand.Factory _dryRunCommandFactory;
private readonly HelpCommand.Factory _helpCommandFactory;
private readonly VersionCommand.Factory _versionCommandFactory;

public CommandFactory(
BuildCommand.Factory buildCommandFactory,
DebugCommand.Factory debugCommandFactory,
DescriptionCommand.Factory descriptionCommandFactory,
DryRunCommand.Factory dryRunCommandFactory,
HelpCommand.Factory helpCommandFactory,
VersionCommand.Factory versionCommandFactory)
{
_buildCommandFactory = buildCommandFactory;
_debugCommandFactory = debugCommandFactory;
_descriptionCommandFactory = descriptionCommandFactory;
_dryRunCommandFactory = dryRunCommandFactory;
_helpCommandFactory = helpCommandFactory;
Expand All @@ -27,6 +30,11 @@ public ICommand CreateBuildCommand()
return _buildCommandFactory();
}

public ICommand CreateDebugCommand()
{
return _debugCommandFactory();
}

public ICommand CreateDescriptionCommand()
{
return _descriptionCommandFactory();
Expand Down
Loading

0 comments on commit 659c665

Please sign in to comment.