Skip to content

Commit a70a81b

Browse files
committed
# Support to run generated assembly with debug capabilities
1 parent 19a772f commit a70a81b

7 files changed

Lines changed: 118 additions & 16 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Reflection;
4+
5+
namespace ScriptCs
6+
{
7+
public class ConsoleCompiledDllDebugger : ICompiledDllDebugger
8+
{
9+
private const string CompiledScriptClass = "Submission#0";
10+
private const string CompiledScriptMethod = "<Factory>";
11+
private const string AttachMessageTemplate =
12+
"Attach to process {0} and press ENTER. Then use the 'go' command in the debugger.";
13+
14+
public void Run(string dllPath, ISession session)
15+
{
16+
var assembly = Assembly.LoadFrom(dllPath);
17+
var type = assembly.GetType(CompiledScriptClass);
18+
var method = type.GetMethod(CompiledScriptMethod, BindingFlags.Static | BindingFlags.Public);
19+
20+
var pid = Process.GetCurrentProcess().Id;
21+
Console.WriteLine(AttachMessageTemplate, pid);
22+
Console.ReadLine();
23+
24+
method.Invoke(null, new[] { session.WrappedSession });
25+
}
26+
}
27+
}

src/ScriptCs.Core/DebugScriptExecutor.cs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
1-
namespace ScriptCs
2-
{
3-
using System.ComponentModel.Composition;
4-
using System.IO;
5-
6-
using Roslyn.Compilers.Common;
7-
8-
using ScriptCs.Exceptions;
1+
using System.ComponentModel.Composition;
2+
using System.IO;
3+
using ScriptCs.Exceptions;
94

5+
namespace ScriptCs
6+
{
107
[Export(Constants.DebugContractName, typeof(IScriptExecutor))]
118
public class DebugScriptExecutor : ScriptExecutor
129
{
10+
private readonly ICompiledDllDebugger compiledDllDebugger;
11+
1312
[ImportingConstructor]
14-
public DebugScriptExecutor(IFileSystem fileSystem, [Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, IScriptHostFactory scriptHostFactory)
13+
public DebugScriptExecutor(
14+
IFileSystem fileSystem,
15+
[Import(Constants.DebugContractName)]IFilePreProcessor filePreProcessor,
16+
IScriptEngine scriptEngine,
17+
ICompiledDllDebugger compiledDllDebugger,
18+
IScriptHostFactory scriptHostFactory)
1519
: base(fileSystem, filePreProcessor, scriptEngine, scriptHostFactory)
1620
{
21+
this.compiledDllDebugger = compiledDllDebugger;
1722
}
1823

19-
public DebugScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine)
20-
: base(fileSystem, filePreProcessor, scriptEngine)
24+
public DebugScriptExecutor(
25+
IFileSystem fileSystem,
26+
IFilePreProcessor filePreProcessor,
27+
IScriptEngine scriptEngine,
28+
ICompiledDllDebugger compiledDllDebugger)
29+
: this(fileSystem, filePreProcessor, scriptEngine, compiledDllDebugger, new ScriptHostFactory())
2130
{
2231
}
2332

@@ -42,7 +51,7 @@ protected override void Execute(string absolutePathToScript, ISession session, s
4251

4352
if (result.Success)
4453
{
45-
54+
this.compiledDllDebugger.Run(outputPath, session);
4655
}
4756
else
4857
{
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.ComponentModel.Composition;
2+
3+
namespace ScriptCs
4+
{
5+
[InheritedExport]
6+
public interface ICompiledDllDebugger
7+
{
8+
void Run(string dllPath, ISession session);
9+
}
10+
}

src/ScriptCs.Core/ISession.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
namespace ScriptCs
1+
using Roslyn.Scripting;
2+
3+
namespace ScriptCs
24
{
35
public interface ISession
46
{
57
IScriptEngine Engine { get; }
8+
Session WrappedSession { get; }
69
object Execute(string code);
710
void AddReference(string assemblyDisplayNameOrPath);
811
void ImportNamespace(string @namespace);

src/ScriptCs.Core/ScriptCs.Core.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
</ItemGroup>
3333
<ItemGroup>
3434
<Compile Include="CompilationResult.cs" />
35+
<Compile Include="ConsoleCompiledDllDebugger.cs" />
3536
<Compile Include="DebugFilePreProcessor.cs" />
3637
<Compile Include="DebugScriptExecutor.cs" />
3738
<Compile Include="Exceptions\CompilationException.cs" />
@@ -46,6 +47,7 @@
4647
<Compile Include="FileSystem.cs" />
4748
<Compile Include="ICompilation.cs" />
4849
<Compile Include="ICompilationResult.cs" />
50+
<Compile Include="ICompiledDllDebugger.cs" />
4951
<Compile Include="IFilePreProcessor.cs" />
5052
<Compile Include="IFileSystem.cs" />
5153
<Compile Include="IPackageAssemblyResolver.cs" />

src/ScriptCs.Core/Wrappers/SessionWrapper.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ public IScriptEngine Engine
1919
}
2020
}
2121

22+
public Session WrappedSession
23+
{
24+
get
25+
{
26+
return this._session;
27+
}
28+
}
29+
2230
public object Execute(string code)
2331
{
2432
return this._session.Execute(code);

test/ScriptCs.Core.Tests/DebugScriptExecutorTests.cs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public static DebugScriptExecutor CreateScriptExecutor(
1616
Mock<IFileSystem> fileSystem = null,
1717
Mock<IFilePreProcessor> fileProcessor = null,
1818
Mock<IScriptEngine> scriptEngine = null,
19-
Mock<IScriptHostFactory> scriptHostFactory = null)
19+
Mock<IScriptHostFactory> scriptHostFactory = null,
20+
Mock<ICompiledDllDebugger> compiledDllDebugger = null)
2021
{
2122
if (fileSystem == null)
2223
{
@@ -40,13 +41,15 @@ public static DebugScriptExecutor CreateScriptExecutor(
4041
scriptEngine.Setup(e => e.CreateSession(It.IsAny<ScriptHost>())).Returns(mockSession.Object);
4142
}
4243

44+
compiledDllDebugger = compiledDllDebugger ?? new Mock<ICompiledDllDebugger>();
45+
4346
if (scriptHostFactory == null)
4447
{
45-
return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object);
48+
return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, compiledDllDebugger.Object);
4649
}
4750
else
4851
{
49-
return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, scriptHostFactory.Object);
52+
return new DebugScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, compiledDllDebugger.Object, scriptHostFactory.Object);
5053
}
5154
}
5255

@@ -175,6 +178,46 @@ public void ShouldThrowCompilationExceptionIfCompilationFails()
175178
compilationResult.Verify(r => r.ErrorMessage, Times.Once());
176179
compilationResult.Verify(r => r.Success, Times.Once());
177180
}
181+
182+
[Fact]
183+
public void ShouldRunCompileAssemblyRunnerOnOutputPathIfCompilationSucceeds()
184+
{
185+
// arrange
186+
var scriptEngine = new Mock<IScriptEngine>();
187+
var session = new Mock<ISession>();
188+
var submission = new Mock<ISubmission<object>>();
189+
var compilation = new Mock<ICompilation>();
190+
var compilationResult = new Mock<ICompilationResult>();
191+
var compiledDllDebugger = new Mock<ICompiledDllDebugger>();
192+
193+
compilationResult.Setup(r => r.Success).Returns(true).Verifiable();
194+
195+
const string PathToScript = @"C:\script.csx";
196+
const string BinDir = @"C:\bin";
197+
const string OutputDllName = "script.dll";
198+
var dllFullPath = Path.Combine(BinDir, OutputDllName);
199+
200+
scriptEngine.Setup(e => e.CreateSession(It.IsAny<ScriptHost>())).Returns(session.Object);
201+
scriptEngine.SetupProperty(e => e.BaseDirectory);
202+
203+
session.Setup(s => s.CompileSubmission<object>(It.IsAny<string>())).Returns(submission.Object);
204+
session.Setup(s => s.Engine).Returns(scriptEngine.Object);
205+
206+
submission.Setup(s => s.Compilation).Returns(compilation.Object);
207+
208+
compilation.Setup(c => c.Emit(It.IsAny<Stream>(), It.IsAny<Stream>())).Returns(compilationResult.Object).Verifiable();
209+
210+
compiledDllDebugger.Setup(r => r.Run(dllFullPath, session.Object)).Verifiable();
211+
212+
var scriptExecutor = DebugScriptExecutorTests.CreateScriptExecutor(scriptEngine: scriptEngine, compiledDllDebugger: compiledDllDebugger);
213+
214+
// act
215+
scriptExecutor.Execute(PathToScript, Enumerable.Empty<string>(), Enumerable.Empty<IScriptPack>());
216+
217+
// assert
218+
compilationResult.Verify(r => r.Success, Times.Once());
219+
compiledDllDebugger.Verify(r => r.Run(dllFullPath, session.Object), Times.Once());
220+
}
178221
}
179222
}
180223
}

0 commit comments

Comments
 (0)